/*******************************************************************************
* Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH 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
*******************************************************************************/
/*
* generated by Xtext
*/
package de.gebit.integrity.formatting;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.formatting.impl.AbstractDeclarativeFormatter;
import org.eclipse.xtext.formatting.impl.FormattingConfig;
import org.eclipse.xtext.parsetree.reconstr.ITokenStream;
import de.gebit.integrity.services.DSLGrammarAccess;
/**
* This class contains custom formatting description.
*
* see : http://www.eclipse.org/Xtext/documentation/latest/xtext.html#formatting on how and when to use it
*
* Also see {@link org.eclipse.xtext.xtext.XtextFormattingTokenSerializer} as an example
*
* @author Rene Schneider - initial API and implementation
*/
public class DSLFormatter extends AbstractDeclarativeFormatter {
@Override
protected void configureFormatting(FormattingConfig aConfig) {
DSLGrammarAccess tempGrammar = (DSLGrammarAccess) getGrammarAccess();
// No line wrapping
aConfig.setAutoLinewrap(9999);
// No spaces after opening bracket or before closing bracket of custom operations...
aConfig.setNoSpace().after(tempGrammar.getCustomOperationAccess().getLeftSquareBracketKeyword_0());
aConfig.setNoSpace().before(tempGrammar.getCustomOperationAccess()
.getPrefixOperandValueOrEnumValueOrOperationCollectionParserRuleCall_2_0_0());
aConfig.setNoSpace().after(tempGrammar.getCustomOperationAccess()
.getPostfixOperandValueOrEnumValueOrOperationCollectionParserRuleCall_4_2_0());
aConfig.setNoSpace().before(tempGrammar.getCustomOperationAccess().getRightSquareBracketKeyword_6());
// ...and the same with standard operations
aConfig.setNoSpace().after(tempGrammar.getStandardOperationAccess().getLeftParenthesisKeyword_0());
aConfig.setNoSpace().before(tempGrammar.getStandardOperationAccess()
.getFirstOperandValueOrEnumValueOrOperationParserRuleCall_2_0());
aConfig.setNoSpace().after(tempGrammar.getStandardOperationAccess()
.getMoreOperandsValueOrEnumValueOrOperationParserRuleCall_4_2_0());
aConfig.setNoSpace().before(tempGrammar.getStandardOperationAccess().getRightParenthesisKeyword_5());
// No spaces at the end of lines and before whitespace between tokens
aConfig.setNoSpace().before(tempGrammar.getNLRule());
aConfig.setNoSpace().before(tempGrammar.getNLFORCEDRule());
aConfig.setNoSpace().before(tempGrammar.getNEWLINERule());
aConfig.setNoSpace().around(tempGrammar.getModelAccess().getNLParserRuleCall_1());
// No spaces before colons, commas, after pluses or before/after hashes
aConfig.setNoSpace().before(tempGrammar.getValueOrEnumValueOrOperationCollectionAccess().getCommaKeyword_1_1());
aConfig.setNoSpace().before(tempGrammar.getForkParameterAccess().getColonKeyword_2());
aConfig.setNoSpace().before(tempGrammar.getParameterAccess().getColonKeyword_2());
aConfig.setNoSpace().before(tempGrammar.getSuiteParameterAccess().getColonKeyword_2());
aConfig.setNoSpace().before(tempGrammar.getVariantValueAccess().getColonKeyword_3());
aConfig.setNoSpace().after(tempGrammar.getArbitraryParameterOrResultNameAccess().getPlusSignKeyword_0());
aConfig.setNoSpace().around(tempGrammar.getMethodReferenceAccess().getNumberSignKeyword_1());
aConfig.setNoSpace().around(tempGrammar.getJavaConstantReferenceAccess().getNumberSignKeyword_1());
aConfig.setNoSpace().before(tempGrammar.getKeyValuePairAccess().getColonKeyword_2());
aConfig.setNoSpace().around(tempGrammar.getVariableAccess().getNumberSignKeyword_1_0());
// No spaces before/after encapsulating <>
aConfig.setNoSpace().after(tempGrammar.getJavaConstantValueAccess().getLessThanSignKeyword_0());
aConfig.setNoSpace().before(tempGrammar.getJavaConstantValueAccess().getGreaterThanSignKeyword_2());
aConfig.setNoSpace().after(tempGrammar.getTypedNestedObjectAccess().getLessThanSignKeyword_0());
aConfig.setNoSpace().before(tempGrammar.getTypedNestedObjectAccess().getGreaterThanSignKeyword_2());
// No spaces at the end of table lines
aConfig.setNoSpace().after(tempGrammar.getTableTestAccess().getVerticalLineKeyword_8_1());
aConfig.setNoSpace().after(tempGrammar.getParameterTableHeaderAccess().getVerticalLineKeyword_2());
aConfig.setNoSpace().after(tempGrammar.getResultTableHeaderAccess().getVerticalLineKeyword_3());
aConfig.setNoSpace().after(tempGrammar.getParameterTableValueAccess().getVerticalLineKeyword_2());
// No spaces before the 'T' divider in ISO date/time strings
aConfig.setNoSpace()
.after(tempGrammar.getIsoDateAndTimeValueAccess().getDateValueISODATETerminalRuleCall_0_0());
// Indentations
// Suites and Packages
aConfig.setIndentation(tempGrammar.getPackageDefinitionAccess().getPackagedefKeyword_0(),
tempGrammar.getPackageDefinitionAccess().getPackageendKeyword_6());
aConfig.setIndentation(tempGrammar.getSuiteDefinitionAccess().getSuitedefKeyword_1(),
tempGrammar.getSuiteDefinitionAccess().getSuiteendKeyword_12());
// Objects
aConfig.setIndentation(tempGrammar.getNestedObjectAccess().getLeftCurlyBracketKeyword_0(),
tempGrammar.getNestedObjectAccess().getRightCurlyBracketKeyword_3());
// Constant Variants
aConfig.setIndentation(tempGrammar.getVariantValueAccess().getNLParserRuleCall_1(),
tempGrammar.getVariantValueAccess().getValueAssignment_5());
// Tests and Calls
aConfig.setIndentation(tempGrammar.getTestAccess().getNLParserRuleCall_2(),
tempGrammar.getTestAccess().getNLParserRuleCall_7());
aConfig.setIndentation(tempGrammar.getCallAccess().getNLParserRuleCall_1(),
tempGrammar.getCallAccess().getNLParserRuleCall_7());
aConfig.setIndentation(tempGrammar.getTableTestAccess().getNLParserRuleCall_1(),
tempGrammar.getTableTestAccess().getNLFORCEDParserRuleCall_10());
}
@Override
public ITokenStream createFormatterStream(EObject aContext, String anIndent, ITokenStream anOut,
boolean aPreserveWhitespaces) {
return super.createFormatterStream(aContext, anIndent, new TableTestFormatterTokenStream(anOut),
aPreserveWhitespaces);
}
@Override
public ITokenStream createFormatterStream(String anIndent, ITokenStream anOut, boolean aPreserveWhitespaces) {
return super.createFormatterStream(anIndent, new TableTestFormatterTokenStream(anOut), aPreserveWhitespaces);
}
/**
* This token stream is basically a filter that sits between the streams, catches tables and formats them before
* they're forwarded.
*
* @author Rene Schneider - initial API and implementation
*
*/
public class TableTestFormatterTokenStream implements ITokenStream {
/**
* Creates a new instance.
*
* @param anOut
* the target stream
*/
public TableTestFormatterTokenStream(ITokenStream anOut) {
out = anOut;
DSLGrammarAccess tempGrammar = (DSLGrammarAccess) getGrammarAccess();
tableTestHeadStartRuleCall = tempGrammar.getTableTestAccess().getNLFORCEDParserRuleCall_4();
tableTestRowStartRuleCall = tempGrammar.getTableTestAccess().getNLFORCEDParserRuleCall_9_0();
tableTestEndRuleCall = tempGrammar.getTableTestAccess().getNLFORCEDParserRuleCall_10();
whitespaceRuleCall = tempGrammar.getNLAccess().getWSTerminalRuleCall_1();
tableColumnDelimiterKeywords.add(tempGrammar.getTableTestAccess().getVerticalLineKeyword_7());
tableColumnDelimiterKeywords.add(tempGrammar.getTableTestAccess().getVerticalLineKeyword_8_1());
tableColumnDelimiterKeywords.add(tempGrammar.getParameterTableHeaderAccess().getVerticalLineKeyword_0());
tableColumnDelimiterKeywords.add(tempGrammar.getParameterTableHeaderAccess().getVerticalLineKeyword_2());
tableColumnDelimiterKeywords.add(tempGrammar.getParameterTableValueAccess().getVerticalLineKeyword_0());
tableColumnDelimiterKeywords.add(tempGrammar.getParameterTableValueAccess().getVerticalLineKeyword_2());
tableColumnDelimiterKeywords.add(tempGrammar.getResultTableHeaderAccess().getVerticalLineKeyword_0());
tableColumnDelimiterKeywords.add(tempGrammar.getResultTableHeaderAccess().getVerticalLineKeyword_3());
}
/**
* The target stream.
*/
private ITokenStream out;
/**
* The buffer to store the table currently processed.
*/
private List<List<List<TokenTuple>>> tableBuffer = new ArrayList<List<List<TokenTuple>>>();
/**
* The current line in the current table.
*/
private List<List<TokenTuple>> currentTableLine;
/**
* The current cell in the current table.
*/
private List<TokenTuple> currentTableCell;
/**
* Whether we are inside a table at all.
*/
private boolean inTable;
/**
* The rule encountered at the beginning of a table.
*/
private final RuleCall tableTestHeadStartRuleCall;
/**
* The rule encountered at the beginning of a table row.
*/
private final RuleCall tableTestRowStartRuleCall;
/**
* The rule encountered at the end of a table.
*/
private final RuleCall tableTestEndRuleCall;
/**
* The whitespace rule.
*/
private final RuleCall whitespaceRuleCall;
/**
* The possible keywords which delimit a table column.
*/
private final Set<Keyword> tableColumnDelimiterKeywords = new HashSet<Keyword>();
@Override
public void flush() throws IOException {
out.flush();
}
@Override
public void writeHidden(EObject aGrammarElement, String aValue) throws IOException {
if (!inTable) {
out.writeHidden(aGrammarElement, aValue);
if (aGrammarElement == tableTestHeadStartRuleCall) {
startNewTable();
}
} else {
if (tableColumnDelimiterKeywords.contains(aGrammarElement)) {
concludeTableCell();
startNewTableCell();
} else if (aGrammarElement == tableTestRowStartRuleCall) {
concludeTableLine();
startNewTableLine();
}
currentTableCell.add(new TokenTuple(aGrammarElement, aValue));
if (aGrammarElement == tableTestEndRuleCall) {
concludeTable();
}
}
}
private void startNewTable() {
inTable = true;
tableBuffer.clear();
startNewTableLine();
}
private void concludeTable() throws IOException {
concludeTableLine();
inTable = false;
formatTable();
writeTableToOut();
}
private void concludeTableLine() {
concludeTableCell();
tableBuffer.add(currentTableLine);
currentTableLine = null;
}
private void concludeTableCell() {
currentTableLine.add(currentTableCell);
currentTableCell = null;
}
private void startNewTableLine() {
currentTableLine = new ArrayList<List<TokenTuple>>();
startNewTableCell();
}
private void startNewTableCell() {
currentTableCell = new ArrayList<TokenTuple>();
}
private void writeTableToOut() throws IOException {
for (List<List<TokenTuple>> tempLine : tableBuffer) {
for (List<TokenTuple> tempCell : tempLine) {
for (TokenTuple tempTuple : tempCell) {
tempTuple.writeHidden(out);
}
}
}
}
private void formatTable() {
List<Integer> tempColWidth = new ArrayList<Integer>();
for (int i = 0; i < 2; i++) {
boolean tempInSurveyMode = (i == 0);
for (List<List<TokenTuple>> tempLine : tableBuffer) {
int tempColumn = 0;
for (int k = 1; k < tempLine.size() - 1; k++) { // first isn't a cell, but the whitespace on the
// left, and last is the whitespace on the right
List<TokenTuple> tempCell = tempLine.get(k);
int tempLength = 0;
for (TokenTuple tempToken : tempCell) {
tempLength += tempToken.getValueLength();
}
if (tempInSurveyMode) {
// just see whether we have found a new max size
if (tempColWidth.size() > tempColumn) {
if (tempColWidth.get(tempColumn) < tempLength) {
tempColWidth.set(tempColumn, tempLength);
}
} else {
tempColWidth.add(tempLength);
}
} else {
// inflate the column width to the max size
int tempCharsToAdd = tempColWidth.get(tempColumn) - tempLength;
if (tempCharsToAdd > 0) {
tempCell.add(new TokenTuple(whitespaceRuleCall, generateWhitespace(tempCharsToAdd)));
}
}
tempColumn++;
}
}
}
}
private String generateWhitespace(int aNumberOfCharacters) {
StringBuffer tempBuffer = new StringBuffer();
for (int i = 0; i < aNumberOfCharacters; i++) {
tempBuffer.append(' ');
}
return tempBuffer.toString();
}
@Override
public void writeSemantic(EObject aGrammarElement, String aValue) throws IOException {
out.writeSemantic(aGrammarElement, aValue);
}
}
private static class TokenTuple {
/**
* The grammar element.
*/
private EObject grammarElement;
/**
* The string value.
*/
private String value;
public TokenTuple(EObject aGrammarElement, String aValue) {
grammarElement = aGrammarElement;
value = aValue;
}
public void writeHidden(ITokenStream anOut) throws IOException {
anOut.writeHidden(grammarElement, value);
}
public int getValueLength() {
if (value != null) {
return value.length();
} else {
return 0;
}
}
}
}