Slide 1

Slide 1 text

Extending JDT with Language Servers Martin Lippert - Pivotal @martinlippert

Slide 2

Slide 2 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ The Background

Slide 3

Slide 3 text

Unless otherwise indicated, these slides are © 2013-2017 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Spring Tools 4 - now GA 3 https://spring.io/tools Spring Tools 4 for Eclipse Spring Tools 4 for Visual Studio Code Spring Tools 4 for Atom IDE

Slide 4

Slide 4 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Integration with JDT is key

Slide 5

Slide 5 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Part 1 - Understanding Java inside the LS

Slide 6

Slide 6 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Understanding Java • Language Servers are different from Eclipse extensions • they know about files • there is no API to understand and analyze languages • You have to build your own language understanding for Java • heavyweight approach: re-use full-blown Eclipse JDT on OSGi • lightweight approach: use a Java language parser of your choice and go 6

Slide 7

Slide 7 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Parsing Java private void scanFiles(IJavaProject project, ASTParser parser, String[] javaFiles, String[] classpathEntries) throws Exception { Map options = JavaCore.getOptions(); JavaCore.setComplianceOptions(JavaCore.VERSION_10, options); ASTParser parser = ASTParser.newParser(AST.JLS10); parser.setCompilerOptions(options); parser.setKind(ASTParser.K_COMPILATION_UNIT); parser.setStatementsRecovery(true); parser.setBindingsRecovery(true); parser.setResolveBindings(true); parser.setIgnoreMethodBodies(false); String[] sourceEntries = new String[0]; parser.setEnvironment(classpathEntries, sourceEntries, null, false); FileASTRequestor requestor = new FileASTRequestor() { @Override public void acceptAST(String sourceFilePath, CompilationUnit cu) { ... } }; parser.createASTs(javaFiles, null, new String[0], requestor, null); } 7

Slide 8

Slide 8 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ private void scanFiles(IJavaProject project, ASTParser parser, String[] javaFiles, String[] classpathEntries) throws Exception { Map options = JavaCore.getOptions(); JavaCore.setComplianceOptions(JavaCore.VERSION_10, options); ASTParser parser = ASTParser.newParser(AST.JLS10); parser.setCompilerOptions(options); parser.setKind(ASTParser.K_COMPILATION_UNIT); parser.setStatementsRecovery(true); parser.setBindingsRecovery(true); parser.setResolveBindings(true); parser.setIgnoreMethodBodies(false); String[] sourceEntries = new String[0]; parser.setEnvironment(classpathEntries, sourceEntries, null, false); FileASTRequestor requestor = new FileASTRequestor() { @Override public void acceptAST(String sourceFilePath, CompilationUnit cu) { ... } }; parser.createASTs(javaFiles, null, new String[0], requestor, null); } Parsing Java 8 depends on your code analysis requirements, skipping method bodies improves performance

Slide 9

Slide 9 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ private void scanFiles(IJavaProject project, ASTParser parser, String[] javaFiles, String[] classpathEntries) throws Exception { Map options = JavaCore.getOptions(); JavaCore.setComplianceOptions(JavaCore.VERSION_10, options); ASTParser parser = ASTParser.newParser(AST.JLS10); parser.setCompilerOptions(options); parser.setKind(ASTParser.K_COMPILATION_UNIT); parser.setStatementsRecovery(true); parser.setBindingsRecovery(true); parser.setResolveBindings(true); parser.setIgnoreMethodBodies(false); String[] sourceEntries = new String[0]; parser.setEnvironment(classpathEntries, sourceEntries, null, false); FileASTRequestor requestor = new FileASTRequestor() { @Override public void acceptAST(String sourceFilePath, CompilationUnit cu) { ... } }; parser.createASTs(javaFiles, null, new String[0], requestor, null); } Parsing Java 9 but where does the classpath information come from?

Slide 10

Slide 10 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Resolving Projects • first attempt: • understand the project structure on our own (use Gradle, Maven, etc.) • => slow, error-prone, could result in mismatches with Java language tooling • second attempt: • ask the Java tooling (Java language server) for resolved projects and updates • requires extra work on the Eclipse side (needs to deliver that information) • requires extra communication 10

Slide 11

Slide 11 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Part 2 - Running the Language Server

Slide 12

Slide 12 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Language Server 12

Slide 13

Slide 13 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Language Server - Definition 13 define the language server via the LSP4E extension point

Slide 14

Slide 14 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Language Server - Mapping 14 map the language server to the existing Java source content type

Slide 15

Slide 15 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Connect Document Events 15 the document connector is responsible for starting and stopping language servers automatically, independent of the used editor

Slide 16

Slide 16 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Part 3 - Connecting to the Java Editor

Slide 17

Slide 17 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Connecting Content-Assist 17 write and define a regular content-assist proposal computer for JDT

Slide 18

Slide 18 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Completion Proposal Computer public class SpringBootJavaCompletionProposalComputer implements IJavaCompletionProposalComputer { private LSContentAssistProcessor lsContentAssistProcessor; public SpringBootJavaCompletionProposalComputer() { lsContentAssistProcessor = new LSContentAssistProcessor(); } @Override public List computeCompletionProposals(ContentAssistInvocationContext context, IProgressMonitor monitor) { ICompletionProposal[] completionProposals = lsContentAssistProcessor.computeCompletionProposals( context.getViewer(), context.getInvocationOffset()); return Arrays.asList(completionProposals); } @Override public List computeContextInformation(ContentAssistInvocationContext context, IProgressMonitor monitor) { IContextInformation[] contextInformation = lsContentAssistProcessor.computeContextInformation( context.getViewer(), context.getInvocationOffset()); return Arrays.asList(contextInformation); } ... } 18

Slide 19

Slide 19 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Completion Proposal Computer public class SpringBootJavaCompletionProposalComputer implements IJavaCompletionProposalComputer { private LSContentAssistProcessor lsContentAssistProcessor; public SpringBootJavaCompletionProposalComputer() { lsContentAssistProcessor = new LSContentAssistProcessor(); } @Override public List computeCompletionProposals(ContentAssistInvocationContext context, IProgressMonitor monitor) { ICompletionProposal[] completionProposals = lsContentAssistProcessor.computeCompletionProposals( context.getViewer(), context.getInvocationOffset()); return Arrays.asList(completionProposals); } @Override public List computeContextInformation(ContentAssistInvocationContext context, IProgressMonitor monitor) { IContextInformation[] contextInformation = lsContentAssistProcessor.computeContextInformation( context.getViewer(), context.getInvocationOffset()); return Arrays.asList(contextInformation); } ... } 19 regular content-assist processor from LSP4E

Slide 20

Slide 20 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Completion Proposal Computer public class SpringBootJavaCompletionProposalComputer implements IJavaCompletionProposalComputer { private LSContentAssistProcessor lsContentAssistProcessor; public SpringBootJavaCompletionProposalComputer() { lsContentAssistProcessor = new LSContentAssistProcessor(); } @Override public List computeCompletionProposals(ContentAssistInvocationContext context, IProgressMonitor monitor) { ICompletionProposal[] completionProposals = lsContentAssistProcessor.computeCompletionProposals( context.getViewer(), context.getInvocationOffset()); return Arrays.asList(completionProposals); } @Override public List computeContextInformation(ContentAssistInvocationContext context, IProgressMonitor monitor) { IContextInformation[] contextInformation = lsContentAssistProcessor.computeContextInformation( context.getViewer(), context.getInvocationOffset()); return Arrays.asList(contextInformation); } ... } 20 call the LSP4E content- assist processor, that’s it

Slide 21

Slide 21 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Live Demo

Slide 22

Slide 22 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Connecting Live Hovers 22 write and define a regular hover provider for JDT

Slide 23

Slide 23 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Hover Provider public class SpringBootJavaHoverProvider implements IJavaEditorTextHover, ITextHoverExtension { private LSBasedHover lsBasedHover; public SpringBootJavaHoverProvider() { lsBasedHover = new LSBasedHover(); } @Override public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { return this.lsBasedHover.getHoverInfo(textViewer, hoverRegion); } @Override public IRegion getHoverRegion(ITextViewer textViewer, int offset) { return this.lsBasedHover.getHoverRegion(textViewer, offset); } ... } 23

Slide 24

Slide 24 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Hover Provider public class SpringBootJavaHoverProvider implements IJavaEditorTextHover, ITextHoverExtension { private LSBasedHover lsBasedHover; public SpringBootJavaHoverProvider() { lsBasedHover = new LSBasedHover(); } @Override public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { return this.lsBasedHover.getHoverInfo(textViewer, hoverRegion); } @Override public IRegion getHoverRegion(ITextViewer textViewer, int offset) { return this.lsBasedHover.getHoverRegion(textViewer, offset); } ... } 24 regular hover provider from LSP4E

Slide 25

Slide 25 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Hover Provider public class SpringBootJavaHoverProvider implements IJavaEditorTextHover, ITextHoverExtension { private LSBasedHover lsBasedHover; public SpringBootJavaHoverProvider() { lsBasedHover = new LSBasedHover(); } @Override public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { return this.lsBasedHover.getHoverInfo(textViewer, hoverRegion); } @Override public IRegion getHoverRegion(ITextViewer textViewer, int offset) { return this.lsBasedHover.getHoverRegion(textViewer, offset); } ... } 25 call the LSP4E hover provider, that’s it

Slide 26

Slide 26 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Live Demo

Slide 27

Slide 27 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Side Notes • to improve reliability, wrap calls to LS… into futures 27

Slide 28

Slide 28 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Code Lenses you need to do NOTHING… 28

Slide 29

Slide 29 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Live Demo

Slide 30

Slide 30 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Outlook

Slide 31

Slide 31 text

Unless otherwise indicated, these slides are © 2013-2018 Pivotal Software, Inc. and licensed under a Creative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ Outlook • get push model in LSP for: • code lenses (custom messages at the moment) • green highlights in the code (custom messages at the moment) • investigate more complicated code analysis tasks • e.g. what happens if we implement more comprehensive content-assist 31

Slide 32

Slide 32 text

> Thanks. https://spring.io/tools https://github.com/spring-projects/sts4 Martin Lippert [email protected]