diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/XMLLanguageServer.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/XMLLanguageServer.java index 803bcd524..9364132ef 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/XMLLanguageServer.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/XMLLanguageServer.java @@ -46,9 +46,10 @@ import org.eclipse.lsp4xml.settings.LogsSettings; import org.eclipse.lsp4xml.settings.ServerSettings; import org.eclipse.lsp4xml.settings.SharedSettings; -import org.eclipse.lsp4xml.settings.XMLExperimentalCapabilities; +import org.eclipse.lsp4xml.settings.XMLExperimentalSettings; import org.eclipse.lsp4xml.settings.XMLFormattingOptions; import org.eclipse.lsp4xml.settings.XMLGeneralClientSettings; +import org.eclipse.lsp4xml.settings.XMLIncrementalSupportSettings; import org.eclipse.lsp4xml.settings.XMLSymbolSettings; import org.eclipse.lsp4xml.settings.capabilities.ServerCapabilitiesInitializer; import org.eclipse.lsp4xml.settings.capabilities.XMLCapabilityManager; @@ -116,7 +117,7 @@ public void initialized(InitializedParams params) { * * @param initializationOptionsSettings the XML settings */ - public void updateSettings(Object initializationOptionsSettings) { + public synchronized void updateSettings(Object initializationOptionsSettings) { if (initializationOptionsSettings == null) { return; } @@ -152,13 +153,12 @@ public void updateSettings(Object initializationOptionsSettings) { FilesUtils.setCachePathSetting(workDir); } - // Experimental capabilities - XMLExperimentalCapabilities experimental = xmlClientSettings.getExperimental(); - if (experimental != null) { - boolean incrementalSupport = experimental.getIncrementalSupport() != null - && experimental.getIncrementalSupport().getEnabled() != null - && experimental.getIncrementalSupport().getEnabled().booleanValue(); - xmlTextDocumentService.setIncrementalSupport(incrementalSupport); + XMLExperimentalSettings experimentalSettings = xmlClientSettings.getExperimental(); + if(experimentalSettings != null) { + XMLIncrementalSupportSettings incrementalSettings = experimentalSettings.getIncrementalSupport(); + if(incrementalSettings != null) { + xmlTextDocumentService.updateIncrementalSettings(incrementalSettings); + } } } ContentModelSettings cmSettings = ContentModelSettings diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/XMLTextDocumentService.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/XMLTextDocumentService.java index 97fe1d365..587d909c7 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/XMLTextDocumentService.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/XMLTextDocumentService.java @@ -74,6 +74,7 @@ import org.eclipse.lsp4xml.services.extensions.save.AbstractSaveContext; import org.eclipse.lsp4xml.settings.SharedSettings; import org.eclipse.lsp4xml.settings.XMLFormattingOptions; +import org.eclipse.lsp4xml.settings.XMLIncrementalSupportSettings; import org.eclipse.lsp4xml.settings.XMLSymbolSettings; /** @@ -412,7 +413,7 @@ private XMLLanguageService getXMLLanguageService() { } public void updateCompletionSettings(CompletionSettings newCompletion) { - sharedSettings.completionSettings.setAutoCloseTags(newCompletion.isAutoCloseTags()); + sharedSettings.setCompletionSettings(newCompletion); } public void updateSymbolSettings(XMLSymbolSettings newSettings) { @@ -436,10 +437,6 @@ public XMLFormattingOptions getSharedFormattingSettings() { return sharedSettings.formattingSettings; } - public void setIncrementalSupport(boolean incrementalSupport) { - this.documents.setIncremental(incrementalSupport); - } - public XMLValidationSettings getValidationSettings() { return sharedSettings.validationSettings; @@ -449,4 +446,9 @@ public SharedSettings getSharedSettings() { return this.sharedSettings; } + public void updateIncrementalSettings(XMLIncrementalSupportSettings settings) { + sharedSettings.experimentalSettings.getIncrementalSupport().setEnabled(settings.getEnabled()); + this.documents.setIncremental(sharedSettings.experimentalSettings.getIncrementalSupport().getEnabled()); + } + } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/commons/TextDocument.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/commons/TextDocument.java index 8bd667df4..8e520dff0 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/commons/TextDocument.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/commons/TextDocument.java @@ -26,12 +26,13 @@ */ public class TextDocument extends TextDocumentItem { + private final Object lock = new Object(); + private static String DEFAULT_DELIMTER = System.lineSeparator(); - private ListLineTracker lineTracker; + private final ListLineTracker lineTracker; - // Buffer of the text document used only in incremental mode. - private StringBuilder buffer; + private boolean incremental; public TextDocument(TextDocumentItem document) { this(document.getText(), document.getUri()); @@ -40,22 +41,23 @@ public TextDocument(TextDocumentItem document) { } public TextDocument(String text, String uri) { + this.lineTracker = new ListLineTracker(); super.setUri(uri); - super.setText(text); + this.setText(text); } public void setIncremental(boolean incremental) { - if (incremental) { - buffer = new StringBuilder(getText()); - } else { - buffer = null; - } + this.incremental = incremental; + } + + public boolean isIncremental() { + return incremental; } @Override public void setText(String text) { super.setText(text); - lineTracker = null; + lineTracker.set(text); } public Position positionAt(int position) throws BadLocationException { @@ -117,10 +119,6 @@ public Range getWordRangeAt(int textOffset, Pattern wordDefinition) { } private ListLineTracker getLineTracker() { - if (lineTracker == null) { - lineTracker = new ListLineTracker(); - lineTracker.set(super.getText()); - } return lineTracker; } @@ -137,8 +135,17 @@ public void update(List changes) { } if (isIncremental()) { try { - synchronized (buffer) { - for (TextDocumentContentChangeEvent changeEvent : changes) { + // Initialize buffer and line tracker from the current text document + String initialText = getText(); + StringBuilder buffer = new StringBuilder(getText()); + ListLineTracker lt = new ListLineTracker(); + lt.set(initialText); + synchronized (lock) { + for (int i = 0; i < changes.size(); i++) { + if (i > 0) { + lt.set(buffer.toString()); + } + TextDocumentContentChangeEvent changeEvent = changes.get(i); Range range = changeEvent.getRange(); int length = 0; @@ -147,17 +154,18 @@ public void update(List changes) { length = changeEvent.getRangeLength().intValue(); } else { // range is optional and if not given, the whole file content is replaced - length = getText().length(); - range = new Range(positionAt(0), positionAt(length)); + length = buffer.length(); + range = new Range(lt.getPositionAt(0), lt.getPositionAt(length)); } String text = changeEvent.getText(); - int startOffset = offsetAt(range.getStart()); + int startOffset = lt.getOffsetAt(range.getStart()); buffer.replace(startOffset, startOffset + length, text); } + // Update the new text content from the updated buffer setText(buffer.toString()); } } catch (BadLocationException e) { - // Should never occurs. + // Should never occur. } } else { // like vscode does, get the last changes @@ -170,8 +178,4 @@ public void update(List changes) { } } - public boolean isIncremental() { - return buffer != null; - } - } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/commons/TextDocuments.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/commons/TextDocuments.java index 10e5d7235..55ff41b76 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/commons/TextDocuments.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/commons/TextDocuments.java @@ -25,10 +25,10 @@ */ public class TextDocuments implements ITextDocumentFactory { - private boolean incremental; - private final Map documents; + private boolean incremental = true; //default on + public TextDocuments() { documents = new HashMap<>(); } @@ -72,7 +72,7 @@ public TextDocument get(String uri) { @Override public TextDocument createDocument(TextDocumentItem document) { TextDocument doc = new TextDocument(document); - doc.setIncremental(incremental); + doc.setIncremental(isIncremental()); return doc; } @@ -121,4 +121,5 @@ public Collection all() { return documents.values(); } } + } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/SharedSettings.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/SharedSettings.java index 180d9d7e7..a9f94ea24 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/SharedSettings.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/SharedSettings.java @@ -25,6 +25,7 @@ public class SharedSettings { public XMLFormattingOptions formattingSettings; public final XMLValidationSettings validationSettings; public final XMLSymbolSettings symbolSettings; + public final XMLExperimentalSettings experimentalSettings; public SharedSettings() { this.completionSettings = new CompletionSettings(); @@ -32,6 +33,7 @@ public SharedSettings() { this.formattingSettings = new XMLFormattingOptions(true); this.validationSettings = new XMLValidationSettings(); this.symbolSettings = new XMLSymbolSettings(); + this.experimentalSettings = new XMLExperimentalSettings(); } public void setFormattingSettings(XMLFormattingOptions formattingOptions) { diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLExperimentalCapabilities.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLExperimentalSettings.java similarity index 59% rename from org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLExperimentalCapabilities.java rename to org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLExperimentalSettings.java index ea368346f..50caa6251 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLExperimentalCapabilities.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLExperimentalSettings.java @@ -14,15 +14,18 @@ * XML experimental capabilities. * */ -public class XMLExperimentalCapabilities { +public class XMLExperimentalSettings { - private XMLIncrementalSupportCapabilities incrementalSupport; + private XMLIncrementalSupportSettings incrementalSupport; - public void setIncrementalSupport(XMLIncrementalSupportCapabilities incrementalSupport) { + public void setIncrementalSupport(XMLIncrementalSupportSettings incrementalSupport) { this.incrementalSupport = incrementalSupport; } - public XMLIncrementalSupportCapabilities getIncrementalSupport() { + public XMLIncrementalSupportSettings getIncrementalSupport() { + if(incrementalSupport == null) { + incrementalSupport = new XMLIncrementalSupportSettings(); + } return incrementalSupport; } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLGeneralClientSettings.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLGeneralClientSettings.java index db189fe9e..8f18f6b25 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLGeneralClientSettings.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLGeneralClientSettings.java @@ -37,8 +37,6 @@ public class XMLGeneralClientSettings { private LogsSettings logs; private XMLFormattingOptions format; - - private XMLExperimentalCapabilities experimental; private CompletionSettings completion; @@ -46,10 +44,27 @@ public class XMLGeneralClientSettings { private XMLSymbolSettings symbols; + private XMLExperimentalSettings experimental; + + + + public XMLExperimentalSettings getExperimental() { + return experimental; + } + + public void setExperimental(XMLExperimentalSettings experimental) { + this.experimental = experimental; + } + public void setLogs(LogsSettings logs) { this.logs = logs; } + public LogsSettings getLogs() { + return logs; + } + + public XMLSymbolSettings getSymbols() { return symbols; } @@ -58,10 +73,7 @@ public void setSymbols(XMLSymbolSettings symbols) { this.symbols = symbols; } - public LogsSettings getLogs() { - return logs; - } - + public void setFormat(XMLFormattingOptions format) { this.format = format; } @@ -69,10 +81,6 @@ public void setFormat(XMLFormattingOptions format) { public XMLFormattingOptions getFormat() { return format; } - - public XMLExperimentalCapabilities getExperimental() { - return experimental; - } /** * Set completion settings diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLIncrementalSupportCapabilities.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLIncrementalSupportSettings.java similarity index 82% rename from org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLIncrementalSupportCapabilities.java rename to org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLIncrementalSupportSettings.java index 92de28d23..7ac965ae1 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLIncrementalSupportCapabilities.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/XMLIncrementalSupportSettings.java @@ -14,11 +14,14 @@ * XML experimental incremental support capabilities. * */ -public class XMLIncrementalSupportCapabilities { +public class XMLIncrementalSupportSettings { private Boolean enabled; public Boolean getEnabled() { + if(enabled == null) { + enabled = true; // default on + } return enabled; } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/capabilities/ServerCapabilitiesInitializer.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/capabilities/ServerCapabilitiesInitializer.java index 6b14b3d52..268087365 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/capabilities/ServerCapabilitiesInitializer.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/capabilities/ServerCapabilitiesInitializer.java @@ -13,7 +13,6 @@ import static org.eclipse.lsp4xml.settings.capabilities.ServerCapabilitiesConstants.DEFAULT_COMPLETION_OPTIONS; import static org.eclipse.lsp4xml.settings.capabilities.ServerCapabilitiesConstants.DEFAULT_LINK_OPTIONS; -import static org.eclipse.lsp4xml.settings.capabilities.ServerCapabilitiesConstants.DEFAULT_SYNC_OPTION; import org.eclipse.lsp4j.ServerCapabilities; import org.eclipse.lsp4j.TextDocumentSyncKind; @@ -37,9 +36,9 @@ private ServerCapabilitiesInitializer() { public static ServerCapabilities getNonDynamicServerCapabilities(ClientCapabilitiesWrapper clientCapabilities, boolean isIncremental) { ServerCapabilities serverCapabilities = new ServerCapabilities(); - // @formatter:off - serverCapabilities.setTextDocumentSync(DEFAULT_SYNC_OPTION); + serverCapabilities.setTextDocumentSync(isIncremental ? TextDocumentSyncKind.Incremental : TextDocumentSyncKind.Full); + serverCapabilities.setDocumentSymbolProvider(!clientCapabilities.isDocumentSymbolDynamicRegistrationSupported()); serverCapabilities.setDocumentHighlightProvider(!clientCapabilities.isDocumentHighlightDynamicRegistered()); serverCapabilities.setCodeActionProvider(!clientCapabilities.isCodeActionDynamicRegistered()); diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/capabilities/XMLCapabilityManager.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/capabilities/XMLCapabilityManager.java index a1032b79b..eeb4d2868 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/capabilities/XMLCapabilityManager.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/settings/capabilities/XMLCapabilityManager.java @@ -145,8 +145,10 @@ public void initializeCapabilities() { } /** - * Registers all capabilities that this server can support client side - * preferences to turn on/off + * Registers(indicates the servers ability to support the service) all capabilities that have the ability to be turned + * on/off on the client side through preferences. + * + * In the case the preference is set to off/false this server will tell the cliet it does not support this capability. * * If a capability is not dynamic, it's handled by * {@link ServerCapabilitiesInitializer} diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/IncrementalParsingTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/IncrementalParsingTest.java new file mode 100644 index 000000000..398eae1d5 --- /dev/null +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/IncrementalParsingTest.java @@ -0,0 +1,250 @@ +/******************************************************************************* +* Copyright (c) 2019 Red Hat Inc. and others. +* All rights reserved. This program and the accompanying materials +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v20.html +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ + +package org.eclipse.lsp4xml.services; + +import java.util.ArrayList; + +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.TextDocumentContentChangeEvent; +import org.eclipse.lsp4xml.commons.TextDocument; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * IncrementalParsingTest + */ +public class IncrementalParsingTest { + String textTemplate = + "\r\n" + + "\r\n" + + "\r\n" + + "\r\n" + + "\r\n" + + "\r\n" + + "\r\n" + + "\r\n"; + + @Test + public void testBasicChange() { + String text = + "<>\r\n" + /// <-- inserting 'a' in tag name + " \r\n" + + " \r\n" + + "\r\n"; + + String expectedText = + "\r\n" + /// <-- inserted 'a' in tag name + " \r\n" + + " \r\n" + + "\r\n"; + + TextDocument document = new TextDocument(text, "uri"); + document.setIncremental(true); + + Range range1 = new Range(new Position(0, 1), new Position(0,1)); + TextDocumentContentChangeEvent change1 = new TextDocumentContentChangeEvent(range1, 0, "a"); + + ArrayList changes = new ArrayList(); + changes.add(change1); + + document.update(changes); + + assertEquals(expectedText, document.getText()); + + } + + @Test + public void testBasicChangeWord() { + String text = + "<>\r\n" + /// <-- inserting 'a' in tag name + " \r\n" + + " \r\n" + + "\r\n"; + + String expectedText = + "\r\n" + /// <-- inserted 'a' in tag name + " \r\n" + + " \r\n" + + "\r\n"; + + TextDocument document = new TextDocument(text, "uri"); + document.setIncremental(true); + + Range range1 = new Range(new Position(0, 1), new Position(0,1)); + TextDocumentContentChangeEvent change1 = new TextDocumentContentChangeEvent(range1, 0, "aaa"); + + ArrayList changes = new ArrayList(); + changes.add(change1); + + document.update(changes); + + assertEquals(expectedText, document.getText()); + } + + @Test + public void testChangeReplaceRange() { + String text = + "\r\n" + /// <-- inserting 'a' in tag name + " \r\n" + + " \r\n" + + "\r\n"; + + String expectedText = + "\r\n" + /// <-- inserted 'a' in tag name + " \r\n" + + " \r\n" + + "\r\n"; + + TextDocument document = new TextDocument(text, "uri"); + document.setIncremental(true); + + Range range1 = new Range(new Position(0, 1), new Position(0,4)); + TextDocumentContentChangeEvent change1 = new TextDocumentContentChangeEvent(range1, 3, "aaa"); + + ArrayList changes = new ArrayList(); + changes.add(change1); + + document.update(changes); + + assertEquals(expectedText, document.getText()); + } + + @Test + public void testBasicChangeMultipleChanges() { + String text = + "<>\r\n" + // <-- inserting 'a' in tag name + " \r\n" + + " \r\n" + // <-- inserting 'b' in tag name + "\r\n"; + + String expectedText = + "\r\n" + // <-- inserted 'a' in tag name + " \r\n" + + " \r\n" + // <-- inserted 'b' in tag name + "\r\n"; + + TextDocument document = new TextDocument(text, "uri"); + document.setIncremental(true); + + Range range1 = new Range(new Position(0, 1), new Position(0,1)); + TextDocumentContentChangeEvent change1 = new TextDocumentContentChangeEvent(range1, 0, "a"); + + Range range2 = new Range(new Position(2, 4), new Position(2,4)); + TextDocumentContentChangeEvent change2 = new TextDocumentContentChangeEvent(range2, 0, "b"); + + ArrayList changes = new ArrayList(); + // The order they are added in is backwards with the largest offset being first + changes.add(change2); + changes.add(change1); + + document.update(changes); + + assertEquals(expectedText, document.getText()); + + } + + @Test + public void testBasicChangeMultipleChangesReplaceRange() { + String text = + "\r\n" + // <-- inserting 'a' in tag name + " \r\n" + + " \r\n" + // <-- inserting 'b' in tag name + "\r\n"; + + String expectedText = + "\r\n" + // <-- inserted 'a' in tag name + " \r\n" + + " \r\n" + // <-- inserted 'b' in tag name + "\r\n"; + + TextDocument document = new TextDocument(text, "uri"); + document.setIncremental(true); + + Range range1 = new Range(new Position(0, 1), new Position(0,4)); + TextDocumentContentChangeEvent change1 = new TextDocumentContentChangeEvent(range1, 3, "a"); + + Range range2 = new Range(new Position(2, 4), new Position(2,7)); + TextDocumentContentChangeEvent change2 = new TextDocumentContentChangeEvent(range2, 3, "b"); + + ArrayList changes = new ArrayList(); + // The order they are added in is backwards with the largest offset being first + changes.add(change2); + changes.add(change1); + + document.update(changes); + + assertEquals(expectedText, document.getText()); + + } + + @Test + public void testBasicDeletionChange() { + String text = + "\r\n" + /// <-- deleting 'a' in tag name + " \r\n" + + " \r\n" + + "\r\n"; + + String expectedText = + "\r\n" + /// <-- deleted 'a' in tag name + " \r\n" + + " \r\n" + + "\r\n"; + + TextDocument document = new TextDocument(text, "uri"); + document.setIncremental(true); + + Range range1 = new Range(new Position(0, 2), new Position(0,3)); + TextDocumentContentChangeEvent change1 = new TextDocumentContentChangeEvent(range1, 1, ""); + + ArrayList changes = new ArrayList(); + changes.add(change1); + + document.update(changes); + + assertEquals(expectedText, document.getText()); + + } + + @Test + public void testMultipleDeletionChanges() { + String text = + "\r\n" + /// <-- deleting 'a' in tag name + " \r\n" + + " \r\n" + + "\r\n"; + + String expectedText = + "\r\n" + /// <-- deleted 'a' in tag name + " \r\n" + + " \r\n" + + "\r\n"; + + TextDocument document = new TextDocument(text, "uri"); + document.setIncremental(true); + + Range range1 = new Range(new Position(0, 2), new Position(0,3)); + TextDocumentContentChangeEvent change1 = new TextDocumentContentChangeEvent(range1, 1, ""); + + Range range2 = new Range(new Position(2, 5), new Position(2,6)); + TextDocumentContentChangeEvent change2 = new TextDocumentContentChangeEvent(range2, 1, ""); + + ArrayList changes = new ArrayList(); + changes.add(change2); + changes.add(change1); + + document.update(changes); + + assertEquals(expectedText, document.getText()); + + } +} \ No newline at end of file