Skip to content

Commit

Permalink
Add support for incremental text document (not XML document) to minimize
Browse files Browse the repository at this point in the history
JSON didChange request size when document changed. This incremental
support is only available with experimental.incrementalSupport.enabled
(see #133)
  • Loading branch information
angelozerr committed Sep 21, 2018
1 parent bad8ffb commit 79055fb
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@
import org.eclipse.lsp4j.services.TextDocumentService;
import org.eclipse.lsp4j.services.WorkspaceService;
import org.eclipse.lsp4xml.commons.ParentProcessWatcher.ProcessLanguageServer;
import org.eclipse.lsp4xml.commons.TextDocument;
import org.eclipse.lsp4xml.dom.XMLDocument;
import org.eclipse.lsp4xml.logs.LogHelper;
import org.eclipse.lsp4xml.commons.TextDocument;
import org.eclipse.lsp4xml.services.XMLLanguageService;
import org.eclipse.lsp4xml.settings.InitializationOptionsSettings;
import org.eclipse.lsp4xml.settings.LogsSettings;
Expand Down Expand Up @@ -70,7 +70,9 @@ public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
xmlTextDocumentService.updateClientCapabilities(params.getCapabilities());
this.parentProcessId = params.getProcessId();
ServerCapabilities capabilities = new ServerCapabilities();
capabilities.setTextDocumentSync(TextDocumentSyncKind.Full);
capabilities
.setTextDocumentSync(xmlTextDocumentService.isIncrementalSupport() ? TextDocumentSyncKind.Incremental
: TextDocumentSyncKind.Full);
capabilities.setDocumentSymbolProvider(true);
capabilities.setDocumentHighlightProvider(true);
capabilities.setCompletionProvider(new CompletionOptions(false, Arrays.asList(".", ":", "<", "\"", "=", "/")));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@
import org.eclipse.lsp4xml.dom.XMLParser;
import org.eclipse.lsp4xml.services.XMLLanguageService;
import org.eclipse.lsp4xml.services.extensions.CompletionSettings;
import org.eclipse.lsp4xml.settings.XMLExperimentalCapabilities;
import org.eclipse.lsp4xml.settings.XMLFormattingOptions;
import org.eclipse.lsp4xml.utils.JSONUtility;

/**
* XML text document service.
Expand Down Expand Up @@ -106,7 +108,7 @@ public XMLTextDocumentService(XMLLanguageServer xmlLanguageServer) {
this.xmlLanguageServer = xmlLanguageServer;
this.documents = new TextDocuments();
XMLParser parser = XMLParser.getInstance();
this.xmlDocuments = new LanguageModelCache<XMLDocument>(10, 60, document -> parser.parse(document));
this.xmlDocuments = new LanguageModelCache<XMLDocument>(10, 60, documents, document -> parser.parse(document));
this.sharedCompletionSettings = new CompletionSettings();
this.sharedFoldingsSettings = new FoldingRangeCapabilities();
this.sharedFormattingOptions = new XMLFormattingOptions(true); // to be sure that formattings options is not
Expand All @@ -122,6 +124,15 @@ public void updateClientCapabilities(ClientCapabilities capabilities) {
&& textDocumentClientCapabilities.getCodeAction().getCodeActionLiteralSupport() != null;
}

// Experimental capabilities
// get value of "experimental.incrementalSupport.enabled"
XMLExperimentalCapabilities experimental = JSONUtility.toModel(capabilities.getExperimental(),
XMLExperimentalCapabilities.class);
boolean incrementalSupport = experimental != null && experimental.getIncrementalSupport() != null
&& experimental.getIncrementalSupport().getEnabled() != null
? experimental.getIncrementalSupport().getEnabled()
: false;
documents.setIncremental(incrementalSupport);
}

public TextDocument getDocument(String uri) {
Expand Down Expand Up @@ -314,4 +325,8 @@ public void setSharedFormattingOptions(XMLFormattingOptions formattingOptions) {
this.sharedFormattingOptions = formattingOptions;
}

public boolean isIncrementalSupport() {
return documents.isIncremental();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Copyright (c) 2018 Angelo ZERR.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
*/
package org.eclipse.lsp4xml.commons;

import org.eclipse.lsp4j.TextDocumentItem;

/**
* {@link TextDocument} factory.
*
*/
public interface ITextDocumentFactory {

/**
* Create a {@link TextDocument} instance from the given
* {@link TextDocumentItem}.
*
* @param document
* @return a {@link TextDocument} instance from the given
* {@link TextDocumentItem}.
*/
TextDocument createDocument(TextDocumentItem document);
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class LanguageModelCache<T> {

private final Map<String, LanguageModeInfo> languageModels;
private final Function<TextDocument, T> parse;
private final ITextDocumentFactory documentFactory;

class LanguageModeInfo {

Expand All @@ -44,9 +45,11 @@ public LanguageModeInfo(T languageModel, int version, String languageId, long cT
}
}

public LanguageModelCache(int maxEntries, int cleanupIntervalTimeInSec, Function<TextDocument, T> parse) {
public LanguageModelCache(int maxEntries, int cleanupIntervalTimeInSec, ITextDocumentFactory documentFactory,
Function<TextDocument, T> parse) {
this.languageModels = new HashMap<>();
this.parse = parse;
this.documentFactory = documentFactory;
}

public T get(TextDocumentItem document) {
Expand Down Expand Up @@ -76,10 +79,8 @@ private synchronized T parseAndGet(TextDocumentItem document, int version, Strin
return languageModel;
}
TextDocument textDocument = document instanceof TextDocument ? (TextDocument) document
: new TextDocument(document);
long start = System.currentTimeMillis();
: documentFactory.createDocument(document);
languageModel = parse.apply(textDocument);
//System.err.println("parsed in " + (System.currentTimeMillis() - start) + "ms");
languageModels.put(uri, new LanguageModeInfo(languageModel, version, languageId, System.currentTimeMillis()));
return languageModel;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@
*/
package org.eclipse.lsp4xml.commons;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentContentChangeEvent;
import org.eclipse.lsp4j.TextDocumentItem;

/**
Expand All @@ -28,15 +30,27 @@ public class TextDocument extends TextDocumentItem {

private ListLineTracker lineTracker;

public TextDocument(TextDocumentItem document) {
this(document.getText(), document.getUri());
// Buffer of the text document used only in incremental mode.
private final StringBuilder buffer;

// incremental support?
private final boolean incremental;

public TextDocument(TextDocumentItem document, boolean incremental) {
this(document.getText(), document.getUri(), incremental);
super.setVersion(document.getVersion());
super.setLanguageId(document.getLanguageId());
}

public TextDocument(String text, String uri) {
this(text, uri, false);
}

public TextDocument(String text, String uri, boolean incremental) {
super.setUri(uri);
super.setText(text);
buffer = incremental ? new StringBuilder(text) : null;
this.incremental = incremental;
}

@Override
Expand Down Expand Up @@ -110,4 +124,50 @@ private ListLineTracker getLineTracker() {
}
return lineTracker;
}

/**
* Update text of the document by using the changes and according the
* incremental support.
*
* @param changes the text document changes.
*/
public void update(List<TextDocumentContentChangeEvent> changes) {
if (changes.size() < 1) {
// no changes, ignore it.
return;
}
if (incremental) {
try {
synchronized (buffer) {
for (TextDocumentContentChangeEvent changeEvent : changes) {

Range range = changeEvent.getRange();
int length = 0;

if (range != null) {
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));
}
String text = changeEvent.getText();
int startOffset = offsetAt(range.getStart());
buffer.replace(startOffset, startOffset + length, text);
}
setText(buffer.toString());
}
} catch (BadLocationException e) {
// Should never occurs.
}
} else {
// like vscode does, get the last changes
// see
// https://github.com/Microsoft/vscode-languageserver-node/blob/master/server/src/main.ts
TextDocumentContentChangeEvent last = changes.size() > 0 ? changes.get(changes.size() - 1) : null;
if (last != null) {
setText(last.getText());
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,37 @@
/**
* A manager for simple text documents
*/
public class TextDocuments {
public class TextDocuments implements ITextDocumentFactory {

private boolean incremental;

private final Map<String, TextDocument> documents;

public TextDocuments() {
documents = new HashMap<>();
}

/**
* Set the incremental support.
*
* @param incremental
*/
public void setIncremental(boolean incremental) {
this.incremental = incremental;
documents.clear();
}

/**
* Returns true if text document is managed in incremental mode and false
* otherwise.
*
* @return true if text document is managed in incremental mode and false
* otherwise.
*/
public boolean isIncremental() {
return incremental;
}

/**
* Returns the document for the given URI. Returns undefined if the document is
* not mananged by this instance.
Expand All @@ -44,21 +67,20 @@ public TextDocument get(String uri) {

public void onDidOpenTextDocument(DidOpenTextDocumentParams params) {
TextDocumentItem document = params.getTextDocument();
documents.put(document.getUri(), new TextDocument(document));
documents.put(document.getUri(), createDocument(document));
}

@Override
public TextDocument createDocument(TextDocumentItem document) {
return new TextDocument(document, incremental);
}

public void onDidChangeTextDocument(DidChangeTextDocumentParams params) {
List<TextDocumentContentChangeEvent> changes = params.getContentChanges();
// like vscode does, get the last changes
// see
// https://github.com/Microsoft/vscode-languageserver-node/blob/master/server/src/main.ts
TextDocumentContentChangeEvent last = changes.size() > 0 ? changes.get(changes.size() - 1) : null;
if (last != null) {
TextDocument document = get(params.getTextDocument().getUri());
if (document != null) {
document.setVersion(params.getTextDocument().getVersion());
document.setText(last.getText());
}
TextDocument document = get(params.getTextDocument().getUri());
if (document != null) {
document.setVersion(params.getTextDocument().getVersion());
document.update(changes);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright (c) 2018 Angelo ZERR
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
*/
package org.eclipse.lsp4xml.settings;

/**
* XML experimental capabilities.
*
*/
public class XMLExperimentalCapabilities {

private XMLIncrementalSupportCapabilities incrementalSupport;

public void setIncrementalSupport(XMLIncrementalSupportCapabilities incrementalSupport) {
this.incrementalSupport = incrementalSupport;
}

public XMLIncrementalSupportCapabilities getIncrementalSupport() {
return incrementalSupport;
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/**
* Copyright (c) 2018 Angelo ZERR
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
*/
package org.eclipse.lsp4xml.settings;

import org.eclipse.lsp4j.FormattingOptions;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Copyright (c) 2018 Angelo ZERR
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation
*/
package org.eclipse.lsp4xml.settings;

/**
* XML experimental incremental support capabilities.
*
*/
public class XMLIncrementalSupportCapabilities {

private Boolean enabled;

public Boolean getEnabled() {
return enabled;
}

public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}

}

0 comments on commit 79055fb

Please sign in to comment.