Last active
August 29, 2025 08:54
-
-
Save FedericoPonzi/9273d951189ab99ad5a7aba92ad0fc69 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Two fixes: | |
1. Align elimination | |
Use the current column as the new indent. Do not emit spaces or push the original entry. | |
```java | |
} else if (entryDoc instanceof Align) { | |
Align alignDoc = (Align) entryDoc; | |
int newIndent = position; // anchor at current column | |
inQueue.addFirst(entry(newIndent, entryMargin, alignDoc.doc())); | |
} | |
``` | |
2. LineOr handling | |
You are double-counting indentation: you set position to entryIndent and also enqueue indent spaces. Reset to column 0 and let margin + spaces advance position. | |
```java | |
} else if (entryDoc instanceof LineOr) { | |
// Start a new line at column 0; margin + spaces will advance position | |
position = 0; | |
// Note reverse order: push spaces first, then margin, so margin is processed first | |
if (entryIndent > 0) { | |
String indentSpaces = Indents.get(entryIndent); | |
inQueue.addFirst(entry(entryIndent, entryMargin, text(indentSpaces))); | |
} | |
inQueue.addFirst(entry(entryIndent, entryMargin, entryMargin)); | |
outQueue.add(topEntry); | |
} | |
``` | |
How to use Align in your DisjListConstruct | |
Align once for the whole block, not after every append. Ensure the parent appends the block immediately after the colon so the anchor column is correct. | |
```java | |
public class DisjListConstruct implements TlaConstruct { | |
@Override public String getName() { return "N_DisjList"; } | |
@Override public int getSupportedNodeKind() { return NodeKind.DISJ_LIST.getId(); } | |
@Override | |
public Doc buildDoc(TreeNode node, ConstructContext context, int indentSize) { | |
var z = node.zero(); | |
assert z != null && z.length > 0; | |
List<Doc> parts = Arrays.stream(z).map(context::buildChild).collect(Collectors.toList()); | |
Doc body = parts.get(0); | |
for (int i = 1; i < parts.size(); i++) { | |
body = body.appendLine(parts.get(i)); | |
} | |
// Align the entire block relative to the current column at the call site | |
return Doc.group(body.align()); | |
} | |
} | |
``` | |
At the call site for your example, build like this so Align anchors right after the colon: | |
```java | |
Doc comp = | |
text("{ x \\in 1 .. max : ") | |
.append(disjListDoc) // disjListDoc is the result of DisjListConstruct | |
.append(text(" }")); | |
return Doc.group(comp); | |
``` | |
What to check next | |
* If the colon and the list are produced by different visitors, ensure the parent composes them in this order: colon + space, then the aligned list. If the list is wrapped in additional nodes after the colon, Align may capture the wrong column. | |
* Add a unit test with a narrow width to force a break and assert the two lines of the predicates start in the same column. | |
* If you need a hanging indent after the colon (e.g., +2 spaces), introduce a helper hang(by, d) = align(indent(by, d)) and use hang(2, disjListBlock). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Represents a {@link Doc} aligned to the current column position. | |
* When a new line occurs within this document, subsequent lines will be | |
* indented to align with the column position where this document started. | |
*/ | |
public static class Align extends Doc { | |
private final Doc doc; | |
protected Align(Doc doc) { | |
this.doc = doc; | |
} | |
public Doc doc() { | |
return doc; | |
} | |
@Override | |
Doc flatten() { | |
return new Align(doc.flatten()); | |
} | |
@Override | |
boolean hasParams() { | |
return doc.hasParams(); | |
} | |
@Override | |
boolean hasLineSeparators() { | |
return doc.hasLineSeparators(); | |
} | |
@Override | |
public Doc bind(String name, Doc value) { | |
return new Align(doc.bind(name, value)); | |
} | |
@Override | |
public Doc bind(Map<String, Doc> bindings) { | |
return new Align(doc.bind(bindings)); | |
} | |
@Override | |
public boolean equals(Object o) { | |
if (this == o) return true; | |
if (o == null || getClass() != o.getClass()) return false; | |
Align align = (Align) o; | |
return Objects.equals(doc, align.doc); | |
} | |
@Override | |
public int hashCode() { | |
return Objects.hash(doc); | |
} | |
@Override | |
public String toString() { | |
return "Align[" + | |
"doc=" + doc + | |
']'; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment