diff options
author | George Fraser <george@fivetran.com> | 2019-01-06 12:38:23 -0800 |
---|---|---|
committer | George Fraser <george@fivetran.com> | 2019-01-06 12:38:23 -0800 |
commit | 7cee5e9b47fd88a089044067993e68cd8c740a63 (patch) | |
tree | 2e1d9b781db2970d7911d117ebaaf2fb5e9b3507 | |
parent | d4e1274a33378d33b45d3effab7f0976e39a1b8a (diff) | |
download | java-language-server-7cee5e9b47fd88a089044067993e68cd8c740a63.zip |
Move activeDocuments to FileStore
-rw-r--r-- | src/main/java/org/javacs/FileStore.java | 122 | ||||
-rw-r--r-- | src/main/java/org/javacs/JavaCompilerService.java | 2 | ||||
-rw-r--r-- | src/main/java/org/javacs/JavaLanguageServer.java | 152 |
3 files changed, 155 insertions, 121 deletions
diff --git a/src/main/java/org/javacs/FileStore.java b/src/main/java/org/javacs/FileStore.java new file mode 100644 index 0000000..8f60e25 --- /dev/null +++ b/src/main/java/org/javacs/FileStore.java @@ -0,0 +1,122 @@ +package org.javacs; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import org.javacs.lsp.DidChangeTextDocumentParams; +import org.javacs.lsp.DidCloseTextDocumentParams; +import org.javacs.lsp.DidOpenTextDocumentParams; +import org.javacs.lsp.TextDocumentContentChangeEvent; + +class FileStore { + + private static final Map<URI, VersionedContent> activeDocuments = new HashMap<>(); + + static boolean isJavaFile(URI uri) { + return uri.getScheme().equals("file") && uri.getPath().endsWith(".java"); + } + + static void open(DidOpenTextDocumentParams params) { + var document = params.textDocument; + var uri = document.uri; + if (!isJavaFile(uri)) return; + activeDocuments.put(uri, new VersionedContent(document.text, document.version)); + } + + static void change(DidChangeTextDocumentParams params) { + var document = params.textDocument; + var uri = document.uri; + if (isJavaFile(uri)) { + var existing = activeDocuments.get(uri); + var newText = existing.content; + + if (document.version > existing.version) { + for (var change : params.contentChanges) { + if (change.range == null) newText = change.text; + else newText = patch(newText, change); + } + + activeDocuments.put(uri, new VersionedContent(newText, document.version)); + } else LOG.warning("Ignored change with version " + document.version + " <= " + existing.version); + } + } + + static void close(DidCloseTextDocumentParams params) { + var document = params.textDocument; + var uri = document.uri; + if (isJavaFile(uri)) { + // Remove from source cache + activeDocuments.remove(uri); + } + } + + static Set<URI> activeDocuments() { + return activeDocuments.keySet(); + } + + static int version(URI openFile) { + if (!activeDocuments.containsKey(openFile)) return -1; + return activeDocuments.get(openFile).version; + } + + static String contents(URI openFile) { + if (!isJavaFile(openFile)) { + LOG.warning("Ignoring non-java file " + openFile); + return ""; + } + if (activeDocuments.containsKey(openFile)) { + return activeDocuments.get(openFile).content; + } + try { + return Files.readAllLines(Paths.get(openFile)).stream().collect(Collectors.joining("\n")); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static String patch(String sourceText, TextDocumentContentChangeEvent change) { + try { + var range = change.range; + var reader = new BufferedReader(new StringReader(sourceText)); + var writer = new StringWriter(); + + // Skip unchanged lines + int line = 0; + + while (line < range.start.line) { + writer.write(reader.readLine() + '\n'); + line++; + } + + // Skip unchanged chars + for (int character = 0; character < range.start.character; character++) writer.write(reader.read()); + + // Write replacement text + writer.write(change.text); + + // Skip replaced text + reader.skip(change.rangeLength); + + // Write remaining text + while (true) { + int next = reader.read(); + + if (next == -1) return writer.toString(); + else writer.write(next); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static final Logger LOG = Logger.getLogger("main"); +} diff --git a/src/main/java/org/javacs/JavaCompilerService.java b/src/main/java/org/javacs/JavaCompilerService.java index 6a0c6d9..e1ad2b8 100644 --- a/src/main/java/org/javacs/JavaCompilerService.java +++ b/src/main/java/org/javacs/JavaCompilerService.java @@ -328,7 +328,7 @@ public class JavaCompilerService { return files; } // If the declaring file isn't a normal file, for example if it's in src.zip - if (!JavaLanguageServer.isJavaFile(toFile.get())) { + if (!FileStore.isJavaFile(toFile.get())) { LOG.info(String.format("...%s is not on the source path", toFile.get())); return files; } diff --git a/src/main/java/org/javacs/JavaLanguageServer.java b/src/main/java/org/javacs/JavaLanguageServer.java index 8ac317c..32d4bdf 100644 --- a/src/main/java/org/javacs/JavaLanguageServer.java +++ b/src/main/java/org/javacs/JavaLanguageServer.java @@ -14,12 +14,8 @@ import com.sun.source.tree.MethodTree; import com.sun.source.tree.Tree; import com.sun.source.tree.VariableTree; import com.sun.source.util.TreePath; -import java.io.BufferedReader; import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; import java.net.URI; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; @@ -37,7 +33,6 @@ import java.util.Set; import java.util.StringJoiner; import java.util.UUID; import java.util.logging.Logger; -import java.util.stream.Collectors; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; @@ -47,8 +42,6 @@ import javax.tools.JavaFileObject; import org.javacs.lsp.*; class JavaLanguageServer extends LanguageServer { - private static final Logger LOG = Logger.getLogger("main"); - // TODO allow multiple workspace roots private Path workspaceRoot; private SourcePath sourcePath; @@ -57,7 +50,6 @@ class JavaLanguageServer extends LanguageServer { private Set<Path> classPath = Set.of(); JavaCompilerService compiler; - private final Map<URI, VersionedContent> activeDocuments = new HashMap<>(); private static int severity(Diagnostic.Kind kind) { switch (kind) { @@ -102,7 +94,7 @@ class JavaLanguageServer extends LanguageServer { continue; } // Find start and end position - var content = contents(uri); + var content = FileStore.contents(uri); var start = position(content, j.getStartPosition()); var end = position(content, j.getEndPosition()); var d = new org.javacs.lsp.Diagnostic(); @@ -272,7 +264,7 @@ class JavaLanguageServer extends LanguageServer { var created = new HashSet<Path>(); var deleted = new HashSet<Path>(); for (var c : params.changes) { - if (!isJavaFile(c.uri)) continue; + if (!FileStore.isJavaFile(c.uri)) continue; var file = Paths.get(c.uri); switch (c.type) { case FileChangeType.Created: @@ -347,8 +339,8 @@ class JavaLanguageServer extends LanguageServer { // TODO reuse previous compilation when changes are small var started = Instant.now(); var uri = position.textDocument.uri; - if (!isJavaFile(uri)) return Optional.empty(); - var content = contents(uri); + if (!FileStore.isJavaFile(uri)) return Optional.empty(); + var content = FileStore.contents(uri); var line = position.position.line + 1; var column = position.position.character + 1; // Figure out what kind of completion we want to do @@ -634,10 +626,12 @@ class JavaLanguageServer extends LanguageServer { // TODO take only URI and invalidate based on version private void updateActiveFile(URI uri) { - if (activeFileCache == null || !activeFileCache.file.equals(uri) || activeFileCacheVersion != version(uri)) { + if (activeFileCache == null + || !activeFileCache.file.equals(uri) + || activeFileCacheVersion != FileStore.version(uri)) { LOG.info("Recompile active file..."); - activeFileCache = compiler.compileFile(uri, contents(uri)); - activeFileCacheVersion = version(uri); + activeFileCache = compiler.compileFile(uri, FileStore.contents(uri)); + activeFileCacheVersion = FileStore.version(uri); } } @@ -645,7 +639,7 @@ class JavaLanguageServer extends LanguageServer { public Optional<Hover> hover(TextDocumentPositionParams position) { // Compile entire file if it's changed since last hover var uri = position.textDocument.uri; - if (!isJavaFile(uri)) return Optional.empty(); + if (!FileStore.isJavaFile(uri)) return Optional.empty(); updateActiveFile(uri); // Find element undeer cursor @@ -749,8 +743,8 @@ class JavaLanguageServer extends LanguageServer { @Override public Optional<SignatureHelp> signatureHelp(TextDocumentPositionParams position) { var uri = position.textDocument.uri; - if (!isJavaFile(uri)) return Optional.empty(); - var content = contents(uri); + if (!FileStore.isJavaFile(uri)) return Optional.empty(); + var content = FileStore.contents(uri); var line = position.position.line + 1; var column = position.position.character + 1; var focus = compiler.compileFocus(uri, content, line, column); @@ -761,7 +755,7 @@ class JavaLanguageServer extends LanguageServer { @Override public Optional<List<Location>> gotoDefinition(TextDocumentPositionParams position) { var fromUri = position.textDocument.uri; - if (!isJavaFile(fromUri)) return Optional.empty(); + if (!FileStore.isJavaFile(fromUri)) return Optional.empty(); var fromLine = position.position.line + 1; var fromColumn = position.position.character + 1; @@ -802,7 +796,7 @@ class JavaLanguageServer extends LanguageServer { @Override public Optional<List<Location>> findReferences(ReferenceParams position) { var toUri = position.textDocument.uri; - if (!isJavaFile(toUri)) return Optional.empty(); + if (!FileStore.isJavaFile(toUri)) return Optional.empty(); var toLine = position.position.line + 1; var toColumn = position.position.character + 1; @@ -845,7 +839,7 @@ class JavaLanguageServer extends LanguageServer { if (name.equals("<init>")) name = el.getEnclosingElement().getSimpleName().toString(); var sources = new ArrayList<JavaFileObject>(); for (var f : files) { - var contents = contents(f); + var contents = FileStore.contents(f); var pruned = Pruner.prune(f, contents, name); sources.add(new StringFileObject(pruned, f)); } @@ -855,7 +849,7 @@ class JavaLanguageServer extends LanguageServer { private List<JavaFileObject> latestText(Collection<URI> files) { var sources = new ArrayList<JavaFileObject>(); for (var f : files) { - sources.add(new StringFileObject(contents(f), f)); + sources.add(new StringFileObject(FileStore.contents(f), f)); } return sources; } @@ -865,17 +859,17 @@ class JavaLanguageServer extends LanguageServer { private int cacheParseVersion = -1; private void updateCachedParse(URI file) { - if (file.equals(cacheParseFile) && version(file) == cacheParseVersion) return; + if (file.equals(cacheParseFile) && FileStore.version(file) == cacheParseVersion) return; LOG.info(String.format("Updating cached parse file to %s", file)); - cacheParse = compiler.parseFile(file, contents(file)); + cacheParse = compiler.parseFile(file, FileStore.contents(file)); cacheParseFile = file; - cacheParseVersion = version(file); + cacheParseVersion = FileStore.version(file); } @Override public List<SymbolInformation> documentSymbol(DocumentSymbolParams params) { var uri = params.textDocument.uri; - if (!isJavaFile(uri)) return List.of(); + if (!FileStore.isJavaFile(uri)) return List.of(); updateCachedParse(uri); var paths = cacheParse.documentSymbols(); var infos = new ArrayList<SymbolInformation>(); @@ -954,7 +948,7 @@ class JavaLanguageServer extends LanguageServer { public List<CodeLens> codeLens(CodeLensParams params) { // TODO just create a blank code lens on every method, then resolve it async var uri = params.textDocument.uri; - if (!isJavaFile(uri)) return List.of(); + if (!FileStore.isJavaFile(uri)) return List.of(); updateCachedParse(uri); var declarations = cacheParse.declarations(); var result = new ArrayList<CodeLens>(); @@ -1288,120 +1282,38 @@ class JavaLanguageServer extends LanguageServer { throw new RuntimeException("TODO"); } - static boolean isJavaFile(URI uri) { - return uri.getScheme().equals("file") && uri.getPath().endsWith(".java"); - } - private List<URI> recentlyOpened = new ArrayList<>(); @Override public void didOpenTextDocument(DidOpenTextDocumentParams params) { - var document = params.textDocument; - var uri = document.uri; - if (!isJavaFile(uri)) return; - LOG.info(String.format("Opened %s", Parser.fileName(uri))); - activeDocuments.put(uri, new VersionedContent(document.text, document.version)); - recentlyOpened.add(uri); - updateCachedParse(uri); // So that subsequent documentSymbol and codeLens requests will be faster + FileStore.open(params); + recentlyOpened.add(params.textDocument.uri); // Lint this document later + updateCachedParse( + params.textDocument.uri); // So that subsequent documentSymbol and codeLens requests will be faster } @Override public void didChangeTextDocument(DidChangeTextDocumentParams params) { - var document = params.textDocument; - var uri = document.uri; - if (isJavaFile(uri)) { - var existing = activeDocuments.get(uri); - var newText = existing.content; - - if (document.version > existing.version) { - for (var change : params.contentChanges) { - if (change.range == null) newText = change.text; - else newText = patch(newText, change); - } - - activeDocuments.put(uri, new VersionedContent(newText, document.version)); - } else LOG.warning("Ignored change with version " + document.version + " <= " + existing.version); - } - } - - private String patch(String sourceText, TextDocumentContentChangeEvent change) { - try { - var range = change.range; - var reader = new BufferedReader(new StringReader(sourceText)); - var writer = new StringWriter(); - - // Skip unchanged lines - int line = 0; - - while (line < range.start.line) { - writer.write(reader.readLine() + '\n'); - line++; - } - - // Skip unchanged chars - for (int character = 0; character < range.start.character; character++) writer.write(reader.read()); - - // Write replacement text - writer.write(change.text); - - // Skip replaced text - reader.skip(change.rangeLength); - - // Write remaining text - while (true) { - int next = reader.read(); - - if (next == -1) return writer.toString(); - else writer.write(next); - } - } catch (IOException e) { - throw new RuntimeException(e); - } + FileStore.change(params); } @Override public void didCloseTextDocument(DidCloseTextDocumentParams params) { - var document = params.textDocument; - var uri = document.uri; - if (isJavaFile(uri)) { - // Remove from source cache - activeDocuments.remove(uri); + FileStore.close(params); + if (FileStore.isJavaFile(params.textDocument.uri)) { // Clear diagnostics - publishDiagnostics(Collections.singletonList(uri), List.of()); + publishDiagnostics(List.of(params.textDocument.uri), List.of()); } } @Override public void didSaveTextDocument(DidSaveTextDocumentParams params) { - var uri = params.textDocument.uri; - if (isJavaFile(uri)) { + if (FileStore.isJavaFile(params.textDocument.uri)) { // Re-lint all active documents - reportErrors(activeDocuments.keySet()); + reportErrors(FileStore.activeDocuments()); } } - Set<URI> activeDocuments() { - return activeDocuments.keySet(); - } - - int version(URI openFile) { - if (!activeDocuments.containsKey(openFile)) return -1; - return activeDocuments.get(openFile).version; - } - - String contents(URI openFile) { - if (!isJavaFile(openFile)) { - LOG.warning("Ignoring non-java file " + openFile); - return ""; - } - if (activeDocuments.containsKey(openFile)) { - return activeDocuments.get(openFile).content; - } - try { - return Files.readAllLines(Paths.get(openFile)).stream().collect(Collectors.joining("\n")); - } catch (IOException e) { - throw new RuntimeException(e); - } - } + private static final Logger LOG = Logger.getLogger("main"); } |