├── eclipse-che ├── chamrousse-workspace-image │ ├── src │ │ └── main │ │ │ └── docker │ │ │ ├── .gitignore │ │ │ ├── launch.sh │ │ │ └── Dockerfile │ └── pom.xml ├── start-che.sh ├── plugin-chamrousse │ ├── che-plugin-chamrousse-lang-ide │ │ ├── src │ │ │ └── main │ │ │ │ ├── resources │ │ │ │ └── org │ │ │ │ │ └── eclipse │ │ │ │ │ └── che │ │ │ │ │ └── plugin │ │ │ │ │ └── chamrousse │ │ │ │ │ └── ide │ │ │ │ │ ├── ChamrousseLocalizationConstant.properties │ │ │ │ │ └── svg │ │ │ │ │ └── chamrousse.svg │ │ │ │ ├── module.gwt.xml │ │ │ │ └── java │ │ │ │ └── org │ │ │ │ └── eclipse │ │ │ │ └── che │ │ │ │ └── plugin │ │ │ │ └── chamrousse │ │ │ │ └── ide │ │ │ │ ├── ChamrousseLocalizationConstant.java │ │ │ │ ├── ChamrousseResources.java │ │ │ │ ├── inject │ │ │ │ └── ChamrousseGinModule.java │ │ │ │ ├── project │ │ │ │ └── ChamrousseProjectWizardRegistrar.java │ │ │ │ ├── ChamrousseExtension.java │ │ │ │ └── action │ │ │ │ └── CreateChamrousseFileAction.java │ │ └── pom.xml │ ├── pom.xml │ └── che-plugin-chamrousse-lang-server │ │ ├── src │ │ └── main │ │ │ └── java │ │ │ └── org │ │ │ └── eclipse │ │ │ └── che │ │ │ └── plugin │ │ │ └── chamrousse │ │ │ ├── inject │ │ │ └── ChamrousseModule.java │ │ │ └── languageserver │ │ │ └── ChamrousseLanguageServerLauncher.java │ │ └── pom.xml └── README.md ├── vscode-chamrousse ├── .gitignore ├── icons │ └── icon128.png ├── images │ ├── statusMarker.png │ └── vscode-java.0.0.1.gif ├── .editorconfig ├── .vscodeignore ├── .project ├── gulpfile.js ├── .vscode │ ├── extensions.json │ ├── settings.json │ ├── launch.json │ └── tasks.json ├── tsconfig.json ├── tslint.json ├── .github │ └── ISSUE_TEMPLATE.md ├── LICENSE ├── language-configuration.json ├── test │ └── index.ts ├── package.json └── src │ ├── protocol.ts │ └── extension.ts ├── fr.alpesjug.lsp.eclipse ├── build.properties ├── .classpath ├── .settings │ └── org.eclipse.jdt.core.prefs ├── META-INF │ └── MANIFEST.MF ├── .project ├── src │ └── fr │ │ └── alpesjug │ │ └── lsp │ │ └── eclipse │ │ └── ChamrousseLanguageServerStreamProvider.java └── plugin.xml ├── Le LanguageServer de Chamrousse ├── .settings │ ├── org.eclipse.m2e.core.prefs │ └── org.eclipse.jdt.core.prefs ├── .project ├── src │ ├── main │ │ ├── resources │ │ │ └── fr │ │ │ │ └── alpesjug │ │ │ │ └── languageserver │ │ │ │ └── chamrousseMap.properties │ │ └── java │ │ │ └── fr │ │ │ └── alpesjug │ │ │ └── languageserver │ │ │ ├── ChamrousseWorkspaceService.java │ │ │ ├── Main.java │ │ │ ├── ChamrousseLanguageServer.java │ │ │ ├── ChamrousseMap.java │ │ │ ├── ChamrousseDocumentModel.java │ │ │ └── ChamrousseTextDocumentService.java │ └── test │ │ └── java │ │ └── fr │ │ └── alpesjug │ │ └── languageserver │ │ └── tests │ │ └── TestLanguageServer.java ├── .classpath └── pom.xml └── README.md /eclipse-che/chamrousse-workspace-image/src/main/docker/.gitignore: -------------------------------------------------------------------------------- 1 | lsp.jar 2 | 3 | -------------------------------------------------------------------------------- /eclipse-che/chamrousse-workspace-image/src/main/docker/launch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | java -jar /home/user/ls-chamrousse/launch.jar 3 | -------------------------------------------------------------------------------- /vscode-chamrousse/.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | server 3 | node_modules 4 | *.vsix 5 | .DS_Store 6 | .vscode-test 7 | undefined 8 | target 9 | -------------------------------------------------------------------------------- /vscode-chamrousse/icons/icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickaelistria/eclipse-languageserver-demo/HEAD/vscode-chamrousse/icons/icon128.png -------------------------------------------------------------------------------- /vscode-chamrousse/images/statusMarker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickaelistria/eclipse-languageserver-demo/HEAD/vscode-chamrousse/images/statusMarker.png -------------------------------------------------------------------------------- /fr.alpesjug.lsp.eclipse/build.properties: -------------------------------------------------------------------------------- 1 | source.. = src/ 2 | output.. = bin/ 3 | bin.includes = META-INF/,\ 4 | .,\ 5 | plugin.xml 6 | -------------------------------------------------------------------------------- /Le LanguageServer de Chamrousse/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /vscode-chamrousse/images/vscode-java.0.0.1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickaelistria/eclipse-languageserver-demo/HEAD/vscode-chamrousse/images/vscode-java.0.0.1.gif -------------------------------------------------------------------------------- /eclipse-che/start-che.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock -e CHE_DOCKER_ALWAYS__PULL__IMAGE="false" -v /tmp/da6:/data florentbenoit/che:chamrousse-demo start --fast 3 | -------------------------------------------------------------------------------- /vscode-chamrousse/.editorconfig: -------------------------------------------------------------------------------- 1 | # Tab indentation 2 | [*] 3 | indent_style = tab 4 | indent_size = 4 5 | trim_trailing_whitespace = true 6 | 7 | [{.travis.yml,npm-shrinkwrap.json,package.json}] 8 | indent_style = space 9 | indent_size = 2 -------------------------------------------------------------------------------- /vscode-chamrousse/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | typings/** 3 | out/test/** 4 | test/** 5 | src/** 6 | images/** 7 | **/*.map 8 | .gitignore 9 | tsconfig.json 10 | vsc-extension-quickstart.md 11 | undefined/** 12 | CONTRIBUTING.md 13 | .vscode-test/** 14 | -------------------------------------------------------------------------------- /vscode-chamrousse/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | vscode-chamrousse 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /vscode-chamrousse/gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const gulp = require('gulp'); 3 | const gulp_tslint = require('gulp-tslint'); 4 | //... 5 | gulp.task('tslint', () => { 6 | return gulp.src(['**/*.ts', '!**/*.d.ts', '!node_modules/**']) 7 | .pipe(gulp_tslint()) 8 | .pipe(gulp_tslint.report()); 9 | }); -------------------------------------------------------------------------------- /vscode-chamrousse/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 6 | "eg2.tslint", 7 | "EditorConfig.EditorConfig" 8 | ] 9 | } -------------------------------------------------------------------------------- /vscode-chamrousse/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "lib": [ 5 | "es6" 6 | ], 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "outDir": "out", 10 | "sourceMap": true 11 | }, 12 | "exclude": [ 13 | "node_modules", 14 | "server", 15 | ".vscode-test" 16 | ] 17 | } -------------------------------------------------------------------------------- /vscode-chamrousse/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-unused-expression": true, 4 | "no-duplicate-variable": true, 5 | "no-duplicate-key": true, 6 | "no-unused-variable": true, 7 | "curly": true, 8 | "class-name": true, 9 | "semicolon": ["always"], 10 | "triple-equals": true, 11 | "quotemark": [true, "single", "avoid-escape"] 12 | } 13 | } -------------------------------------------------------------------------------- /fr.alpesjug.lsp.eclipse/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /fr.alpesjug.lsp.eclipse/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.source=1.8 8 | -------------------------------------------------------------------------------- /vscode-chamrousse/.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | [provide a description of the issue] 2 | 3 | ##### Environment 4 | - Operating System: 5 | - JDK version: 6 | - Visual Studio Code version: 7 | - Java extension version: 8 | 9 | ##### Steps To Reproduce 10 | 1. [step 1] 11 | 2. [step 2] 12 | 13 | [attach a sample project reproducing the error] 14 | 15 | ##### Current Result 16 | 17 | ##### Expected Result 18 | 19 | ##### Additional Informations 20 | -------------------------------------------------------------------------------- /eclipse-che/chamrousse-workspace-image/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM eclipse/ubuntu_jdk8 2 | 3 | #ENV DEBIAN_FRONTEND noninteractive 4 | 5 | RUN mkdir /home/user/ls-chamrousse 6 | ADD launch.sh /home/user/ls-chamrousse/launch.sh 7 | ADD lsp.jar /home/user/ls-chamrousse/launch.jar 8 | RUN sudo chmod 755 /home/user/ls-chamrousse/launch.sh && \ 9 | sudo chgrp -R 0 /home/user/ls-chamrousse && \ 10 | sudo chmod -R g+rwX /home/user/ls-chamrousse 11 | -------------------------------------------------------------------------------- /vscode-chamrousse/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "out": false // set this to true to hide the "out" folder with the compiled JS files 5 | }, 6 | "search.exclude": { 7 | "out": true // set this to false to include "out" folder in search results 8 | }, 9 | "typescript.tsdk": "./node_modules/typescript/lib", 10 | "vsicons.presets.angular": false // we want to use the TS server from our node_modules folder to control its version 11 | } -------------------------------------------------------------------------------- /fr.alpesjug.lsp.eclipse/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Bundle-ManifestVersion: 2 3 | Bundle-Name: Consume the Toulouse LS in Eclipse 4 | Bundle-SymbolicName: fr.alpesjug.lsp.eclipse;singleton:=true 5 | Bundle-Version: 1.0.0.qualifier 6 | Bundle-RequiredExecutionEnvironment: JavaSE-1.8 7 | Require-Bundle: org.eclipse.ui.genericeditor;bundle-version="1.0.0", 8 | org.eclipse.lsp4e;bundle-version="0.2.0", 9 | org.eclipse.lsp4j;bundle-version="0.2.0", 10 | org.eclipse.core.contenttype;bundle-version="3.6.0", 11 | org.eclipse.core.runtime 12 | -------------------------------------------------------------------------------- /vscode-chamrousse/LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2017 Mickael Istria 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. -------------------------------------------------------------------------------- /vscode-chamrousse/language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "//", 4 | "blockComment": [ "/*", "*/" ] 5 | }, 6 | "brackets": [ 7 | ["{", "}"], 8 | ["[", "]"], 9 | ["(", ")"] 10 | ], 11 | "autoClosingPairs": [ 12 | ["{", "}"], 13 | ["[", "]"], 14 | ["(", ")"], 15 | ["\"", "\""], 16 | ["'", "'"], 17 | { "open": "/**", "close": " */", "notIn": ["string"] } 18 | ], 19 | "surroundingPairs": [ 20 | ["{", "}"], 21 | ["[", "]"], 22 | ["(", ")"], 23 | ["\"", "\""], 24 | ["'", "'"], 25 | ["<", ">"] 26 | ] 27 | } -------------------------------------------------------------------------------- /Le LanguageServer de Chamrousse/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Le LanguageServer de Chamrousse 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.m2e.core.maven2Nature 22 | 23 | 24 | -------------------------------------------------------------------------------- /eclipse-che/plugin-chamrousse/che-plugin-chamrousse-lang-ide/src/main/resources/org/eclipse/che/plugin/chamrousse/ide/ChamrousseLocalizationConstant.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2012-2017 Red Hat, Inc. 3 | # All rights reserved. This program and the accompanying materials 4 | # are made available under the terms of the Eclipse Public License v1.0 5 | # which accompanies this distribution, and is available at 6 | # http://www.eclipse.org/legal/epl-v10.html 7 | # 8 | # Contributors: 9 | # Red Hat, Inc. - initial API and implementation 10 | # 11 | 12 | ##### Action ##### 13 | chamrousse.action.create.file.title = Chamrousse File 14 | chamrousse.action.create.file.description = Create Chamrousse File 15 | -------------------------------------------------------------------------------- /fr.alpesjug.lsp.eclipse/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | fr.alpesjug.lsp.eclipse 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.pde.ManifestBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.pde.SchemaBuilder 20 | 21 | 22 | 23 | 24 | 25 | org.eclipse.pde.PluginNature 26 | org.eclipse.jdt.core.javanature 27 | 28 | 29 | -------------------------------------------------------------------------------- /Le LanguageServer de Chamrousse/src/main/resources/fr/alpesjug/languageserver/chamrousseMap.properties: -------------------------------------------------------------------------------- 1 | Tsd\u0020de\u0020Casserousse.startsFrom=Olympique Hommes 2 | Tsd\u0020de\u0020Casserousse.type=TS 3 | Col\u0020de\u0020Balme.startsFrom=Olympique Hommes,TSD de Casserousse 4 | Col\u0020de\u0020Balme.type=Blue 5 | Balmette.startsFrom=Olympique Hommes,Olympique Dames,TSD de Casserousse 6 | Balmette.type=Green 7 | Olympique\u0020Hommes.starts=TC de la Croix 8 | Olympique\u0020Hommes=Black 9 | TC\u0020de\u0020la\u0020Croix.startsFrom=Col de Balme,Balmette 10 | TC\u0020de\u0020la\u0020Croix.type=TC 11 | Olympique\u0020Dames.startsFrom=TC de la Croix,Retour P2 12 | Olympique\u0020Dames.type=Red 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | # TODO: enrich language 21 | #Retour\u0020P2.startsFrom=Olympique Hommes 22 | #Retour\u0020P2.type=Blue -------------------------------------------------------------------------------- /eclipse-che/plugin-chamrousse/che-plugin-chamrousse-lang-ide/src/main/module.gwt.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /Le LanguageServer de Chamrousse/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate 4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.compliance=1.8 7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 12 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 13 | org.eclipse.jdt.core.compiler.release=disabled 14 | org.eclipse.jdt.core.compiler.source=1.8 15 | -------------------------------------------------------------------------------- /Le LanguageServer de Chamrousse/src/main/java/fr/alpesjug/languageserver/ChamrousseWorkspaceService.java: -------------------------------------------------------------------------------- 1 | package fr.alpesjug.languageserver; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.CompletableFuture; 5 | 6 | import org.eclipse.lsp4j.DidChangeConfigurationParams; 7 | import org.eclipse.lsp4j.DidChangeWatchedFilesParams; 8 | import org.eclipse.lsp4j.SymbolInformation; 9 | import org.eclipse.lsp4j.WorkspaceSymbolParams; 10 | import org.eclipse.lsp4j.services.WorkspaceService; 11 | 12 | public class ChamrousseWorkspaceService implements WorkspaceService { 13 | 14 | @Override 15 | public CompletableFuture> symbol(WorkspaceSymbolParams params) { 16 | return null; 17 | } 18 | 19 | @Override 20 | public void didChangeConfiguration(DidChangeConfigurationParams params) { 21 | } 22 | 23 | @Override 24 | public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) { 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /vscode-chamrousse/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | { 3 | "version": "0.1.0", 4 | "configurations": [ 5 | { 6 | "name": "Launch Extension", 7 | "type": "extensionHost", 8 | "request": "launch", 9 | "runtimeExecutable": "${execPath}", 10 | "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--debug" ], 11 | "stopOnEntry": false, 12 | "sourceMaps": true, 13 | "outDir": "${workspaceRoot}/out/src", 14 | "preLaunchTask": "compile" 15 | }, 16 | { 17 | "name": "Launch Tests", 18 | "type": "extensionHost", 19 | "request": "launch", 20 | "runtimeExecutable": "${execPath}", 21 | "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], 22 | "stopOnEntry": false, 23 | "sourceMaps": true, 24 | "outDir": "${workspaceRoot}/out/test", 25 | "preLaunchTask": "compile" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /fr.alpesjug.lsp.eclipse/src/fr/alpesjug/lsp/eclipse/ChamrousseLanguageServerStreamProvider.java: -------------------------------------------------------------------------------- 1 | package fr.alpesjug.lsp.eclipse; 2 | 3 | import java.io.File; 4 | import java.util.Arrays; 5 | 6 | import org.eclipse.lsp4e.server.ProcessStreamConnectionProvider; 7 | import org.eclipse.lsp4e.server.StreamConnectionProvider; 8 | 9 | public class ChamrousseLanguageServerStreamProvider extends ProcessStreamConnectionProvider 10 | implements StreamConnectionProvider { 11 | 12 | 13 | public ChamrousseLanguageServerStreamProvider() { 14 | super( 15 | Arrays.asList("/usr/bin/java", "-jar", "/home/mistria/workspaceDemoLSP/Le LanguageServer de Chamrousse/target/chamrousse-languageserver-0.0.1-SNAPSHOT-jar-with-dependencies.jar"), 16 | new File(".").getAbsolutePath()); 17 | // super( 18 | // Arrays.asList(new String[] { "docker", 19 | // "run", 20 | // "-v", 21 | // "/home/mistria:/home/mistria", 22 | // "-i", 23 | // "chamrousse-ls", 24 | // }), System.getProperty("user.dir")); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /eclipse-che/plugin-chamrousse/che-plugin-chamrousse-lang-ide/src/main/java/org/eclipse/che/plugin/chamrousse/ide/ChamrousseLocalizationConstant.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2017 Red Hat, Inc. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Red Hat, Inc. - initial API and implementation 10 | */ 11 | package org.eclipse.che.plugin.chamrousse.ide; 12 | 13 | import com.google.gwt.i18n.client.Messages; 14 | 15 | /** 16 | * Localization constants. 17 | * 18 | * @author Florent Benoit 19 | */ 20 | public interface ChamrousseLocalizationConstant extends Messages { 21 | @Key("chamrousse.action.create.file.title") 22 | String createChamrousseFileActionTitle(); 23 | 24 | @Key("chamrousse.action.create.file.description") 25 | String createChamrousseFileActionDescription(); 26 | } 27 | -------------------------------------------------------------------------------- /Le LanguageServer de Chamrousse/src/main/java/fr/alpesjug/languageserver/Main.java: -------------------------------------------------------------------------------- 1 | package fr.alpesjug.languageserver; 2 | 3 | import java.io.InputStream; 4 | import java.io.OutputStream; 5 | import java.util.concurrent.ExecutionException; 6 | import java.util.concurrent.Future; 7 | 8 | import org.eclipse.lsp4j.jsonrpc.Launcher; 9 | import org.eclipse.lsp4j.launch.LSPLauncher; 10 | import org.eclipse.lsp4j.services.LanguageClient; 11 | 12 | public class Main { 13 | 14 | public static void main(String[] args) throws InterruptedException, ExecutionException { 15 | startServer(System.in, System.out); 16 | } 17 | 18 | public static void startServer(InputStream in, OutputStream out) throws InterruptedException, ExecutionException { 19 | ChamrousseLanguageServer server = new ChamrousseLanguageServer(); 20 | Launcher l = LSPLauncher.createServerLauncher(server, in, out); 21 | Future startListening = l.startListening(); 22 | server.setRemoteProxy(l.getRemoteProxy()); 23 | startListening.get(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /eclipse-che/plugin-chamrousse/che-plugin-chamrousse-lang-ide/src/main/java/org/eclipse/che/plugin/chamrousse/ide/ChamrousseResources.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2017 Red Hat, Inc. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Red Hat, Inc. - initial API and implementation 10 | */ 11 | package org.eclipse.che.plugin.chamrousse.ide; 12 | 13 | import com.google.gwt.core.client.GWT; 14 | import com.google.gwt.resources.client.ClientBundle; 15 | import org.vectomatic.dom.svg.ui.SVGResource; 16 | 17 | /** @author Florent Benoit */ 18 | public interface ChamrousseResources extends ClientBundle { 19 | ChamrousseResources INSTANCE = GWT.create(ChamrousseResources.class); 20 | 21 | @Source("svg/chamrousse.svg") 22 | SVGResource pythonFile(); 23 | 24 | @Source("svg/chamrousse.svg") 25 | SVGResource category(); 26 | } 27 | -------------------------------------------------------------------------------- /vscode-chamrousse/test/index.ts: -------------------------------------------------------------------------------- 1 | // 2 | // PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING 3 | // 4 | // This file is providing the test runner to use when running extension tests. 5 | // By default the test runner in use is Mocha based. 6 | // 7 | // You can provide your own test runner if you want to override it by exporting 8 | // a function run(testRoot: string, clb: (error:Error) => void) that the extension 9 | // host can call to run the tests. The test runner is expected to use console.log 10 | // to report the results back to the caller. When the tests are finished, return 11 | // a possible error to the callback or null if none. 12 | 13 | var testRunner = require('vscode/lib/testrunner'); 14 | 15 | // You can directly control Mocha options by uncommenting the following lines 16 | // See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info 17 | testRunner.configure({ 18 | ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.) 19 | useColors: true // colored output from test results 20 | }); 21 | 22 | module.exports = testRunner; -------------------------------------------------------------------------------- /fr.alpesjug.lsp.eclipse/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 12 | 13 | 14 | 16 | 20 | 21 | 24 | 25 | 26 | 28 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /eclipse-che/plugin-chamrousse/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 4.0.0 16 | 17 | che-plugin-parent 18 | org.eclipse.che.plugin 19 | 6.0.0-M5-SNAPSHOT 20 | ../pom.xml 21 | 22 | che-plugin-chamrousse-parent 23 | pom 24 | Che Plugin :: Chamrousse :: Parent 25 | 26 | che-plugin-chamrousse-lang-server 27 | che-plugin-chamrousse-lang-ide 28 | 29 | 30 | -------------------------------------------------------------------------------- /eclipse-che/README.md: -------------------------------------------------------------------------------- 1 | ## build workspace image 2 | 3 | ``` 4 | $ cd chamrousse-workspace-image 5 | $ mvn clean install 6 | ``` 7 | 8 | it will build local docker image 9 | 10 | ``` 11 | [INFO] DOCKER> [florentbenoit/chamrousse:latest]: Created docker-build.tar in 65 milliseconds 12 | [INFO] DOCKER> [florentbenoit/chamrousse:latest]: Built image sha256:a48db 13 | ``` 14 | 15 | ## Start Eclipse Che 16 | Then we can start Eclipse Che with script start-che.sh 17 | the script includes parameter CHE_DOCKER_ALWAYS__PULL__IMAGE="false" to not try to pull image from dockerhub at each start (helpful if internet access is down) 18 | 19 | ## Build stack 20 | Once che is started and available at http://localhost:8080 we add the chamrousse stack from http://localhost:8080/dashboard/#/stacks 21 | 22 | "Build stack from recipe" 23 | 24 | we select `docker image` tab and enter `florentbenoit/chamrousse` 25 | 26 | we pickup a name like "A chamrousse stack" and save 27 | 28 | ## Create and start workspace 29 | From http://localhost:8080/dashboard/#/workspaces 30 | Select `Add workspace` and pickup "A chamrousse stack` from the list 31 | 32 | ## Create a project 33 | Once workspace is booted 34 | Create a project with menu "Workspace/Create project..." 35 | Select blank type and enter project name like "Chamrousse" 36 | 37 | ## Create a file 38 | Right click on "chamrousse" project and select "New..." and "Chamrousse File" 39 | 40 | pickup dummy name like example 41 | Use ctrl+tab in the ski file and there is code assist 42 | -------------------------------------------------------------------------------- /Le LanguageServer de Chamrousse/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /eclipse-che/plugin-chamrousse/che-plugin-chamrousse-lang-ide/src/main/java/org/eclipse/che/plugin/chamrousse/ide/inject/ChamrousseGinModule.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2017 Red Hat, Inc. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Red Hat, Inc. - initial API and implementation 10 | */ 11 | package org.eclipse.che.plugin.chamrousse.ide.inject; 12 | 13 | import com.google.gwt.inject.client.AbstractGinModule; 14 | import com.google.gwt.inject.client.multibindings.GinMultibinder; 15 | import com.google.inject.Provides; 16 | import com.google.inject.Singleton; 17 | import com.google.inject.name.Named; 18 | import org.eclipse.che.ide.api.extension.ExtensionGinModule; 19 | import org.eclipse.che.ide.api.filetypes.FileType; 20 | import org.eclipse.che.ide.api.project.type.wizard.ProjectWizardRegistrar; 21 | import org.eclipse.che.plugin.chamrousse.ide.ChamrousseResources; 22 | 23 | /** @author Florent Benoit */ 24 | @ExtensionGinModule 25 | public class ChamrousseGinModule extends AbstractGinModule { 26 | 27 | @Override 28 | protected void configure() { 29 | GinMultibinder.newSetBinder(binder(), ProjectWizardRegistrar.class) 30 | .addBinding() 31 | .to(org.eclipse.che.plugin.chamrousse.ide.project.ChamrousseProjectWizardRegistrar.class); 32 | } 33 | 34 | @Provides 35 | @Singleton 36 | @Named("ChamrousseFileType") 37 | protected FileType providePythonFile() { 38 | return new FileType(ChamrousseResources.INSTANCE.pythonFile(), "ski"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /eclipse-che/plugin-chamrousse/che-plugin-chamrousse-lang-ide/src/main/java/org/eclipse/che/plugin/chamrousse/ide/project/ChamrousseProjectWizardRegistrar.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2017 Red Hat, Inc. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Red Hat, Inc. - initial API and implementation 10 | */ 11 | package org.eclipse.che.plugin.chamrousse.ide.project; 12 | 13 | import com.google.inject.Provider; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import javax.validation.constraints.NotNull; 17 | import org.eclipse.che.ide.api.project.MutableProjectConfig; 18 | import org.eclipse.che.ide.api.project.type.wizard.ProjectWizardRegistrar; 19 | import org.eclipse.che.ide.api.wizard.WizardPage; 20 | 21 | /** 22 | * Provides information for registering Python project type into project wizard. 23 | * 24 | * @author Florent Benoit 25 | */ 26 | public class ChamrousseProjectWizardRegistrar implements ProjectWizardRegistrar { 27 | private final List>> wizardPages; 28 | 29 | public ChamrousseProjectWizardRegistrar() { 30 | wizardPages = new ArrayList<>(); 31 | } 32 | 33 | @NotNull 34 | public String getProjectTypeId() { 35 | return "chamrousse"; 36 | } 37 | 38 | @NotNull 39 | public String getCategory() { 40 | return "chamrousse"; 41 | } 42 | 43 | @NotNull 44 | public List>> getWizardPages() { 45 | return wizardPages; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /vscode-chamrousse/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-chamrousse", 3 | "displayName": "Language Support for Chamrousse", 4 | "description": "Language Support for Chamrousse", 5 | "author": "Mickael Istria", 6 | "icon": "icons/icon128.png", 7 | "license": "WTFPL", 8 | "version": "0.0.1", 9 | "preview": true, 10 | "publisher": "Mickael Istria", 11 | "engines": { 12 | "vscode": "^1.7.0" 13 | }, 14 | "repository": { 15 | 16 | }, 17 | "categories": [ 18 | "Languages", 19 | "Linters" 20 | ], 21 | "activationEvents": [ 22 | "onLanguage:ski", 23 | "workspaceContains:*.ski" 24 | ], 25 | "main": "./out/src/extension", 26 | "contributes": { 27 | "languages": [{ 28 | "id": "ski", 29 | "extensions": [ ".ski" ], 30 | "configuration": "./language-configuration.json" 31 | }] 32 | }, 33 | "scripts": { 34 | "vscode:prepublish": "tsc -p ./", 35 | "compile": "tsc -watch -p ./", 36 | "postinstall": "node ./node_modules/vscode/bin/install", 37 | "test": "node ./node_modules/vscode/bin/test", 38 | "tslint": "gulp tslint" 39 | }, 40 | "devDependencies": { 41 | "typescript": "^2.0.3", 42 | "vscode": "^1.0.0", 43 | "mocha": "^2.3.3", 44 | "@types/node": "^6.0.40", 45 | "@types/mocha": "^2.2.32", 46 | "@types/glob":"5.0.30", 47 | "gulp" :"^3.9.1", 48 | "gulp-tslint": "^6.1.2", 49 | "tslint" : "^3.15.1" 50 | }, 51 | "dependencies": { 52 | "vscode-languageclient": "^2.6.3", 53 | "find-java-home": "0.1.4", 54 | "http-proxy-agent": "^1.0.0", 55 | "https-proxy-agent": "^1.0.0", 56 | "tmp" : "^0.0.29", 57 | "decompress": "^4.0.0", 58 | "progress-stream": "^1.2.0", 59 | "path-exists":"^3.0.0", 60 | "expand-home-dir":"^0.0.3", 61 | "glob":"^7.1.1" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /vscode-chamrousse/src/protocol.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import { RequestType, NotificationType, TextDocumentIdentifier} from 'vscode-languageclient'; 4 | import { Command } from 'vscode'; 5 | 6 | /** 7 | * The message type. Copied from vscode protocol 8 | */ 9 | export enum MessageType { 10 | /** 11 | * An error message. 12 | */ 13 | Error = 1, 14 | /** 15 | * A warning message. 16 | */ 17 | Warning = 2, 18 | /** 19 | * An information message. 20 | */ 21 | Info = 3, 22 | /** 23 | * A log message. 24 | */ 25 | Log = 4, 26 | } 27 | 28 | /** 29 | * A functionality status 30 | */ 31 | export enum FeatureStatus { 32 | /** 33 | * Disabled. 34 | */ 35 | disabled = 0, 36 | /** 37 | * Enabled manually. 38 | */ 39 | interactive = 1, 40 | /** 41 | * Enabled automatically. 42 | */ 43 | automatic = 2, 44 | } 45 | 46 | export interface StatusReport { 47 | message: string; 48 | type: string; 49 | } 50 | 51 | export interface ActionableMessage { 52 | severity: MessageType; 53 | message: string; 54 | data?: any; 55 | commands?: Command[]; 56 | } 57 | 58 | export namespace StatusNotification { 59 | export const type: NotificationType = { get method() { return 'language/status'; } }; 60 | } 61 | 62 | export namespace ClassFileContentsRequest { 63 | export const type: RequestType = { get method() { return 'java/classFileContents'; }}; 64 | } 65 | 66 | export namespace ProjectConfigurationUpdateRequest { 67 | export const type: NotificationType = { get method() { return 'java/projectConfigurationUpdate'; }}; 68 | } 69 | 70 | export namespace ActionableNotification { 71 | export const type: NotificationType = { get method() { return 'language/actionableNotification'; }}; 72 | } -------------------------------------------------------------------------------- /eclipse-che/plugin-chamrousse/che-plugin-chamrousse-lang-server/src/main/java/org/eclipse/che/plugin/chamrousse/inject/ChamrousseModule.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012-2017 Codenvy, S.A. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Codenvy, S.A. - initial API and implementation 10 | *******************************************************************************/ 11 | package org.eclipse.che.plugin.chamrousse.inject; 12 | 13 | import static java.util.Arrays.asList; 14 | 15 | import com.google.inject.AbstractModule; 16 | import com.google.inject.multibindings.Multibinder; 17 | import org.eclipse.che.api.languageserver.launcher.LanguageServerLauncher; 18 | import org.eclipse.che.api.languageserver.shared.model.LanguageDescription; 19 | import org.eclipse.che.inject.DynaModule; 20 | import org.eclipse.che.plugin.chamrousse.languageserver.ChamrousseLanguageServerLauncher; 21 | 22 | /** 23 | * @author Florent Benoit 24 | */ 25 | @DynaModule 26 | public class ChamrousseModule extends AbstractModule { 27 | 28 | public static final String LANGUAGE_ID = "chamrousse"; 29 | private static final String[] EXTENSIONS = new String[] {"tls", "gnb", "ski"}; 30 | private static final String MIME_TYPE = "text/x-chamroussse"; 31 | 32 | 33 | @Override 34 | protected void configure() { 35 | 36 | Multibinder.newSetBinder(binder(), LanguageServerLauncher.class).addBinding().to(ChamrousseLanguageServerLauncher.class); 37 | 38 | 39 | LanguageDescription description = new LanguageDescription(); 40 | description.setFileExtensions(asList(EXTENSIONS)); 41 | description.setLanguageId(LANGUAGE_ID); 42 | description.setMimeType(MIME_TYPE); 43 | Multibinder.newSetBinder(binder(), LanguageDescription.class) 44 | .addBinding() 45 | .toInstance(description); 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Le LanguageServer de Chamrousse/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | fr.alpesjug 4 | chamrousse-languageserver 5 | 0.0.1-SNAPSHOT 6 | Demo d'un Language Server (code en Java) pour les Grenoblois 7 | 8 | 9 | org.eclipse.lsp4j 10 | org.eclipse.lsp4j 11 | 0.6.0 12 | 13 | 14 | org.eclipse.lsp4j 15 | org.eclipse.lsp4j.jsonrpc 16 | 0.6.0 17 | 18 | 19 | junit 20 | junit 21 | 4.11 22 | test 23 | 24 | 25 | commons-io 26 | commons-io 27 | 2.6 28 | 29 | 30 | 31 | 32 | 1.8 33 | 1.8 34 | 35 | 36 | 37 | 38 | 39 | maven-assembly-plugin 40 | 41 | 42 | make-assembly 43 | package 44 | 45 | single 46 | 47 | 48 | 49 | 50 | fr.alpesjug.languageserver.Main 51 | 52 | 53 | 54 | jar-with-dependencies 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /vscode-chamrousse/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | // A task runner that calls a custom npm script that compiles the extension. 9 | { 10 | "version": "0.1.0", 11 | // we want to run npm 12 | "command": "npm", 13 | // the command is a shell script 14 | "isShellCommand": true, 15 | // show the output window only if unrecognized errors occur. 16 | "showOutput": "silent", 17 | "suppressTaskName": true, 18 | "tasks": [ 19 | { 20 | "taskName": "compile", 21 | // we run the custom script "compile" as defined in package.json 22 | "args": [ 23 | "run", 24 | "compile", 25 | "--loglevel", 26 | "silent" 27 | ], 28 | // The tsc compiler is started in watching mode 29 | "isWatching": true, 30 | // use the standard tsc in watch mode problem matcher to find compile problems in the output. 31 | "problemMatcher": "$tsc-watch", 32 | "isBuildCommand": true 33 | }, 34 | { 35 | "taskName": "test", 36 | "args": [ 37 | "run", 38 | "test" 39 | ], 40 | "isTestCommand": true 41 | }, 42 | { 43 | "taskName": "build-server", 44 | // we run the custom script "compile" as defined in package.json 45 | "args": [ 46 | "run", 47 | "build-server", 48 | "--loglevel", 49 | "silent" 50 | ], 51 | // The tsc compiler is started in watching mode 52 | "isWatching": false 53 | }, 54 | { 55 | "taskName": "tslint", 56 | "args": [ 57 | "run", 58 | "tslint" 59 | ], 60 | "problemMatcher": { 61 | "owner": "tslint", 62 | "fileLocation": [ 63 | "relative", 64 | "${workspaceRoot}" 65 | ], 66 | "severity": "warning", 67 | "pattern": { 68 | "regexp": "^(\\S.*)\\[(\\d+), (\\d+)\\]:\\s+(.*)$", 69 | "file": 1, 70 | "line": 2, 71 | "column": 3, 72 | "message": 4 73 | } 74 | } 75 | } 76 | ] 77 | } -------------------------------------------------------------------------------- /eclipse-che/plugin-chamrousse/che-plugin-chamrousse-lang-ide/src/main/java/org/eclipse/che/plugin/chamrousse/ide/ChamrousseExtension.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2017 Red Hat, Inc. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Red Hat, Inc. - initial API and implementation 10 | */ 11 | package org.eclipse.che.plugin.chamrousse.ide; 12 | 13 | import static org.eclipse.che.ide.api.action.IdeActions.GROUP_FILE_NEW; 14 | import static org.eclipse.che.plugin.python.shared.ProjectAttributes.PYTHON_CATEGORY; 15 | 16 | import com.google.inject.Inject; 17 | import com.google.inject.name.Named; 18 | import org.eclipse.che.ide.api.action.ActionManager; 19 | import org.eclipse.che.ide.api.action.DefaultActionGroup; 20 | import org.eclipse.che.ide.api.constraints.Constraints; 21 | import org.eclipse.che.ide.api.extension.Extension; 22 | import org.eclipse.che.ide.api.filetypes.FileType; 23 | import org.eclipse.che.ide.api.filetypes.FileTypeRegistry; 24 | import org.eclipse.che.ide.api.icon.Icon; 25 | import org.eclipse.che.ide.api.icon.IconRegistry; 26 | import org.eclipse.che.plugin.chamrousse.ide.action.CreateChamrousseFileAction; 27 | 28 | /** 29 | * Chamrousse extension entry point. 30 | * 31 | * @author Florent Benoit 32 | */ 33 | @Extension(title = "Chamrousse") 34 | public class ChamrousseExtension { 35 | @Inject 36 | public ChamrousseExtension( 37 | FileTypeRegistry fileTypeRegistry, 38 | CreateChamrousseFileAction createChamrousseFileAction, 39 | ActionManager actionManager, 40 | org.eclipse.che.plugin.chamrousse.ide.ChamrousseResources chamrousseResources, 41 | IconRegistry iconRegistry, 42 | @Named("ChamrousseFileType") FileType chamrousseFile) { 43 | fileTypeRegistry.registerFileType(chamrousseFile); 44 | 45 | DefaultActionGroup newGroup = (DefaultActionGroup) actionManager.getAction(GROUP_FILE_NEW); 46 | actionManager.registerAction("chamrousseFile", createChamrousseFileAction); 47 | newGroup.add(createChamrousseFileAction, Constraints.FIRST); 48 | 49 | iconRegistry.registerIcon( 50 | new Icon(PYTHON_CATEGORY + ".samples.category.icon", chamrousseResources.category())); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Le LanguageServer de Chamrousse/src/main/java/fr/alpesjug/languageserver/ChamrousseLanguageServer.java: -------------------------------------------------------------------------------- 1 | package fr.alpesjug.languageserver; 2 | 3 | import java.util.Collections; 4 | import java.util.concurrent.CompletableFuture; 5 | 6 | import org.eclipse.lsp4j.CodeActionOptions; 7 | import org.eclipse.lsp4j.CodeLensOptions; 8 | import org.eclipse.lsp4j.CompletionOptions; 9 | import org.eclipse.lsp4j.InitializeParams; 10 | import org.eclipse.lsp4j.InitializeResult; 11 | import org.eclipse.lsp4j.ServerCapabilities; 12 | import org.eclipse.lsp4j.TextDocumentSyncKind; 13 | import org.eclipse.lsp4j.services.LanguageClient; 14 | import org.eclipse.lsp4j.services.LanguageServer; 15 | import org.eclipse.lsp4j.services.TextDocumentService; 16 | import org.eclipse.lsp4j.services.WorkspaceService; 17 | 18 | public class ChamrousseLanguageServer implements LanguageServer { 19 | 20 | private TextDocumentService textService; 21 | private WorkspaceService workspaceService; 22 | LanguageClient client; 23 | 24 | public ChamrousseLanguageServer() { 25 | textService = new ChamrousseTextDocumentService(this); 26 | workspaceService = new ChamrousseWorkspaceService(); 27 | } 28 | 29 | public CompletableFuture initialize(InitializeParams params) { 30 | final InitializeResult res = new InitializeResult(new ServerCapabilities()); 31 | res.getCapabilities().setCodeActionProvider(new CodeActionOptions()); 32 | res.getCapabilities().setCompletionProvider(new CompletionOptions(false, ChamrousseMap.INSTANCE.getAllPossibleChars())); 33 | res.getCapabilities().setDefinitionProvider(Boolean.TRUE); 34 | res.getCapabilities().setHoverProvider(Boolean.TRUE); 35 | res.getCapabilities().setReferencesProvider(Boolean.TRUE); 36 | res.getCapabilities().setTextDocumentSync(TextDocumentSyncKind.Full); 37 | res.getCapabilities().setDocumentSymbolProvider(Boolean.TRUE); 38 | res.getCapabilities().setCodeLensProvider(new CodeLensOptions(true)); 39 | 40 | return CompletableFuture.completedFuture(res); 41 | } 42 | 43 | public CompletableFuture shutdown() { 44 | return CompletableFuture.supplyAsync(() -> Boolean.TRUE); 45 | } 46 | 47 | public void exit() { 48 | } 49 | 50 | public TextDocumentService getTextDocumentService() { 51 | return this.textService; 52 | } 53 | 54 | public WorkspaceService getWorkspaceService() { 55 | return this.workspaceService; 56 | } 57 | 58 | public void setRemoteProxy(LanguageClient remoteProxy) { 59 | this.client = remoteProxy; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /eclipse-che/plugin-chamrousse/che-plugin-chamrousse-lang-ide/src/main/java/org/eclipse/che/plugin/chamrousse/ide/action/CreateChamrousseFileAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2017 Red Hat, Inc. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Red Hat, Inc. - initial API and implementation 10 | */ 11 | package org.eclipse.che.plugin.chamrousse.ide.action; 12 | 13 | import com.google.inject.Inject; 14 | import com.google.inject.Provider; 15 | import com.google.inject.Singleton; 16 | import com.google.web.bindery.event.shared.EventBus; 17 | import org.eclipse.che.ide.CoreLocalizationConstant; 18 | import org.eclipse.che.ide.api.app.AppContext; 19 | import org.eclipse.che.ide.api.editor.EditorAgent; 20 | import org.eclipse.che.ide.api.notification.NotificationManager; 21 | import org.eclipse.che.ide.newresource.AbstractNewResourceAction; 22 | import org.eclipse.che.ide.ui.dialogs.DialogFactory; 23 | import org.eclipse.che.plugin.chamrousse.ide.ChamrousseLocalizationConstant; 24 | import org.eclipse.che.plugin.chamrousse.ide.ChamrousseResources; 25 | 26 | /** 27 | * Action to create new chamrousse source file. 28 | * 29 | * @author Florent Benoit 30 | */ 31 | @Singleton 32 | public class CreateChamrousseFileAction extends AbstractNewResourceAction { 33 | 34 | @Inject 35 | public CreateChamrousseFileAction( 36 | ChamrousseLocalizationConstant localizationConstant, 37 | ChamrousseResources chamrousseResources, 38 | DialogFactory dialogFactory, 39 | CoreLocalizationConstant coreLocalizationConstant, 40 | EventBus eventBus, 41 | AppContext appContext, 42 | NotificationManager notificationManager, 43 | Provider editorAgentProvider) { 44 | super( 45 | localizationConstant.createChamrousseFileActionTitle(), 46 | localizationConstant.createChamrousseFileActionDescription(), 47 | chamrousseResources.pythonFile(), 48 | dialogFactory, 49 | coreLocalizationConstant, 50 | eventBus, 51 | appContext, 52 | notificationManager, 53 | editorAgentProvider); 54 | } 55 | 56 | @Override 57 | protected String getExtension() { 58 | return "ski"; 59 | } 60 | 61 | @Override 62 | protected String getDefaultContent() { 63 | return ""; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Language Server Protocol demo 2 | 3 | This repository contains several projects to demonstrate the Language Server Protocol in action together with some Eclipse technologies: 4 | 5 | This was used for the AlpesJug demo in April 2017: 6 | * https://www.meetup.com/AlpesJUG/events/238766199/ 7 | * https://bluejeans.com/s/GtDcO/ 8 | 9 | ## Content 10 | 11 | ### Le LanguageServer de Chamrousse 12 | 13 | This is a Maven module demonstrating usage of [Eclipse LSP4J](https://github.com/eclipse/lsp4j) to develop language servers in Java just by implementing the right classes. 14 | 15 | This Maven module produces a jar-with-dependencies that is the language server delivery, and could produce additional artifacts (such as a Docker image). 16 | 17 | Worth mentioning: 18 | * The dependency to lsp4j in `pom.xml` 19 | * ChamrouseLanguageServer, ChamrousseTextDocumentService simply implementing LSP4J's interfaces to provide operations 20 | * The Main class simply starting the language server and binding it to the stdio streams of the process 21 | 22 | ### fr.alpesjug.lsp.eclipse 23 | 24 | This is an Eclipse plugin that relies on [Eclipse LSP4E](https://projects.eclipse.org/projects/technology.lsp4e) to interact with the language server above. 25 | 26 | Demo with *Right-click > Run As > Eclipse plugin*: 27 | * Diagnostic -on code and trees- + quickfixes 28 | * Completion 29 | * Hover 30 | * References 31 | * Jump to definition (F3) 32 | 33 | Worth mentioning simplicity (on code in dev IDE, not demo one): 34 | * entries in `plugin.xml` to define the server and bind it to content-type 35 | * Show the class only spawns a process and connects to its stdio streams 36 | 37 | ### vscode-chamrousse 38 | 39 | (copied and adapted from Eclipse JDT-based [vscode-java](https://github.com/redhat-developer/vscode-java)) 40 | 41 | Demo from VSCode, open `vscode-chamrousse` and press *F5* to Debug: 42 | * show diagnostics 43 | * completion 44 | * hover 45 | * ... 46 | 47 | Show the code (from dev VSCode, not debug instance): 48 | * open `src/extension.ts`, line 25 49 | * see it's spawning a process and connecting to stdio streams 50 | 51 | ### in Eclipse Che 52 | 53 | TODO 54 | 55 | ## Script 56 | 57 | * Show and demo the modules individually 58 | * When LS is shown working in all IDEs, modify it (look for `EDIT` in the code of the language server). Possible changes: 59 | * Language > Syntaxic change: allow a new syntax in the language (such as comments) in ChamrousseDocumentModel 60 | * Language > Lexical change : allow new words in the language in `chamrousseMap.properties` 61 | * Tool > Functional change: improve completion or quickfix to show possible values that don't produce errors 62 | * Tool > Cosmetic change: improve the hover to show the color 63 | * Rebuild server 64 | * Restart the various IDEs to show that the changes are taken into account **without need to change any functional code** 65 | 66 | Conclusion: good separation of concerns makes it much easier to maintain the language support in all IDEs at once. 67 | -------------------------------------------------------------------------------- /eclipse-che/plugin-chamrousse/che-plugin-chamrousse-lang-ide/src/main/resources/org/eclipse/che/plugin/chamrousse/ide/svg/chamrousse.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 12 | 18 | 25 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /eclipse-che/plugin-chamrousse/che-plugin-chamrousse-lang-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 4.0.0 16 | 17 | che-plugin-parent 18 | org.eclipse.che.plugin 19 | 6.0.0-M5-SNAPSHOT 20 | ../pom.xml 21 | 22 | plugin-chamrousse-lang-server 23 | Che Plugin :: Chamrousse LSP :: Extension Server 24 | 25 | false 26 | 27 | 28 | 29 | com.google.guava 30 | guava 31 | 32 | 33 | com.google.inject 34 | guice 35 | 36 | 37 | com.google.inject.extensions 38 | guice-multibindings 39 | 40 | 41 | org.eclipse.che.core 42 | che-core-api-core 43 | 44 | 45 | org.eclipse.che.core 46 | che-core-api-languageserver 47 | 48 | 49 | org.eclipse.che.core 50 | che-core-api-languageserver-shared 51 | 52 | 53 | org.eclipse.che.core 54 | che-core-api-project 55 | 56 | 57 | org.eclipse.che.core 58 | che-core-commons-inject 59 | 60 | 61 | org.eclipse.che.plugin 62 | che-plugin-csharp-lang-shared 63 | 64 | 65 | org.eclipse.lsp4j 66 | org.eclipse.lsp4j 67 | 68 | 69 | org.eclipse.lsp4j 70 | org.eclipse.lsp4j.jsonrpc 71 | 72 | 73 | org.slf4j 74 | slf4j-api 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Le LanguageServer de Chamrousse/src/main/java/fr/alpesjug/languageserver/ChamrousseMap.java: -------------------------------------------------------------------------------- 1 | package fr.alpesjug.languageserver; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.Collection; 8 | import java.util.HashMap; 9 | import java.util.HashSet; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.Properties; 13 | import java.util.Set; 14 | import java.util.stream.Collectors; 15 | 16 | public class ChamrousseMap { 17 | 18 | public static final ChamrousseMap INSTANCE = new ChamrousseMap(); 19 | 20 | final Properties props = new Properties(); 21 | final Set all; 22 | final Map> startsFrom; 23 | final Map> arrivesTo; 24 | final Map type; 25 | 26 | private ChamrousseMap() { 27 | InputStream propertiesStream = ChamrousseMap.class.getResourceAsStream("/" + ChamrousseMap.class.getPackage().getName().replace(".", "/") + "/chamrousseMap.properties"); 28 | try { 29 | props.load(propertiesStream); 30 | propertiesStream.close(); 31 | } catch (IOException e) { 32 | e.printStackTrace(); 33 | } 34 | 35 | this.all = props.keySet().stream() 36 | .map(key -> ((String)key).split("\\.")[0]) 37 | .collect(Collectors.toSet()); 38 | this.startsFrom = props.entrySet().stream() 39 | .filter(entry -> ((String)entry.getKey()).endsWith(".startsFrom")) 40 | .collect(Collectors.toMap( 41 | entry -> ((String)entry.getKey()).split("\\.")[0], 42 | entry -> Arrays.asList(((String)entry.getValue()).split(",")))); 43 | this.arrivesTo = new HashMap>(); 44 | this.startsFrom.forEach((arrival, starts) -> { 45 | starts.stream().forEach(start -> { 46 | Collection arrivals = arrivesTo.get(start); 47 | if (arrivals == null) { 48 | arrivals = new HashSet<>(); 49 | } 50 | arrivals.add(arrival); 51 | arrivesTo.put(start, arrivals); 52 | }); 53 | }); 54 | this.type = props.entrySet().stream() 55 | .filter(entry -> ((String)entry.getKey()).endsWith(".type")) 56 | .collect(Collectors.toMap( 57 | entry -> ((String)entry.getKey()).split("\\.")[0], 58 | entry -> (String)entry.getValue())); 59 | } 60 | 61 | /** 62 | * @return the list of routes that link from with to 63 | */ 64 | public List findWaysBetween(String from, String to) { 65 | List res = new ArrayList(); 66 | for (String way : all) { 67 | if (startsFrom.get(way) != null && startsFrom.get(way).contains(from) && 68 | arrivesTo.get(way) != null && arrivesTo.get(way).contains(to)) { 69 | res.add(way); 70 | } 71 | } 72 | return res; 73 | } 74 | 75 | public boolean startsFrom(String route, String potentialStart) { 76 | return this.startsFrom.get(route) != null && this.startsFrom.get(route).contains(potentialStart); 77 | } 78 | 79 | public boolean isLift(String name) { 80 | return name.toUpperCase().startsWith("TC") || name.toUpperCase().startsWith("TS"); 81 | } 82 | 83 | public List getAllPossibleChars() { 84 | Set allChars = new HashSet<>(); 85 | for (String route : all) { 86 | route.chars().mapToObj(n -> "" + Character.valueOf((char)n)).forEach(allChars::add); 87 | } 88 | return new ArrayList<>(allChars); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /eclipse-che/plugin-chamrousse/che-plugin-chamrousse-lang-ide/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 4.0.0 16 | 17 | che-plugin-python-parent 18 | org.eclipse.che.plugin 19 | 6.0.0-M5-SNAPSHOT 20 | 21 | che-plugin-chamrousse-lang-ide 22 | gwt-lib 23 | Che Plugin :: Chamrousse :: IDE 24 | 25 | 26 | com.google.gwt.inject 27 | gin 28 | 29 | 30 | com.google.inject 31 | guice 32 | 33 | 34 | javax.validation 35 | validation-api 36 | 37 | 38 | org.eclipse.che.core 39 | che-core-ide-api 40 | 41 | 42 | org.eclipse.che.core 43 | che-core-ide-app 44 | 45 | 46 | org.eclipse.che.core 47 | che-core-ide-ui 48 | 49 | 50 | org.eclipse.che.plugin 51 | che-plugin-python-lang-shared 52 | 53 | 54 | org.eclipse.che.plugin 55 | che-plugin-python-lang-shared 56 | sources 57 | 58 | 59 | org.vectomatic 60 | lib-gwt-svg 61 | 62 | 63 | com.google.gwt 64 | gwt-user 65 | provided 66 | 67 | 68 | 69 | 70 | 71 | net.ltgt.gwt.maven 72 | gwt-maven-plugin 73 | true 74 | 75 | org.eclipse.che.plugin.chamrousse.Chamrousse 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /eclipse-che/chamrousse-workspace-image/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | fr.alpesjug 4 | chamrousse-languageserver-workspace-image 5 | 0.0.1-SNAPSHOT 6 | Che Workspace Image 7 | 8 | 9 | fr.alpesjug 10 | chamrousse-languageserver 11 | jar-with-dependencies 12 | 0.0.1-SNAPSHOT 13 | 14 | 15 | 16 | 17 | 1.8 18 | 1.8 19 | 20 | 21 | 22 | 23 | 24 | 25 | org.apache.maven.plugins 26 | maven-dependency-plugin 27 | 3.0.0 28 | 29 | 30 | copy 31 | package 32 | 33 | copy 34 | 35 | 36 | 37 | 38 | 39 | 40 | fr.alpesjug 41 | chamrousse-languageserver 42 | jar-with-dependencies 43 | 0.0.1-SNAPSHOT 44 | src/main/docker 45 | lsp.jar 46 | 47 | 48 | false 49 | true 50 | 51 | 52 | 53 | 54 | io.fabric8 55 | 0.20.1 56 | docker-maven-plugin 57 | 58 | 59 | start 60 | pre-integration-test 61 | 62 | build 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | florentbenoit/chamrousse 71 | 72 | Dockerfile 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /eclipse-che/plugin-chamrousse/che-plugin-chamrousse-lang-server/src/main/java/org/eclipse/che/plugin/chamrousse/languageserver/ChamrousseLanguageServerLauncher.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012-2017 Codenvy, S.A. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * 8 | * Contributors: 9 | * Codenvy, S.A. - initial API and implementation 10 | *******************************************************************************/ 11 | package org.eclipse.che.plugin.chamrousse.languageserver; 12 | 13 | import com.google.inject.Inject; 14 | import com.google.inject.Singleton; 15 | import java.io.IOException; 16 | import java.nio.file.Path; 17 | import java.nio.file.Paths; 18 | import java.util.Arrays; 19 | import org.eclipse.che.api.languageserver.exception.LanguageServerException; 20 | import org.eclipse.che.api.languageserver.launcher.LanguageServerLauncherTemplate; 21 | import org.eclipse.che.api.languageserver.registry.DocumentFilter; 22 | import org.eclipse.che.api.languageserver.registry.LanguageServerDescription; 23 | import org.eclipse.che.plugin.chamrousse.inject.ChamrousseModule; 24 | import org.eclipse.lsp4j.jsonrpc.Launcher; 25 | import org.eclipse.lsp4j.services.LanguageClient; 26 | import org.eclipse.lsp4j.services.LanguageServer; 27 | 28 | /** 29 | * @author Florent benoit 30 | */ 31 | @Singleton 32 | public class ChamrousseLanguageServerLauncher extends LanguageServerLauncherTemplate { 33 | 34 | 35 | private static final LanguageServerDescription DESCRIPTION = createServerDescription(); 36 | 37 | private final Path launchScript; 38 | 39 | private static final String REGEX = ".*\\.ski"; 40 | 41 | 42 | @Inject 43 | public ChamrousseLanguageServerLauncher() { 44 | launchScript = Paths.get(System.getenv("HOME"), "ls-chamrousse/launch.sh"); 45 | } 46 | 47 | /** 48 | * Gets the language server description 49 | */ 50 | @Override 51 | public LanguageServerDescription getDescription() { 52 | return DESCRIPTION; 53 | } 54 | 55 | @Override 56 | public boolean isAbleToLaunch() { 57 | return launchScript.toFile().exists(); 58 | } 59 | 60 | @Override 61 | protected Process startLanguageServerProcess(String projectPath) throws LanguageServerException { 62 | ProcessBuilder processBuilder = new ProcessBuilder(launchScript.toString()); 63 | processBuilder.redirectInput(ProcessBuilder.Redirect.PIPE); 64 | processBuilder.redirectOutput(ProcessBuilder.Redirect.PIPE); 65 | 66 | try { 67 | return processBuilder.start(); 68 | } catch (IOException e) { 69 | throw new LanguageServerException("Cannot start Chamrousse language server", e); 70 | } 71 | } 72 | 73 | @Override 74 | protected LanguageServer connectToLanguageServer(final Process languageServerProcess, LanguageClient client) { 75 | Launcher launcher = Launcher.createLauncher(client, LanguageServer.class, 76 | languageServerProcess.getInputStream(), languageServerProcess.getOutputStream()); 77 | launcher.startListening(); 78 | return launcher.getRemoteProxy(); 79 | } 80 | 81 | 82 | private static LanguageServerDescription createServerDescription() { 83 | LanguageServerDescription description = 84 | new LanguageServerDescription( 85 | "org.eclipse.che.plugin.chamrousse.languageserver", 86 | null, 87 | Arrays.asList(new DocumentFilter(ChamrousseModule.LANGUAGE_ID, REGEX, null))); 88 | return description; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Le LanguageServer de Chamrousse/src/main/java/fr/alpesjug/languageserver/ChamrousseDocumentModel.java: -------------------------------------------------------------------------------- 1 | package fr.alpesjug.languageserver; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.Reader; 6 | import java.io.StringReader; 7 | import java.util.ArrayList; 8 | import java.util.Collections; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.Map.Entry; 13 | import java.util.Optional; 14 | 15 | public class ChamrousseDocumentModel { 16 | 17 | public static abstract class DocumentLine { 18 | final int line; 19 | final String text; 20 | final int charOffset; 21 | 22 | protected DocumentLine(int line, int charOffset, String text) { 23 | this.line = line; 24 | this.charOffset = charOffset; 25 | this.text = text; 26 | } 27 | } 28 | 29 | public static class Route extends DocumentLine { 30 | final String name; 31 | 32 | public Route(int line, int charOffset, String text, String name) { 33 | super(line, charOffset, text); 34 | this.name = name; 35 | } 36 | } 37 | 38 | public static class VariableDefinition extends DocumentLine { 39 | final String variableName; 40 | final String variableValue; 41 | 42 | public VariableDefinition(int lineNumber, int charOffset, String text, String variableName, String value) { 43 | super(lineNumber, charOffset, text); 44 | this.variableName = variableName; 45 | variableValue = value; 46 | } 47 | 48 | } 49 | 50 | private final List lines = new ArrayList<>(); 51 | private final List routes = new ArrayList<>(); 52 | private final Map variables = new HashMap<>(); 53 | 54 | public ChamrousseDocumentModel(String text) { 55 | try ( 56 | Reader r = new StringReader(text); 57 | BufferedReader reader = new BufferedReader(r); 58 | ) { 59 | String lineText; 60 | int lineNumber = 0; 61 | while ((lineText = reader.readLine()) != null) { 62 | DocumentLine line = null; 63 | // TODO: language syntax change 64 | /*if (lineText.startsWith("#")) { 65 | continue; 66 | }*/ 67 | if (lineText.contains("=")) { 68 | line = variableDefinition(lineNumber, lineText); 69 | } else if (!lineText.trim().isEmpty()) { 70 | Route route = new Route(lineNumber, 0, lineText, resolve(lineText)); 71 | routes.add(route); 72 | line = route; 73 | } 74 | if (line != null) { 75 | lines.add(line); 76 | } 77 | lineNumber++; 78 | } 79 | } catch (IOException e) { 80 | e.printStackTrace(); 81 | } 82 | } 83 | 84 | private String resolve(String line) { 85 | for (Entry variable : variables.entrySet()) { 86 | line = line.replace("${" + variable.getKey() + "}", variable.getValue().variableValue); 87 | } 88 | return line; 89 | } 90 | 91 | private VariableDefinition variableDefinition(int lineNumber, String line) { 92 | String[] segments = line.split("="); 93 | if (segments.length == 2) { 94 | VariableDefinition def = new VariableDefinition(lineNumber, 0, line, segments[0], segments[1]); 95 | variables.put(def.variableName, def); 96 | return def; 97 | } 98 | return null; 99 | } 100 | 101 | public List getResolvedRoutes() { 102 | return Collections.unmodifiableList(this.routes); 103 | } 104 | 105 | public String getVariable(int lineNumber, int character) { 106 | Optional docLine = this.lines.stream().filter(line -> line.line == lineNumber).findFirst(); 107 | if (!docLine.isPresent()) { 108 | return null; 109 | } 110 | String text = docLine.get().text; 111 | if (text.contains("=") && character < text.indexOf("=")) { 112 | return text.split("=")[0]; 113 | } 114 | int prefix = text.substring(0, character).lastIndexOf("${"); 115 | int suffix = text.indexOf("}", character); 116 | if (prefix >= 0 && suffix >= 0) { 117 | return text.substring(prefix + "${".length(), suffix); 118 | } 119 | return null; 120 | } 121 | 122 | public Route getRoute(int line) { 123 | for (Route route : getResolvedRoutes()) { 124 | if (route.line == line) { 125 | return route; 126 | } 127 | } 128 | return null; 129 | } 130 | 131 | public int getDefintionLine(String variable) { 132 | if (this.variables.containsKey(variable)) { 133 | return this.variables.get(variable).line; 134 | } 135 | return -1; 136 | } 137 | 138 | public List getResolvedLines() { 139 | return Collections.unmodifiableList(this.lines); 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /Le LanguageServer de Chamrousse/src/test/java/fr/alpesjug/languageserver/tests/TestLanguageServer.java: -------------------------------------------------------------------------------- 1 | package fr.alpesjug.languageserver.tests; 2 | 3 | import java.io.File; 4 | import java.io.PipedInputStream; 5 | import java.io.PipedOutputStream; 6 | import java.util.ArrayList; 7 | import java.util.Collections; 8 | import java.util.List; 9 | import java.util.concurrent.CompletableFuture; 10 | 11 | import org.eclipse.lsp4j.CodeAction; 12 | import org.eclipse.lsp4j.CodeActionContext; 13 | import org.eclipse.lsp4j.CodeActionParams; 14 | import org.eclipse.lsp4j.Command; 15 | import org.eclipse.lsp4j.Diagnostic; 16 | import org.eclipse.lsp4j.DidChangeTextDocumentParams; 17 | import org.eclipse.lsp4j.DidOpenTextDocumentParams; 18 | import org.eclipse.lsp4j.Hover; 19 | import org.eclipse.lsp4j.InitializeParams; 20 | import org.eclipse.lsp4j.Location; 21 | import org.eclipse.lsp4j.MessageActionItem; 22 | import org.eclipse.lsp4j.MessageParams; 23 | import org.eclipse.lsp4j.Position; 24 | import org.eclipse.lsp4j.PublishDiagnosticsParams; 25 | import org.eclipse.lsp4j.ReferenceParams; 26 | import org.eclipse.lsp4j.ShowMessageRequestParams; 27 | import org.eclipse.lsp4j.TextDocumentContentChangeEvent; 28 | import org.eclipse.lsp4j.TextDocumentIdentifier; 29 | import org.eclipse.lsp4j.TextDocumentItem; 30 | import org.eclipse.lsp4j.TextDocumentPositionParams; 31 | import org.eclipse.lsp4j.VersionedTextDocumentIdentifier; 32 | import org.eclipse.lsp4j.jsonrpc.Launcher; 33 | import org.eclipse.lsp4j.jsonrpc.messages.Either; 34 | import org.eclipse.lsp4j.launch.LSPLauncher; 35 | import org.eclipse.lsp4j.services.LanguageClient; 36 | import org.eclipse.lsp4j.services.LanguageServer; 37 | import org.junit.Assert; 38 | import org.junit.Test; 39 | 40 | import fr.alpesjug.languageserver.ChamrousseLanguageServer; 41 | import fr.alpesjug.languageserver.Main; 42 | 43 | public class TestLanguageServer { 44 | 45 | public void checkHover(LanguageServer ls) throws Exception { 46 | ls.initialize(new InitializeParams()); 47 | TextDocumentItem doc = new TextDocumentItem(); 48 | File f = File.createTempFile("blah", ".ski"); 49 | f.deleteOnExit(); 50 | doc.setUri(f.toURI().toString()); 51 | doc.setText("Balmette"); 52 | ls.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(doc)); 53 | 54 | TextDocumentIdentifier id = new TextDocumentIdentifier(doc.getUri()); 55 | CompletableFuture hover = ls.getTextDocumentService().hover(new TextDocumentPositionParams(id, new Position(0, 1))); 56 | Assert.assertEquals("Green", hover.get().getContents().getLeft().get(0).getLeft()); 57 | 58 | hover = ls.getTextDocumentService().hover(new TextDocumentPositionParams(id, new Position(0, 0))); 59 | Assert.assertEquals("Green", hover.get().getContents().getLeft().get(0).getLeft()); 60 | } 61 | 62 | @Test 63 | public void checkHoverLocal() throws Exception { 64 | checkHover(new ChamrousseLanguageServer()); 65 | } 66 | 67 | @Test 68 | public void testMain() throws Exception { 69 | PipedInputStream serverInput = new PipedInputStream(); 70 | PipedOutputStream serverOutput = new PipedOutputStream(); 71 | new Thread(() -> { 72 | try { 73 | new Main().startServer(serverInput, serverOutput); 74 | } catch (Exception e) { 75 | e.printStackTrace(); 76 | } 77 | }).start(); 78 | Launcher createClientLauncher = LSPLauncher.createClientLauncher(new LanguageClient() { 79 | 80 | @Override 81 | public void telemetryEvent(Object object) { 82 | } 83 | 84 | @Override 85 | public CompletableFuture showMessageRequest(ShowMessageRequestParams requestParams) { 86 | return null; 87 | } 88 | 89 | @Override 90 | public void showMessage(MessageParams messageParams) { 91 | } 92 | 93 | @Override 94 | public void publishDiagnostics(PublishDiagnosticsParams diagnostics) { 95 | } 96 | 97 | @Override 98 | public void logMessage(MessageParams message) { 99 | } 100 | }, new PipedInputStream(serverOutput), new PipedOutputStream(serverInput)); 101 | createClientLauncher.startListening(); 102 | LanguageServer server = createClientLauncher.getRemoteProxy(); 103 | checkHover(server); 104 | } 105 | 106 | @Test 107 | public void testQuickFixes() throws Exception { 108 | ChamrousseLanguageServer ls = new ChamrousseLanguageServer(); 109 | List diagnostics = new ArrayList<>(); 110 | ls.setRemoteProxy(new LanguageClient() { 111 | @Override 112 | public void telemetryEvent(Object object) { 113 | } 114 | 115 | @Override 116 | public CompletableFuture showMessageRequest(ShowMessageRequestParams requestParams) { 117 | return null; 118 | } 119 | 120 | @Override 121 | public void showMessage(MessageParams messageParams) { 122 | } 123 | 124 | @Override 125 | public void publishDiagnostics(PublishDiagnosticsParams d) { 126 | diagnostics.clear(); 127 | diagnostics.addAll(d.getDiagnostics()); 128 | } 129 | 130 | @Override 131 | public void logMessage(MessageParams message) { 132 | } 133 | }); 134 | TextDocumentItem doc = new TextDocumentItem(); 135 | File f = File.createTempFile("blah", ".tls"); 136 | f.deleteOnExit(); 137 | doc.setUri(f.toURI().toString()); 138 | doc.setText("choucroute"); 139 | ls.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(doc)); 140 | Thread.sleep(1000); 141 | Assert.assertEquals("Missing diagnostic", 1, diagnostics.size()); 142 | Diagnostic diagnostic = diagnostics.get(0); 143 | List> resolutions = ls.getTextDocumentService().codeAction(new CodeActionParams(new TextDocumentIdentifier(doc.getUri()), diagnostic.getRange(), new CodeActionContext(Collections.singletonList(diagnostic)))).get(); 144 | Assert.assertEquals("Missing resolution", 1, resolutions.size()); 145 | TextDocumentContentChangeEvent change = new TextDocumentContentChangeEvent(); 146 | 147 | change.setText("\nunknown track"); 148 | ls.getTextDocumentService().didChange(new DidChangeTextDocumentParams(new VersionedTextDocumentIdentifier(1), Collections.singletonList(change))); 149 | Thread.sleep(1000); 150 | Assert.assertEquals("Missing diagnostics", 1, diagnostics.size()); 151 | diagnostic = diagnostics.get(0); 152 | Assert.assertEquals(1, diagnostic.getRange().getStart().getLine()); 153 | Assert.assertEquals(0, diagnostic.getRange().getStart().getCharacter()); 154 | } 155 | 156 | @Test 157 | public void testReferences() throws Exception { 158 | ChamrousseLanguageServer ls = new ChamrousseLanguageServer(); 159 | TextDocumentItem doc = new TextDocumentItem(); 160 | File f = File.createTempFile("blah", ".tls"); 161 | f.deleteOnExit(); 162 | doc.setUri(f.toURI().toString()); 163 | doc.setText("${var}\n${var}\n${var}"); 164 | ls.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(doc)); 165 | 166 | ReferenceParams params = new ReferenceParams(); 167 | params.setTextDocument(new TextDocumentIdentifier(doc.getUri())); 168 | params.setPosition(new Position(0,4)); 169 | List list = ls.getTextDocumentService().references(params).get(); 170 | Assert.assertEquals(3, list.size()); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /vscode-chamrousse/src/extension.ts: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | import * as path from 'path'; 5 | import { workspace, ExtensionContext, window, StatusBarAlignment, commands, ViewColumn, Uri, CancellationToken, TextDocumentContentProvider, TextEditor, WorkspaceConfiguration, languages, IndentAction } from 'vscode'; 6 | import { LanguageClient, LanguageClientOptions, StreamInfo, Position as LSPosition, Location as LSLocation, Protocol2Code, ServerOptions, TransportKind, Executable } from 'vscode-languageclient'; 7 | 8 | var electron = require('./electron_j'); 9 | var os = require('os'); 10 | var glob = require('glob'); 11 | import { StatusNotification,ClassFileContentsRequest,ProjectConfigurationUpdateRequest,MessageType,ActionableNotification,FeatureStatus } from './protocol'; 12 | 13 | 14 | var storagePath; 15 | var oldConfig; 16 | 17 | var lastStatus; 18 | 19 | export function activate(context: ExtensionContext) { 20 | // Let's enable Javadoc symbols autocompletion, shamelessly copied from MIT licensed code at 21 | // https://github.com/Microsoft/vscode/blob/9d611d4dfd5a4a101b5201b8c9e21af97f06e7a7/extensions/typescript/src/typescriptMain.ts#L186 22 | languages.setLanguageConfiguration('ski', { 23 | wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, 24 | }); 25 | 26 | 27 | storagePath = context.storagePath; 28 | if (!storagePath) { 29 | storagePath = getTempWorkspace(); 30 | } 31 | let serverOptions: Executable = { 32 | command: '/usr/bin/java', 33 | args: [ "-jar", "/home/mistria/workspaceDemoLSP/Le LanguageServer de Chamrousse/target/chamrousse-languageserver-0.0.1-SNAPSHOT-jar-with-dependencies.jar" ] 34 | }; 35 | 36 | // Options to control the language client 37 | let clientOptions: LanguageClientOptions = { 38 | // Register the server for ski 39 | documentSelector: ['ski'], 40 | synchronize: { 41 | configurationSection: 'ski', 42 | // Notify the server about file changes to .java files contain in the workspace 43 | fileEvents: [ 44 | workspace.createFileSystemWatcher('**/*.ski'), 45 | ], 46 | } 47 | }; 48 | 49 | let item = window.createStatusBarItem(StatusBarAlignment.Right, Number.MIN_VALUE); 50 | oldConfig = getServerConfiguration(); 51 | // Create the language client and start the client. 52 | let languageClient = new LanguageClient('ski','Language Support for Chamrousse', serverOptions, clientOptions); 53 | languageClient.onNotification(StatusNotification.type, (report) => { 54 | console.log(report.message); 55 | switch (report.type) { 56 | case 'Started': 57 | item.text = '$(thumbsup)'; 58 | lastStatus = item.text; 59 | break; 60 | case 'Error': 61 | item.text = '$(thumbsdown)'; 62 | lastStatus = item.text; 63 | break; 64 | case 'Message': 65 | item.text = report.message; 66 | setTimeout(()=> {item.text = lastStatus;}, 3000); 67 | break; 68 | } 69 | item.command = 'java.open.output'; 70 | item.tooltip = report.message; 71 | toggleItem(window.activeTextEditor, item); 72 | }); 73 | languageClient.onNotification(ActionableNotification.type, (notification) => { 74 | let show = null; 75 | switch (notification.severity) { 76 | case MessageType.Log: 77 | show = logNotification; 78 | break; 79 | case MessageType.Info: 80 | show = window.showInformationMessage; 81 | break; 82 | case MessageType.Warning: 83 | show = window.showWarningMessage; 84 | break; 85 | case MessageType.Error: 86 | show = window.showErrorMessage; 87 | break; 88 | } 89 | if (!show) { 90 | return; 91 | } 92 | const titles = notification.commands.map(a => a.title); 93 | 94 | show(notification.message, ...titles).then((selection )=>{ 95 | for(let action of notification.commands) { 96 | if (action.title === selection) { 97 | let args:any[] = (action.arguments)?action.arguments:[]; 98 | commands.executeCommand(action.command, ...args); 99 | break; 100 | } 101 | } 102 | }); 103 | }); 104 | 105 | commands.registerCommand('java.open.output', ()=>{ 106 | languageClient.outputChannel.show(ViewColumn.Three); 107 | }); 108 | 109 | window.onDidChangeActiveTextEditor((editor) =>{ 110 | toggleItem(editor, item); 111 | }); 112 | 113 | let provider: TextDocumentContentProvider= { 114 | onDidChange: null, 115 | provideTextDocumentContent: (uri: Uri, token: CancellationToken): Thenable => { 116 | return languageClient.sendRequest(ClassFileContentsRequest.type, { uri: uri.toString() }, token).then((v: string):string => { 117 | return v || ''; 118 | }); 119 | } 120 | }; 121 | workspace.registerTextDocumentContentProvider('ski', provider); 122 | 123 | item.text = 'Starting Le Language Server de Chamrousse...'; 124 | toggleItem(window.activeTextEditor, item); 125 | let disposable = languageClient.start(); 126 | // Push the disposable to the context's subscriptions so that the 127 | // client can be deactivated on extension deactivation 128 | context.subscriptions.push(disposable); 129 | } 130 | 131 | function logNotification(message:string, ...items: string[]) { 132 | return new Promise((resolve, reject) => { 133 | console.log(message); 134 | }); 135 | } 136 | 137 | function setIncompleteClasspathSeverity(severity:string) { 138 | const config = getServerConfiguration(); 139 | const section = 'errors.incompleteClasspath.severity'; 140 | config.update(section, severity, true).then( 141 | () => console.log(section + ' globally set to '+severity), 142 | (error) => console.log(error) 143 | ); 144 | } 145 | 146 | function projectConfigurationUpdate(languageClient:LanguageClient, uri?: Uri) { 147 | let resource = uri; 148 | if (!(resource instanceof Uri)) { 149 | if (window.activeTextEditor) { 150 | resource = window.activeTextEditor.document.uri; 151 | } 152 | } 153 | } 154 | 155 | function setProjectConfigurationUpdate(languageClient:LanguageClient, uri: Uri, status:FeatureStatus) { 156 | const config = getServerConfiguration(); 157 | const section = 'configuration.updateBuildConfiguration'; 158 | 159 | const st = FeatureStatus[status]; 160 | config.update(section, st).then( 161 | () => console.log(section + ' set to '+st), 162 | (error) => console.log(error) 163 | ); 164 | if (status !== FeatureStatus.disabled) { 165 | projectConfigurationUpdate(languageClient, uri); 166 | } 167 | } 168 | function toggleItem(editor: TextEditor, item) { 169 | if(editor && editor.document && 170 | (editor.document.languageId === 'ski')){ 171 | item.show(); 172 | } else{ 173 | item.hide(); 174 | } 175 | } 176 | 177 | function hasConfigKeyChanged(key, oldConfig, newConfig) { 178 | return oldConfig.get(key) !== newConfig.get(key); 179 | } 180 | 181 | export function parseVMargs(params:any[], vmargsLine:string) { 182 | if (!vmargsLine) { 183 | return; 184 | } 185 | let vmargs = vmargsLine.match(/(?:[^\s"]+|"[^"]*")+/g); 186 | if (vmargs === null) { 187 | return; 188 | } 189 | vmargs.forEach (arg => { 190 | //remove all standalone double quotes 191 | arg = arg.replace( /(\\)?"/g, function ($0, $1) { return ($1 ? $0 : ''); }); 192 | //unescape all escaped double quotes 193 | arg = arg.replace( /(\\)"/g, '"'); 194 | if (params.indexOf(arg) < 0) { 195 | params.push(arg); 196 | } 197 | }); 198 | } 199 | 200 | function getTempWorkspace() { 201 | return path.resolve(os.tmpdir(),'vscodesws_'+makeRandomHexString(5)); 202 | } 203 | 204 | function makeRandomHexString(length) { 205 | var chars = ['0', '1', '2', '3', '4', '5', '6', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; 206 | var result = ''; 207 | for (var i = 0; i < length; i++) { 208 | var idx = Math.floor(chars.length * Math.random()); 209 | result += chars[idx]; 210 | } 211 | return result; 212 | } 213 | 214 | function startedInDebugMode(): boolean { 215 | let args = (process as any).execArgv; 216 | if (args) { 217 | return args.some((arg) => /^--debug=?/.test(arg) || /^--debug-brk=?/.test(arg)); 218 | }; 219 | return false; 220 | } 221 | 222 | function getServerConfiguration():WorkspaceConfiguration { 223 | return workspace.getConfiguration('ski'); 224 | } -------------------------------------------------------------------------------- /Le LanguageServer de Chamrousse/src/main/java/fr/alpesjug/languageserver/ChamrousseTextDocumentService.java: -------------------------------------------------------------------------------- 1 | package fr.alpesjug.languageserver; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.Collections; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.concurrent.CompletableFuture; 10 | import java.util.stream.Collectors; 11 | 12 | import org.eclipse.lsp4j.CodeAction; 13 | import org.eclipse.lsp4j.CodeActionKind; 14 | import org.eclipse.lsp4j.CodeActionParams; 15 | import org.eclipse.lsp4j.CodeLens; 16 | import org.eclipse.lsp4j.CodeLensParams; 17 | import org.eclipse.lsp4j.Command; 18 | import org.eclipse.lsp4j.CompletionItem; 19 | import org.eclipse.lsp4j.CompletionList; 20 | import org.eclipse.lsp4j.CompletionParams; 21 | import org.eclipse.lsp4j.Diagnostic; 22 | import org.eclipse.lsp4j.DiagnosticSeverity; 23 | import org.eclipse.lsp4j.DidChangeTextDocumentParams; 24 | import org.eclipse.lsp4j.DidCloseTextDocumentParams; 25 | import org.eclipse.lsp4j.DidOpenTextDocumentParams; 26 | import org.eclipse.lsp4j.DidSaveTextDocumentParams; 27 | import org.eclipse.lsp4j.DocumentFormattingParams; 28 | import org.eclipse.lsp4j.DocumentHighlight; 29 | import org.eclipse.lsp4j.DocumentOnTypeFormattingParams; 30 | import org.eclipse.lsp4j.DocumentRangeFormattingParams; 31 | import org.eclipse.lsp4j.DocumentSymbol; 32 | import org.eclipse.lsp4j.DocumentSymbolParams; 33 | import org.eclipse.lsp4j.Hover; 34 | import org.eclipse.lsp4j.Location; 35 | import org.eclipse.lsp4j.MarkedString; 36 | import org.eclipse.lsp4j.Position; 37 | import org.eclipse.lsp4j.PublishDiagnosticsParams; 38 | import org.eclipse.lsp4j.Range; 39 | import org.eclipse.lsp4j.ReferenceParams; 40 | import org.eclipse.lsp4j.RenameParams; 41 | import org.eclipse.lsp4j.SignatureHelp; 42 | import org.eclipse.lsp4j.SymbolInformation; 43 | import org.eclipse.lsp4j.SymbolKind; 44 | import org.eclipse.lsp4j.TextDocumentEdit; 45 | import org.eclipse.lsp4j.TextDocumentIdentifier; 46 | import org.eclipse.lsp4j.TextDocumentPositionParams; 47 | import org.eclipse.lsp4j.TextEdit; 48 | import org.eclipse.lsp4j.VersionedTextDocumentIdentifier; 49 | import org.eclipse.lsp4j.WorkspaceEdit; 50 | import org.eclipse.lsp4j.jsonrpc.messages.Either; 51 | import org.eclipse.lsp4j.services.TextDocumentService; 52 | 53 | import fr.alpesjug.languageserver.ChamrousseDocumentModel.Route; 54 | import fr.alpesjug.languageserver.ChamrousseDocumentModel.VariableDefinition; 55 | 56 | public class ChamrousseTextDocumentService implements TextDocumentService { 57 | 58 | private final Map docs = Collections.synchronizedMap(new HashMap<>()); 59 | private final ChamrousseLanguageServer chamrousseLanguageServer; 60 | private final Map documentVersions = new HashMap<>(); 61 | 62 | public ChamrousseTextDocumentService(ChamrousseLanguageServer chamrousseLanguageServer) { 63 | this.chamrousseLanguageServer = chamrousseLanguageServer; 64 | } 65 | 66 | @Override 67 | public CompletableFuture, CompletionList>> completion(CompletionParams params) { 68 | return CompletableFuture.supplyAsync(() -> Either.forRight(new CompletionList(false, ChamrousseMap.INSTANCE.all.stream() 69 | .map(word -> { 70 | CompletionItem item = new CompletionItem(); 71 | item.setLabel(word); 72 | item.setInsertText(word); 73 | return item; 74 | }).collect(Collectors.toList())))); 75 | } 76 | 77 | @Override 78 | public CompletableFuture resolveCompletionItem(CompletionItem unresolved) { 79 | return null; 80 | } 81 | 82 | @Override 83 | public CompletableFuture hover(TextDocumentPositionParams position) { 84 | return CompletableFuture.supplyAsync(() -> { 85 | ChamrousseDocumentModel doc = docs.get(position.getTextDocument().getUri()); 86 | Hover res = new Hover(); 87 | List> content = doc.getResolvedRoutes().stream() 88 | .filter(route -> route.line == position.getPosition().getLine()) 89 | .map(route -> route.name) 90 | .map(ChamrousseMap.INSTANCE.type::get) 91 | .map(this::getHoverContent) 92 | .collect(Collectors.toList()); 93 | res.setContents(content); 94 | return res; 95 | }); 96 | } 97 | 98 | private Either getHoverContent(String type) { 99 | return Either.forLeft(type); 100 | // TODO: cosmetic tool improvement, show colors 101 | // return Either.forLeft("" + type + ""); 102 | } 103 | 104 | @Override 105 | public CompletableFuture signatureHelp(TextDocumentPositionParams position) { 106 | return null; 107 | } 108 | 109 | @Override 110 | public CompletableFuture> definition(TextDocumentPositionParams position) { 111 | return CompletableFuture.supplyAsync(() -> { 112 | ChamrousseDocumentModel doc = docs.get(position.getTextDocument().getUri()); 113 | String variable = doc.getVariable(position.getPosition().getLine(), position.getPosition().getCharacter()); 114 | if (variable != null) { 115 | int variableLine = doc.getDefintionLine(variable); 116 | if (variableLine == -1) { 117 | return Collections.emptyList(); 118 | } 119 | Location location = new Location(position.getTextDocument().getUri(), new Range( 120 | new Position(variableLine, 0), 121 | new Position(variableLine, variable.length()) 122 | )); 123 | return Collections.singletonList(location); 124 | } 125 | return null; 126 | }); 127 | } 128 | 129 | @Override 130 | public CompletableFuture> references(ReferenceParams params) { 131 | return CompletableFuture.supplyAsync(() -> { 132 | ChamrousseDocumentModel doc = docs.get(params.getTextDocument().getUri()); 133 | String variable = doc.getVariable(params.getPosition().getLine(), params.getPosition().getCharacter()); 134 | if (variable != null) { 135 | return doc.getResolvedRoutes().stream() 136 | .filter(route -> route.text.contains("${" + variable + "}") || route.text.startsWith(variable + "=")) 137 | .map(route -> new Location(params.getTextDocument().getUri(), new Range( 138 | new Position(route.line, route.text.indexOf(variable)), 139 | new Position(route.line, route.text.indexOf(variable) + variable.length()) 140 | ))) 141 | .collect(Collectors.toList()); 142 | } 143 | String routeName = doc.getResolvedRoutes().stream() 144 | .filter(route -> route.line == params.getPosition().getLine()) 145 | .collect(Collectors.toList()) 146 | .get(0) 147 | .name; 148 | return doc.getResolvedRoutes().stream() 149 | .filter(route -> route.name.equals(routeName)) 150 | .map(route -> new Location(params.getTextDocument().getUri(), new Range( 151 | new Position(route.line, 0), 152 | new Position(route.line, route.text.length())))) 153 | .collect(Collectors.toList()); 154 | }); 155 | } 156 | 157 | @Override 158 | public CompletableFuture> documentHighlight(TextDocumentPositionParams position) { 159 | return null; 160 | } 161 | 162 | @Override 163 | public CompletableFuture>> documentSymbol(DocumentSymbolParams params) { 164 | return CompletableFuture.supplyAsync(() -> 165 | docs.get(params.getTextDocument().getUri()).getResolvedLines().stream().map(line -> { 166 | SymbolInformation symbol = new SymbolInformation(); 167 | symbol.setLocation(new Location(params.getTextDocument().getUri(), new Range( 168 | new Position(line.line, line.charOffset), 169 | new Position(line.line, line.charOffset + line.text.length())))); 170 | if (line instanceof VariableDefinition) { 171 | symbol.setKind(SymbolKind.Variable); 172 | symbol.setName(((VariableDefinition) line).variableName); 173 | } else if (line instanceof Route) { 174 | symbol.setKind(SymbolKind.String); 175 | symbol.setName(((Route) line).name); 176 | } 177 | Either res = Either.forLeft(symbol); 178 | return res; 179 | }).collect(Collectors.toList()) 180 | ); 181 | } 182 | 183 | @Override 184 | public CompletableFuture>> codeAction(CodeActionParams params) { 185 | String docUri = params.getTextDocument().getUri(); 186 | return CompletableFuture.supplyAsync(() -> 187 | params.getContext().getDiagnostics().stream() 188 | .map(diagnostic -> { 189 | List res = new ArrayList<>(); 190 | CodeAction removeAction = new CodeAction("Enlever ce troncon"); 191 | removeAction.setKind(CodeActionKind.QuickFix); 192 | Integer docVersion = this.documentVersions.get(docUri); 193 | removeAction.setEdit(new WorkspaceEdit(Collections.singletonList(Either.forLeft( 194 | new TextDocumentEdit(new VersionedTextDocumentIdentifier(docUri, docVersion), 195 | Collections.singletonList( 196 | new TextEdit(diagnostic.getRange(), ""))))))); 197 | removeAction.setDiagnostics(Collections.singletonList(diagnostic)); 198 | res.add(removeAction); 199 | // TODO syntaxic change: support comment (Tool part of syntax/parser change) 200 | // CodeAction commentAction = new CodeAction("Commenter ce troncon"); 201 | // commentAction.setEdit(new WorkspaceEdit(Collections.singletonList(Either.forLeft( 202 | // new TextDocumentEdit(new VersionedTextDocumentIdentifier(docUri, docVersion), 203 | // Collections.singletonList( 204 | // new TextEdit(new Range(diagnostic.getRange().getStart(), diagnostic.getRange().getStart()), "#"))))))); 205 | // commentAction.setDiagnostics(Collections.singletonList(diagnostic)); 206 | // res.add(commentAction); 207 | // TODO Functional change: Add a nice productive feature 208 | // ChamrousseDocumentModel doc = docs.get(params.getTextDocument().getUri()); 209 | // Route route = doc.getRoute(params.getRange().getStart().getLine()); 210 | // if (route != null) { 211 | // int index = doc.getResolvedRoutes().indexOf(route); 212 | // if (index >= 0) 213 | // if (index > 0) { 214 | // Route previousRoute = doc.getResolvedRoutes().get(doc.getResolvedRoutes().indexOf(route) - 1); 215 | // for (String way : ChamrousseMap.INSTANCE.findWaysBetween(previousRoute.name, route.name)) { 216 | // CodeAction insertCodeAction = new CodeAction("Inserer '" + way + "' pour rejoindre les 2 pistes"); 217 | // insertCodeAction.setKind(CodeActionKind.QuickFix); 218 | // insertCodeAction.setEdit(new WorkspaceEdit(Collections.singletonList(Either.forLeft( 219 | // new TextDocumentEdit(new VersionedTextDocumentIdentifier(docUri, docVersion), Collections.singletonList( 220 | // new TextEdit(new Range(diagnostic.getRange().getStart(), diagnostic.getRange().getStart()), way + "\n"))))))); 221 | // insertCodeAction.setDiagnostics(Collections.singletonList(diagnostic)); 222 | // res.add(insertCodeAction); 223 | // } 224 | // if (index + 1 < doc.getResolvedRoutes().size()) { 225 | // Route nextRoute = doc.getResolvedRoutes().get(index + 1); 226 | // for (String way : ChamrousseMap.INSTANCE.findWaysBetween(previousRoute.name, nextRoute.name)) { 227 | // CodeAction replaceCodeAction = new CodeAction("Remplacer par '" + way + "' pour rejoindre les 2 pistes"); 228 | // replaceCodeAction.setKind(CodeActionKind.QuickFix); 229 | // replaceCodeAction.setEdit(new WorkspaceEdit(Collections.singletonList(Either.forLeft( 230 | // new TextDocumentEdit(new VersionedTextDocumentIdentifier(docUri, docVersion), Collections.singletonList( 231 | // new TextEdit(diagnostic.getRange(), way))))))); 232 | // replaceCodeAction.setDiagnostics(Collections.singletonList(diagnostic)); 233 | // res.add(replaceCodeAction); 234 | // } 235 | // } 236 | // } 237 | // } 238 | return res; 239 | }) 240 | .flatMap(Collection::stream) 241 | .map(codeAction -> { 242 | Either either = Either.forRight(codeAction); 243 | return either; 244 | }).collect(Collectors.toList()) 245 | ); 246 | } 247 | 248 | @Override 249 | public CompletableFuture> codeLens(CodeLensParams params) { 250 | return CompletableFuture.completedFuture(Collections.emptyList()); 251 | // TODO IDE feature change 252 | // return CompletableFuture.supplyAsync(() -> docs.get(params.getTextDocument().getUri()).getResolvedRoutes().stream().map(route -> 253 | // new CodeLens(new Range(new Position(route.line, 0), new Position(route.line, 1)), new Command(ChamrousseMap.INSTANCE.isLift(route.name) ? "🚡up" : "⛷️down", "kikoo"), null) 254 | // ).collect(Collectors.toList())); 255 | } 256 | 257 | @Override 258 | public CompletableFuture resolveCodeLens(CodeLens unresolved) { 259 | return null; 260 | } 261 | 262 | @Override 263 | public CompletableFuture> formatting(DocumentFormattingParams params) { 264 | return null; 265 | } 266 | 267 | @Override 268 | public CompletableFuture> rangeFormatting(DocumentRangeFormattingParams params) { 269 | return null; 270 | } 271 | 272 | @Override 273 | public CompletableFuture> onTypeFormatting(DocumentOnTypeFormattingParams params) { 274 | return null; 275 | } 276 | 277 | @Override 278 | public CompletableFuture rename(RenameParams params) { 279 | return null; 280 | } 281 | 282 | @Override 283 | public void didOpen(DidOpenTextDocumentParams params) { 284 | ChamrousseDocumentModel model = new ChamrousseDocumentModel(params.getTextDocument().getText()); 285 | this.docs.put(params.getTextDocument().getUri(), 286 | model); 287 | CompletableFuture.runAsync(() -> 288 | chamrousseLanguageServer.client.publishDiagnostics( 289 | new PublishDiagnosticsParams(params.getTextDocument().getUri(), validate(model)) 290 | ) 291 | ); 292 | } 293 | 294 | @Override 295 | public void didChange(DidChangeTextDocumentParams params) { 296 | // modify internal state 297 | this.documentVersions.put(params.getTextDocument().getUri(), params.getTextDocument().getVersion() + 1); 298 | ChamrousseDocumentModel model = new ChamrousseDocumentModel(params.getContentChanges().get(0).getText()); 299 | this.docs.put(params.getTextDocument().getUri(), 300 | model); 301 | // send notification 302 | CompletableFuture.runAsync(() -> { 303 | List diagnostics = validate(model); 304 | chamrousseLanguageServer.client.publishDiagnostics( 305 | new PublishDiagnosticsParams(params.getTextDocument().getUri(), diagnostics) 306 | ); 307 | } 308 | ); 309 | } 310 | 311 | private List validate(ChamrousseDocumentModel model) { 312 | List res = new ArrayList<>(); 313 | Route previousRoute = null; 314 | for (Route route : model.getResolvedRoutes()) { 315 | if (!ChamrousseMap.INSTANCE.all.contains(route.name)) { 316 | Diagnostic diagnostic = new Diagnostic(); 317 | diagnostic.setSeverity(DiagnosticSeverity.Error); 318 | diagnostic.setMessage("Ca existe pas a Chamrousse ca"); 319 | diagnostic.setRange(new Range( 320 | new Position(route.line, route.charOffset), 321 | new Position(route.line, route.charOffset + route.text.length()))); 322 | res.add(diagnostic); 323 | } else if (previousRoute != null && !ChamrousseMap.INSTANCE.startsFrom(route.name, previousRoute.name)) { 324 | Diagnostic diagnostic = new Diagnostic(); 325 | diagnostic.setSeverity(DiagnosticSeverity.Warning); 326 | diagnostic.setMessage("Il n'y a pas de passage de '" + previousRoute.name + "' a '" + route.name + "'"); 327 | diagnostic.setRange(new Range( 328 | new Position(route.line, route.charOffset), 329 | new Position(route.line, route.charOffset + route.text.length()))); 330 | res.add(diagnostic); 331 | } 332 | previousRoute = route; 333 | } 334 | return res; 335 | } 336 | 337 | @Override 338 | public void didClose(DidCloseTextDocumentParams params) { 339 | this.docs.remove(params.getTextDocument().getUri()); 340 | } 341 | 342 | @Override 343 | public void didSave(DidSaveTextDocumentParams params) { 344 | } 345 | 346 | } 347 | --------------------------------------------------------------------------------