/*******************************************************************************
* Copyright (c) 2006-2015 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Kyu Lee <klee@redhat.com> - initial API and implementation
*******************************************************************************/
package org.eclipse.linuxtools.internal.changelog.core.editors;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.StringTokenizer;
import org.eclipse.jface.text.formatter.IFormattingStrategy;
public class ChangeLogFormattingStrategy implements IFormattingStrategy {
private static final String NEW_LINE_CHAR = "\n";
private static final String WHITE_SPACE_CHAR = " ";
private static final String TAB_SPACE_CHAR = "\t";
private static final String DELIMITER_CHARS = NEW_LINE_CHAR + WHITE_SPACE_CHAR + TAB_SPACE_CHAR;
private static final int MAX_WIDTH = 80;
private static final SimpleDateFormat isoDate = new SimpleDateFormat("yyyy-MM-dd");
@Override
public String format(String content, boolean isLineStart,
String indentation, int[] positions) {
String firstLine = "";
// if first line is not from the start, ignore it
if (!isLineStart) {
int eol;
if ((eol = content.indexOf(NEW_LINE_CHAR)) == content.length() - 1) {
return content;
} else {
firstLine = content.substring(0, eol + 1);
content = content.substring(eol + 1);
}
}
content.replaceFirst("(\\s+)?\\n(\\s+)?", NEW_LINE_CHAR);
StringTokenizer candidateWords = new StringTokenizer(content, DELIMITER_CHARS, true);
String formattedContent = formatContent(candidateWords, indentation.length());
return firstLine.concat(formattedContent);
}
private String formatContent(StringTokenizer candidateWords, int indentationLength) {
StringBuilder formattedWords = new StringBuilder();
int currentLineLength = indentationLength;
while (candidateWords.hasMoreTokens()) {
String cword = candidateWords.nextToken();
if (isDelimeter(cword)) {
continue;
}
// if the word is date, start new line and include
// names, email, then an empty line.
else if (isDate(cword)) {
// see if we are in middle of line and
// if so, start new line, else continue.
if (!isOnNewLine(formattedWords)) {
formattedWords.append(NEW_LINE_CHAR);
}
if (formattedWords.length() > 0) {
formattedWords.append(NEW_LINE_CHAR);
}
// insert date
formattedWords.append(cword + WHITE_SPACE_CHAR);
// insert name/email
while (candidateWords.hasMoreTokens()) {
cword = candidateWords.nextToken();
if (cword.equals(NEW_LINE_CHAR)) {
formattedWords.append(NEW_LINE_CHAR);
break;
}
if (isEmail(cword)) {
formattedWords.append(WHITE_SPACE_CHAR)
.append(WHITE_SPACE_CHAR)
.append(cword)
.append(NEW_LINE_CHAR)
.append(NEW_LINE_CHAR);
currentLineLength = indentationLength;
break;
}
if (!isDelimeter(cword)) {
formattedWords.append(WHITE_SPACE_CHAR).append(cword);
}
}
}
// means beginning of file name, so whole filename should be
// in one line.
else if (isStar(cword)) {
// see if we are in middle of line and
// if so, start new line, else continue.
if (!isOnNewLine(formattedWords)) {
formattedWords.append(NEW_LINE_CHAR);
currentLineLength = indentationLength;
}
formattedWords.append(TAB_SPACE_CHAR).append(cword);
currentLineLength += cword.length() + 1;
// this should be path name
if (candidateWords.countTokens() >= 2) {
candidateWords.nextToken();
cword = candidateWords.nextToken();
formattedWords.append(WHITE_SPACE_CHAR).append(cword);
currentLineLength += cword.length() + 1;
}
}
else if (cword.startsWith("(")) {
if (formattedWords.length() > 0) {
formattedWords.append(NEW_LINE_CHAR);
}
formattedWords.append(TAB_SPACE_CHAR);
currentLineLength = 1;
// add until closing bracket
boolean skipMultiWhiteSpace = false;
while (!cword.endsWith("):") && candidateWords.hasMoreTokens()) {
if (cword.equals(NEW_LINE_CHAR)) {
break;
}
if (cword.equals(WHITE_SPACE_CHAR) && !skipMultiWhiteSpace) {
formattedWords.append(cword);
currentLineLength += cword.length();
skipMultiWhiteSpace = true;
}
if (!isDelimeter(cword)) {
formattedWords.append(cword);
currentLineLength += cword.length();
skipMultiWhiteSpace = false;
}
cword = candidateWords.nextToken();
}
formattedWords.append(cword);
currentLineLength += cword.length();
}
else if (currentLineLength + cword.length() > MAX_WIDTH) {
formattedWords.append(NEW_LINE_CHAR)
.append(TAB_SPACE_CHAR)
.append(cword);
currentLineLength = indentationLength + cword.length();
} else {
if (isOnNewLine(formattedWords)) {
formattedWords.append(TAB_SPACE_CHAR);
} else {
formattedWords.append(WHITE_SPACE_CHAR);
}
formattedWords.append(cword);
currentLineLength += cword.length() + 1;
}
}
return formattedWords.toString();
}
private boolean isDate(String inputStr) {
try {
return isoDate.parse(inputStr) != null;
} catch (ParseException e) {
// Don't care
}
return false;
}
private boolean isEmail(String inputStr) {
return inputStr.startsWith("<") && inputStr.endsWith(">");
}
private boolean isStar(String inputStr) {
return inputStr.equals("*");
}
private boolean isDelimeter(String cword) {
return DELIMITER_CHARS.contains(cword);
}
private boolean isOnNewLine(StringBuilder formattedWords) {
int len = formattedWords.length();
return len == 0 || formattedWords.charAt(len - 1) == NEW_LINE_CHAR.charAt(0);
}
@Override
public void formatterStarts(String initialIndentation) {
}
@Override
public void formatterStops() {
}
}