Hi all,
I am facing an issue where I would like to align the start position of list items.
I want to align the list items using spaces and not indentation, because indentation is smaller than what is required for them to be aligned.
Problem occurs if the unformatted text exists on a line where a newLine will be added elsewhere and this results in miscalculation of lineoffset of first element which is used to align the rest of the list.
Grammar:
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals
generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"
DSL returns XTDSL:
models+=Model*
;
Model returns XTModel:
{XTModel} 'startList' '(' greetings+=Greeting*')'';';
Greeting returns XTGreeting:
'list' ids_list=identifier_list ':' 'endlist' ';';
identifier_list returns XTIdentifierList:
ids+=identifier (',' ids+=identifier)*
;
identifier returns XTIdentifier:
{XTIdentifier} ID
;
Formatter:
def dispatch void format(XTDSL xtdsl, extension IFormattableDocument document) {
xtdsl.models.forEach[format]
}
def dispatch void format(XTModel xtmodel, extension IFormattableDocument document) {
xtmodel.greetings.forEach[format]
xtmodel.regionFor.keyword("startList").append[oneSpace]
xtmodel.regionFor.keyword("(").append[noSpace]
xtmodel.regionFor.keyword(")").prepend[noSpace]
xtmodel.regionFor.keyword(";").prepend[noSpace]
xtmodel.append[newLine]
alignGreetingsOnColon(xtmodel.greetings, document)
alignGreetingsStartOffset(xtmodel.greetings, document)
}
def dispatch void format(XTGreeting xTGreeting, extension IFormattableDocument document) {
xTGreeting.regionFor.keyword("list").append[oneSpace]
xTGreeting.regionFor.keyword(":").prepend[oneSpace]
xTGreeting.regionFor.keyword("endlist").prepend[oneSpace].append[noSpace]
xTGreeting.ids_list.format
}
def dispatch void format(XTIdentifierList xTIdentifierList, extension IFormattableDocument document) {
xTIdentifierList.regionFor.keywords(",").forEach[prepend[noSpace]append[oneSpace]]
}
def void alignGreetingsOnColon(EList<XTGreeting> greetings, extension IFormattableDocument document) {
var width = -1
for (greeting : greetings) {
val colonSemanticRegion = greeting.regionFor.keyword(":")
if (colonSemanticRegion != null) {
width = Math.max(width, colonSemanticRegion.previousSemanticRegion.endOffset - greeting.allSemanticRegions.get(0).offset + 1);
}
}
println("Width = " + width)
if (width > 0) {
for (greeting : greetings) {
val colonRegion = greeting.regionFor.keyword(":")
if (colonRegion != null) {
val numberOfSpaces = width - (colonRegion.previousSemanticRegion.endOffset - greeting.allSemanticRegions.get(0).offset);
colonRegion.prepend[space = Strings.repeat(" ", numberOfSpaces); highPriority]
}
}
}
}
def void alignGreetingsStartOffset(EList<XTGreeting> greetings, extension IFormattableDocument document) {
if (greetings.length > 0) {
val firstElement = greetings.get(0)
val firstSR = firstElement.allSemanticRegions.get(0)
val lineOffsetOfFirstElement = firstSR.offset - firstSR.textRegionAccess.regionForLineAtOffset(firstSR.offset).offset
for (element : greetings) {
if (element != firstElement && lineOffsetOfFirstElement > 0) {
element.allSemanticRegions.get(0).prepend[space = System.lineSeparator + Strings.repeat(" ", lineOffsetOfFirstElement)]
}
}
}
}
Testcase:
startList (); startList (list A, B, C, D : endlist;list E : endlist;
list F, G : endlist;);
Actual:
startList ();
startList (list A, B, C, D : endlist;
list E : endlist;
list F, G : endlist;);
Expected:
startList ();
startList (list A, B, C, D : endlist;
list E : endlist;
list F, G : endlist;);
Because the Testcase text will have newLine added after the first startList ();, the result is lineOffsetOfFirstElement has 13 added to it which is the length of the first startList();
If I execute the format action twice I reach the expected result.
My questions are:
- Is there a better way to achieve this?
- Can I reformat after the first format pass is done?
- Can I apply the added replacements before doing the alignment because the alignment is dependent on the formatted text?
- Can I have multiple formatters executed sequentially?