Use language-server-commons from manifest-yml vscode extension

This commit is contained in:
Kris De Volder
2016-09-22 14:25:16 -07:00
parent e3d8095ae7
commit 9cf8006dde
17 changed files with 18 additions and 832 deletions

View File

@@ -4,7 +4,7 @@
"description": "Provides validation and content assist for Cloudfoundry manifest.yml files",
"icon": "icon.png",
"version": "0.0.1",
"publisher": "Pivotal Inc.",
"publisher": "Pivotal",
"repository": {
"type": "git",
"url": "https://github.com/kdvolder/vscode-lsapi-example.git"

View File

@@ -6,7 +6,9 @@
set -e # fail at the first sign of trouble
mvn clean package ## build language server fat jar
#Ensure commons are built and uptodate in local maven cache
mvn -f ../commons/pom.xml clean install
mvn clean package
npm install
vsce package

View File

@@ -2,10 +2,16 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.kdvolder</groupId>
<artifactId>vscode-manifest-yaml</artifactId>
<packaging>jar</packaging>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>commons-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../commons/pom.xml</relativePath>
</parent>
<repositories>
<!-- Local repository with tools.jar -->
<repository>
@@ -13,17 +19,8 @@
<name>Local repository for JAR files</name>
<url>file://${basedir}/repo</url>
</repository>
<!-- Sonatype snapshots repository -->
<repository>
<id>oss-sonatype</id>
<name>oss-sonatype</name>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>distribution-repository</id>
@@ -31,52 +28,13 @@
<url>file://${basedir}/dist</url>
</repository>
</distributionManagement>
<properties>
<jackson-2-version>2.5.0</jackson-2-version>
<jersey-2-version>2.10</jersey-2-version>
</properties>
<dependencies>
<!-- Java implementation of VS Code language server protocol -->
<!-- Language Servers -->
<dependency>
<groupId>io.typefox.lsapi</groupId>
<artifactId>io.typefox.lsapi</artifactId>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.typefox.lsapi</groupId>
<artifactId>io.typefox.lsapi.services</artifactId>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.typefox.lsapi</groupId>
<artifactId>io.typefox.lsapi.annotations</artifactId>
<version>0.2.0-SNAPSHOT</version>
</dependency>
<!-- JSON -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson-2-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson-2-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-2-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson-2-version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>${jackson-2-version}</version>
<groupId>org.springframework.ide.vscode</groupId>
<artifactId>language-server-commons</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- Yaml -->
<dependency>
@@ -90,19 +48,6 @@
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<!-- Testing framework -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.5.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>

View File

@@ -1,11 +0,0 @@
package org.springframework.ide.vscode.util;
public class Assert {
public static void isNull(String msg, Object obj) {
if (obj!=null) {
throw new IllegalStateException(msg);
}
}
}

View File

@@ -1,11 +0,0 @@
package org.springframework.ide.vscode.util;
import java.util.concurrent.CompletableFuture;
import io.typefox.lsapi.CompletionList;
import io.typefox.lsapi.TextDocumentPositionParams;
@FunctionalInterface
public interface CompletionHandler {
CompletableFuture<CompletionList> handle(TextDocumentPositionParams params);
}

View File

@@ -1,10 +0,0 @@
package org.springframework.ide.vscode.util;
import java.util.concurrent.CompletableFuture;
import io.typefox.lsapi.CompletionItem;
@FunctionalInterface
public interface CompletionResolveHandler {
CompletableFuture<CompletionItem> handle(CompletionItem unresolved);
}

View File

@@ -1,13 +0,0 @@
package org.springframework.ide.vscode.util;
import java.util.concurrent.CompletableFuture;
public class Futures {
public static <T> CompletableFuture<T> of(T value) {
CompletableFuture<T> f = new CompletableFuture<T>();
f.complete(value);
return f;
}
}

View File

@@ -1,51 +0,0 @@
package org.springframework.ide.vscode.util;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JSR310Module;
public class JSON {
public static final ObjectMapper JSON = new ObjectMapper().registerModule(new Jdk8Module())
.registerModule(new JSR310Module())
.registerModule(pathAsJson())
.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
private static SimpleModule pathAsJson() {
SimpleModule m = new SimpleModule();
m.addSerializer(Path.class, new JsonSerializer<Path>() {
@Override
public void serialize(Path path,
JsonGenerator gen,
SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
gen.writeString(path.toString());
}
});
m.addDeserializer(Path.class, new JsonDeserializer<Path>() {
@Override
public Path deserialize(JsonParser parse,
DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
return Paths.get(parse.getText());
}
});
return m;
}
}

View File

@@ -1,21 +0,0 @@
package org.springframework.ide.vscode.util;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class ListenerList<T> {
private List<Consumer<T>> listeners = new ArrayList<>();
public synchronized void fire(T evt) {
for (Consumer<T> l : listeners) {
l.accept(evt);
}
}
public void add(Consumer<T> l) {
listeners.add(l);
}
}

View File

@@ -1,67 +0,0 @@
package org.springframework.ide.vscode.util;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.Instant;
import java.util.StringJoiner;
import java.util.logging.*;
public class LoggingFormat extends Formatter {
public static ThreadLocal<Integer> request = new ThreadLocal<>();
@Override
public String format(LogRecord record) {
StringJoiner joiner = new StringJoiner("\t");
joiner.add(record.getLevel().getName());
joiner.add(requestAsString());
joiner.add(Thread.currentThread().getName());
joiner.add(Instant.ofEpochMilli(record.getMillis()).toString());
// joiner.add(record.getLoggerName());
joiner.add(record.getSourceClassName() + "#" + record.getSourceMethodName());
joiner.add(record.getMessage());
String result = joiner.toString() + "\n";
Throwable thrown = record.getThrown();
if (thrown != null) {
StringWriter stackTrace = new StringWriter();
PrintWriter print = new PrintWriter(stackTrace);
thrown.printStackTrace(print);
print.flush();
result = result + stackTrace + "\n";
}
return result;
}
private CharSequence requestAsString() {
Integer i = request.get();
if (i == null)
return "?";
else
return Integer.toString(i);
}
private static boolean started = false;
public static void startLogging() throws IOException {
if (!started) {
started = true;
Logger root = Logger.getLogger("");
FileHandler file = new FileHandler("javac-services.%g.log", 100_000, 1, false);
root.addHandler(file);
for (Handler h : root.getHandlers())
h.setFormatter(new LoggingFormat());
}
}
}

View File

@@ -1,43 +0,0 @@
package org.springframework.ide.vscode.util;
import java.util.Map;
/**
* Convenience wrapper around a 'settings' object. Provides some useful accessor methods to
* retrieve properties from the settings object.
*/
public class Settings {
private Object settings;
public Settings(Object settings) {
this.settings = settings;
}
public Integer getInt(String... names) {
Object val = getProperty(names);
if (val instanceof Number) {
return ((Number) val).intValue();
}
return null;
}
public Object getProperty(String... names) {
return getProperty(settings, names, 0);
}
@SuppressWarnings("rawtypes")
private static Object getProperty(Object settings, String[] names, int i) {
if (i >= names.length) {
return settings;
} else if (settings instanceof Map) {
Object sub = ((Map)settings).get(names[i]);
return getProperty(sub, names, i+1);
} else {
return null;
}
}
}

View File

@@ -1,33 +0,0 @@
package org.springframework.ide.vscode.util;
import io.typefox.lsapi.MessageParams;
import io.typefox.lsapi.MessageParamsImpl;
public class ShowMessageException extends RuntimeException {
private static final long serialVersionUID = 1L;
public final MessageParams message;
public ShowMessageException(MessageParams message, Exception cause) {
super(message.getMessage(), cause);
this.message = message;
}
public static ShowMessageException error(String message, Exception cause) {
return create(MessageParams.TYPE_ERROR, message, cause);
}
public static ShowMessageException warning(String message, Exception cause) {
return create(MessageParams.TYPE_WARNING, message, cause);
}
private static ShowMessageException create(int type, String message, Exception cause) {
MessageParamsImpl m = new MessageParamsImpl();
m.setMessage(message);
m.setType(type);
return new ShowMessageException(m, cause);
}
}

View File

@@ -1,131 +0,0 @@
package org.springframework.ide.vscode.util;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import io.typefox.lsapi.InitializeParams;
import io.typefox.lsapi.InitializeResult;
import io.typefox.lsapi.InitializeResultImpl;
import io.typefox.lsapi.MessageParams;
import io.typefox.lsapi.MessageParamsImpl;
import io.typefox.lsapi.ServerCapabilitiesImpl;
import io.typefox.lsapi.ShowMessageRequestParams;
import io.typefox.lsapi.services.LanguageServer;
import io.typefox.lsapi.services.WindowService;
/**
* Abstract base class to implement LanguageServer. Bits and pieces copied from
* the 'JavaLanguageServer' example which seem generally useful / reusable end up in
* here so we can try to keep the subclass itself more 'clutter free' and focus on
* what its really doing and not the 'wiring and plumbing'.
*/
public abstract class SimpleLanguageServer implements LanguageServer {
private static final Logger LOG = Logger.getLogger(SimpleLanguageServer.class.getName());
private Consumer<MessageParams> showMessage = m -> {};
private Path workspaceRoot;
private SimpleTextDocumentService tds;
private SimpleWorkspaceService workspace;
@Override
public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
LOG.info("Initializing");
String rootPath = params.getRootPath();
if (rootPath==null) {
LOG.warning("workspaceRoot NOT SET");
} else {
this.workspaceRoot= Paths.get(rootPath).toAbsolutePath().normalize();
LOG.info("workspaceRoot = "+workspaceRoot);
}
InitializeResultImpl result = new InitializeResultImpl();
ServerCapabilitiesImpl cap = getServerCapabilities();
result.setCapabilities(cap);
return CompletableFuture.completedFuture(result);
}
@Override
public WindowService getWindowService() {
return new WindowService() {
@Override
public void onShowMessage(Consumer<MessageParams> callback) {
showMessage = callback;
}
@Override
public void onShowMessageRequest(Consumer<ShowMessageRequestParams> callback) {
}
@Override
public void onLogMessage(Consumer<MessageParams> callback) {
}
};
}
public void onError(String message, Throwable error) {
if (error instanceof ShowMessageException)
showMessage.accept(((ShowMessageException) error).message);
else {
LOG.log(Level.SEVERE, message, error);
MessageParamsImpl m = new MessageParamsImpl();
m.setMessage(message);
m.setType(MessageParams.TYPE_ERROR);
showMessage.accept(m);
}
}
protected abstract ServerCapabilitiesImpl getServerCapabilities();
@Override
public void shutdown() {
}
@Override
public void exit() {
}
public Path getWorkspaceRoot() {
return workspaceRoot;
}
@Override
public synchronized SimpleTextDocumentService getTextDocumentService() {
if (tds==null) {
tds = createTextDocumentService();
}
return tds;
}
protected SimpleTextDocumentService createTextDocumentService() {
return new SimpleTextDocumentService();
}
public SimpleWorkspaceService createWorkspaceService() {
return new SimpleWorkspaceService();
}
@Override
public synchronized SimpleWorkspaceService getWorkspaceService() {
if (workspace==null) {
workspace = createWorkspaceService();
}
return workspace;
}
}

View File

@@ -1,271 +0,0 @@
package org.springframework.ide.vscode.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.logging.Logger;
import io.typefox.lsapi.CodeActionParams;
import io.typefox.lsapi.CodeLens;
import io.typefox.lsapi.CodeLensParams;
import io.typefox.lsapi.Command;
import io.typefox.lsapi.CompletionItem;
import io.typefox.lsapi.CompletionList;
import io.typefox.lsapi.DiagnosticImpl;
import io.typefox.lsapi.DidChangeTextDocumentParams;
import io.typefox.lsapi.DidCloseTextDocumentParams;
import io.typefox.lsapi.DidOpenTextDocumentParams;
import io.typefox.lsapi.DidSaveTextDocumentParams;
import io.typefox.lsapi.DocumentFormattingParams;
import io.typefox.lsapi.DocumentHighlight;
import io.typefox.lsapi.DocumentOnTypeFormattingParams;
import io.typefox.lsapi.DocumentRangeFormattingParams;
import io.typefox.lsapi.DocumentSymbolParams;
import io.typefox.lsapi.Hover;
import io.typefox.lsapi.Location;
import io.typefox.lsapi.PublishDiagnosticsParams;
import io.typefox.lsapi.PublishDiagnosticsParamsImpl;
import io.typefox.lsapi.Range;
import io.typefox.lsapi.ReferenceParams;
import io.typefox.lsapi.RenameParams;
import io.typefox.lsapi.SignatureHelp;
import io.typefox.lsapi.SymbolInformation;
import io.typefox.lsapi.TextDocumentContentChangeEvent;
import io.typefox.lsapi.TextDocumentPositionParams;
import io.typefox.lsapi.TextEdit;
import io.typefox.lsapi.VersionedTextDocumentIdentifier;
import io.typefox.lsapi.WorkspaceEdit;
import io.typefox.lsapi.services.TextDocumentService;
public class SimpleTextDocumentService implements TextDocumentService {
private static final Logger LOG = Logger.getLogger(SimpleTextDocumentService.class.getName());
private Consumer<PublishDiagnosticsParams> publishDiagnostics = (p) -> {};
private Map<String, TextDocument> documents = new HashMap<>();
private ListenerList<TextDocumentContentChange> documentChangeListeners = new ListenerList<>();
private CompletionHandler completionHandler = null;
private CompletionResolveHandler completionResolveHandler = null;
public synchronized void onCompletion(CompletionHandler h) {
Assert.isNull("A completion handler is already set, multiple handlers not supported yet", completionHandler);
this.completionHandler = h;
}
public synchronized void onCompletionResolve(CompletionResolveHandler h) {
Assert.isNull("A completionResolveHandler handler is already set, multiple handlers not supported yet", completionResolveHandler);
this.completionResolveHandler = h;
}
/**
* Gets all documents this service is tracking, generally these are the documents that have been opened / changed,
* and not yet closed.
*/
public synchronized Collection<TextDocument> getAll() {
return new ArrayList<>(documents.values());
}
@Override
public final void didChange(DidChangeTextDocumentParams params) {
VersionedTextDocumentIdentifier docId = params.getTextDocument();
String url = docId.getUri();
if (url!=null) {
LOG.info("Document changed: "+url);
TextDocument doc = getOrCreateDocument(url);
for (TextDocumentContentChangeEvent change : params.getContentChanges()) {
doc.apply(change);
didChangeContent(doc, change);
}
}
}
@Override
public void didOpen(DidOpenTextDocumentParams params) {
//LOG.info("didOpen: "+params);
//Example message:
//{
// "jsonrpc":"2.0",
// "method":"textDocument/didOpen",
// "params":{
// "textDocument":{
// "uri":"file:///home/kdvolder/tmp/hello-java/hello.txt",
// "languageId":"plaintext",
// "version":1,
// "text":"This is some text ya-all o\nsss typescript\n"
// }
// }
//}
String url = params.getTextDocument().getUri();
if (url!=null) {
String text = params.getTextDocument().getText();
TextDocument doc = getOrCreateDocument(url);
doc.setText(text);
TextDocumentContentChangeEvent change = new TextDocumentContentChangeEvent() {
@Override
public Range getRange() {
return null;
}
@Override
public Integer getRangeLength() {
return null;
}
@Override
public String getText() {
return text;
}
};
TextDocumentContentChange evt = new TextDocumentContentChange(doc, change);
documentChangeListeners.fire(evt);
}
}
@Override
public void didClose(DidCloseTextDocumentParams params) {
String url = params.getTextDocument().getUri();
if (url!=null) {
documents.remove(url);
}
}
void didChangeContent(TextDocument doc, TextDocumentContentChangeEvent change) {
documentChangeListeners.fire(new TextDocumentContentChange(doc, change));
}
public void onDidChangeContent(Consumer<TextDocumentContentChange> l) {
documentChangeListeners.add(l);
}
private synchronized TextDocument getOrCreateDocument(String url) {
TextDocument doc = documents.get(url);
if (doc==null) {
documents.put(url, doc = new TextDocument(url));
}
return doc;
}
@Override
public CompletableFuture<CompletionList> completion(TextDocumentPositionParams position) {
CompletionHandler h = completionHandler;
if (h!=null) {
return completionHandler.handle(position);
}
return null; //TODO: does caller handle nulls? Or do we need to provide something that create a empty completion list?
}
@Override
public CompletableFuture<CompletionItem> resolveCompletionItem(CompletionItem unresolved) {
CompletionResolveHandler h = completionResolveHandler;
if (h!=null) {
return h.handle(unresolved);
}
return null;
}
@Override
public CompletableFuture<Hover> hover(TextDocumentPositionParams position) {
// TODO Auto-generated method stub
return null;
}
@Override
public CompletableFuture<SignatureHelp> signatureHelp(TextDocumentPositionParams position) {
// TODO Auto-generated method stub
return null;
}
@Override
public CompletableFuture<List<? extends Location>> definition(TextDocumentPositionParams position) {
// TODO Auto-generated method stub
return null;
}
@Override
public CompletableFuture<List<? extends Location>> references(ReferenceParams params) {
// TODO Auto-generated method stub
return null;
}
@Override
public CompletableFuture<DocumentHighlight> documentHighlight(TextDocumentPositionParams position) {
// TODO Auto-generated method stub
return null;
}
@Override
public CompletableFuture<List<? extends SymbolInformation>> documentSymbol(DocumentSymbolParams params) {
// TODO Auto-generated method stub
return null;
}
@Override
public CompletableFuture<List<? extends Command>> codeAction(CodeActionParams params) {
// TODO Auto-generated method stub
return null;
}
@Override
public CompletableFuture<List<? extends CodeLens>> codeLens(CodeLensParams params) {
// TODO Auto-generated method stub
return null;
}
@Override
public CompletableFuture<CodeLens> resolveCodeLens(CodeLens unresolved) {
// TODO Auto-generated method stub
return null;
}
@Override
public CompletableFuture<List<? extends TextEdit>> formatting(DocumentFormattingParams params) {
// TODO Auto-generated method stub
return null;
}
@Override
public CompletableFuture<List<? extends TextEdit>> rangeFormatting(DocumentRangeFormattingParams params) {
// TODO Auto-generated method stub
return null;
}
@Override
public CompletableFuture<List<? extends TextEdit>> onTypeFormatting(DocumentOnTypeFormattingParams params) {
// TODO Auto-generated method stub
return null;
}
@Override
public CompletableFuture<WorkspaceEdit> rename(RenameParams params) {
// TODO Auto-generated method stub
return null;
}
@Override
public void didSave(DidSaveTextDocumentParams params) {
// TODO Auto-generated method stub
}
@Override
public synchronized void onPublishDiagnostics(Consumer<PublishDiagnosticsParams> callback) {
publishDiagnostics = publishDiagnostics.andThen(callback);
}
public void publishDiagnostics(TextDocument doc, List<DiagnosticImpl> diagnostics) {
if (diagnostics!=null && !diagnostics.isEmpty()) {
PublishDiagnosticsParamsImpl params = new PublishDiagnosticsParamsImpl();
params.setUri(doc.getUri());
params.setDiagnostics(diagnostics);
publishDiagnostics.accept(params);
}
}
}

View File

@@ -1,38 +0,0 @@
package org.springframework.ide.vscode.util;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import io.typefox.lsapi.DidChangeConfigurationParams;
import io.typefox.lsapi.DidChangeWatchedFilesParams;
import io.typefox.lsapi.SymbolInformation;
import io.typefox.lsapi.WorkspaceSymbolParams;
import io.typefox.lsapi.services.WorkspaceService;
public class SimpleWorkspaceService implements WorkspaceService {
private ListenerList<Settings> configurationListeners = new ListenerList<>();
@Override
public CompletableFuture<List<? extends SymbolInformation>> symbol(WorkspaceSymbolParams params) {
// TODO Auto-generated method stub
return null;
}
@Override
public void didChangeConfiguraton(DidChangeConfigurationParams params) {
configurationListeners.fire(new Settings(params.getSettings()));
}
@Override
public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) {
// TODO Auto-generated method stub
}
public void onDidChangeConfiguraton(Consumer<Settings> l) {
configurationListeners.add(l);
}
}

View File

@@ -1,38 +0,0 @@
package org.springframework.ide.vscode.util;
import io.typefox.lsapi.Range;
import io.typefox.lsapi.TextDocumentContentChangeEvent;
public class TextDocument {
private final String uri;
private String text = "";
public TextDocument(String uri) {
this.uri = uri;
}
public String getUri() {
return uri;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public void apply(TextDocumentContentChangeEvent change) {
Range rng = change.getRange();
if (rng==null) {
//full sync mode
this.text = change.getText();
} else {
//incremental sync mode
throw new IllegalStateException("Incremental sync not yet implemented");
}
}
}

View File

@@ -1,23 +0,0 @@
package org.springframework.ide.vscode.util;
import io.typefox.lsapi.TextDocumentContentChangeEvent;
public class TextDocumentContentChange {
private final TextDocument document;
private final TextDocumentContentChangeEvent change;
public TextDocumentContentChange(TextDocument doc, TextDocumentContentChangeEvent change) {
this.document = doc;
this.change = change;
}
public TextDocument getDocument() {
return document;
}
public TextDocumentContentChangeEvent getChange() {
return change;
}
}