Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
1b343dd
Implement Roslyn-style red-green tree architecture for DOM parser
angelozerr Sep 4, 2026
432395f
Implement incremental reparse and atomic swap for red-green tree
angelozerr Sep 4, 2026
29d4340
Add recursive descent to incremental parser for deep structural sharing
angelozerr Sep 5, 2026
54c28fc
Add detailed documentation for incremental red-green parser
angelozerr Sep 5, 2026
aa9bb76
Reduce memory by extracting only GreenDocument from previous model
angelozerr Sep 5, 2026
745a573
Add lazy red tree building for incremental parses
angelozerr Sep 5, 2026
190a379
Reduce memory footprint of red-green tree and DOM nodes
angelozerr Sep 5, 2026
ab58dc7
Reduce TextDocument.update allocation with persistent StringBuilder
angelozerr Sep 5, 2026
598b50d
Migrate getText() callers to CharSequence to eliminate toString() copies
angelozerr Sep 5, 2026
4ef5771
Reduce DOM memory: tag interning, DOMNode[] children, GreenElement ref
angelozerr Sep 5, 2026
08ea773
Release StringBuilder after text materialization to avoid double
angelozerr Sep 5, 2026
158a598
Reduce memory spikes: lazy initial parse, compact GreenElement, early GC
angelozerr Sep 5, 2026
1cca6f0
Fix incremental parser corruption and reduce memory spikes
angelozerr Sep 6, 2026
75dc6f4
Reduce DOM memory by 14.5 MB: compact attributes, DOMAttr fields, lazy
angelozerr Sep 6, 2026
18515a9
Derive endTagCloseRel from flag and optimize text-only incremental edits
angelozerr Sep 6, 2026
649928d
Move attributeNodes from DOMNode to DOMElement/PI saving 4.4 MB
angelozerr Sep 6, 2026
44ab703
Eliminate getText() materialization: use CharSequence throughout
angelozerr Sep 6, 2026
18e3da3
Reduce GC pressure: replace LinkedHashSet with array in
angelozerr Sep 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
494 changes: 494 additions & 0 deletions docs/Incremental-Red-Green-Parser.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,6 @@ DOMNode findNodeAt(Locator locator) {
private static String getTextContent(DOMElement element) {
int start = element.getStartTagCloseOffset() + 1;
int end = element.getEndTagOpenOffset();
return element.getOwnerDocument().getText().substring(start, end);
return element.getOwnerDocument().getTextSequence().subSequence(start, end).toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.eclipse.lemminx.commons.TextDocument;
import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.dom.DOMParser;
import org.eclipse.lemminx.dom.green.GreenDocument;
import org.eclipse.lemminx.extensions.contentmodel.settings.XMLValidationRootSettings;
import org.eclipse.lemminx.services.DocumentSymbolsResult;
import org.eclipse.lemminx.services.SymbolInformationResult;
Expand Down Expand Up @@ -202,8 +203,25 @@ public XMLTextDocumentService(XMLLanguageServer xmlLanguageServer) {
this.xmlLanguageServer = xmlLanguageServer;
DOMParser parser = DOMParser.getInstance();
this.documents = new ModelTextDocuments<DOMDocument>((document, cancelChecker) -> {
if (document instanceof ModelTextDocument) {
@SuppressWarnings("unchecked")
ModelTextDocument<DOMDocument> mtd = (ModelTextDocument<DOMDocument>) document;
Object prevData = mtd.getPreviousIncrementalData();
ModelTextDocument.EditInfo editInfo = mtd.getPendingEdit();
if (prevData instanceof GreenDocument && editInfo != null) {
DOMDocument result = parser.parseIncremental(document,
(GreenDocument) prevData,
editInfo.getStartOffset(),
editInfo.getDeleteLength(),
editInfo.getInsertLength(),
getXMLLanguageService().getResolverExtensionManager(),
true, cancelChecker);
mtd.clearPreviousIncrementalData();
return result;
}
}
return parser.parse(document, getXMLLanguageService().getResolverExtensionManager(), true, cancelChecker);
});
}, DOMDocument::getGreenDocument);
this.sharedSettings = new SharedSettings();
this.limitExceededWarner = null;
this.xmlValidatorDelayer = new ModelValidatorDelayer<DOMDocument>((document) -> {
Expand Down
Loading
Loading