Xtext's new Formatter API
Transcript of Xtext's new Formatter API
![Page 1: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/1.jpg)
Moritz Eysholdt, itemis AG
XTEXT’S NEW FORMATTER API
![Page 2: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/2.jpg)
AGENDA• motivation
• use cases
• ITextRegionAccess
• IFormattableDocument
• example formatter
• testing
![Page 3: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/3.jpg)
DEFINITION
![Page 4: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/4.jpg)
DEFINITION
“improve readability and emphasize structure of a document
without changing its meaning”
![Page 5: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/5.jpg)
DEFINITION
“improve readability and emphasize structure of a document
without changing its meaning”
“prettify spaces, line wraps, tabs and indentation without changing the AST”
![Page 6: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/6.jpg)
…if it does change the AST, it’s probably a clean-up action or refactoring
![Page 7: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/7.jpg)
MOTIVATION
![Page 8: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/8.jpg)
I’m lazy
readability
diff & merge
bug prevention
MOTIVATION
![Page 9: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/9.jpg)
I’m lazy
readability
diff & merge
bug prevention
With Formatter: CTRL+SHIFT+F
MOTIVATION
![Page 10: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/10.jpg)
I’m lazy
readability
diff & merge
bug prevention
With Formatter: CTRL+SHIFT+F
Without Formatter: →→⇒⇒__↓ →→⇒⇒⇒⇒__↓ ¶ ↑↑⇒↓↓⇒⇒¶
MOTIVATION
![Page 11: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/11.jpg)
I’m lazy
readability
diff & merge
bug prevention
MOTIVATION
![Page 12: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/12.jpg)
bad formatting… - obscures the code’s structure - unnecessarily consumes brain
cycles to filter out anomalies
I’m lazy
readability
diff & merge
bug prevention
MOTIVATION
![Page 13: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/13.jpg)
I’m lazy
readability
diff & merge
bug prevention
MOTIVATION
![Page 14: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/14.jpg)
• whitespace-only changes in diffs are annoying
I’m lazy
readability
diff & merge
bug prevention
MOTIVATION
![Page 15: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/15.jpg)
• whitespace-only changes in diffs are annoying
• merge conflicts because of whitespace-only super annoying
I’m lazy
readability
diff & merge
bug prevention
MOTIVATION
![Page 16: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/16.jpg)
• whitespace-only changes in diffs are annoying
• merge conflicts because of whitespace-only super annoying
• only commit formatted code!
I’m lazy
readability
diff & merge
bug prevention
MOTIVATION
![Page 17: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/17.jpg)
I’m lazy
readability
diff & merge
bug prevention
MOTIVATION
![Page 18: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/18.jpg)
I’m lazy
readability
diff & merge
bug prevention
MOTIVATION
![Page 19: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/19.jpg)
I’m lazy
readability
diff & merge
bug prevention
MOTIVATION
![Page 20: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/20.jpg)
I’m lazy
readability
diff & merge
bug prevention
MOTIVATION
![Page 21: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/21.jpg)
wrong indentation! proper formatting would have
increased the chances of spotting this bug!
I’m lazy
readability
diff & merge
bug prevention
MOTIVATION
![Page 22: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/22.jpg)
USE CASES
![Page 23: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/23.jpg)
on demand
serialization
semantic quickfix
USE CASES
![Page 24: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/24.jpg)
on demand
serialization
semantic quickfix
CTRL+SHIFT+F….and via context menu
USE CASES
![Page 25: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/25.jpg)
on demand
serialization
semantic quickfix
USE CASES
![Page 26: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/26.jpg)
on demand
serialization
semantic quickfix
Use an Xtext grammar to convert an EMF model to text. Formatter contributes indentation, newlines, space, etc.
USE CASES
![Page 27: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/27.jpg)
on demand
serialization
semantic quickfix
Use an Xtext grammar to convert an EMF model to text. Formatter contributes indentation, newlines, space, etc.
Serializer Use Cases: - non-textual (e.g. graphical) editors - model migration
USE CASES
![Page 28: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/28.jpg)
on demand
serialization
semantic quickfix
USE CASES
@Fix(IssueCodes.INVALID_FEATURE_NAME)public void fixName(final Issue issue, IssueResolutionAcceptor acceptor) { acceptor.accept(issue, "Uncapitalize name", "", "", new ISemanticModification() { @Override public void apply(EObject element, IModificationContext context) { ((Feature) element).setName(toFirstLower(issue.getData()[0])); } });}
![Page 29: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/29.jpg)
ARCHITECTURE
![Page 30: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/30.jpg)
messy
formatter
pretty
![Page 31: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/31.jpg)
messy
formatter
pretty
developer
creates
developer creates formatter, NoEngine!
![Page 32: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/32.jpg)
messy
formatter
pretty
developer
creates
text
model(AST)
text-regions(CST)
in
in
in
Input: Text, AST and CST
![Page 33: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/33.jpg)
messy
formatter
pretty
developer
creates
text
model(AST)
text-regions(CST)
in
in
in
text replacements
apply
Output: TextReplacements
![Page 34: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/34.jpg)
messy
formatter
pretty
grammar
developer
creates
text
model(AST)
text-regions(CST)
in
in
in
text replacements
apply
references
access to grammar
![Page 35: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/35.jpg)
fragment = formatting2.Formatter2Fragment auto-inject {}
fragment = formatting.FormatterFragment auto-inject {}
GeneratorFragment for MWE2
![Page 36: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/36.jpg)
import org.eclipse.xtext.formatting2.AbstractFormatter2!class StatesFormatter extends AbstractFormatter2 {! def dispatch void format(Model model, extension IFormattableDocument document) { model.regionFor.keyword(";").prepend[noSpace] }}
Model: "machine" name=QualifiedName “;";
![Page 37: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/37.jpg)
import org.eclipse.xtext.formatting2.AbstractFormatter2!class StatesFormatter extends AbstractFormatter2 {! def dispatch void format(Model model, extension IFormattableDocument document) { model.regionFor.keyword(";").prepend[noSpace] }}
Model: "machine" name=QualifiedName “;";
extends AbstractFormatter2
![Page 38: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/38.jpg)
import org.eclipse.xtext.formatting2.AbstractFormatter2!class StatesFormatter extends AbstractFormatter2 {! def dispatch void format(Model model, extension IFormattableDocument document) { model.regionFor.keyword(";").prepend[noSpace] }}
Model: "machine" name=QualifiedName “;";
dispatch over AST elements
![Page 39: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/39.jpg)
import org.eclipse.xtext.formatting2.AbstractFormatter2!class StatesFormatter extends AbstractFormatter2 {! def dispatch void format(Model model, extension IFormattableDocument document) { model.regionFor.keyword(";").prepend[noSpace] }}
1. start with the EObject
Model: "machine" name=QualifiedName “;";
![Page 40: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/40.jpg)
import org.eclipse.xtext.formatting2.AbstractFormatter2!class StatesFormatter extends AbstractFormatter2 {! def dispatch void format(Model model, extension IFormattableDocument document) { model.regionFor.keyword(";").prepend[noSpace] }}
1. start with the EObject 2. find desired semantic text region using ITextRegionAccess
Model: "machine" name=QualifiedName “;";
![Page 41: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/41.jpg)
import org.eclipse.xtext.formatting2.AbstractFormatter2!class StatesFormatter extends AbstractFormatter2 {! def dispatch void format(Model model, extension IFormattableDocument document) { model.regionFor.keyword(";").prepend[noSpace] }}
1. start with the EObject 2. find desired semantic text region using ITextRegionAccess 3. register formatting information on IFormattableDocument
Model: "machine" name=QualifiedName “;";
![Page 42: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/42.jpg)
TEXT REGIONS
![Page 43: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/43.jpg)
text:StringDocument
getText():String
offset:intlength:int
TextRegion1 *
TextRegions… …represent a substring …can overlap …can be empty
![Page 44: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/44.jpg)
regionForOffset(int offset, int length)regionForDocument()
resource:XtextResource
ITextRegionAccess
regionForEObject(EObject object)regionForRootEObject()
the document. created from node
model or via serializer
![Page 45: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/45.jpg)
getText():String
offset : intlength: int
ITextRegion
regionForOffset(int offset, int length)regionForDocument()
resource:XtextResource
ITextRegionAccess
regionForEObject(EObject object)regionForRootEObject()
returns
regions for anything
![Page 46: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/46.jpg)
non-hidden token 0..n hidden tokens
ISequentialRegion
getText():String
offset : intlength: int
ITextRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
regionForOffset(int offset, int length)regionForDocument()
resource:XtextResource
ITextRegionAccess
regionForEObject(EObject object)regionForRootEObject()
returns
strictly alternating linked list of
hidden/semantic regions
![Page 47: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/47.jpg)
whitespace token comment token
ISequentialRegion
getText():String
offset : intlength: int
ITextRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPartparts
IWhitespace IComment
regionForOffset(int offset, int length)regionForDocument()
resource:XtextResource
ITextRegionAccess
regionForEObject(EObject object)regionForRootEObject()
returns
![Page 48: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/48.jpg)
eObject:EObjectgrammarElement:EObject
IEObjectRegion ISequentialRegion
getText():String
offset : intlength: int
ITextRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
regionForOffset(int offset, int length)regionForDocument()
resource:XtextResource
ITextRegionAccess
regionForEObject(EObject object)regionForRootEObject()
returns
returns
leadingtrailing
for AST element
![Page 49: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/49.jpg)
eObject:EObjectgrammarElement:EObject
IEObjectRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
leadingtrailing
![Page 50: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/50.jpg)
eObject:EObjectgrammarElement:EObject
IEObjectRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
leadingtrailing
/* Copyright */machine my.X;!// First Statestate
1. Take Document
1.
![Page 51: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/51.jpg)
eObject:EObjectgrammarElement:EObject
IEObjectRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
leadingtrailing
/* Copyright */machine my.X;!// First Statestate
Model: "machine" name=QualifiedName ";" elements+=State*;!State: {State} ‘state';!QualifiedName: ID ('.' ID)*;
1. Take Document 2. Parse it using Grammar
1.
2.
![Page 52: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/52.jpg)
class StatesFormatter extends AbstractFormatter2 {! def dispatch void format(Model model, extension IFormattableDocument document) { println(textRegionAccess.toString()) }}
eObject:EObjectgrammarElement:EObject
IEObjectRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
leadingtrailing
/* Copyright */machine my.X;!// First Statestate
Model: "machine" name=QualifiedName ";" elements+=State*;!State: {State} ‘state';!QualifiedName: ID ('.' ID)*;
1. Take Document 2. Parse it using Grammar 3. Dump it via textRegionAccess.toString()
1.
2.
3.
![Page 53: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/53.jpg)
class StatesFormatter extends AbstractFormatter2 {! def dispatch void format(Model model, extension IFormattableDocument document) { println(textRegionAccess) }}
eObject:EObjectgrammarElement:EObject
IEObjectRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
leadingtrailing
/* Copyright */machine my.X;!// First Statestate
Model: "machine" name=QualifiedName ";" elements+=State*;!State: {State} ‘state';!QualifiedName: ID ('.' ID)*;
1. Take Document 2. Parse it using Grammar 3. Dump it via textRegionAccess.toString() 4. See what we get (next slide)
1.
2.
3.
![Page 54: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/54.jpg)
/* Copyright */machine my.X;!// First Statestate
Model: "machine" name=QualifiedName ";" elements+=State*;!State: {State} ‘state';!QualifiedName: ID ('.' ID)*;
Columns: 1:offset 2:length 3:kind 4: text 5:grammarElementKind: H=IHiddenRegion S=ISemanticRegion B/E=IEObjectRegion! 0 H "/* Copyright */" Comment:TerminalRule'ML_COMMENT' 16 "\n" Whitespace:TerminalRule'WS' B Model'my.X' Model16 7 S "machine" Model:'machine'23 1 H " " Whitespace:TerminalRule'WS'24 4 S "my.X" Model:name=QualifiedName28 0 H28 1 S ";" Model:';'29 H "\n\n" Whitespace:TerminalRule'WS' 17 "// First State\n" Comment:TerminalRule'SL_COMMENT' B State Model:elements+=State path:Model'my.X'/elements[0]46 5 S "state" State:'state' E State Model:elements+=State path:Model'my.X'/elements[0] E Model'my.X' Model51 0 H
eObject:EObjectgrammarElement:EObject
IEObjectRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
leadingtrailing
![Page 55: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/55.jpg)
/* Copyright */machine my.X;!// First Statestate
Model: "machine" name=QualifiedName ";" elements+=State*;!State: {State} ‘state';!QualifiedName: ID ('.' ID)*;
Columns: 1:offset 2:length 3:kind 4: text 5:grammarElementKind: H=IHiddenRegion S=ISemanticRegion B/E=IEObjectRegion! 0 H "/* Copyright */" Comment:TerminalRule'ML_COMMENT' 16 "\n" Whitespace:TerminalRule'WS' B Model'my.X' Model16 7 S "machine" Model:'machine'23 1 H " " Whitespace:TerminalRule'WS'24 4 S "my.X" Model:name=QualifiedName28 0 H28 1 S ";" Model:';'29 H "\n\n" Whitespace:TerminalRule'WS' 17 "// First State\n" Comment:TerminalRule'SL_COMMENT' B State Model:elements+=State path:Model'my.X'/elements[0]46 5 S "state" State:'state' E State Model:elements+=State path:Model'my.X'/elements[0] E Model'my.X' Model51 0 H
eObject:EObjectgrammarElement:EObject
IEObjectRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
leadingtrailing
![Page 56: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/56.jpg)
/* Copyright */machine my.X;!// First Statestate
Model: "machine" name=QualifiedName ";" elements+=State*;!State: {State} ‘state';!QualifiedName: ID ('.' ID)*;
Columns: 1:offset 2:length 3:kind 4: text 5:grammarElementKind: H=IHiddenRegion S=ISemanticRegion B/E=IEObjectRegion! 0 H "/* Copyright */" Comment:TerminalRule'ML_COMMENT' 16 "\n" Whitespace:TerminalRule'WS' B Model'my.X' Model16 7 S "machine" Model:'machine'23 1 H " " Whitespace:TerminalRule'WS'24 4 S "my.X" Model:name=QualifiedName28 0 H28 1 S ";" Model:';'29 H "\n\n" Whitespace:TerminalRule'WS' 17 "// First State\n" Comment:TerminalRule'SL_COMMENT' B State Model:elements+=State path:Model'my.X'/elements[0]46 5 S "state" State:'state' E State Model:elements+=State path:Model'my.X'/elements[0] E Model'my.X' Model51 0 H
eObject:EObjectgrammarElement:EObject
IEObjectRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
leadingtrailing
![Page 57: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/57.jpg)
Columns: 1:offset 2:length 3:kind 4: text 5:grammarElementKind: H=IHiddenRegion S=ISemanticRegion B/E=IEObjectRegion! 0 H "/* Copyright */" Comment:TerminalRule'ML_COMMENT' 16 "\n" Whitespace:TerminalRule'WS' B Model'my.X' Model16 7 S "machine" Model:'machine'23 1 H " " Whitespace:TerminalRule'WS'24 4 S "my.X" Model:name=QualifiedName28 0 H28 1 S ";" Model:';'29 H "\n\n" Whitespace:TerminalRule'WS' 17 "// First State\n" Comment:TerminalRule'SL_COMMENT' B State Model:elements+=State path:Model'my.X'/elements[0]46 5 S "state" State:'state' E State Model:elements+=State path:Model'my.X'/elements[0] E Model'my.X' Model51 0 H
/* Copyright */machine my.X;!// First Statestate
Model: "machine" name=QualifiedName ";" elements+=State*;!State: {State} ‘state';!QualifiedName: ID ('.' ID)*;
eObject:EObjectgrammarElement:EObject
IEObjectRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
leadingtrailing
keyword
datatype
![Page 58: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/58.jpg)
Columns: 1:offset 2:length 3:kind 4: text 5:grammarElementKind: H=IHiddenRegion S=ISemanticRegion B/E=IEObjectRegion! 0 H "/* Copyright */" Comment:TerminalRule'ML_COMMENT' 16 "\n" Whitespace:TerminalRule'WS' B Model'my.X' Model16 7 S "machine" Model:'machine'23 1 H " " Whitespace:TerminalRule'WS'24 4 S "my.X" Model:name=QualifiedName28 0 H28 1 S ";" Model:';'29 H "\n\n" Whitespace:TerminalRule'WS' 17 "// First State\n" Comment:TerminalRule'SL_COMMENT' B State Model:elements+=State path:Model'my.X'/elements[0]46 5 S "state" State:'state' E State Model:elements+=State path:Model'my.X'/elements[0] E Model'my.X' Model51 0 H
/* Copyright */machine my.X;!// First Statestate
Model: "machine" name=QualifiedName ";" elements+=State*;!State: {State} ‘state';!QualifiedName: ID ('.' ID)*;
eObject:EObjectgrammarElement:EObject
IEObjectRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
leadingtrailing
empty
first region in document
last region in document
1 part
2 parts
![Page 59: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/59.jpg)
Columns: 1:offset 2:length 3:kind 4: text 5:grammarElementKind: H=IHiddenRegion S=ISemanticRegion B/E=IEObjectRegion! 0 H "/* Copyright */" Comment:TerminalRule'ML_COMMENT' 16 "\n" Whitespace:TerminalRule'WS' B Model'my.X' Model16 7 S "machine" Model:'machine'23 1 H " " Whitespace:TerminalRule'WS'24 4 S "my.X" Model:name=QualifiedName28 0 H28 1 S ";" Model:';'29 H "\n\n" Whitespace:TerminalRule'WS' 17 "// First State\n" Comment:TerminalRule'SL_COMMENT' B State Model:elements+=State path:Model'my.X'/elements[0]46 5 S "state" State:'state' E State Model:elements+=State path:Model'my.X'/elements[0] E Model'my.X' Model51 0 H
/* Copyright */machine my.X;!// First Statestate
Model: "machine" name=QualifiedName ";" elements+=State*;!State: {State} ‘state';!QualifiedName: ID ('.' ID)*;
eObject:EObjectgrammarElement:EObject
IEObjectRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
leadingtrailing
![Page 60: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/60.jpg)
Columns: 1:offset 2:length 3:kind 4: text 5:grammarElementKind: H=IHiddenRegion S=ISemanticRegion B/E=IEObjectRegion! 0 H "/* Copyright */" Comment:TerminalRule'ML_COMMENT' 16 "\n" Whitespace:TerminalRule'WS' B Model'my.X' Model16 7 S "machine" Model:'machine'23 1 H " " Whitespace:TerminalRule'WS'24 4 S "my.X" Model:name=QualifiedName28 0 H28 1 S ";" Model:';'29 H "\n\n" Whitespace:TerminalRule'WS' 17 "// First State\n" Comment:TerminalRule'SL_COMMENT' B State Model:elements+=State path:Model'my.X'/elements[0]46 5 S "state" State:'state' E State Model:elements+=State path:Model'my.X'/elements[0] E Model'my.X' Model51 0 H
/* Copyright */machine my.X;!// First Statestate
Model: "machine" name=QualifiedName ";" elements+=State*;!State: {State} ‘state';!QualifiedName: ID ('.' ID)*;
eObject:EObjectgrammarElement:EObject
IEObjectRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
leadingtrailing
![Page 61: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/61.jpg)
Columns: 1:offset 2:length 3:kind 4: text 5:grammarElementKind: H=IHiddenRegion S=ISemanticRegion B/E=IEObjectRegion! 0 H "/* Copyright */" Comment:TerminalRule'ML_COMMENT' 16 "\n" Whitespace:TerminalRule'WS' B Model'my.X' Model16 7 S "machine" Model:'machine'23 1 H " " Whitespace:TerminalRule'WS'24 4 S "my.X" Model:name=QualifiedName28 0 H28 1 S ";" Model:';'29 H "\n\n" Whitespace:TerminalRule'WS' 17 "// First State\n" Comment:TerminalRule'SL_COMMENT' B State Model:elements+=State path:Model'my.X'/elements[0]46 5 S "state" State:'state' E State Model:elements+=State path:Model'my.X'/elements[0] E Model'my.X' Model51 0 H
/* Copyright */machine my.X;!// First Statestate
Model: "machine" name=QualifiedName ";" elements+=State*;!State: {State} ‘state';!QualifiedName: ID ('.' ID)*;
eObject:EObjectgrammarElement:EObject
IEObjectRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
leadingtrailing
begin
end
grammarElement
path
![Page 62: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/62.jpg)
Columns: 1:offset 2:length 3:kind 4: text 5:grammarElementKind: H=IHiddenRegion S=ISemanticRegion B/E=IEObjectRegion! 0 H "/* Copyright */" Comment:TerminalRule'ML_COMMENT' 16 "\n" Whitespace:TerminalRule'WS' B Model'my.X' Model16 7 S "machine" Model:'machine'23 1 H " " Whitespace:TerminalRule'WS'24 4 S "my.X" Model:name=QualifiedName28 0 H28 1 S ";" Model:';'29 H "\n\n" Whitespace:TerminalRule'WS' 17 "// First State\n" Comment:TerminalRule'SL_COMMENT' B State Model:elements+=State path:Model'my.X'/elements[0]46 5 S "state" State:'state' E State Model:elements+=State path:Model'my.X'/elements[0] E Model'my.X' Model51 0 H
/* Copyright */machine my.X;!// First Statestate
Model: "machine" name=QualifiedName ";" elements+=State*;!State: {State} ‘state';!QualifiedName: ID ('.' ID)*;
eObject:EObjectgrammarElement:EObject
IEObjectRegion
undefined:boolean
IHiddenRegion
grammarElement:EObject
ISemanticRegion nextprevious
previousnext
grammarElement:EObject
IHiddenRegionPart
children
parts
IWhitespace IComment
leadingtrailing
![Page 63: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/63.jpg)
1. start with the EObject 2. find desired semantic text region using ITextRegionAccess 3. register formatting information on IFormattableDocument
(Recap)
import org.eclipse.xtext.formatting2.AbstractFormatter2!class StatesFormatter extends AbstractFormatter2 {! def dispatch void format(Model model, extension IFormattableDocument document) { model.regionFor.keyword(";").prepend[noSpace] }}
Model: "machine" name=QualifiedName “;";
![Page 64: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/64.jpg)
FIND SEMANTIC REGIONS
// in local eObject only eObject.regionFortextRegionAccess.regionForEObject(eObject).regionFor!// in eObject or any of its childreneObject.allRegionsFortextRegionAccess.regionForEObject(eObject).allRegionsFor!// in whole documenttextRegionAccess.regionForRootEObject.allRegionsFor
}// first matched semantic region.keyword(",").feature(StatesPackage.Literals.STATE__NAME).keyword(actionsKeyword_2_1_0).assignment(actionsAssignment_2_1_1).ruleCall(actionsINTTerminalRuleCall_2_1_1_0)!// all matched semantic region.keywords(",").features(StatesPackage.Literals.STATE__NAME).keywords(actionsKeyword_2_1_0).assignments(actionsAssignment_2_1_1).ruleCalls(actionsINTTerminalRuleCall_2_1_1_0)!.keywordPairs("(", ")")
{
![Page 65: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/65.jpg)
FIND SEMANTIC REGIONS
// in local eObject only eObject.regionFortextRegionAccess.regionForEObject(eObject).regionFor!// in eObject or any of its childreneObject.allRegionsFortextRegionAccess.regionForEObject(eObject).allRegionsFor!// in whole documenttextRegionAccess.regionForRootEObject.allRegionsFor
}// first matched semantic region.keyword(",").feature(StatesPackage.Literals.STATE__NAME).keyword(actionsKeyword_2_1_0).assignment(actionsAssignment_2_1_1).ruleCall(actionsINTTerminalRuleCall_2_1_1_0)!// all matched semantic region.keywords(",").features(StatesPackage.Literals.STATE__NAME).keywords(actionsKeyword_2_1_0).assignments(actionsAssignment_2_1_1).ruleCalls(actionsINTTerminalRuleCall_2_1_1_0)!.keywordPairs("(", ")")
{ITextRegionAccess
![Page 66: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/66.jpg)
FIND SEMANTIC REGIONS
// in local eObject only eObject.regionFortextRegionAccess.regionForEObject(eObject).regionFor!// in eObject or any of its childreneObject.allRegionsFortextRegionAccess.regionForEObject(eObject).allRegionsFor!// in whole documenttextRegionAccess.regionForRootEObject.allRegionsFor
}// first matched semantic region.keyword(",").feature(StatesPackage.Literals.STATE__NAME).keyword(actionsKeyword_2_1_0).assignment(actionsAssignment_2_1_1).ruleCall(actionsINTTerminalRuleCall_2_1_1_0)!// all matched semantic region.keywords(",").features(StatesPackage.Literals.STATE__NAME).keywords(actionsKeyword_2_1_0).assignments(actionsAssignment_2_1_1).ruleCalls(actionsINTTerminalRuleCall_2_1_1_0)!.keywordPairs("(", ")")
{ITextRegionExtensions
![Page 67: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/67.jpg)
FIND SEMANTIC REGIONS
// in local eObject only eObject.regionFortextRegionAccess.regionForEObject(eObject).regionFor!// in eObject or any of its childreneObject.allRegionsFortextRegionAccess.regionForEObject(eObject).allRegionsFor!// in whole documenttextRegionAccess.regionForRootEObject.allRegionsFor
}// first matched semantic region.keyword(",").feature(StatesPackage.Literals.STATE__NAME).keyword(actionsKeyword_2_1_0).assignment(actionsAssignment_2_1_1).ruleCall(actionsINTTerminalRuleCall_2_1_1_0)!// all matched semantic region.keywords(",").features(StatesPackage.Literals.STATE__NAME).keywords(actionsKeyword_2_1_0).assignments(actionsAssignment_2_1_1).ruleCalls(actionsINTTerminalRuleCall_2_1_1_0)!.keywordPairs("(", ")")
{Keywords (String)
![Page 68: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/68.jpg)
FIND SEMANTIC REGIONS
// in local eObject only eObject.regionFortextRegionAccess.regionForEObject(eObject).regionFor!// in eObject or any of its childreneObject.allRegionsFortextRegionAccess.regionForEObject(eObject).allRegionsFor!// in whole documenttextRegionAccess.regionForRootEObject.allRegionsFor
}// first matched semantic region.keyword(",").feature(StatesPackage.Literals.STATE__NAME).keyword(actionsKeyword_2_1_0).assignment(actionsAssignment_2_1_1).ruleCall(actionsINTTerminalRuleCall_2_1_1_0)!// all matched semantic region.keywords(",").features(StatesPackage.Literals.STATE__NAME).keywords(actionsKeyword_2_1_0).assignments(actionsAssignment_2_1_1).ruleCalls(actionsINTTerminalRuleCall_2_1_1_0)!.keywordPairs("(", ")")
{EMF EStructuralFeature (EAttribute, EReference)
![Page 69: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/69.jpg)
FIND SEMANTIC REGIONS
// in local eObject only eObject.regionFortextRegionAccess.regionForEObject(eObject).regionFor!// in eObject or any of its childreneObject.allRegionsFortextRegionAccess.regionForEObject(eObject).allRegionsFor!// in whole documenttextRegionAccess.regionForRootEObject.allRegionsFor
}// first matched semantic region.keyword(",").feature(StatesPackage.Literals.STATE__NAME).keyword(actionsKeyword_2_1_0).assignment(actionsAssignment_2_1_1).ruleCall(actionsINTTerminalRuleCall_2_1_1_0)!// all matched semantic region.keywords(",").features(StatesPackage.Literals.STATE__NAME).keywords(actionsKeyword_2_1_0).assignments(actionsAssignment_2_1_1).ruleCalls(actionsINTTerminalRuleCall_2_1_1_0)!.keywordPairs("(", ")")
{Grammar Element (from MyLanguageGrammarAccess)
![Page 70: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/70.jpg)
TEXT REGION RECAP
![Page 71: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/71.jpg)
TEXT REGION RECAP• ITextRegionAccess (for Xtend, ITextRegionExtensions)
![Page 72: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/72.jpg)
TEXT REGION RECAP• ITextRegionAccess (for Xtend, ITextRegionExtensions)
• linked list of strictly alternating ISemanticRegion and IHiddenRegion
![Page 73: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/73.jpg)
TEXT REGION RECAP• ITextRegionAccess (for Xtend, ITextRegionExtensions)
• linked list of strictly alternating ISemanticRegion and IHiddenRegion
• IHiddenRegion can be empty
![Page 74: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/74.jpg)
TEXT REGION RECAP• ITextRegionAccess (for Xtend, ITextRegionExtensions)
• linked list of strictly alternating ISemanticRegion and IHiddenRegion
• IHiddenRegion can be empty
• IHiddenRegion contains parts, e.g. IComment and IWhitespace
![Page 75: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/75.jpg)
TEXT REGION RECAP• ITextRegionAccess (for Xtend, ITextRegionExtensions)
• linked list of strictly alternating ISemanticRegion and IHiddenRegion
• IHiddenRegion can be empty
• IHiddenRegion contains parts, e.g. IComment and IWhitespace
• IEObjectRegion for elements from AST
![Page 76: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/76.jpg)
TEXT REGION RECAP• ITextRegionAccess (for Xtend, ITextRegionExtensions)
• linked list of strictly alternating ISemanticRegion and IHiddenRegion
• IHiddenRegion can be empty
• IHiddenRegion contains parts, e.g. IComment and IWhitespace
• IEObjectRegion for elements from AST
• use toString() during debugging!
![Page 77: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/77.jpg)
import org.eclipse.xtext.formatting2.AbstractFormatter2!class StatesFormatter extends AbstractFormatter2 {! def dispatch void format(Model model, extension IFormattableDocument document) { model.regionFor.keyword(";").prepend[noSpace] }}
1. start with the EObject 2. find desired semantic text region using ITextRegionAccess 3. register formatting information on IFormattableDocument
Model: "machine" name=QualifiedName “;"; (Recap)
![Page 78: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/78.jpg)
import org.eclipse.xtext.formatting2.AbstractFormatter2!class StatesFormatter extends AbstractFormatter2 {! def dispatch void format(Model model, extension IFormattableDocument document) { model.regionFor.keyword(";").prepend[noSpace] }}
1. start with the EObject 2. find desired semantic text region using ITextRegionAccess 3. register formatting information on IFormattableDocument
Model: "machine" name=QualifiedName “;"; (Recap)
![Page 79: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/79.jpg)
FORMATTABLE DOCUMENT
![Page 80: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/80.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!! // ...}
API: specify formatting information for hidden regions
Implementation: store text replacers for text regions
![Page 81: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/81.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!! // ...}
API: specify formatting information for hidden regions
Implementation: store text replacers for text regions
![Page 82: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/82.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!!! // ...}
specify for one or two
offset : intlength: int
IHiddenRegion
autowrap()setPriority(int priority)indent()newLine()setNewLines(int newLines)setNewLines(int min, int default, int max)noSpace()oneSpace()setSpace(String space)
IHiddenRegionFormatter
![Page 83: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/83.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!!! // ...}
specify for one or two
offset : intlength: int
IHiddenRegion
autowrap()setPriority(int priority)indent()newLine()setNewLines(int newLines)setNewLines(int min, int default, int max)noSpace()oneSpace()setSpace(String space)
IHiddenRegionFormatter
class StatesFormatter extends AbstractFormatter2 {! def dispatch void format(Model model, extension IFormattableDocument document) { model.regionFor.keyword(";").prepend[noSpace] }}
![Page 84: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/84.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!!! // ...}
specify for one or two
offset : intlength: int
IHiddenRegion
autowrap()setPriority(int priority)indent()newLine()setNewLines(int newLines)setNewLines(int min, int default, int max)noSpace()oneSpace()setSpace(String space)
IHiddenRegionFormatter
space, newLines, indent, autowrap
![Page 85: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/85.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!!! // ...}
specify for one or two
offset : intlength: int
IHiddenRegion
autowrap()setPriority(int priority)indent()newLine()setNewLines(int newLines)setNewLines(int min, int default, int max)noSpace()oneSpace()setSpace(String space)
IHiddenRegionFormatter
IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion
IHiddenRegionPart
IWhitespace IComment
1
* remember the strictly alternating
list of hidden/semantic regions
![Page 86: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/86.jpg)
interface IFormattableDocument {!!!!!!! // set for provided hidden region def set(IHiddenRegion hiddenRegion, (IHiddenRegionFormatter)=>void init)! // append after the provided semantic region def append(ISemanticRegion appendAfter, (IHiddenRegionFormatter)=>void init) def append(EObject appendAfter, (IHiddenRegionFormatter)=>void init)! // prepend before the provided semantic region def prepend(ISemanticRegion prependBefore, (IHiddenRegionFormatter)=>void init) def prepend(EObject prependBefore, (IHiddenRegionFormatter)=>void init)!!!!!!!!!!! // ...}
specify for one IHiddenRegionFormatter IHiddenRegion
![Page 87: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/87.jpg)
interface IFormattableDocument {!!!!!!! // set for provided hidden region def set(IHiddenRegion hiddenRegion, (IHiddenRegionFormatter)=>void init)! // append after the provided semantic region def append(ISemanticRegion appendAfter, (IHiddenRegionFormatter)=>void init) def append(EObject appendAfter, (IHiddenRegionFormatter)=>void init)! // prepend before the provided semantic region def prepend(ISemanticRegion prependBefore, (IHiddenRegionFormatter)=>void init) def prepend(EObject prependBefore, (IHiddenRegionFormatter)=>void init)!!!!!!!!!!! // ...}
specify for one
IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion
IHiddenRegionFormatter IHiddenRegion
![Page 88: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/88.jpg)
interface IFormattableDocument {!!!!!!! // set for provided hidden region def set(IHiddenRegion hiddenRegion, (IHiddenRegionFormatter)=>void init)! // append after the provided semantic region def append(ISemanticRegion appendAfter, (IHiddenRegionFormatter)=>void init) def append(EObject appendAfter, (IHiddenRegionFormatter)=>void init)! // prepend before the provided semantic region def prepend(ISemanticRegion prependBefore, (IHiddenRegionFormatter)=>void init) def prepend(EObject prependBefore, (IHiddenRegionFormatter)=>void init)!!!!!!!!!!! // ...}
specify for one
IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion
IHiddenRegionFormatter IHiddenRegion
![Page 89: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/89.jpg)
interface IFormattableDocument {!!!!!!! // set for provided hidden region def set(IHiddenRegion hiddenRegion, (IHiddenRegionFormatter)=>void init)! // append after the provided semantic region def append(ISemanticRegion appendAfter, (IHiddenRegionFormatter)=>void init) def append(EObject appendAfter, (IHiddenRegionFormatter)=>void init)! // prepend before the provided semantic region def prepend(ISemanticRegion prependBefore, (IHiddenRegionFormatter)=>void init) def prepend(EObject prependBefore, (IHiddenRegionFormatter)=>void init)!!!!!!!!!!! // ...}
specify for one
IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion
IHiddenRegionFormatter IHiddenRegion
![Page 90: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/90.jpg)
interface IFormattableDocument {!!!!!!! // set for provided hidden region def set(IHiddenRegion hiddenRegion, (IHiddenRegionFormatter)=>void init)! // append after the provided semantic region def append(ISemanticRegion appendAfter, (IHiddenRegionFormatter)=>void init) def append(EObject appendAfter, (IHiddenRegionFormatter)=>void init)! // prepend before the provided semantic region def prepend(ISemanticRegion prependBefore, (IHiddenRegionFormatter)=>void init) def prepend(EObject prependBefore, (IHiddenRegionFormatter)=>void init)!!!!!!!!!!! // ...}
specify for one
IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion
IHiddenRegionFormatter IHiddenRegion
![Page 91: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/91.jpg)
interface IFormattableDocument {!!!!!!! // set for provided hidden region def set(IHiddenRegion hiddenRegion, (IHiddenRegionFormatter)=>void init)! // append after the provided semantic region def append(ISemanticRegion appendAfter, (IHiddenRegionFormatter)=>void init) def append(EObject appendAfter, (IHiddenRegionFormatter)=>void init)! // prepend before the provided semantic region def prepend(ISemanticRegion prependBefore, (IHiddenRegionFormatter)=>void init) def prepend(EObject prependBefore, (IHiddenRegionFormatter)=>void init)!!!!!!!!!!! // ...}
specify for one
IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion
IHiddenRegionFormatter IHiddenRegion
![Page 92: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/92.jpg)
interface IFormattableDocument {!!!!!!! // set for both provided hidden regions def set(IHiddenRegion r1, IHiddenRegion r2, (IHiddenRegionFormatter)=>void init)! // before and after provided semantic region def surround(ISemanticRegion semanticRegion, (IHiddenRegionFormatter)=>void init) def surround(EObject owner, (IHiddenRegionFormatter)=>void init)! // set for two inwards-bound hidden regions def interior(ISemanticRegion r1, ISemanticRegion r2, (IHiddenRegionFormatter)=>void init) def interior(EObject object, (IHiddenRegionFormatter)=>void init)!!!!!!!!!!! // ...}
specify for two IHiddenRegionFormatter IHiddenRegion
![Page 93: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/93.jpg)
interface IFormattableDocument {!!!!!!! // set for both provided hidden regions def set(IHiddenRegion r1, IHiddenRegion r2, (IHiddenRegionFormatter)=>void init)! // before and after provided semantic region def surround(ISemanticRegion semanticRegion, (IHiddenRegionFormatter)=>void init) def surround(EObject owner, (IHiddenRegionFormatter)=>void init)! // set for two inwards-bound hidden regions def interior(ISemanticRegion r1, ISemanticRegion r2, (IHiddenRegionFormatter)=>void init) def interior(EObject object, (IHiddenRegionFormatter)=>void init)!!!!!!!!!!! // ...}
specify for two IHiddenRegionFormatter IHiddenRegion
IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion
![Page 94: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/94.jpg)
interface IFormattableDocument {!!!!!!! // set for both provided hidden regions def set(IHiddenRegion r1, IHiddenRegion r2, (IHiddenRegionFormatter)=>void init)! // before and after provided semantic region def surround(ISemanticRegion semanticRegion, (IHiddenRegionFormatter)=>void init) def surround(EObject owner, (IHiddenRegionFormatter)=>void init)! // set for two inwards-bound hidden regions def interior(ISemanticRegion r1, ISemanticRegion r2, (IHiddenRegionFormatter)=>void init) def interior(EObject object, (IHiddenRegionFormatter)=>void init)!!!!!!!!!!! // ...}
specify for two IHiddenRegionFormatter IHiddenRegion
IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion
![Page 95: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/95.jpg)
interface IFormattableDocument {!!!!!!! // set for both provided hidden regions def set(IHiddenRegion r1, IHiddenRegion r2, (IHiddenRegionFormatter)=>void init)! // before and after provided semantic region def surround(ISemanticRegion semanticRegion, (IHiddenRegionFormatter)=>void init) def surround(EObject owner, (IHiddenRegionFormatter)=>void init)! // set for two inwards-bound hidden regions def interior(ISemanticRegion r1, ISemanticRegion r2, (IHiddenRegionFormatter)=>void init) def interior(EObject object, (IHiddenRegionFormatter)=>void init)!!!!!!!!!!! // ...}
specify for two IHiddenRegionFormatter IHiddenRegion
IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion
![Page 96: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/96.jpg)
interface IFormattableDocument {!!!!!!! // set for both provided hidden regions def set(IHiddenRegion r1, IHiddenRegion r2, (IHiddenRegionFormatter)=>void init)! // before and after provided semantic region def surround(ISemanticRegion semanticRegion, (IHiddenRegionFormatter)=>void init) def surround(EObject owner, (IHiddenRegionFormatter)=>void init)! // set for two inwards-bound hidden regions def interior(ISemanticRegion r1, ISemanticRegion r2, (IHiddenRegionFormatter)=>void init) def interior(EObject object, (IHiddenRegionFormatter)=>void init)!!!!!!!!!!! // ...}
specify for two IHiddenRegionFormatter IHiddenRegion
IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion
![Page 97: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/97.jpg)
interface IFormattableDocument {!!!!!!! // set for both provided hidden regions def set(IHiddenRegion r1, IHiddenRegion r2, (IHiddenRegionFormatter)=>void init)! // before and after provided semantic region def surround(ISemanticRegion semanticRegion, (IHiddenRegionFormatter)=>void init) def surround(EObject owner, (IHiddenRegionFormatter)=>void init)! // set for two inwards-bound hidden regions def interior(ISemanticRegion r1, ISemanticRegion r2, (IHiddenRegionFormatter)=>void init) def interior(EObject object, (IHiddenRegionFormatter)=>void init)!!!!!!!!!!! // ...}
specify for two IHiddenRegionFormatter IHiddenRegion
IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion ISemanitcRegion IHiddenRegion
![Page 98: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/98.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!!! // ...}
![Page 99: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/99.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!!! // ...}
Why specify formatting for two hidden regions at once?
![Page 100: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/100.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!!! // ...}
Why specify formatting for two hidden regions at once?- indent() spans from first to second hidden region!
![Page 101: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/101.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!!! // ...}
Why specify formatting for two hidden regions at once?- indent() spans from first to second hidden region!- convenience
![Page 102: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/102.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!!! // ...}
Why specify formatting for two hidden regions at once?- indent() spans from first to second hidden region!- convenience
![Page 103: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/103.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!!! // ...}
Why specify formatting for two hidden regions at once?- indent() spans from first to second hidden region!- convenience
Why not increaseIndent() and decreaseIndent() individually?
![Page 104: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/104.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!!! // ...}
Why specify formatting for two hidden regions at once?- indent() spans from first to second hidden region!- convenience
Why not increaseIndent() and decreaseIndent() individually?- likely to not be applied symmetrically due to bugs, exceptions
![Page 105: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/105.jpg)
----------- RootDocument with ITextReplacers (syntax: <offset|text>) -----------machine my.X;state<19| >foo<23| >actions 1, 2, 3;<43|>end!--------------------------------------------------------------------------------19 1 " ": HiddenRegionReplacer: space=' ';indentInc=123 2 "\n ": HiddenRegionReplacer: newLine=143 1 "\n": HiddenRegionReplacer: newLine=1;indentDec=1
def dispatch void format(State state, extension IFormattableDocument document) { state.interior[indent] state.regionFor.feature(STATE__NAME).prepend[oneSpace].append[newLine] state.regionFor.keyword("end").prepend[newLine] println(document.toString)}
State: {State} 'state' name=ID ('actions' actions+=INT ("," actions+=INT)* ";")? 'end';
![Page 106: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/106.jpg)
----------- RootDocument with ITextReplacers (syntax: <offset|text>) -----------machine my.X;state<19| >foo<23| >actions 1, 2, 3;<43|>end!--------------------------------------------------------------------------------19 1 " ": HiddenRegionReplacer: space=' ';indentInc=123 2 "\n ": HiddenRegionReplacer: newLine=143 1 "\n": HiddenRegionReplacer: newLine=1;indentDec=1
def dispatch void format(State state, extension IFormattableDocument document) { state.interior[indent] state.regionFor.feature(STATE__NAME).prepend[oneSpace].append[newLine] state.regionFor.keyword("end").prepend[newLine] println(document.toString)}
State: {State} 'state' name=ID ('actions' actions+=INT ("," actions+=INT)* ";")? 'end';
![Page 107: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/107.jpg)
----------- RootDocument with ITextReplacers (syntax: <offset|text>) -----------machine my.X;state<19| >foo<23| >actions 1, 2, 3;<43|>end!--------------------------------------------------------------------------------19 1 " ": HiddenRegionReplacer: space=' ';indentInc=123 2 "\n ": HiddenRegionReplacer: newLine=143 1 "\n": HiddenRegionReplacer: newLine=1;indentDec=1
def dispatch void format(State state, extension IFormattableDocument document) { state.interior[indent] state.regionFor.feature(STATE__NAME).prepend[oneSpace].append[newLine] state.regionFor.keyword("end").prepend[newLine] println(document.toString)}
State: {State} 'state' name=ID ('actions' actions+=INT ("," actions+=INT)* ";")? 'end';
![Page 108: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/108.jpg)
----------- RootDocument with ITextReplacers (syntax: <offset|text>) -----------machine my.X;state<19| >foo<23| >actions 1, 2, 3;<43|>end!--------------------------------------------------------------------------------19 1 " ": HiddenRegionReplacer: space=' ';indentInc=123 2 "\n ": HiddenRegionReplacer: newLine=143 1 "\n": HiddenRegionReplacer: newLine=1;indentDec=1
def dispatch void format(State state, extension IFormattableDocument document) { state.interior[indent] state.regionFor.feature(STATE__NAME).prepend[oneSpace].append[newLine] state.regionFor.keyword("end").prepend[newLine] println(document.toString)}
State: {State} 'state' name=ID ('actions' actions+=INT ("," actions+=INT)* ";")? 'end';
![Page 109: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/109.jpg)
----------- RootDocument with ITextReplacers (syntax: <offset|text>) -----------machine my.X;state<19| >foo<23| >actions 1, 2, 3;<43|>end!--------------------------------------------------------------------------------19 1 " ": HiddenRegionReplacer: space=' ';indentInc=123 2 "\n ": HiddenRegionReplacer: newLine=143 1 "\n": HiddenRegionReplacer: newLine=1;indentDec=1
def dispatch void format(State state, extension IFormattableDocument document) { state.interior[indent] state.regionFor.feature(STATE__NAME).prepend[oneSpace].append[newLine] state.regionFor.keyword("end").prepend[newLine] println(document.toString)}
State: {State} 'state' name=ID ('actions' actions+=INT ("," actions+=INT)* ";")? 'end';
![Page 110: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/110.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!! // ...}
API: specify formatting information for hidden regions
Implementation: store text replacers for text regions
![Page 111: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/111.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!! // ...}
offset : intlength: intnewText: String
ITextReplacementautowrap()setPriority(int priority)indent()newLine()setNewLines(int newLines)setNewLines(int min, int default, int max)noSpace()oneSpace()setSpace(String space)
IHiddenRegionFormatter
( )*?Recap: The formatter outputs text replacements!
![Page 112: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/112.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!}
createReplacements(ITextReplacerContext context): ITextReplacerContext
ITextReplacer
HiddenRegionReplacer
autowrap()setPriority(int priority)indent()newLine()setNewLines(int newLines)setNewLines(int min, int default, int max)noSpace()oneSpace()setSpace(String space)
IHiddenRegionFormatter
configures
configures a HiddenRegionReplacer
![Page 113: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/113.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!}
creates TextReplacements
createReplacements(ITextReplacerContext context): ITextReplacerContext
ITextReplacer
offset : intlength: intnewText: String
ITextReplacementHiddenRegionReplacer
autowrap()setPriority(int priority)indent()newLine()setNewLines(int newLines)setNewLines(int min, int default, int max)noSpace()oneSpace()setSpace(String space)
IHiddenRegionFormatter
configures
creates
![Page 114: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/114.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!}
specific for TextRegion
createReplacements(ITextReplacerContext context): ITextReplacerContext
ITextReplacer
offset : intlength: intnewText: String
ITextReplacementHiddenRegionReplacer
autowrap()setPriority(int priority)indent()newLine()setNewLines(int newLines)setNewLines(int min, int default, int max)noSpace()oneSpace()setSpace(String space)
IHiddenRegionFormatter
configures
offset : intlength: int
ITextRegion
1
1
creates
![Page 115: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/115.jpg)
interface IFormattableDocument {!!!!!!!!!!!! !!!!!!!!!!!!!}
createReplacements(ITextReplacerContext context): ITextReplacerContext
ITextReplacer
offset : intlength: intnewText: String
ITextReplacementHiddenRegionReplacer
autowrap()setPriority(int priority)indent()newLine()setNewLines(int newLines)setNewLines(int min, int default, int max)noSpace()oneSpace()setSpace(String space)
IHiddenRegionFormatter
configures
getIndentation(): intwithIndentation(int indent): ITextReplacerContextgetParent(): ITextReplacerContextaddReplacement(ITextReplacement repl)getAllReplacements():List<ITextReplacement>
ITextReplacerContext
uses
offset : intlength: int
ITextRegion
1
1
creates
collects
context collects replacements
![Page 116: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/116.jpg)
class FormattableDocument {
! Map<ITextRegion, ITextReplacer> replacers;! def List<ITextReplacement> renderToTextReplacements() { val List<ITextReplacer> sorted = sortByOffset(replacers) var ITextReplacerContext context = createTextReplacerContext() for (ITextReplacer replacer : sorted) { context = replacer.createReplacements(context) } return context.getAllReplacements() }}!!!!!!class MyReplacer implements ITextReplacer {! override ITextReplacerContext createReplacements(ITextReplacerContext context) { val ITextReplacement replacement = region.replaceWith(" ") context.addReplacement(replacement) val int oldIndentation = context.getIndentation() return context.withIndentation(oldIndentation + 1) }}
createReplacements(ITextReplacerContext context): ITextReplacerContext
ITextReplacer
offset : intlength: intnewText: String
ITextReplacementHiddenRegionReplacer
getIndentation(): intwithIndentation(int indent): ITextReplacerContextgetParent(): ITextReplacerContextaddReplacement(ITextReplacement repl)getAllReplacements():List<ITextReplacement>
ITextReplacerContext
uses
offset : intlength: int
ITextRegion
1
1
creates
collects
![Page 117: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/117.jpg)
class FormattableDocument {
! Map<ITextRegion, ITextReplacer> replacers;! def List<ITextReplacement> renderToTextReplacements() { val List<ITextReplacer> sorted = sortByOffset(replacers) var ITextReplacerContext context = createTextReplacerContext() for (ITextReplacer replacer : sorted) { context = replacer.createReplacements(context) } return context.getAllReplacements() }}!!!!!!class MyReplacer implements ITextReplacer {! override ITextReplacerContext createReplacements(ITextReplacerContext context) { val ITextReplacement replacement = region.replaceWith(" ") context.addReplacement(replacement) val int oldIndentation = context.getIndentation() return context.withIndentation(oldIndentation + 1) }}
createReplacements(ITextReplacerContext context): ITextReplacerContext
ITextReplacer
offset : intlength: intnewText: String
ITextReplacementHiddenRegionReplacer
getIndentation(): intwithIndentation(int indent): ITextReplacerContextgetParent(): ITextReplacerContextaddReplacement(ITextReplacement repl)getAllReplacements():List<ITextReplacement>
ITextReplacerContext
uses
offset : intlength: int
ITextRegion
1
1
creates
collects
sorted
![Page 118: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/118.jpg)
class FormattableDocument {
! Map<ITextRegion, ITextReplacer> replacers;! def List<ITextReplacement> renderToTextReplacements() { val List<ITextReplacer> sorted = sortByOffset(replacers) var ITextReplacerContext context = createTextReplacerContext() for (ITextReplacer replacer : sorted) { context = replacer.createReplacements(context) } return context.getAllReplacements() }}!!!!!!class MyReplacer implements ITextReplacer {! override ITextReplacerContext createReplacements(ITextReplacerContext context) { val ITextReplacement replacement = region.replaceWith(" ") context.addReplacement(replacement) val int oldIndentation = context.getIndentation() return context.withIndentation(oldIndentation + 1) }}
createReplacements(ITextReplacerContext context): ITextReplacerContext
ITextReplacer
offset : intlength: intnewText: String
ITextReplacementHiddenRegionReplacer
getIndentation(): intwithIndentation(int indent): ITextReplacerContextgetParent(): ITextReplacerContextaddReplacement(ITextReplacement repl)getAllReplacements():List<ITextReplacement>
ITextReplacerContext
uses
offset : intlength: int
ITextRegion
1
1
creates
collects
invoke in sorted order
![Page 119: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/119.jpg)
class FormattableDocument {
! Map<ITextRegion, ITextReplacer> replacers;! def List<ITextReplacement> renderToTextReplacements() { val List<ITextReplacer> sorted = sortByOffset(replacers) var ITextReplacerContext context = createTextReplacerContext() for (ITextReplacer replacer : sorted) { context = replacer.createReplacements(context) } return context.getAllReplacements() }}!!!!!!class MyReplacer implements ITextReplacer {! override ITextReplacerContext createReplacements(ITextReplacerContext context) { val ITextReplacement replacement = region.replaceWith(" ") context.addReplacement(replacement) val int oldIndentation = context.getIndentation() return context.withIndentation(oldIndentation + 1) }}
createReplacements(ITextReplacerContext context): ITextReplacerContext
ITextReplacer
offset : intlength: intnewText: String
ITextReplacementHiddenRegionReplacer
getIndentation(): intwithIndentation(int indent): ITextReplacerContextgetParent(): ITextReplacerContextaddReplacement(ITextReplacement repl)getAllReplacements():List<ITextReplacement>
ITextReplacerContext
uses
offset : intlength: int
ITextRegion
1
1
creates
collects
in/out context
![Page 120: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/120.jpg)
class FormattableDocument {
! Map<ITextRegion, ITextReplacer> replacers;! def List<ITextReplacement> renderToTextReplacements() { val List<ITextReplacer> sorted = sortByOffset(replacers) var ITextReplacerContext context = createTextReplacerContext() for (ITextReplacer replacer : sorted) { context = replacer.createReplacements(context) } return context.getAllReplacements() }}!!!!!!class MyReplacer implements ITextReplacer {! override ITextReplacerContext createReplacements(ITextReplacerContext context) { val ITextReplacement replacement = region.replaceWith(" ") context.addReplacement(replacement) val int oldIndentation = context.getIndentation() return context.withIndentation(oldIndentation + 1) }}
createReplacements(ITextReplacerContext context): ITextReplacerContext
ITextReplacer
offset : intlength: intnewText: String
ITextReplacementHiddenRegionReplacer
getIndentation(): intwithIndentation(int indent): ITextReplacerContextgetParent(): ITextReplacerContextaddReplacement(ITextReplacement repl)getAllReplacements():List<ITextReplacement>
ITextReplacerContext
uses
offset : intlength: int
ITextRegion
1
1
creates
collects
return replacements
![Page 121: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/121.jpg)
class FormattableDocument {
! Map<ITextRegion, ITextReplacer> replacers;! def List<ITextReplacement> renderToTextReplacements() { val List<ITextReplacer> sorted = sortByOffset(replacers) var ITextReplacerContext context = createTextReplacerContext() for (ITextReplacer replacer : sorted) { context = replacer.createReplacements(context) } return context.getAllReplacements() }}!!!!!!class MyReplacer implements ITextReplacer {! override ITextReplacerContext createReplacements(ITextReplacerContext context) { val ITextReplacement replacement = region.replaceWith(" ") context.addReplacement(replacement) val int oldIndentation = context.getIndentation() return context.withIndentation(oldIndentation + 1) }}
createReplacements(ITextReplacerContext context): ITextReplacerContext
ITextReplacer
offset : intlength: intnewText: String
ITextReplacementHiddenRegionReplacer
getIndentation(): intwithIndentation(int indent): ITextReplacerContextgetParent(): ITextReplacerContextaddReplacement(ITextReplacement repl)getAllReplacements():List<ITextReplacement>
ITextReplacerContext
uses
offset : intlength: int
ITextRegion
1
1
creates
collects
create replacement
![Page 122: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/122.jpg)
class FormattableDocument {
! Map<ITextRegion, ITextReplacer> replacers;! def List<ITextReplacement> renderToTextReplacements() { val List<ITextReplacer> sorted = sortByOffset(replacers) var ITextReplacerContext context = createTextReplacerContext() for (ITextReplacer replacer : sorted) { context = replacer.createReplacements(context) } return context.getAllReplacements() }}!!!!!!class MyReplacer implements ITextReplacer {! override ITextReplacerContext createReplacements(ITextReplacerContext context) { val ITextReplacement replacement = region.replaceWith(" ") context.addReplacement(replacement) val int oldIndentation = context.getIndentation() return context.withIndentation(oldIndentation + 1) }}
createReplacements(ITextReplacerContext context): ITextReplacerContext
ITextReplacer
offset : intlength: intnewText: String
ITextReplacementHiddenRegionReplacer
getIndentation(): intwithIndentation(int indent): ITextReplacerContextgetParent(): ITextReplacerContextaddReplacement(ITextReplacement repl)getAllReplacements():List<ITextReplacement>
ITextReplacerContext
uses
offset : intlength: int
ITextRegion
1
1
creates
collects
add to context
![Page 123: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/123.jpg)
class FormattableDocument {
! Map<ITextRegion, ITextReplacer> replacers;! def List<ITextReplacement> renderToTextReplacements() { val List<ITextReplacer> sorted = sortByOffset(replacers) var ITextReplacerContext context = createTextReplacerContext() for (ITextReplacer replacer : sorted) { context = replacer.createReplacements(context) } return context.getAllReplacements() }}!!!!!!class MyReplacer implements ITextReplacer {! override ITextReplacerContext createReplacements(ITextReplacerContext context) { val ITextReplacement replacement = region.replaceWith(" ") context.addReplacement(replacement) val int oldIndentation = context.getIndentation() return context.withIndentation(oldIndentation + 1) }}
createReplacements(ITextReplacerContext context): ITextReplacerContext
ITextReplacer
offset : intlength: intnewText: String
ITextReplacementHiddenRegionReplacer
getIndentation(): intwithIndentation(int indent): ITextReplacerContextgetParent(): ITextReplacerContextaddReplacement(ITextReplacement repl)getAllReplacements():List<ITextReplacement>
ITextReplacerContext
uses
offset : intlength: int
ITextRegion
1
1
creates
collects
return cloned context
![Page 124: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/124.jpg)
class FormattableDocument {
! Map<ITextRegion, ITextReplacer> replacers;! def List<ITextReplacement> renderToTextReplacements() { val List<ITextReplacer> sorted = sortByOffset(replacers) var ITextReplacerContext context = createTextReplacerContext() for (ITextReplacer replacer : sorted) { context = replacer.createReplacements(context) } return context.getAllReplacements() }}!!!!!!class MyReplacer implements ITextReplacer {! override ITextReplacerContext createReplacements(ITextReplacerContext context) { val ITextReplacement replacement = region.replaceWith(" ") context.addReplacement(replacement) val int oldIndentation = context.getIndentation() return context.withIndentation(oldIndentation + 1) }}
createReplacements(ITextReplacerContext context): ITextReplacerContext
ITextReplacer
offset : intlength: intnewText: String
ITextReplacementHiddenRegionReplacer
getIndentation(): intwithIndentation(int indent): ITextReplacerContextgetParent(): ITextReplacerContextaddReplacement(ITextReplacement repl)getAllReplacements():List<ITextReplacement>
ITextReplacerContext
uses
offset : intlength: int
ITextRegion
1
1
creates
collects
![Page 125: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/125.jpg)
EXAMPLES
![Page 126: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/126.jpg)
state foo actions 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13; end
AutoWrap
def dispatch void format(State state, extension IFormattableDocument document) { for (k : state.regionFor.keywords(“,")) { k.prepend[noSpace].append[oneSpace; autowrap] }}
State: 'state' name=ID 'actions' actions+=INT ("," actions+=INT)* ";" 'end';
![Page 127: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/127.jpg)
state foo actions 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13; end
AutoWrap
def dispatch void format(State state, extension IFormattableDocument document) { for (k : state.regionFor.keywords(“,")) { k.prepend[noSpace].append[oneSpace; autowrap] }}
State: 'state' name=ID 'actions' actions+=INT ("," actions+=INT)* ";" 'end';
![Page 128: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/128.jpg)
def dispatch void format(State state, extension IFormattableDocument document) { val IAutowrapFormatter af = [ region, wrapped, doc | val first = (region as IWhitespace).hiddenRegion val last = state.regionFor.keyword(";").previousHiddenRegion doc.set(first, last, [indent]) ] for (k : state.regionFor.keywords(",")) { k.prepend[noSpace].append[oneSpace; autowrap; onAutowrap = af] }}
AutoWrap with Handler
State: 'state' name=ID 'actions' actions+=INT ("," actions+=INT)* ";" 'end';
state foo actions 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13; end
![Page 129: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/129.jpg)
def dispatch void format(State state, extension IFormattableDocument document) { val IAutowrapFormatter af = [ region, wrapped, doc | val first = (region as IWhitespace).hiddenRegion val last = state.regionFor.keyword(";").previousHiddenRegion doc.set(first, last, [indent]) ] for (k : state.regionFor.keywords(",")) { k.prepend[noSpace].append[oneSpace; autowrap; onAutowrap = af] }}
AutoWrap with Handler
State: 'state' name=ID 'actions' actions+=INT ("," actions+=INT)* ";" 'end';
state foo actions 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13; end
![Page 130: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/130.jpg)
def dispatch void format(State state, extension IFormattableDocument document) { val IAutowrapFormatter af = [ region, wrapped, doc | val first = (region as IWhitespace).hiddenRegion val last = state.regionFor.keyword(";").previousHiddenRegion doc.set(first, last, [indent]) ] for (k : state.regionFor.keywords(",")) { k.prepend[noSpace].append[oneSpace; autowrap; onAutowrap = af] }}
AutoWrap with Handler
State: 'state' name=ID 'actions' actions+=INT ("," actions+=INT)* ";" 'end';
state foo actions 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13; end
![Page 131: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/131.jpg)
def dispatch void format(State state, extension IFormattableDocument document) { val IAutowrapFormatter af = [ region, wrapped, doc | val first = (region as IWhitespace).hiddenRegion val last = state.regionFor.keyword(";").previousHiddenRegion doc.set(first, last, [indent]) ] for (k : state.regionFor.keywords(",")) { k.prepend[noSpace].append[oneSpace; autowrap; onAutowrap = af] }}
AutoWrap with Handler
State: 'state' name=ID 'actions' actions+=INT ("," actions+=INT)* ";" 'end';
state foo actions 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13; end
![Page 132: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/132.jpg)
Conditional Formatting state bar 1 => foo; 2 => foo; 3 => foo; 4 => foo; 5 => foo;end
state bar 1 => foo; 2 => foo; 3 => foo; end
def dispatch void format(State state, extension IFormattableDocument document) { state.formatConditionally( [ doc | val extension slDoc = doc.requireFitsInLine state.regionFor.feature(STATE__NAME).surround[oneSpace] for (t : state.transitions) { t.format.append[oneSpace] } ], [ extension doc | state.interior[indent] state.regionFor.feature(STATE__NAME).prepend[oneSpace].append[newLine] for (t : state.transitions) { t.format.append[newLine] } ] )}
State: 'state' name=ID transitions+=Transition* 'end';
![Page 133: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/133.jpg)
Conditional Formatting state bar 1 => foo; 2 => foo; 3 => foo; 4 => foo; 5 => foo;end
state bar 1 => foo; 2 => foo; 3 => foo; end
def dispatch void format(State state, extension IFormattableDocument document) { state.formatConditionally( [ doc | val extension slDoc = doc.requireFitsInLine state.regionFor.feature(STATE__NAME).surround[oneSpace] for (t : state.transitions) { t.format.append[oneSpace] } ], [ extension doc | state.interior[indent] state.regionFor.feature(STATE__NAME).prepend[oneSpace].append[newLine] for (t : state.transitions) { t.format.append[newLine] } ] )}
State: 'state' name=ID transitions+=Transition* 'end';
XOR
![Page 134: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/134.jpg)
Conditional Formatting state bar 1 => foo; 2 => foo; 3 => foo; 4 => foo; 5 => foo;end
state bar 1 => foo; 2 => foo; 3 => foo; end
def dispatch void format(State state, extension IFormattableDocument document) { state.formatConditionally( [ doc | val extension slDoc = doc.requireFitsInLine state.regionFor.feature(STATE__NAME).surround[oneSpace] for (t : state.transitions) { t.format.append[oneSpace] } ], [ extension doc | state.interior[indent] state.regionFor.feature(STATE__NAME).prepend[oneSpace].append[newLine] for (t : state.transitions) { t.format.append[newLine] } ] )}
State: 'state' name=ID transitions+=Transition* 'end';
![Page 135: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/135.jpg)
Conditional Formatting state bar 1 => foo; 2 => foo; 3 => foo; 4 => foo; 5 => foo;end
state bar 1 => foo; 2 => foo; 3 => foo; end
def dispatch void format(State state, extension IFormattableDocument document) { state.formatConditionally( [ doc | val extension slDoc = doc.requireFitsInLine state.regionFor.feature(STATE__NAME).surround[oneSpace] for (t : state.transitions) { t.format.append[oneSpace] } ], [ extension doc | state.interior[indent] state.regionFor.feature(STATE__NAME).prepend[oneSpace].append[newLine] for (t : state.transitions) { t.format.append[newLine] } ] )}
State: 'state' name=ID transitions+=Transition* 'end';
![Page 136: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/136.jpg)
Conditional Formatting state bar 1 => foo; 2 => foo; 3 => foo; 4 => foo; 5 => foo;end
state bar 1 => foo; 2 => foo; 3 => foo; end
def dispatch void format(State state, extension IFormattableDocument document) { state.formatConditionally( [ doc | val extension slDoc = doc.requireFitsInLine state.regionFor.feature(STATE__NAME).surround[oneSpace] for (t : state.transitions) { t.format.append[oneSpace] } ], [ extension doc | state.interior[indent] state.regionFor.feature(STATE__NAME).prepend[oneSpace].append[newLine] for (t : state.transitions) { t.format.append[newLine] } ] )}
State: 'state' name=ID transitions+=Transition* 'end';
![Page 137: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/137.jpg)
Pattern-Aware formatting
def dispatch void format(State state, extension IFormattableDocument document) { if (state.regionFor.keyword("end").previousHiddenRegion.isMultiline) { state.interior[indent] state.regionFor.feature(STATE__NAME).prepend[oneSpace].append[newLine] for (t : state.transitions) { t.format.append[newLine] } } else { state.regionFor.feature(STATE__NAME).surround[oneSpace] for (t : state.transitions) { t.format.append[oneSpace] } } }
state bar 1 => foo;end
state bar 1 => foo; end
State: 'state' name=ID transitions+=Transition* 'end';
![Page 138: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/138.jpg)
Pattern-Aware formatting
def dispatch void format(State state, extension IFormattableDocument document) { if (state.regionFor.keyword("end").previousHiddenRegion.isMultiline) { state.interior[indent] state.regionFor.feature(STATE__NAME).prepend[oneSpace].append[newLine] for (t : state.transitions) { t.format.append[newLine] } } else { state.regionFor.feature(STATE__NAME).surround[oneSpace] for (t : state.transitions) { t.format.append[oneSpace] } } }
State: 'state' name=ID transitions+=Transition* 'end';
state bar 1 => foo;end
state bar 1 => foo; end
![Page 139: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/139.jpg)
Table-based formattingstate baz 1 => foo; 12 => foo; 123 => foo;end
def dispatch void format(State state, extension IFormattableDocument document) { state.interior[indent] val width = state.transitions.map[regionFor.feature(TRANSITION__EVENT).length].max + 1; for (t : state.transitions) { val region = t.regionFor.feature(TRANSITION__EVENT) region.append[space = Strings.repeat(" ", width - region.length)] t.regionFor.keyword(";").prepend[noSpace].append[newLine] } }
State: 'state' name=ID transitions+=Transition* 'end';
![Page 140: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/140.jpg)
Table-based formattingstate baz 1 => foo; 12 => foo; 123 => foo;end
def dispatch void format(State state, extension IFormattableDocument document) { state.interior[indent] val width = state.transitions.map[regionFor.feature(TRANSITION__EVENT).length].max + 1; for (t : state.transitions) { val region = t.regionFor.feature(TRANSITION__EVENT) region.append[space = Strings.repeat(" ", width - region.length)] t.regionFor.keyword(";").prepend[noSpace].append[newLine] } }
State: 'state' name=ID transitions+=Transition* 'end';
![Page 141: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/141.jpg)
Table-based formattingstate baz 1 => foo; 12 => foo; 123 => foo;end
def dispatch void format(State state, extension IFormattableDocument document) { state.interior[indent] val width = state.transitions.map[regionFor.feature(TRANSITION__EVENT).length].max + 1; for (t : state.transitions) { val region = t.regionFor.feature(TRANSITION__EVENT) region.append[space = Strings.repeat(" ", width - region.length)] t.regionFor.keyword(";").prepend[noSpace].append[newLine] } }
State: 'state' name=ID transitions+=Transition* 'end';
![Page 142: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/142.jpg)
TESTS
![Page 143: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/143.jpg)
org.eclipse.xtext.junit4.formatter.FormatterTester@Test def void example1() { assertFormatted[ toBeFormatted = ''' entity Foo { propertyName:String op name() { } } ''' ]} @Test def void example2() {
assertFormatted[ expectation = ''' entity Foo { op foo():String { "xx" } } ''' toBeFormatted = ''' entity Foo { op foo ( ) : String { "xx" } } ''' ]}
![Page 144: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/144.jpg)
THE OLD FORMATTER
• no access to text, Node Model or AST
• not enhanceable engine
• will be deprecated
![Page 145: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/145.jpg)
RELEASES
• Alpha release as part of Xtext 2.8.0, 2.8.1, 2.8.3
• Beta release as of Xtext 2.9-beta
• stable (public API) release (hopefully) with Xtext 2.9
![Page 146: Xtext's new Formatter API](https://reader030.fdocuments.us/reader030/viewer/2022012312/55abe5711a28ab3d298b4798/html5/thumbnails/146.jpg)
Questions?