mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 16:58:56 +00:00
[formatter] Use configurable line separator
https://bugs.eclipse.org/bugs/show_bug.cgi?id=347782
This commit is contained in:
parent
08be34013d
commit
a29baf41f1
11 changed files with 143 additions and 25 deletions
|
@ -0,0 +1,21 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 itemis AG (http://www.itemis.eu) 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.formatting;
|
||||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.parsetree.reconstr.ITokenStream;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.3
|
||||
*/
|
||||
public interface IFormatterExtension {
|
||||
|
||||
ITokenStream createFormatterStream(EObject context, String initalIndentation, ITokenStream outputStream, boolean preserveWhitespaces);
|
||||
|
||||
}
|
|
@ -13,10 +13,15 @@ import java.io.FileOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.eclipse.emf.common.util.URI;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.EcoreUtil2;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.formatting.IElementMatcherProvider;
|
||||
import org.eclipse.xtext.formatting.IElementMatcherProvider.IElementMatcher;
|
||||
import org.eclipse.xtext.formatting.IIndentationInformation;
|
||||
import org.eclipse.xtext.formatting.ILineSeparatorInformation;
|
||||
import org.eclipse.xtext.formatting.IWhitespaceInformationProvider;
|
||||
import org.eclipse.xtext.formatting.impl.AbstractFormattingConfig.ElementPattern;
|
||||
import org.eclipse.xtext.parsetree.reconstr.IHiddenTokenHelper;
|
||||
import org.eclipse.xtext.parsetree.reconstr.ITokenStream;
|
||||
|
@ -43,13 +48,11 @@ public abstract class AbstractDeclarativeFormatter extends BaseFormatter {
|
|||
@Inject
|
||||
private IHiddenTokenHelper hiddenTokenHelper;
|
||||
|
||||
@Inject(optional = true)
|
||||
private IIndentationInformation indentInfo = new IIndentationInformation() {
|
||||
public String getIndentString() {
|
||||
return "\t";
|
||||
}
|
||||
};
|
||||
@Inject
|
||||
private IWhitespaceInformationProvider whitespaceInformationProvider;
|
||||
|
||||
private URI contextResourceURI;
|
||||
|
||||
@Inject
|
||||
private IElementMatcherProvider matcherProvider;
|
||||
|
||||
|
@ -60,10 +63,21 @@ public abstract class AbstractDeclarativeFormatter extends BaseFormatter {
|
|||
return new FormattingConfigBasedStream(out, indent, getConfig(), createMatcher(), hiddenTokenHelper,
|
||||
preserveWhitespaces);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @since 2.3
|
||||
*/
|
||||
@Override
|
||||
public ITokenStream createFormatterStream(EObject context, String indent, ITokenStream out, boolean preserveWhitespaces) {
|
||||
if(context != null)
|
||||
contextResourceURI = EcoreUtil2.getNormalizedResourceURI(context);
|
||||
return new FormattingConfigBasedStream(out, indent, getConfig(), createMatcher(), hiddenTokenHelper,
|
||||
preserveWhitespaces);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
protected FormattingConfig createFormattingConfig() {
|
||||
FormattingConfig cfg = new FormattingConfig(grammarAccess, hiddenTokenHelper, indentInfo);
|
||||
FormattingConfig cfg = new FormattingConfig2(grammarAccess, hiddenTokenHelper, getIndentInfo(), getLineSeparatorInfo());
|
||||
cfg.setWhitespaceRule(getWSRule());
|
||||
return cfg;
|
||||
}
|
||||
|
@ -89,9 +103,16 @@ public abstract class AbstractDeclarativeFormatter extends BaseFormatter {
|
|||
}
|
||||
|
||||
protected IIndentationInformation getIndentInfo() {
|
||||
return indentInfo;
|
||||
return whitespaceInformationProvider.getIndentationInformation(contextResourceURI);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @since 2.3
|
||||
*/
|
||||
protected ILineSeparatorInformation getLineSeparatorInfo() {
|
||||
return whitespaceInformationProvider.getLineSeparatorInformation(contextResourceURI);
|
||||
}
|
||||
|
||||
protected IElementMatcherProvider getMatcherProvider() {
|
||||
return matcherProvider;
|
||||
}
|
||||
|
|
|
@ -8,17 +8,26 @@
|
|||
package org.eclipse.xtext.formatting.impl;
|
||||
|
||||
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.formatting.IFormatter;
|
||||
import org.eclipse.xtext.formatting.IFormatterExtension;
|
||||
import org.eclipse.xtext.parsetree.reconstr.ITokenStream;
|
||||
|
||||
/**
|
||||
* @author Moritz Eysholdt - Initial contribution and API
|
||||
*/
|
||||
public abstract class AbstractFormatter implements IFormatter {
|
||||
public abstract class AbstractFormatter implements IFormatter, IFormatterExtension {
|
||||
|
||||
public ITokenStream createFormatterStream(String initalIndentation,
|
||||
ITokenStream outputStream, boolean preserveWhitespaces) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.3
|
||||
*/
|
||||
public ITokenStream createFormatterStream(EObject context, String initalIndentation, ITokenStream outputStream,
|
||||
boolean preserveWhitespaces) {
|
||||
return createFormatterStream(initalIndentation, outputStream, preserveWhitespaces);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.eclipse.xtext.parsetree.reconstr.ITokenStreamExtension;
|
|||
*/
|
||||
public abstract class AbstractTokenStream implements ITokenStreamExtension {
|
||||
|
||||
|
||||
public void flush() throws IOException {
|
||||
}
|
||||
|
||||
|
@ -32,4 +33,5 @@ public abstract class AbstractTokenStream implements ITokenStreamExtension {
|
|||
*/
|
||||
public void init(ParserRule startRule) {
|
||||
}
|
||||
|
||||
}
|
|
@ -20,7 +20,7 @@ public class BaseFormatter extends AbstractFormatter {
|
|||
|
||||
@Inject
|
||||
protected IGrammarAccess grammar;
|
||||
|
||||
|
||||
protected TerminalRule getWSRule() {
|
||||
// FIXME: make this configurable
|
||||
return (TerminalRule) GrammarUtil.findRuleForName(grammar.getGrammar(),
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.util.regex.Pattern;
|
|||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
import org.eclipse.xtext.formatting.IFormatter;
|
||||
import org.eclipse.xtext.formatting.IFormatterExtension;
|
||||
import org.eclipse.xtext.formatting.INodeModelStreamer;
|
||||
import org.eclipse.xtext.nodemodel.ICompositeNode;
|
||||
import org.eclipse.xtext.nodemodel.ILeafNode;
|
||||
|
@ -75,7 +76,11 @@ public class DefaultNodeModelFormatter extends AbstractNodeModelFormatter {
|
|||
String indent = getIndentation(root, offset);
|
||||
TokenStringBuffer buf = new TokenStringBuffer();
|
||||
ITokenStream out = offset == 0 ? buf : new FilterFirstWhitespaceStream(buf);
|
||||
ITokenStream fmt = formatter.createFormatterStream(indent, out, false);
|
||||
ITokenStream fmt;
|
||||
if(formatter instanceof IFormatterExtension)
|
||||
fmt = ((IFormatterExtension) formatter).createFormatterStream(root.getSemanticElement(), indent, out, false);
|
||||
else
|
||||
fmt = formatter.createFormatterStream(indent, out, false);
|
||||
try {
|
||||
ITextRegion range = nodeModelStreamer.feedTokenStream(fmt, root, offset, length);
|
||||
return new FormattedRegion(range.getOffset(), range.getLength(), buf.toString());
|
||||
|
@ -99,13 +104,13 @@ public class DefaultNodeModelFormatter extends AbstractNodeModelFormatter {
|
|||
}
|
||||
|
||||
// go backwards until first linewrap
|
||||
Pattern p = Pattern.compile("\\n([ \\t]*)");
|
||||
Pattern p = Pattern.compile("(\\n|\\r)([ \\t]*)");
|
||||
for (int i = r.size() - 1; i >= 0; i--) {
|
||||
Matcher m = p.matcher(r.get(i).getText());
|
||||
if (m.find()) {
|
||||
String ind = m.group(1);
|
||||
String ind = m.group(2);
|
||||
while (m.find())
|
||||
ind = m.group(1);
|
||||
ind = m.group(2);
|
||||
return ind;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,6 +170,10 @@ public class FormattingConfig extends AbstractFormattingConfig {
|
|||
whitespaceRule = rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link FormattingConfig2} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public FormattingConfig(IGrammarAccess grammarAccess, IHiddenTokenHelper hiddenTokenHelper,
|
||||
IIndentationInformation indentInfo) {
|
||||
super(grammarAccess, hiddenTokenHelper);
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012 itemis AG (http://www.itemis.eu) 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.formatting.impl;
|
||||
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.formatting.IIndentationInformation;
|
||||
import org.eclipse.xtext.formatting.ILineSeparatorInformation;
|
||||
import org.eclipse.xtext.parsetree.reconstr.IHiddenTokenHelper;
|
||||
|
||||
/**
|
||||
* @author Jan Koehnlein - Initial contribution and API
|
||||
* @since 2.3
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class FormattingConfig2 extends FormattingConfig {
|
||||
|
||||
protected ILineSeparatorInformation lineSeparatorInfo;
|
||||
|
||||
public FormattingConfig2(IGrammarAccess grammarAccess, IHiddenTokenHelper hiddenTokenHelper,
|
||||
IIndentationInformation indentInfo, ILineSeparatorInformation lineSeparatorInfo) {
|
||||
super(grammarAccess, hiddenTokenHelper, indentInfo);
|
||||
this.lineSeparatorInfo = lineSeparatorInfo;
|
||||
}
|
||||
|
||||
public ILineSeparatorInformation getLineSeparatorInfo() {
|
||||
return lineSeparatorInfo;
|
||||
}
|
||||
}
|
|
@ -277,9 +277,11 @@ public class FormattingConfigBasedStream extends BaseTokenStream {
|
|||
if (lastNLIndex >= 0)
|
||||
return (value.length() - lastNLIndex) - 1;
|
||||
if (preserveSpaces && leadingWS != null) {
|
||||
int lastNLIndexInLeadingWs = leadingWS.lastIndexOf('\n');
|
||||
int lastNLIndexInLeadingWs = leadingWS.lastIndexOf(getLineSeparator());
|
||||
if (lastNLIndexInLeadingWs >= 0)
|
||||
return ((leadingWS.length() - lastNLIndexInLeadingWs) + value.length()) - 1;
|
||||
// TODO Moritz: replaced -1 by -getLineSeparator.length()
|
||||
// is that correct?
|
||||
return ((leadingWS.length() - lastNLIndexInLeadingWs) + value.length()) - getLineSeparator().length();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -288,7 +290,7 @@ public class FormattingConfigBasedStream extends BaseTokenStream {
|
|||
if (leadingWS == null)
|
||||
return -1;
|
||||
int c = 0, i = -1;
|
||||
while ((i = leadingWS.indexOf('\n', i + 1)) >= 0)
|
||||
while ((i = leadingWS.indexOf(getLineSeparator(), i + getLineSeparator().length())) >= 0)
|
||||
c++;
|
||||
return c;
|
||||
}
|
||||
|
@ -316,7 +318,7 @@ public class FormattingConfigBasedStream extends BaseTokenStream {
|
|||
if (e instanceof SpaceLocator)
|
||||
return false;
|
||||
}
|
||||
return hiddenTokenHelper.getWhitespaceRuleFor(hiddenTokenDefinition, "\n") != null;
|
||||
return hiddenTokenHelper.getWhitespaceRuleFor(hiddenTokenDefinition, getLineSeparator()) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -345,14 +347,25 @@ public class FormattingConfigBasedStream extends BaseTokenStream {
|
|||
|
||||
protected boolean preserveSpaces;
|
||||
|
||||
public FormattingConfigBasedStream(ITokenStream out, String indentation, FormattingConfig cfg,
|
||||
public FormattingConfigBasedStream(ITokenStream out, String initialIndentation, FormattingConfig cfg,
|
||||
IElementMatcher<ElementPattern> matcher, IHiddenTokenHelper hiddenTokenHelper, boolean preserveSpaces) {
|
||||
super(out);
|
||||
this.cfg = cfg;
|
||||
this.matcher = matcher;
|
||||
this.hiddenTokenHelper = hiddenTokenHelper;
|
||||
this.preserveSpaces = preserveSpaces;
|
||||
this.indentationPrefix = indentation == null ? "" : indentation;
|
||||
this.indentationPrefix = initialIndentation == null ? "" : initialIndentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.3
|
||||
*/
|
||||
protected String getLineSeparator() {
|
||||
if (cfg instanceof FormattingConfig2) {
|
||||
return ((FormattingConfig2) cfg).getLineSeparatorInfo().getLineSeparator();
|
||||
} else {
|
||||
return System.getProperty("line.separator");
|
||||
}
|
||||
}
|
||||
|
||||
protected void addLineEntry(EObject grammarElement, String value, boolean isHidden) throws IOException {
|
||||
|
|
|
@ -16,12 +16,13 @@ import java.util.List;
|
|||
import org.eclipse.emf.common.util.Diagnostic;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.formatting.IFormatter;
|
||||
import org.eclipse.xtext.formatting.IFormatterExtension;
|
||||
import org.eclipse.xtext.parsetree.reconstr.IParseTreeConstructor.TreeConstructionReport;
|
||||
import org.eclipse.xtext.parsetree.reconstr.impl.TokenStringBuffer;
|
||||
import org.eclipse.xtext.parsetree.reconstr.impl.WriterTokenStream;
|
||||
import org.eclipse.xtext.util.ReplaceRegion;
|
||||
import org.eclipse.xtext.resource.SaveOptions;
|
||||
import org.eclipse.xtext.serializer.ISerializer;
|
||||
import org.eclipse.xtext.util.ReplaceRegion;
|
||||
import org.eclipse.xtext.validation.IConcreteSyntaxValidator;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
@ -52,7 +53,11 @@ public class Serializer implements ISerializer {
|
|||
throw new IConcreteSyntaxValidator.InvalidConcreteSyntaxException(
|
||||
"These errors need to be fixed before the model can be serialized.", diagnostics);
|
||||
}
|
||||
ITokenStream formatterTokenStream = formatter.createFormatterStream(null, tokenStream, !options.isFormatting());
|
||||
ITokenStream formatterTokenStream;
|
||||
if(formatter instanceof IFormatterExtension)
|
||||
formatterTokenStream = ((IFormatterExtension) formatter).createFormatterStream(obj, null, tokenStream, !options.isFormatting());
|
||||
else
|
||||
formatterTokenStream = formatter.createFormatterStream(null, tokenStream, !options.isFormatting());
|
||||
TreeConstructionReport report = parseTreeReconstructor.serializeSubtree(obj, formatterTokenStream);
|
||||
formatterTokenStream.flush();
|
||||
return report;
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.eclipse.emf.common.util.Diagnostic;
|
|||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.formatting.IFormatter;
|
||||
import org.eclipse.xtext.formatting.IFormatterExtension;
|
||||
import org.eclipse.xtext.nodemodel.ICompositeNode;
|
||||
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
|
||||
import org.eclipse.xtext.parsetree.reconstr.ITokenStream;
|
||||
|
@ -97,7 +98,11 @@ public class Serializer implements ISerializer {
|
|||
}
|
||||
|
||||
ISerializationDiagnostic.Acceptor errors = ISerializationDiagnostic.EXCEPTION_THROWING_ACCEPTOR;
|
||||
ITokenStream formatterTokenStream = formatter.createFormatterStream(null, tokenStream, !options.isFormatting());
|
||||
ITokenStream formatterTokenStream;
|
||||
if(formatter instanceof IFormatterExtension)
|
||||
formatterTokenStream = ((IFormatterExtension) formatter).createFormatterStream(obj, null, tokenStream, !options.isFormatting());
|
||||
else
|
||||
formatterTokenStream = formatter.createFormatterStream(null, tokenStream, !options.isFormatting());
|
||||
EObject context = getContext(obj);
|
||||
ISequenceAcceptor acceptor = new TokenStreamSequenceAdapter(formatterTokenStream, errors);
|
||||
serialize(obj, context, acceptor, errors);
|
||||
|
|
Loading…
Reference in a new issue