[xtext][formatter] Javadoc proofreading

Also a few minor typos in method or parameter names.
Added two methods to interfaces to avoid bogus cast
operations in the implementation classes.

Change-Id: I662d3c9a1028e489b00adcbf6921a13f0d07f44c
This commit is contained in:
Sebastian Zarnekow 2015-02-11 14:06:55 +01:00
parent eb6ecc5183
commit 617965332c
39 changed files with 553 additions and 262 deletions

View file

@ -9,12 +9,12 @@ package org.eclipse.xtext.formatting2;
import java.util.List;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.xtext.AbstractRule;
import org.eclipse.xtext.Keyword;
import org.eclipse.xtext.RuleCall;
import org.eclipse.xtext.formatting2.internal.CommentReplacer;
import org.eclipse.xtext.formatting2.internal.FormattableDocument;
import org.eclipse.xtext.formatting2.internal.HiddenRegionFormatting;
import org.eclipse.xtext.formatting2.internal.HiddenRegionFormattingMerger;
import org.eclipse.xtext.formatting2.internal.HiddenRegionReplacer;
@ -38,38 +38,53 @@ import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.xbase.lib.Extension;
/**
* <p>
* This is an abstract base class for language-specific formatters.
* </p>
*
* <p>
* It is the formatters responsibility to create a list of text replacements, which, when applied to a text document,
* increase the documents readability for humans. At the same time the text changes should not have an impact on the
* semantic model a parser would create from the document.
* </p>
*
* <p>
* Formatters based on this class compute text replacements in two logical steps: First, they traverses the semantic
* model and collect {@link ITextReplacer}s. Each TextReplacer is responsible for a (small) section of the document. In
* a second step, the TextReplacers are are executed from the beginning to the end of the document and create the actual
* text replacements. This decoupling allows it to traverse the semantic model in arbitrary order and yet compute
* information that requires sequential processing of the document, e.g. indentation.
* model and collect {@link ITextReplacer text replaces}. Each replacer is responsible for a (small) section of the
* document. In a second step, the replacers are executed from the beginning to the end of the document and create the
* actual {@link TextReplacement text replacements}. This decoupling allows it to traverse the semantic model in
* arbitrary order and yet compute information that requires sequential processing of the document, e.g. indentation.
* </p>
*
* <p>
* To allow subclasses to implement this mechanism conveniently, there are several helper classes:
* </p>
*
* <ul>
* <li>{@link ITextRegionAccess} allows to obtain text regions for elements from the semantic model.</li>
* <li>{@link ITextReplacer} creates {@link ITextReplacement}s for a specific region in the document.</li>
* <li>{@link IFormattableDocument} collects {@link ITextReplacer}s and validates if they overlap.</li>
* <li>{@link ITextRegionAccess} allows to obtain text regions for elements in the semantic model.</li>
* <li>{@link ITextReplacer} creates {@link ITextReplacement replacements} for a specific region in the document.</li>
* <li>{@link IFormattableDocument} collects {@link ITextReplacer replacers} and validates if they overlap.</li>
* </ul>
*
* A formatter based on this class typically uses {@link ITextRegionAccess} to obtain the {@link IHiddenRegion} which
* precedes or trails EObjects, EStructuralFeatures, Keywords, RuleCalls. This {@link IHiddenRegion} represents the
* whitespace, newlines and comments between semantic tokens. No matter if there are zero or N hidden tokens between two
* semantic tokens, there is always exactly one {@link IHiddenRegion}. In other words, the {@link IHiddenRegion} groups
* all hidden tokens between two semantic tokens.
* <p>
* A formatter based on this class typically uses the {@link ITextRegionAccess} to obtain the {@link IHiddenRegion}
* which precedes or trails {@link EObject semantic object}, {@link EStructuralFeature features}, {@link Keyword
* keywords}, or {@link RuleCall rule calls}. This {@link IHiddenRegion} represents the whitespace, newlines and
* comments between semantic tokens. No matter if there are zero or N hidden tokens between two semantic tokens, there
* is always exactly one {@link IHiddenRegion}. In other words, the {@link IHiddenRegion} groups all hidden tokens
* between two semantic tokens.
* </p>
*
* <p>
* For the {@link IHiddenRegion}, the formatter will create a {@link ITextReplacer} and store the replacer in the
* {@link IFormattableDocument}. Typically this is a {@link HiddenRegionReplacer} parameterized with an
* {@link IHiddenRegionFormatting}. The {@link HiddenRegionReplacer} will then delegate to {@link WhitespaceReplacer} or
* {@link CommentReplacer}, depending on which kind of tokens are inside the hidden region.
* {@link IHiddenRegionFormatting}. The {@link HiddenRegionReplacer} will then delegate to a {@link WhitespaceReplacer}
* or {@link CommentReplacer}, depending on which kind of tokens are inside the hidden region.
* </p>
*
* To format a document with syntax confirming to the parser rule
* <p>
* To format a document with syntax confirming to the parser rule:
* </p>
*
* <pre>
* Entity:
@ -78,7 +93,9 @@ import org.eclipse.xtext.xbase.lib.Extension;
* '}';
* </pre>
*
* <p>
* the following formatter implementation (Xtend code) can be used:
* </p>
*
* <pre>
* def dispatch void format(Entity entity, extension IFormattableDocument document) {
@ -92,25 +109,42 @@ import org.eclipse.xtext.xbase.lib.Extension;
* }
* </pre>
*
* For the full example, see the DomainModel Example. It can be accessed via Eclipse -> File -> New -> Example.
* <p>
* For the full example, see the DomainModel Example. It can be accessed via {@code Eclipse -> File -> New -> Example.}
* </p>
*
* The class 'Entity' is part of the semantic model.
* <p>
* The class {@code Entity} is part of the semantic model.
* </p>
*
* The methods 'regionForFeature()' and 'regionForKeyword' are extension methods:
* <p>
* The methods {@code regionForFeature()} and {@code regionForKeyword} are extension methods:
* {@link ITextRegionAccess#regionForFeature(EObject, EStructuralFeature)} and
* {@link ITextRegionAccess#regionForKeyword(EObject, String)}. They return an {@link ISemanticRegion}.
* </p>
*
* The methods 'prepend', 'append' and 'surround' are extension methods from {@link IFormattableDocument}. They create
* and register an {@link HiddenRegionReplacer} for the {@link IHiddenRegion} before and/or after the provided
* {@link ISemanticRegion}.
* <p>
* The methods {@code prepend()}, {@code append()} and {@code surround()} are extension methods from
* {@link IFormattableDocument}. They create and register an {@link HiddenRegionReplacer} for the {@link IHiddenRegion}
* before and/or after the provided {@link ISemanticRegion}.
* </p>
*
* <p>
* Override {@code create*()} methods to customize formatter-local services.
* </p>
*
* @see org.eclipse.xtext.formatting2 for an introduction to the topic
* @see IFormatter2 to invoke a formatter
* <p>
* This implementation is stateful and cannot be used in parallel.
* </p>
*
* @see #format(Object, IFormattableDocument) - overwrite to implement a formatter
* @see #initalize(FormatterRequest) - overwrite to set values of member fields
* @see #reset() - overwrite to cleanup after execution
* @see "overwrite create*() methods to customize formatter-local services"
* @see org.eclipse.xtext.formatting2 The package {@code org.eclipse.xtext.formatting2} for an introduction to the topic
* @see IFormatter2 {@code IFormatter2}: the interface to invoke the formatter
*
* @see #format(Object, IFormattableDocument) The method {@code format(Object, IFormattableDocument)} should be
* overridden to implement a formatter
* @see #initalize(FormatterRequest) The method {@code initalize(FormatterRequest)} should be overridden to set values
* of member fields
* @see #reset() The method {@code reset()} should be overridden to cleanup after execution.
*
* @author Moritz Eysholdt - Initial contribution and API
* @since 2.8
@ -132,17 +166,17 @@ public abstract class AbstractFormatter2 implements IFormatter2 {
}
/**
* Fall-back for null-values in a subclasse's dispatch method.
* Fall-back for subclasses that accidently try to dispatch over null values.
*/
protected void _format(Void obj, IFormattableDocument document) {
}
/**
* For {@link XtextResource}s, assume we want to format the first EObject from the contents list only. Because
* For {@link XtextResource resources}, assume we want to format the first EObject from the contents list only. Because
* that's where the parser puts the semantic model.
*/
protected void _format(XtextResource resource, IFormattableDocument document) {
EList<EObject> contents = resource.getContents();
List<EObject> contents = resource.getContents();
if (!contents.isEmpty()) {
EObject model = contents.get(0);
format(model, document);
@ -166,10 +200,6 @@ public abstract class AbstractFormatter2 implements IFormatter2 {
throw new IllegalStateException("No " + ITextReplacer.class.getSimpleName() + " configured for " + elementName);
}
public IFormattableDocument createFormattableDocument() {
return new RootDocument(this);
}
public IFormattableSubDocument createFormattableSubDocument(ITextSegment region, IFormattableDocument parent) {
return new SubDocument(region, parent);
}
@ -201,15 +231,19 @@ public abstract class AbstractFormatter2 implements IFormatter2 {
public ITextReplacer createWhitespaceReplacer(ITextSegment hiddens, IHiddenRegionFormatting formatting) {
return new WhitespaceReplacer(hiddens, formatting);
}
public IFormattableDocument createFormattableRootDocument() {
return new RootDocument(this);
}
@Override
final public List<ITextReplacement> format(FormatterRequest request) {
public final List<ITextReplacement> format(FormatterRequest request) {
try {
initalize(request);
IFormattableDocument document = createFormattableDocument();
IFormattableDocument document = createFormattableRootDocument();
XtextResource xtextResource = request.getTextRegionAccess().getResource();
format(xtextResource, document);
List<ITextReplacement> replacements = ((FormattableDocument) document).renderToTextReplacements();
List<ITextReplacement> replacements = document.renderToTextReplacements();
return replacements;
} finally {
reset();

View file

@ -8,6 +8,9 @@
package org.eclipse.xtext.formatting2;
/**
* An exception to indicate that a region of the document was formatted with
* conflicting settings.
*
* @author Moritz Eysholdt - Initial contribution and API
*/
public class ConflictingFormattingException extends RuntimeException {

View file

@ -11,19 +11,20 @@ import static java.lang.System.*;
import org.eclipse.xtext.preferences.ITypedPreferenceValues;
import org.eclipse.xtext.preferences.IntegerKey;
import org.eclipse.xtext.preferences.PreferenceKeysProvider;
import org.eclipse.xtext.preferences.StringKey;
import org.eclipse.xtext.preferences.TypedPreferenceKey;
import org.eclipse.xtext.preferences.TypedPreferenceValues;
/**
* General preference keys used by this formatting infrastructure. Formatters based on this infrastructure should honor
* these keys as well.
* <p>General preference keys used by this formatting infrastructure. Formatters based on this infrastructure should honor
* these keys as well.</p>
*
* To set a values for one of these keys, use {@link FormatterRequest#setPreferences(ITypedPreferenceValues)}.
* <p>To set a values for one of these keys, use {@link FormatterRequest#setPreferences(ITypedPreferenceValues)}.</p>
*
* To access a value for one of these keys, use {@link AbstractFormatter2#getPreference(TypedPreferenceKey)}.
* <p>To access a value for one of these keys, use {@link AbstractFormatter2#getPreference(TypedPreferenceKey)}.</p>
*
* To introduce new keys, subclass this class.
* <p>To introduce new keys, subclass this class (see also {@link PreferenceKeysProvider#allConstantKeys(Class...)}.</p>
*
* @author Moritz Eysholdt - Initial contribution and API
* @since 2.8
@ -32,7 +33,7 @@ import org.eclipse.xtext.preferences.TypedPreferenceValues;
public class FormatterPreferenceKeys {
/**
* The characters used to wrap lines. Usually "\n" or "\r\n".
* The characters used to wrap lines. Usually {@code \n} or {@code \r\n}.
*/
public static StringKey lineSeparator = new StringKey("line.separator", getProperty("line.separator"));
@ -42,7 +43,7 @@ public class FormatterPreferenceKeys {
public static StringKey indentation = new StringKey("indentation", "\t");
/**
* The width of one level of indentation counted in characters. If {@link #indentation} is "\t" and the
* The width of one level of indentation counted in characters. If {@link #indentation} is {@code \t} and the
* display-width of one tab is fours, then this values should be four. The formatter uses this value to compute when
* {@link #maxLineWidth} has been exceeded.
*/

View file

@ -7,6 +7,7 @@
*******************************************************************************/
package org.eclipse.xtext.formatting2;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@ -15,15 +16,15 @@ import org.eclipse.xtext.preferences.IPreferenceValuesProvider;
import com.google.inject.BindingAnnotation;
/**
* A marker annotation for Google Guice.
* <p>Marks an instance of {@link IPreferenceValuesProvider} as the one that should be used by the formatter.</p>
*
* Marks an instance of {@link IPreferenceValuesProvider} as the one that should be used by the formatter.
* <p>A {@link BindingAnnotation marker annotation} for Google Guice.</p>
*
* @author Moritz Eysholdt - Initial contribution and API
* @since 2.8
*/
@BindingAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FormatterPreferences {
}

View file

@ -21,15 +21,18 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* A Request tells the formatter what and how to format.
* <p>A request tells the formatter what and how to format.</p>
*
* When invoking the formatter, the request is passed into {@link IFormatter2#format(FormatterRequest)}.
* <p>When invoking the formatter, the request is passed into {@link IFormatter2#format(FormatterRequest)}.</p>
*
* @see #textRegionAccess - the to-be-formatted semantic model with text regions.
* @see #preferences - provide for preferences key from e.g. {@link FormatterPreferenceKeys}.
* @see #regions - restrict the text regions for which {@link ITextReplacement}s are produced.
* @see #allowIdentityEdits - do not suppress text replacements that do not cause changes.
* @see #formatUndenfinedTokensOnly - only format regions that have no whitespace information yet.
* <p>A request carries information about:<p>
* <ul>
* <li> The {@link #textRegionAccess} which allows to obtain the to-be-formatted semantic model with text regions.</li>
* <li>{@link #preferences Preferences} with keys from e.g. {@link FormatterPreferenceKeys}.</li>
* <li>{@link #regions} that describe how to restrict the text regions for which {@link ITextReplacement replacements} are produced.</li>
* <li>An option to {@link #allowIdentityEdits()} which will disable to automated suppression of text replacements that do not cause changes.</li>
* <li>A setting for green-field formatting ({@link #formatUndenfinedTokensOnly}): only format regions that have no whitespace information yet.</li>
* </ul>
*
* @author Moritz Eysholdt - Initial contribution and API
* @since 2.8
@ -37,21 +40,30 @@ import com.google.common.collect.Maps;
public class FormatterRequest {
/**
* Restrict the formatter to produce {@link ITextReplacement}s inside the specified regions only. If no regions are
* Restrict the formatter to produce {@link ITextReplacement replacements} inside the specified regions only. If no regions are
* specified, the whole document is formatted.
*/
private Collection<ITextRegion> regions = Lists.newArrayList();
/**
* @see #regions
*/
public FormatterRequest addRegion(ITextRegion region) {
this.regions.add(region);
return this;
}
/**
* @see #regions
*/
public FormatterRequest setRegions(Collection<ITextRegion> regions) {
this.regions = regions;
return this;
}
/**
* @see #regions
*/
public Collection<ITextRegion> getRegions() {
return regions;
}
@ -61,6 +73,9 @@ public class FormatterRequest {
*/
private ITextRegionAccess textRegionAccess;
/**
* @see #textRegionAccess
*/
public ITextRegionAccess getTextRegionAccess() {
return textRegionAccess;
}
@ -78,18 +93,24 @@ public class FormatterRequest {
}
/**
* Allow the formatter to produce {@link ITextReplacement}s that replace regions with text equal to the text of the
* region. Since these TextReplacements do not cause text changes, one usually doens't want to have them in a
* Allow the formatter to produce {@link ITextReplacement replacements} that replace regions with text equal to the text of the
* region. Since these replacements do not cause text changes, one usually doens't want to have them in a
* production environment. However, they are useful to test if a formatter considers all significant regions, e.g.
* all {@link IHiddenRegion}s.
* all {@link IHiddenRegion hidden regions}.
*/
private boolean allowIdentityEdits;
/**
* @see #allowIdentityEdits
*/
public FormatterRequest setAllowIdentityEdits(boolean allowIdentityEdits) {
this.allowIdentityEdits = allowIdentityEdits;
return this;
}
/**
* @see #allowIdentityEdits
*/
public boolean allowIdentityEdits() {
return allowIdentityEdits;
}
@ -99,11 +120,17 @@ public class FormatterRequest {
*/
private ITypedPreferenceValues preferences;
/**
* @see #preferences
*/
public FormatterRequest setPreferences(ITypedPreferenceValues preferenceValues) {
this.preferences = preferenceValues;
return this;
}
/**
* @see #preferences
*/
public ITypedPreferenceValues getPreferences() {
if (preferences == null)
preferences = new MapBasedPreferenceValues(Maps.<String, String> newLinkedHashMap());
@ -111,34 +138,40 @@ public class FormatterRequest {
}
/**
* {@link IHiddenRegion}s are considers undefined when their whitespace/comments are unknown. This happens for
* HiddenRegions that emerged between programmatically created (not parsed!) model elements.
* {@link IHiddenRegion Hidden regions} are considered undefined when their whitespace/comments are unknown. This happens for
* regions that emerged between programmatically created (not parsed!) model elements.
*
* Enable this options if, for example, you serialize a model after applying a quick fix, refactoring or have it
* edited in a graphical editor and you want to keep the whitespace-changes to a minimum.
*/
private boolean formatUndenfinedTokensOnly;
/**
* @see #formatUndenfinedTokensOnly
*/
public boolean isFormatUndefinedHiddenRegionsOnly() {
return formatUndenfinedTokensOnly;
}
private boolean formatUndenfinedTokensOnly;
/**
* @see #formatUndenfinedTokensOnly
*/
public FormatterRequest setFormatUndenfinedTokensOnly(boolean formatUndenfinedTokensOnly) {
this.formatUndenfinedTokensOnly = formatUndenfinedTokensOnly;
return this;
}
/**
* Exceptions that occur during formatting are passed to this handler. The handler may choose to throw them, log
* them, or ignore them. Formatting continues, unless the handler throws an exception.
* <p>Exceptions that occur during formatting are passed to this handler. The handler may choose to throw them, log
* them, or ignore them. Formatting continues, unless the handler throws an exception.</p>
*
* Logging exceptions and continuing formatting is the default behavior.
* <p>Logging exceptions and continuing formatting is the default behavior.</p>
*
* Throwing exceptions is useful in unit tests.
* <p>Throwing exceptions is useful in unit tests.</p>
*
* Ignoring exceptions is useful when formatting a document with syntax errors.
* <p>Ignoring exceptions is useful when formatting a document with syntax errors.</p>
*
* Defaults to the {@link ExceptionAcceptor#LOGGING Logging Acceptor}
* <p>Defaults to the {@link ExceptionAcceptor#LOGGING Logging Acceptor}</p>
*
* @see ExceptionAcceptor#LOGGING
* @see ExceptionAcceptor#THROWING
@ -146,12 +179,18 @@ public class FormatterRequest {
*/
private IAcceptor<Exception> exceptionHandler;
/**
* @see #exceptionHandler
*/
public IAcceptor<Exception> getExceptionHandler() {
if (exceptionHandler == null)
return ExceptionAcceptor.LOGGING;
return exceptionHandler;
}
/**
* @see #exceptionHandler
*/
public FormatterRequest setExceptionHandler(IAcceptor<Exception> problemHandler) {
this.exceptionHandler = problemHandler;
return this;

View file

@ -7,6 +7,11 @@
*******************************************************************************/
package org.eclipse.xtext.formatting2;
/**
* Indicates that a condition formatting attempt failed.
*
* @author Moritz Eysholdt - Initial contribution and API
*/
@SuppressWarnings("serial")
public class FormattingNotApplicableException extends RuntimeException {
}

View file

@ -7,6 +7,16 @@
*******************************************************************************/
package org.eclipse.xtext.formatting2;
/**
* A strategy for formatting that is to be applied on auto wrapping.
*
* @author Moritz Eysholdt - Initial contribution and API
*
* @see IHiddenRegionFormatter#setOnAutowrap(IAutowrapFormatter)
*/
public interface IAutowrapFormatter { // TODO: add region
/**
* Called if the region is supposed to wrapped.
*/
void format(IHiddenRegionFormatter wrapped, IFormattableDocument document);
}

View file

@ -7,6 +7,8 @@
*******************************************************************************/
package org.eclipse.xtext.formatting2;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.formatting2.regionaccess.IHiddenRegion;
import org.eclipse.xtext.formatting2.regionaccess.ISemanticRegion;
@ -16,16 +18,22 @@ import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import com.google.common.base.Predicate;
/**
* A FormattableDocument is a stateful object that holds a list of {@link ITextReplacer}s. Each TextReplacer is
* responsible for a text region inside this document. The document can be populated with TextReplacers in any order.
* However, it is not possible and not intended to register two or more TextReplacers for the same or overlapping
* TextRegion.
* <p>
* A FormattableDocument is a stateful object that holds a list of {@link ITextReplacer replacers}. Each replacer is
* responsible for a text region inside this document. The document can be populated with replacers in any order.
* However, it is not possible and not intended to register two or more replacers for the same or overlapping
* {@link ITextSegment region}.
* </p>
*
* Eventually, all TextReplacers are invoked from the beginning of the document to the end of the document. Each
* TextReplacer produces {@link ITextReplacement}s for their region. A {@link ITextReplacerContext} is passed on from
* Replacer to Replacer and holds state such as the current indentation level.
* <p>
* Eventually, all replacers are invoked from the beginning of the document to the end of the document. Each replacer
* produces {@link ITextReplacement text replacements} for their region. A {@link ITextReplacerContext} is passed on
* from replacer to replacer and holds state such as the current indentation level.
* </p>
*
* Besides this, a FormattableDocument
* <p>
* Besides this, a formattable document
* </p>
* <ul>
* <li>offers convenience API to define formatting for HiddenRegions. See {@link ITextRegionAccess} for a definition of
* HiddenRegions and {@link IHiddenRegionFormatter} for how they can be formatted.</li>
@ -41,32 +49,99 @@ import com.google.common.base.Predicate;
*/
public interface IFormattableDocument {
IFormattableDocument withReplacerFilter(Predicate<ITextReplacer> filter);
/**
* Creates a delegate that allows to filter subsequent replacers based on the
* given condition. Replacers are used if the predicate yields <code>true</code>.
*/
IFormattableDocument withReplacerFilter(Predicate<? super ITextReplacer> filter);
/**
* Returns the region that is formatted.
*/
ITextSegment getRegion();
/**
* Returns the formatter that is being used.
*/
AbstractFormatter2 getFormatter();
/**
* Returns the current formatting request.
*/
FormatterRequest getRequest();
/**
* Add a new replacer to the document.
*/
void addReplacer(ITextReplacer replacer);
/**
* Render the document.
*/
List<ITextReplacement> renderToTextReplacements();
ISemanticRegion append(ISemanticRegion semanticRegion, Procedure1<IHiddenRegionFormatter> after);
/**
* Append the given semantic region and obtain the formatting information for trailing
* whitespace and comments from the given procedure.
*
* Returns the given semantic region.
*/
ISemanticRegion append(ISemanticRegion semanticRegion, Procedure1<? super IHiddenRegionFormatter> after);
<T extends EObject> T append(T semanticRegion, Procedure1<IHiddenRegionFormatter> after);
/**
* Append the given information and obtain the formatting information for trailing
* whitespace and comments from the given procedure.
*
* Returns the given semantic object.
*/
<T extends EObject> T append(T semanticRegion, Procedure1<? super IHiddenRegionFormatter> after);
/**
* Append the given semantic region and obtain the formatting information for leading
* whitespace and comments from the given procedure.
*
* Returns the given semantic region.
*/
ISemanticRegion prepend(ISemanticRegion semanticRegion, Procedure1<? super IHiddenRegionFormatter> before);
/**
* Append the given information and obtain the formatting information for leading
* whitespace and comments from the given procedure.
*
* Returns the given semantic object.
*/
<T extends EObject> T prepend(T semanticRegion, Procedure1<? super IHiddenRegionFormatter> before);
/**
* Append the given semantic region and obtain the formatting information for leading and trailing
* whitespace and comments from the given procedure.
*
* Returns the given semantic region.
*/
ISemanticRegion surround(ISemanticRegion semanticRegion, Procedure1<? super IHiddenRegionFormatter> beforeAndAfter);
/**
* Append the given information and obtain the formatting information for leading and trailing
* whitespace and comments from the given procedure.
*
* Returns the given semantic object.
*/
<T extends EObject> T surround(T owner, Procedure1<? super IHiddenRegionFormatter> beforeAndAfter);
/**
* Apply the formatting of the first sub formatter that succeeds to the given owner's region.
*/
void formatConditionally(EObject owner, ISubFormatter... formatters) throws FormattingNotApplicableException;
/**
* Apply the formatting of the first sub formatter that succeeds to the given region.
*/
void formatConditionally(int offset, int length, ISubFormatter... formatters)
throws FormattingNotApplicableException;
AbstractFormatter2 getFormatter();
/**
* Format the given hidden region with the initialized formatter.
*/
IHiddenRegion set(IHiddenRegion hiddenRegion, Procedure1<? super IHiddenRegionFormatter> init);
FormatterRequest getRequest();
ISemanticRegion prepend(ISemanticRegion semanticRegion, Procedure1<IHiddenRegionFormatter> before);
<T extends EObject> T prepend(T semanticRegion, Procedure1<IHiddenRegionFormatter> before);
IHiddenRegion set(IHiddenRegion hiddenRegion, Procedure1<IHiddenRegionFormatter> init);
ISemanticRegion surround(ISemanticRegion semanticRegion, Procedure1<IHiddenRegionFormatter> beforeAndAfter);
<T extends EObject> T surround(T owner, Procedure1<IHiddenRegionFormatter> beforeAndAfter);
}

View file

@ -7,6 +7,13 @@
*******************************************************************************/
package org.eclipse.xtext.formatting2;
/**
* A sub document describes the formatting for a part of the entire document.
*
* @author Moritz Eysholdt - Initial contribution and API
*
* @see AbstractFormatter2#createFormattableSubDocument(ITextSegment, IFormattableDocument)
*/
public interface IFormattableSubDocument extends IFormattableDocument {
IFormattableSubDocument requireFitsInLine(); // TODO: fits in line completely vs. first line fits in line.

View file

@ -10,14 +10,19 @@ package org.eclipse.xtext.formatting2;
import java.util.List;
/**
* <p>
* Use this interface to invoke a formatter.
* </p>
*
* <p>
* An Xtext language should have an implementation for this interface bound in its runtime module.
* </p>
*
* @see org.eclipse.xtext.formatting2 for an introduction to formatting
* @see AbstractFormatter2 to implement your own formatter
* @see FormatterRequest to specify what an how sould be formatted
* @see TextReplacements#apply(CharSequence, Iterable) to apply {@link ITextReplacement}s to a CharSequence or String.
* @see org.eclipse.xtext.formatting2 The package org.eclipse.xtext.formatting2 for an introduction to formatting
* @see AbstractFormatter2 The base class {@code AbstractFormatter2} to implement your own formatter.
* @see FormatterRequest The class {@code FormatterRequest} to specify what and how sould be formatted.
* @see TextReplacements#apply(CharSequence, Iterable) {@çode Textplacements#apply} to apply replacements to a
* CharSequence or String.
*
* @author Moritz Eysholdt - Initial contribution and API
* @since 2.8

View file

@ -8,6 +8,10 @@
package org.eclipse.xtext.formatting2;
/**
* An {@link IHiddenRegionFormatter} is used to build a formatting
* setting for a hidden region.
*
* @see IHiddenRegionFormatting
* @noimplement This interface is not intended to be implemented by clients.
* @noextend This interface is not intended to be extended by clients.
* @author Moritz Eysholdt - Initial contribution and API
@ -18,46 +22,123 @@ public interface IHiddenRegionFormatter {
final int LOW_PRIORITY = -1;
final int NORMAL_PRIORITY = 0;
/**
* Allows to obtain the configured formatting setting.
*/
IHiddenRegionFormatting asBean();
/**
* Configure autowrap. Same as {@link #autowrap(int) autowrap(0)}.
*/
void autowrap();
void autowrap(int triggerLenght);
void decreaseIndentation();
FormatterRequest getRequest();
void highPriority();
void increaseIndentation();
void noIndentation();
void lowPriority();
void newLine();
/**
* Configure autowrap. The triggerLength allows to shift the wrapping point
* beyond its actual position in the file. If a line has multiple wrapping points
* it will scan backwards for the first autowrapped region. The triggerLength
* moves this region logically such it will be found earlier.
*/
void autowrap(int triggerLength);
/**
* Suppresses auto wrap in this hidden region.
*/
void noAutowrap();
void noSpace();
void oneSpace();
void setDecreaseIndentation(int indentation);
void setIncreaseIndentation(int indentation);
void setNewLines(int newLines);
void setNewLines(int minNewLines, int defaultNewLines, int maxNewLines);
/**
* Callback if autowrapping was applied.
*/
void setOnAutowrap(IAutowrapFormatter formatter);
/**
* Returns teh current formatter request and allows to read configuration settings.
*/
FormatterRequest getRequest();
/**
* When merging, treat this configuration with a high priority.
* @see #lowPriority()
* @see #HIGH_PRIORITY
*/
void highPriority();
/**
* When merging, treat this configuration with a low priority.
* @see #highPriority()
* @see #LOW_PRIORITY
*/
void lowPriority();
/**
* Sets the priority of this formatting configuration. Used when two
* configurations should be merged.
* The priority of this formatter; the default value is {@link #NORMAL_PRIORITY}.
*/
void setPriority(int priority);
/**
* Decrease the indentation by one level.
* Subsequent calls decrease the indentation further.
* @see #setDecreaseIndentation(int)
*/
void decreaseIndentation();
/**
* Increase the indentation by one level.
*/
void increaseIndentation();
/**
* Decreases the indentation by the given number of levels.
* @see #setIncreaseIndentation(int)
*/
void setDecreaseIndentation(int indentation);
/**
* Increases the indentation by the given number of levels.
*/
void setIncreaseIndentation(int indentation);
/**
* Resets the indentation level to zero.
*/
void noIndentation();
/**
* Forces a line break in this hidden region.
* Same as {@link #setNewLines(int) setNewLines(1)}.
*/
void newLine();
/**
* Forces the number of newlines in this hidden region.
* Same as {@link #setNewLines(int, int, int) setNewLines(nl, nl, nl)}
*/
void setNewLines(int newLines);
/**
* Configures the given new lines for this hidden region.
* Keeps the current configuration if it is in the valid boundaries
* of {@code minNewLines} and {@code maxNewLines}. Applies {@code defaultNewLines}
* otherwise.
*/
void setNewLines(int minNewLines, int defaultNewLines, int maxNewLines);
/**
* No space is added at this hidden region.
* Same as {@link #setSpace(String) setSpace("")}.
*/
void noSpace();
/**
* One space is added at this hidden region.
* Same as {@link #setSpace(String) setSpace(" ")}.
*/
void oneSpace();
/**
* The given space is used for this hidden region.
*/
void setSpace(String space);
}

View file

@ -10,13 +10,17 @@ package org.eclipse.xtext.formatting2;
import org.eclipse.xtext.formatting2.internal.HiddenRegionFormatting;
/**
* <p>
* HiddenRegionFormatting specifies formatting information for a HiddenRegion. A HiddenRegion is the group of all hidden
* tokens (whitespace and commend) between to non-hidden tokens.
*
* HiddenRegionFormattings can sometimes be automatically merged when two are registered for the same region in an
* {@link IFormattableDocument}.
* tokens (whitespace and comments) between to non-hidden tokens.
* </p>
*
* <p>
* HiddenRegionFormattings can sometimes be automatically {@link #mergeValuesFrom(IHiddenRegionFormatting) merged} when
* two different formattings are registered for the same region in an {@link IFormattableDocument}.
* </p>
*
* @see IHiddenRegionFormatter
* @noimplement This interface is not intended to be implemented by clients, use {@link HiddenRegionFormatting}
* @noextend This interface is not intended to be extended by clients, use {@link HiddenRegionFormatting}
* @author Moritz Eysholdt - Initial contribution and API
@ -40,7 +44,7 @@ public interface IHiddenRegionFormatting {
Integer getNewLineMin();
Boolean getNoIndetation();
Boolean getNoIndentation();
IAutowrapFormatter getOnAutowrap();

View file

@ -10,6 +10,9 @@ package org.eclipse.xtext.formatting2;
import java.util.List;
/**
* Generic interface to describe an external merger for some
* mergable type.
*
* @author Moritz Eysholdt - Initial contribution and API
* @since 2.8
*/

View file

@ -8,10 +8,15 @@
package org.eclipse.xtext.formatting2;
/**
* @author Moritz Eysholdt - Initial contribution and API
* An ISubFormatter is responsible to format a sub document.
*
* @author Moritz Eysholdt - Initial contribution and API
* @since 2.8
*/
public interface ISubFormatter {
/**
* Format the given document or throw a {@link FormattingNotApplicableException}
* if the document cannot be formatted by this formatter.
*/
void format(IFormattableSubDocument document) throws FormattingNotApplicableException;
}

View file

@ -8,6 +8,9 @@
package org.eclipse.xtext.formatting2;
/**
* A replacement describes which new text is to be inserted
* at a given offset and length.
*
* @author Moritz Eysholdt - Initial contribution and API
* @since 2.8
*/

View file

@ -10,17 +10,24 @@ package org.eclipse.xtext.formatting2;
import com.google.common.base.Function;
/**
* A TextReplacer is responsible for a text region inside a {@link IFormattableDocument} and produces
* {@link ITextReplacement}s for that region.
* <p>
* A TextReplacer is responsible for a {@link ITextSegment text region} inside a {@link IFormattableDocument} and
* produces {@link ITextReplacement replacements} for that region.
* </p>
*
* The {@link IFormattableDocument} ensures that TextReplacers are executed in the correct order, i.e. from the
* beginning of the document to the end of the document.
* <p>
* The {@link IFormattableDocument} ensures that replacers are executed in the correct order, i.e. from the beginning of
* the document to the end of the document.
* </p>
*
* @author Moritz Eysholdt - Initial contribution and API
* @since 2.8
*/
public interface ITextReplacer {
/**
* A function that maps a given replacer to the region that it replaces.
*/
public final static Function<ITextReplacer, ITextSegment> GET_REGION = new Function<ITextReplacer, ITextSegment>() {
@Override
public ITextSegment apply(ITextReplacer input) {
@ -28,7 +35,14 @@ public interface ITextReplacer {
}
};
/**
* The replaced region.
*/
ITextSegment getRegion();
/**
* Creates the real replacements for this region. The given context
* may be altered and returned afterwards.
*/
ITextReplacerContext createReplacements(ITextReplacerContext context);
}

View file

@ -10,10 +10,12 @@ package org.eclipse.xtext.formatting2;
import java.util.List;
/**
* Relevant state and methods during execution of a TextReplacer.
* Relevant state and methods during execution of a {@link ITextReplacer text replacer}.
*
* @noextend This interface is not intended to be extended by clients.
* @noimplement This interface is not intended to be implemented by clients.
* @since 2.8
* @author Moritz Eysholdt - Initial API and implementation
*/
public interface ITextReplacerContext {
@ -25,6 +27,11 @@ public interface ITextReplacerContext {
int getIndentation();
/**
* Returns the current indentation as a string.
* @see #getIndentationString(int)
* @see #getIndentation()
*/
String getIndentationString();
String getIndentationString(int indentationLevel);
@ -47,7 +54,7 @@ public interface ITextReplacerContext {
void replaceText(CharSequence text);
void replaceText(int offset, int lenght, CharSequence text);
void replaceText(int offset, int length, CharSequence text);
void replaceText(ITextReplacement replacement);
@ -60,6 +67,8 @@ public interface ITextReplacerContext {
void setNextReplacerIsChild();
ITextReplacerContext withIndentation(int indentation);
ITextReplacerContext withDocument(IFormattableDocument document);
ITextReplacerContext withReplacer(ITextReplacer replacer);

View file

@ -13,6 +13,9 @@ import org.eclipse.xtext.formatting2.regionaccess.ITextRegionAccess;
import org.eclipse.xtext.util.ITextRegion;
/**
* A text segment describes a part of a document and carries a few more information,
* e.g. about the current indentation level.
*
* @author Moritz Eysholdt - Initial contribution and API
* @since 2.8
*/

View file

@ -7,7 +7,6 @@
*******************************************************************************/
package org.eclipse.xtext.formatting2;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -22,25 +21,15 @@ import org.eclipse.xtext.formatting2.internal.TextReplacementList;
*/
public class TextReplacements {
/**
* Applies all 'replacements' on 'input'.
* <p>Applies all 'replacements' on 'input'.</p>
*
* Replaces the text regions in 'input' identified by {@link ITextReplacement#getOffset()} and
* {@link ITextReplacement#getLength()} with {@link ITextReplacement#getReplacementText()}.
* <p>Replaces the text regions in 'input' identified by {@link ITextReplacement#getOffset()} and
* {@link ITextReplacement#getLength()} with {@link ITextReplacement#getReplacementText()}.</p>
*
* @return The text after the replacements have been applied.
*/
public static String apply(CharSequence input, Iterable<? extends ITextReplacement> replacements) {
ArrayList<ITextReplacement> list = new TextReplacementList<ITextReplacement>(replacements);
Collections.sort(list);
int lastOffset = 0;
StringBuilder result = new StringBuilder();
for (ITextReplacement r : list) {
result.append(input.subSequence(lastOffset, r.getOffset()));
result.append(r.getReplacementText());
lastOffset = r.getOffset() + r.getLength();
}
result.append(input.subSequence(lastOffset, input.length()));
return result.toString();
return doApply(input, 0, replacements);
}
/**
@ -48,18 +37,20 @@ public class TextReplacements {
* is treated as relative to {@link ITextSegment#getOffset()} from 'input'.
*/
public static String apply(ITextSegment input, Iterable<? extends ITextReplacement> replacements) {
return doApply(input.getText(), input.getOffset(), replacements);
}
private static String doApply(CharSequence input, int offset, Iterable<? extends ITextReplacement> replacements) {
List<ITextReplacement> list = new TextReplacementList<ITextReplacement>(replacements);
Collections.sort(list);
String text = input.getText();
int offset = input.getOffset();
int lastOffset = 0;
StringBuilder result = new StringBuilder();
for (ITextReplacement r : list) {
result.append(text.subSequence(lastOffset, r.getOffset() - offset));
result.append(input.subSequence(lastOffset, r.getOffset() - offset));
result.append(r.getReplacementText());
lastOffset = (r.getOffset() - offset) + r.getLength();
}
result.append(text.subSequence(lastOffset, text.length()));
result.append(input.subSequence(lastOffset, input.length()));
return result.toString();
}
}

View file

@ -54,23 +54,23 @@ public class TextRegionListToString {
@Override
public String toString() {
int offsetDigits = 0;
int lenghtDigits = 0;
int lengthDigits = 0;
for (Item item : items) {
if (item.region != null) {
int lenghtD = String.valueOf(item.region.getLength()).length();
if (lenghtDigits < lenghtD)
lenghtDigits = lenghtD;
int lenghtO = String.valueOf(item.region.getOffset()).length();
if (offsetDigits < lenghtO)
offsetDigits = lenghtO;
int lengthD = String.valueOf(item.region.getLength()).length();
if (lengthDigits < lengthD)
lengthDigits = lengthD;
int lengthO = String.valueOf(item.region.getOffset()).length();
if (offsetDigits < lengthO)
offsetDigits = lengthO;
}
}
List<String> result = Lists.newArrayListWithExpectedSize(items.size());
String prefix = Strings.repeat(" ", offsetDigits + lenghtDigits + 2);
String prefix = Strings.repeat(" ", offsetDigits + lengthDigits + 2);
for (Item item : items) {
if (item.region != null) {
String offset = Strings.padStart(String.valueOf(item.region.getOffset()), offsetDigits, ' ');
String length = Strings.padStart(String.valueOf(item.region.getLength()), lenghtDigits, ' ');
String length = Strings.padStart(String.valueOf(item.region.getLength()), lengthDigits, ' ');
result.add(offset + " " + length + " " + item.text);
} else if (item.indented) {
result.add(prefix + item.text);

View file

@ -44,15 +44,15 @@ public class TextRegionsInTextToString {
protected String box(String title, String content) {
final int width = 80;
final int min = 3;
int titleLenght = title.length() + 2;
final int left = Math.max((width - titleLenght) / 2, min);
int titleLength = title.length() + 2;
final int left = Math.max((width - titleLength) / 2, min);
StringBuilder result = new StringBuilder();
result.append(Strings.repeat("-", left));
result.append(" ");
result.append(title);
result.append(" ");
if (left > min)
result.append(Strings.repeat("-", width - left - titleLenght));
result.append(Strings.repeat("-", width - left - titleLength));
result.append("\n");
result.append(org.eclipse.xtext.util.Strings.trimTrailingLineBreak(content));
result.append("\n");

View file

@ -59,11 +59,11 @@ public class TextRegionsToString {
return "<" + region.getOffset() + ":" + region.getLength() + "|" + replacement + ">";
}
protected String quote(String string, int maxLenght) {
protected String quote(String string, int maxLength) {
if (string == null)
return "null";
if (string.length() > maxLenght)
string = string.substring(0, maxLenght - 3) + "...";
if (string.length() > maxLength)
string = string.substring(0, maxLength - 3) + "...";
string = string.replace("\n", "\\n").replace("\r", "\\r");
return "\"" + string + "\"";
}

View file

@ -56,15 +56,15 @@ public class TextRegionsWithTitleToString {
protected String box(String title, String content) {
final int width = 80;
final int min = 3;
int titleLenght = title.length() + 2;
final int left = Math.max((width - titleLenght) / 2, min);
int titleLength = title.length() + 2;
final int left = Math.max((width - titleLength) / 2, min);
StringBuilder result = new StringBuilder();
result.append(Strings.repeat("-", left));
result.append(" ");
result.append(title);
result.append(" ");
if (left > min)
result.append(Strings.repeat("-", width - left - titleLenght));
result.append(Strings.repeat("-", width - left - titleLength));
result.append("\n");
result.append(org.eclipse.xtext.util.Strings.trimTrailingLineBreak(content));
result.append("\n");
@ -139,7 +139,7 @@ public class TextRegionsWithTitleToString {
for (int i = 0; i < this.items.size(); i++) {
Item item = this.items.get(i);
ITextSegment region = item.getRegion();
String regionStr = "offset=" + region.getOffset() + " lenght=" + region.getLength();
String regionStr = "offset=" + region.getOffset() + " length=" + region.getLength();
String open = i < BRACKETS_OPEN.length ? BRACKETS_OPEN[i] : "[" + i + "[";
String close = i < BRACKETS_CLOSE.length ? BRACKETS_CLOSE[i] : "]" + i + "]";
builder.append(open + close + ": " + item.getTitle() + " at " + regionStr + "\n");

View file

@ -74,11 +74,11 @@ public class TokenAccessToString {
return hightlightOrigin;
}
protected String quote(String string, int maxLenght) {
protected String quote(String string, int maxLength) {
if (string == null)
return "null";
if (string.length() > maxLenght)
string = string.substring(0, maxLenght - 3) + "...";
if (string.length() > maxLength)
string = string.substring(0, maxLength - 3) + "...";
string = string.replace("\n", "\\n").replace("\r", "\\r");
return "\"" + string + "\"";
}

View file

@ -82,13 +82,13 @@ public class ArrayListTextSegmentSet<T> extends TextSegmentSet<T> {
contents.add(low + 1, merged);
} else {
int segmentLengh = getRegion(segment).getLength();
int totalLenght = 0;
int totalLength = 0;
for (int i = 1; i < conflicting.size(); i++)
totalLenght += getRegion(conflicting.get(i)).getLength();
if (segmentLengh >= totalLenght)
totalLength += getRegion(conflicting.get(i)).getLength();
if (segmentLengh >= totalLength)
for (int i = high - 1; i > low; i--)
contents.remove(i);
if (segmentLengh > totalLenght) {
if (segmentLengh > totalLength) {
getTraces().put(segment, new RegionTrace(getTitle(segment), getRegion(segment)));
contents.add(low + 1, segment);
}

View file

@ -18,9 +18,9 @@ import com.google.common.base.Predicate;
*/
public class FilteredSubDocument extends SubDocument {
private final Predicate<ITextReplacer> filter;
private final Predicate<? super ITextReplacer> filter;
public FilteredSubDocument(ITextSegment region, IFormattableDocument parent, Predicate<ITextReplacer> filter) {
public FilteredSubDocument(ITextSegment region, IFormattableDocument parent, Predicate<? super ITextReplacer> filter) {
super(region, parent);
this.filter = filter;
}

View file

@ -73,7 +73,7 @@ public abstract class FormattableDocument implements IFormattableDocument {
}
@Override
public ISemanticRegion append(ISemanticRegion token, Procedure1<IHiddenRegionFormatter> after) {
public ISemanticRegion append(ISemanticRegion token, Procedure1<? super IHiddenRegionFormatter> after) {
if (token != null) {
IHiddenRegion gap = token.getNextHiddenRegion();
set(gap, after);
@ -82,7 +82,7 @@ public abstract class FormattableDocument implements IFormattableDocument {
}
@Override
public <T extends EObject> T append(T owner, Procedure1<IHiddenRegionFormatter> after) {
public <T extends EObject> T append(T owner, Procedure1<? super IHiddenRegionFormatter> after) {
if (owner != null) {
IHiddenRegion gap = getTextRegionAccess().trailingHiddenRegion(owner);
set(gap, after);
@ -111,7 +111,7 @@ public abstract class FormattableDocument implements IFormattableDocument {
protected ITextReplacerContext createReplacements(ITextReplacerContext previous) {
Integer maxLineWidth = getRequest().getPreferences().getPreference(FormatterPreferenceKeys.maxLineWidth);
ITextReplacerContext context = ((TextReplacerContext) previous).withDocument(this);
ITextReplacerContext context = previous.withDocument(this);
ITextReplacerContext wrappable = null;
Set<ITextReplacer> wrapped = Sets.newHashSet();
LinkedList<ITextReplacer> queue = new LinkedList<ITextReplacer>();
@ -149,7 +149,7 @@ public abstract class FormattableDocument implements IFormattableDocument {
}
context = nextContext;
}
return ((TextReplacerContext) context).withDocument(previous.getDocument());
return context.withDocument(previous.getDocument());
}
protected TextSegmentSet<ITextReplacer> createTextReplacerSet() {
@ -203,7 +203,7 @@ public abstract class FormattableDocument implements IFormattableDocument {
}
@Override
public ISemanticRegion prepend(ISemanticRegion token, Procedure1<IHiddenRegionFormatter> before) {
public ISemanticRegion prepend(ISemanticRegion token, Procedure1<? super IHiddenRegionFormatter> before) {
if (token != null) {
IHiddenRegion gap = token.getPreviousHiddenRegion();
set(gap, before);
@ -212,7 +212,7 @@ public abstract class FormattableDocument implements IFormattableDocument {
}
@Override
public <T extends EObject> T prepend(T owner, Procedure1<IHiddenRegionFormatter> before) {
public <T extends EObject> T prepend(T owner, Procedure1<? super IHiddenRegionFormatter> before) {
if (owner != null) {
IHiddenRegion gap = getTextRegionAccess().leadingHiddenRegion(owner);
set(gap, before);
@ -220,6 +220,7 @@ public abstract class FormattableDocument implements IFormattableDocument {
return owner;
}
@Override
public List<ITextReplacement> renderToTextReplacements() {
ITextReplacerContext first = getFormatter().createTextReplacerContext(this);
ITextReplacerContext last = createReplacements(first);
@ -228,11 +229,11 @@ public abstract class FormattableDocument implements IFormattableDocument {
}
@Override
public IHiddenRegion set(IHiddenRegion hiddenRegion, Procedure1<IHiddenRegionFormatter> init) {
public IHiddenRegion set(IHiddenRegion hiddenRegion, Procedure1<? super IHiddenRegionFormatter> init) {
if (hiddenRegion != null) {
AbstractFormatter2 formatter = getFormatter();
IHiddenRegionFormatting formatting = formatter.createHiddenRegionFormatting();
init.apply((IHiddenRegionFormatter) formatting);
init.apply(formatting.asFormatter());
ITextReplacer replacer = formatter.createHiddenRegionReplacer(hiddenRegion, formatting);
addReplacer(replacer);
}
@ -240,14 +241,14 @@ public abstract class FormattableDocument implements IFormattableDocument {
}
@Override
public ISemanticRegion surround(ISemanticRegion token, Procedure1<IHiddenRegionFormatter> beforeAndAfter) {
public ISemanticRegion surround(ISemanticRegion token, Procedure1<? super IHiddenRegionFormatter> beforeAndAfter) {
prepend(token, beforeAndAfter);
append(token, beforeAndAfter);
return token;
}
@Override
public <T extends EObject> T surround(T owner, Procedure1<IHiddenRegionFormatter> beforeAndAfter) {
public <T extends EObject> T surround(T owner, Procedure1<? super IHiddenRegionFormatter> beforeAndAfter) {
prepend(owner, beforeAndAfter);
append(owner, beforeAndAfter);
return owner;
@ -264,7 +265,7 @@ public abstract class FormattableDocument implements IFormattableDocument {
}
@Override
public IFormattableSubDocument withReplacerFilter(Predicate<ITextReplacer> filter) {
public IFormattableSubDocument withReplacerFilter(Predicate<? super ITextReplacer> filter) {
return new FilteredSubDocument(getRegion(), this, filter);
}

View file

@ -52,8 +52,8 @@ public class HiddenRegionFormatting implements IHiddenRegionFormatter, IHiddenRe
}
@Override
public void autowrap(int triggerLenght) {
autowrap = triggerLenght;
public void autowrap(int triggerLength) {
autowrap = triggerLength;
}
@Override
@ -96,7 +96,7 @@ public class HiddenRegionFormatting implements IHiddenRegionFormatter, IHiddenRe
}
@Override
public Boolean getNoIndetation() {
public Boolean getNoIndentation() {
return noIndentation;
}
@ -156,7 +156,7 @@ public class HiddenRegionFormatting implements IHiddenRegionFormatter, IHiddenRe
setNewLinesMax(merge(getNewLineMax(), other.getNewLineMax(), strategy, "newLineMax"));
setAutowrap(merge(getAutowrap(), other.getAutowrap(), strategy, "autowrap"));
setOnAutowrap(merge(getOnAutowrap(), other.getOnAutowrap(), strategy, "onAutowrap"));
setNoIndentation(merge(getNoIndetation(), other.getNoIndetation(), strategy, "noIndentation"));
setNoIndentation(merge(getNoIndentation(), other.getNoIndentation(), strategy, "noIndentation"));
if (getIndentationIncrease() != null && other.getIndentationIncrease() != null)
setIndentationIncrease(getIndentationIncrease() + other.getIndentationIncrease());

View file

@ -19,7 +19,7 @@ public class RegionTrace extends RuntimeException {
private final ITextSegment region;
public RegionTrace(String message, ITextSegment region) {
super(message + " at offset=" + region.getOffset() + " lenght=" + region.getLength());
super(message + " at offset=" + region.getOffset() + " length=" + region.getLength());
this.region = region;
}

View file

@ -110,13 +110,13 @@ public class TextReplacerContext implements ITextReplacerContext {
String between = access.getText(endOffset, lastOffset - endOffset);
int idx = between.lastIndexOf('\n');
if (idx >= 0)
return count + logicalLenght(between.substring(idx + 1));
count += logicalLenght(between);
return count + logicalLength(between.substring(idx + 1));
count += logicalLength(between);
String text = rep.getReplacementText();
int idx2 = text.lastIndexOf('\n');
if (idx2 >= 0)
return count + logicalLenght(text.substring(idx2 + 1));
count += logicalLenght(text);
return count + logicalLength(text.substring(idx2 + 1));
count += logicalLength(text);
lastOffset = rep.getOffset();
}
current = current.getPreviousContext();
@ -124,7 +124,7 @@ public class TextReplacerContext implements ITextReplacerContext {
String rest = access.getText(0, lastOffset);
int idx = rest.lastIndexOf('\n');
if (idx >= 0)
return count + logicalLenght(rest.substring(idx + 1));
return count + logicalLength(rest.substring(idx + 1));
count += lastOffset;
return count;
}
@ -191,7 +191,7 @@ public class TextReplacerContext implements ITextReplacerContext {
return true; // TODO: implement
}
protected int logicalLenght(String text) {
protected int logicalLength(String text) {
ITypedPreferenceValues preferences = getDocument().getRequest().getPreferences();
String indentation = preferences.getPreference(FormatterPreferenceKeys.indentation);
if (!"\t".equals(indentation))
@ -214,9 +214,9 @@ public class TextReplacerContext implements ITextReplacerContext {
}
@Override
public void replaceText(int offset, int lenght, CharSequence text) {
public void replaceText(int offset, int length, CharSequence text) {
Preconditions.checkNotNull(text);
ITextReplacement replacement = document.getFormatter().createTextReplacement(offset, lenght, text.toString());
ITextReplacement replacement = document.getFormatter().createTextReplacement(offset, length, text.toString());
replaceText(replacement);
}
@ -299,6 +299,7 @@ public class TextReplacerContext implements ITextReplacerContext {
return Joiner.on("; ").join(items);
}
@Override
public ITextReplacerContext withDocument(IFormattableDocument document) {
TextReplacerContext context = new TextReplacerContext(document, this, indentation, null);
if (this.nextReplacerIsChild)

View file

@ -86,7 +86,7 @@ public class WhitespaceReplacer implements ITextReplacer {
if (space != null)
context.replaceText(region, space);
} else {
boolean noIndentation = formatting.getNoIndetation() == Boolean.TRUE;
boolean noIndentation = formatting.getNoIndentation() == Boolean.TRUE;
String newLines = context.getNewLinesString(newLineCount);
String indentation = noIndentation ? "" : context.getIndentationString(indentationCount);
context.replaceText(region, newLines + indentation);

View file

@ -1,31 +1,30 @@
package org.eclipse.xtext.formatting2;
/**
* Xtext formatting infrastructure 2.0.
* <p>Xtext formatting infrastructure since Xtext 2.8.</p>
*
* A formatter is responsible for arranging line-wraps, indentation, whitespace, etc. in a text document to improve is
* <p>A formatter is responsible for arranging line-wraps, indentation, whitespace, etc. in a text document to improve its
* readability and emphasize its structure. A formatter is not supposed to alter a document in a way that impacts the
* semantic model.
* semantic model.</p>
*
* This infrastructure is capable of formatting documents based on the node model and based on the serializer's output.
* <p>This infrastructure is capable of formatting documents based on the node model and based on the serializer's output.
* The actual formatting is done by constructing a list of text replacements. Applying the text replacement turns the
* unformatted document into a formatted document. Purpose of this infrastructure is to make it convenient for
* implementers to construct these text replacements.
* implementers to construct these text replacements.</p>
*
* To run the formatter, you'll need to construct a {@link FormatterRequest}, get an instance of {@link IFormatter2}
* from your language's Guice Injector and call {@link IFormatter2#format(FormatterRequest)}. The result will be a list
* of text replacements. Use {@link TextReplacements#apply(CharSequence, Iterable)} to apply the replacements to a
* String/CharSequence, if desired.
* <p>To run the formatter, you'll need to construct a {@link org.eclipse.xtext.formatting2.FormatterRequest}, get an instance of {@link org.eclipse.xtext.formatting2.IFormatter2}
* from your language's Guice Injector and call {@link org.eclipse.xtext.formatting2.IFormatter2#format(FormatterRequest)}. The result will be a list
* of text replacements. Use {@link org.eclipse.xtext.formatting2.TextReplacements#apply(CharSequence, Iterable)} to apply the replacements to a
* String/CharSequence, if desired.</p>
*
* To implement a formatter or to understand how to implement a formatter, see {@link AbstractFormatter2}.
* <p>To implement a formatter or to understand how to implement a formatter, see {@link org.eclipse.xtext.formatting2.AbstractFormatter2}.</p>
*
* @see IFormatter2 - use this interface to invoke the formatter
* @see AbstractFormatter2 - subclass this class to implement a formatter
* @see ITextReplacement - a text-substitution at a defined offset inside a larger text
* @see FormatterRequest - per-execution scoped configuration for the formatter.
* Per-language configuration is handled by the Guice-Injector
* @see org.eclipse.xtext.formatting2.IFormatter2 Use the IFormatter2 to invoke the formatter
* @see org.eclipse.xtext.formatting2.AbstractFormatter2 Extend the AbstractFormatter2 to implement a formatter
* @see org.eclipse.xtext.formatting2.FormatterRequest The FormatterRequest is a per-execution scoped configuration for the formatter.
* Per-language configuration is handled by the injector
* or {@link org.eclipse.xtext.formatting2.AbstractFormatter2}.
*
* @author Moritz Eysholdt - Initial contribution and API
* @since 2.8
*/
package org.eclipse.xtext.formatting2;

View file

@ -8,14 +8,13 @@
package org.eclipse.xtext.formatting2.regionaccess;
/**
* Represents a comment.
* <p>Represents a comment.</p>
*
* For Xtext languages extending common.Terminals, these are tokens parsed with the terminal rules 'ML_COMMENT' and
* 'SL_COMMENT'.
* <p>For Xtext languages extending common.Terminals, these are tokens parsed with the terminal rules 'ML_COMMENT' and
* 'SL_COMMENT'.</p>
*
* @author Moritz Eysholdt - Initial contribution and API
*
*
* @see IWhitespace
* @see IHiddenRegionPart
*

View file

@ -10,7 +10,7 @@ package org.eclipse.xtext.formatting2.regionaccess;
import java.util.List;
/**
* Represents and groups all {@link IWhitespace} and {@link IComment}s between two {@link ISemanticRegion}s. May be
* <p>Represents and groups all {@link IWhitespace} and {@link IComment comments} between two {@link ISemanticRegion semantic regions}. May be
* empty.
*
* @author Moritz Eysholdt - Initial contribution and API
@ -30,7 +30,7 @@ public interface IHiddenRegion extends ISequentialRegion {
boolean containsComment();
/**
* @return all {@link IWhitespace}s and {@link IComment}s that belong to this {@link IHiddenRegion}.
* @return all {@link IWhitespace white spaces} and {@link IComment comments} that belong to this {@link IHiddenRegion}.
*/
List<IHiddenRegionPart> getParts();

View file

@ -12,7 +12,7 @@ import org.eclipse.xtext.TerminalRule;
import org.eclipse.xtext.formatting2.ITextSegment;
/**
* Super-Interface for {@link IWhitespace} and {@link IComment}.
* Common interface for {@link IWhitespace} and {@link IComment}.
*
* @author Moritz Eysholdt - Initial contribution and API
*/

View file

@ -10,10 +10,10 @@ package org.eclipse.xtext.formatting2.regionaccess;
import org.eclipse.xtext.formatting2.ITextSegment;
/**
* Super-Interface for {@link IHiddenRegion} and {@link ISemanticRegion}.
* <p>Common interface for {@link IHiddenRegion} and {@link ISemanticRegion}.</p>
*
* {@link IHiddenRegion} and {@link ISemanticRegion} are arranged strictly alternating in a linked list. This interface
* provides the method to navigate that list.
* <p>{@link IHiddenRegion} and {@link ISemanticRegion} are arranged strictly alternating in a linked list. This interface
* provides the method to navigate that list.</p>
*
* @author Moritz Eysholdt - Initial contribution and API
*/

View file

@ -20,30 +20,29 @@ import org.eclipse.xtext.nodemodel.ILeafNode;
import org.eclipse.xtext.resource.XtextResource;
/**
* This class provides access to text regions ({@link ITextSegment}s) based on the semantic model. A text region
* describes the offset and length in characters of a semantic elements within a text document.
* <p>This class provides access to {@link ITextSegment text regions } based on the semantic model. A text region
* describes the offset and length in characters of a semantic elements within a text document.</p>
*
* Technically, it is a lightweight facade over the node model or the serializer's output.
* <p>Technically, it is a lightweight facade over the node model or the serializer's output.</p>
*
* The text regions are arranged as a linked list of strictly alternating {@link ISemanticRegion}s and
* {@link IHiddenRegion}s. HiddenRegions group all hidden tokens (typically whitespace, newlines, tabs and comments)
* <p>The text regions are arranged as a linked list of strictly alternating {@link ISemanticRegion semantic regions} and
* {@link IHiddenRegion hidden region}. HiddenRegions group all hidden tokens (typically whitespace, newlines, tabs and comments)
* between two semantic tokens. HiddenRegions are empty, but do exist, if there are no hidden tokens between two
* semantic elements.
* semantic elements.</p>
*
* Tokens are considered to be hidden, when they have been parsed via terminal rule referenced in "hidden(...)" in the
* Xtext grammar. In the node model, hidden tokens carry {@link ILeafNode#isHidden()} == true.
* <p>Tokens are considered to be hidden, when they have been parsed via terminal rule referenced in "hidden(...)" in the
* Xtext grammar. In the node model, hidden tokens are usually marked as {@link ILeafNode#isHidden() hidden == true}.</p>
*
* A semantic token can be the value of an EAttribute, a CrossReference or a keyword.
* <p>A semantic token can be the value of an EAttribute, a CrossReference or a keyword.</p>
*
* A {@link IHiddenRegion} contains a list of {@link IHiddenRegionPart}s, which are either {@link IWhitespace}s or
* {@link IComment}s. A HidenRegion can be empty.
* <p>A {@link IHiddenRegion} contains a list of {@link IHiddenRegionPart parts}, which are either {@link IWhitespace white space} or
* {@link IComment comments}. A HiddenRegion can be empty.</p>
*
* The purpose of this class is:
* <ul>
* <li>Allow the formatter to operate on a parsed document (node model) and a serialized model.</li>
* <li>Provide a convenient abstraction for formatting (tokens, HiddenRegions).
* <li>Fast access to TextRegions. The node model would be too slow to traverse due to its large expression trees.</li>
* <li>Shield users from surprises due to the node model's structure.</li>
* </ul>
*
* @author Moritz Eysholdt - Initial contribution and API
@ -64,8 +63,8 @@ public interface ITextRegionAccess {
ITextSegment expandRegionsByLines(int leadingLines, int trailingLines, ITextSegment... regions);
/**
* @return The very first {@link IHiddenRegion} inside the linked list of alternating {@link IHiddenRegion}s and
* {@link ISemanticRegion}s.
* @return The very first {@link IHiddenRegion} inside the linked list of alternating {@link IHiddenRegion hidden regions} and
* {@link ISemanticRegion semantic regions}.
*/
IHiddenRegion getFirstRegionInFile();
@ -75,7 +74,7 @@ public interface ITextRegionAccess {
AbstractElement getInvokingGrammarElement(EObject obj);
/**
* @return The XtextResource that backs the document this class provides access to.
* @return The {@link XtextResource} that backs the document this class provides access to.
*/
XtextResource getResource();
@ -152,7 +151,7 @@ public interface ITextRegionAccess {
ITextSegment regionForEObject(EObject object); // TODO: should be semantic region?
/**
* @return returns the first {@link ISemanticRegion} that represents the value of owner.eGet(feature). May be null.
* @return returns the first {@link ISemanticRegion} that represents the value of {@code owner.eGet(feature)}. May be null.
*/
ISemanticRegion regionForFeature(EObject owner, EStructuralFeature feature);
@ -169,13 +168,13 @@ public interface ITextRegionAccess {
ISemanticRegion regionForRuleCallTo(EObject owner, AbstractRule rule);
/**
* @return All {@link ISemanticRegion}s that represent one of the provided 'keyword's and directly belong to the
* @return All {@link ISemanticRegion semantic regions} that represent one of the provided 'keyword's and directly belong to the
* provided 'EObject'. Keywords of child-EObjects are not considered.
*/
List<ISemanticRegion> regionsForKeywords(EObject owner, String... string);
/**
* @return All {@link ISemanticRegion}s that represent a RuleCall to one of the provided AbstractRules and directly
* @return All {@link ISemanticRegion semantic regions} that represent a RuleCall to one of the provided AbstractRules and directly
* belong to the provided 'EObject'. RuleCalls of child-EObjects are not considered. May be null.
*/
List<ISemanticRegion> regionsForRuleCallsTo(EObject owner, AbstractRule... rule);

View file

@ -8,9 +8,9 @@
package org.eclipse.xtext.formatting2.regionaccess;
/**
* Represents a whitespace token inside a {@link IHiddenRegion}.
* <p>Represents a whitespace token inside a {@link IHiddenRegion}.</p>
*
* Whitespace are usually hidden tokens for which all characters have {@link Character#isWhitespace(char)} == true.
* <p>Whitespace are usually hidden tokens for which all characters have {@link Character#isWhitespace(char) isWhitespace == true}.</p>
*
* @author Moritz Eysholdt - Initial contribution and API
*
@ -21,5 +21,4 @@ package org.eclipse.xtext.formatting2.regionaccess;
* @since 2.8
*/
public interface IWhitespace extends IHiddenRegionPart {
}

View file

@ -1,12 +1,12 @@
package org.eclipse.xtext.formatting2.regionaccess;
/**
* This package contains the {@link ITextRegionAccess} and related classes.
* This package contains the {@link org.eclipse.xtext.formatting2.regionaccess.ITextRegionAccess} and related classes.
* They map semantic model elements to regions within a text document.
*
* @see ITextRegionAccess
* @see org.eclipse.xtext.formatting2.regionaccess.ITextRegionAccess
*
* @since 2.8
*
* @author Moritz Eysholdt - Initial contribution and API
*/
package org.eclipse.xtext.formatting2.regionaccess;