diff --git a/eclipse-distribution/pom.xml b/eclipse-distribution/pom.xml index 207e8961a..8c25bfeeb 100644 --- a/eclipse-distribution/pom.xml +++ b/eclipse-distribution/pom.xml @@ -225,7 +225,7 @@ orbit p2 - http://download.eclipse.org/tools/orbit/downloads/drops/S20180302171354/repository/ + http://download.eclipse.org/tools/orbit/downloads/drops/S20180504181223/repository/ + maven-extras-mirror p2 diff --git a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/src/org/springsource/ide/eclipse/commons/frameworks/test/util/ACondition.java b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/src/org/springsource/ide/eclipse/commons/frameworks/test/util/ACondition.java index 69a7f96e6..a7da3ccb3 100644 --- a/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/src/org/springsource/ide/eclipse/commons/frameworks/test/util/ACondition.java +++ b/headless-services/jdt-ls-extension/org.springframework.tooling.jdt.ls.commons.test/src/org/springsource/ide/eclipse/commons/frameworks/test/util/ACondition.java @@ -238,9 +238,14 @@ public abstract class ACondition { } } } - + public static boolean inUIThread() { - return Display.getDefault().getThread() == Thread.currentThread(); + try { + return Display.getDefault().getThread() == Thread.currentThread(); + } catch (Exception e) { + e.printStackTrace(); + return false; + } } public static StringBuffer getStackDumps() { diff --git a/theia-extensions/theia-cf-manifest-yaml/README.md b/theia-extensions/theia-cf-manifest-yaml/README.md index 2ade37e3a..ea10ce590 100644 --- a/theia-extensions/theia-cf-manifest-yaml/README.md +++ b/theia-extensions/theia-cf-manifest-yaml/README.md @@ -14,6 +14,14 @@ Install npm and node. Install yarn. npm install -g yarn + +## Install dependencies + +Install dependencies and compile the code. + + yarn + +Note: it is also running `yarn rebuild:browser` and `yarn rebuild:electron`, thus one could navigate to the proper folder and launch it ## Running the browser example diff --git a/theia-extensions/theia-cf-manifest-yaml/cf-manifest-yaml/src/browser/cf-manifest-yaml-contribution.ts b/theia-extensions/theia-cf-manifest-yaml/cf-manifest-yaml/src/browser/cf-manifest-yaml-contribution.ts deleted file mode 100644 index 5f1e97bbf..000000000 --- a/theia-extensions/theia-cf-manifest-yaml/cf-manifest-yaml/src/browser/cf-manifest-yaml-contribution.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { injectable, inject } from "inversify"; -import { CommandContribution, CommandRegistry, MenuContribution, MenuModelRegistry, MessageService } from "@theia/core/lib/common"; -import { CommonMenus } from "@theia/core/lib/browser"; - -export const CfManifestYamlCommand = { - id: 'CfManifestYaml.command', - label: "Shows a message" -}; - -@injectable() -export class CfManifestYamlCommandContribution implements CommandContribution { - - constructor( - @inject(MessageService) private readonly messageService: MessageService, - ) { } - - registerCommands(registry: CommandRegistry): void { - registry.registerCommand(CfManifestYamlCommand, { - execute: () => this.messageService.info('Hello World!') - }); - } -} - -@injectable() -export class CfManifestYamlMenuContribution implements MenuContribution { - - registerMenus(menus: MenuModelRegistry): void { - menus.registerMenuAction(CommonMenus.EDIT_FIND, { - commandId: CfManifestYamlCommand.id, - label: 'Say Hello' - }); - } -} \ No newline at end of file diff --git a/theia-extensions/theia-cf-manifest-yaml/cf-manifest-yaml/src/node/cf-manifest-yaml-contribution.ts b/theia-extensions/theia-cf-manifest-yaml/cf-manifest-yaml/src/node/cf-manifest-yaml-contribution.ts index f1b13ae33..d21302eae 100644 --- a/theia-extensions/theia-cf-manifest-yaml/cf-manifest-yaml/src/node/cf-manifest-yaml-contribution.ts +++ b/theia-extensions/theia-cf-manifest-yaml/cf-manifest-yaml/src/node/cf-manifest-yaml-contribution.ts @@ -33,6 +33,7 @@ export class CfManifestYamlContribution extends BaseLanguageServerContribution { '-Dsts.lsp.client=theia', '-Dlsp.completions.indentation.enable=true', '-Dlsp.yaml.completions.errors.disable=true', + '-Dorg.slf4j.simpleLogger.logFile=cf-manifest-yaml.log' ]; } diff --git a/theia-extensions/theia-concourse/.gitignore b/theia-extensions/theia-concourse/.gitignore new file mode 100644 index 000000000..efbb05f07 --- /dev/null +++ b/theia-extensions/theia-concourse/.gitignore @@ -0,0 +1,8 @@ +node_modules +.browser_modules +lib +*.log +*-app/* +!*-app/package.json +/**/server + diff --git a/theia-extensions/theia-concourse/.vscode/launch.json b/theia-extensions/theia-concourse/.vscode/launch.json new file mode 100644 index 000000000..63be10364 --- /dev/null +++ b/theia-extensions/theia-concourse/.vscode/launch.json @@ -0,0 +1,60 @@ +{ + // Use IntelliSense to learn about possible Node.js debug attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Start Browser Backend", + "program": "${workspaceRoot}/browser-app/src-gen/backend/main.js", + "args": [ + "--loglevel=debug", + "--port=3000", + "--no-cluster" + ], + "env": { + "NODE_ENV": "development" + }, + "sourceMaps": true, + "outFiles": [ + "${workspaceRoot}/node_modules/@theia/*/lib/**/*.js", + "${workspaceRoot}/browser-app/lib/**/*.js", + "${workspaceRoot}/browser-app/src-gen/**/*.js" + ], + "smartStep": true, + "internalConsoleOptions": "openOnSessionStart", + "outputCapture": "std" + }, + { + "type": "node", + "request": "launch", + "name": "Start Electron Backend", + "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron", + "windows": { + "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd" + }, + "program": "${workspaceRoot}/electron-app/src-gen/frontend/electron-main.js", + "protocol": "inspector", + "args": [ + "--loglevel=debug", + "--hostname=localhost", + "--no-cluster" + ], + "env": { + "NODE_ENV": "development" + }, + "sourceMaps": true, + "outFiles": [ + "${workspaceRoot}/electron-app/src-gen/frontend/electron-main.js", + "${workspaceRoot}/electron-app/src-gen/backend/main.js", + "${workspaceRoot}/electron-app/lib/**/*.js", + "${workspaceRoot}/node_modules/@theia/*/lib/**/*.js" + ], + "smartStep": true, + "internalConsoleOptions": "openOnSessionStart", + "outputCapture": "std" + } + ] +} \ No newline at end of file diff --git a/theia-extensions/theia-concourse/README.md b/theia-extensions/theia-concourse/README.md new file mode 100644 index 000000000..99ad843ba --- /dev/null +++ b/theia-extensions/theia-concourse/README.md @@ -0,0 +1,81 @@ +# Concourse Extension for Theia IDE +The example of how to build the Theia-based applications with the concourse-extension. + +## Getting started + +Install [nvm](https://github.com/creationix/nvm#install-script). + + curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.5/install.sh | bash + +Install npm and node. + + nvm install 8 + nvm use 8 + +Install yarn. + + npm install -g yarn + +## Install dependencies + +Install dependencies and compile the code. + + yarn + +Note: it is also running `yarn rebuild:browser` and `yarn rebuild:electron`, thus one could navigate to the proper folder and launch it + +## Running the browser example + + yarn rebuild:browser + cd browser-app + yarn start + +Open http://localhost:3000 in the browser. + +## Running the Electron example + + yarn rebuild:electron + cd electron-app + yarn start + +## Developing with the browser example + +Start watching of the hello world extension. + + cd concourse-extension + yarn watch + +Start watching of the browser example. + + yarn rebuild:browser + cd browser-app + yarn watch + +Launch `Start Browser Backend` configuration from VS code. + +Open http://localhost:3000 in the browser. + +## Developing with the Electron example + +Start watching of the hello world extension. + + cd concourse-extension + yarn watch + +Start watching of the electron example. + + yarn rebuild:electron + cd electron-app + yarn watch + +Launch `Start Electron Backend` configuration from VS code. + +## Publishing concourse-extension + +Create a npm user and login to the npm registry, [more on npm publishing](https://docs.npmjs.com/getting-started/publishing-npm-packages). + + npm login + +Publish packages with lerna to update versions properly across local packages, [more on publishing with lerna](https://github.com/lerna/lerna#publish). + + npx lerna publish diff --git a/theia-extensions/theia-concourse/browser-app/package.json b/theia-extensions/theia-concourse/browser-app/package.json new file mode 100644 index 000000000..e29365f8f --- /dev/null +++ b/theia-extensions/theia-concourse/browser-app/package.json @@ -0,0 +1,32 @@ +{ + "private": true, + "name": "browser-app", + "version": "0.0.0", + "dependencies": { + "@theia/core": "latest", + "@theia/filesystem": "latest", + "@theia/workspace": "latest", + "@theia/preferences": "latest", + "@theia/navigator": "latest", + "@theia/process": "latest", + "@theia/terminal": "latest", + "@theia/editor": "latest", + "@theia/languages": "latest", + "@theia/markers": "latest", + "@theia/monaco": "latest", + "@theia/typescript": "latest", + "@theia/messages": "latest", + "@theia/concourse": "0.0.0" + }, + "devDependencies": { + "@theia/cli": "latest" + }, + "scripts": { + "prepare": "theia build", + "start": "theia start", + "watch": "theia build --watch" + }, + "theia": { + "target": "browser" + } +} \ No newline at end of file diff --git a/theia-extensions/theia-concourse/concourse/package.json b/theia-extensions/theia-concourse/concourse/package.json new file mode 100644 index 000000000..9c7a5148c --- /dev/null +++ b/theia-extensions/theia-concourse/concourse/package.json @@ -0,0 +1,36 @@ +{ + "name": "@theia/concourse", + "keywords": [ + "theia-extension" + ], + "version": "0.0.0", + "files": [ + "lib", + "src" + ], + "dependencies": { + "@theia/core": "latest", + "@theia/languages": "latest", + "@pivotal-tools/jvm-launch-utils": "0.0.11", + "@types/glob": "^5.0.30", + "glob": "^7.1.2" + }, + "devDependencies": { + "rimraf": "latest", + "typescript": "latest", + "download": "^6.2.5" + }, + "scripts": { + "prepare": "yarn run clean && yarn run download && yarn run build", + "download": "node script.js", + "clean": "rimraf lib", + "build": "tsc", + "watch": "tsc -w" + }, + "theiaExtensions": [ + { + "frontend": "lib/browser/concourse-frontend-module", + "backend": "lib/node/concourse-backend-module" + } + ] +} \ No newline at end of file diff --git a/theia-extensions/theia-concourse/concourse/properties.json b/theia-extensions/theia-concourse/concourse/properties.json new file mode 100644 index 000000000..5ba610250 --- /dev/null +++ b/theia-extensions/theia-concourse/concourse/properties.json @@ -0,0 +1,3 @@ +{ + "jarUrl": "https://s3.amazonaws.com/dist.springsource.com/release/STS4/fatjars/concourse-language-server-0.2.1-201805111942.jar" +} diff --git a/theia-extensions/theia-concourse/concourse/script.js b/theia-extensions/theia-concourse/concourse/script.js new file mode 100644 index 000000000..08321c90c --- /dev/null +++ b/theia-extensions/theia-concourse/concourse/script.js @@ -0,0 +1,34 @@ +const fs = require('fs'); +const path = require('path'); +const url = require('url'); +const glob = require('glob'); +const download = require('download'); +const PROPERTIES = require('./properties.json'); + +let fileExists = function(path) { + return new Promise((resolve, reject) => { + fs.access(path, fs.R_OK, error => { + resolve(!error || error.code !== 'ENOENT'); + }) + }); +}; + +const serverHome = path.join(__dirname, 'server'); +const filePaths = glob.sync('concourse-language-server*.jar', { cwd: serverHome }); + +if (filePaths.length === 0) { + const serverDownloadUrl = PROPERTIES.jarUrl; + const fileName = path.basename(url.parse(serverDownloadUrl).pathname); + const localFileName = path.join(serverHome, fileName.startsWith('concourse-language-server') ? fileName : 'concourse-language-server.jar'); + console.log(`Downloading ${serverDownloadUrl} to ${localFileName}`); + fileExists(serverHome) + .then(doesExist => { if (!doesExist) fs.mkdir(serverHome) }) + .then(() => download(serverDownloadUrl)) + .then(data => fs.writeFileSync(localFileName, data)) + .then(() => fileExists(localFileName)) + .then(doesExist => { if (!doesExist) throw Error(`Failed to install the ${this.getServerName()} language server`); }) + .then(() => console.log(`Successfully downloaded ${serverDownloadUrl}`)); +} + + + diff --git a/theia-extensions/theia-concourse/concourse/src/browser/concourse-frontend-module.ts b/theia-extensions/theia-concourse/concourse/src/browser/concourse-frontend-module.ts new file mode 100644 index 000000000..f93cc62f0 --- /dev/null +++ b/theia-extensions/theia-concourse/concourse/src/browser/concourse-frontend-module.ts @@ -0,0 +1,16 @@ +/** + * Generated using theia-extension-generator + */ + +import { ContainerModule } from "inversify"; +import { ConcourseClientContribution } from './language-client-contribution'; +import { LanguageClientContribution } from '@theia/languages/lib/browser'; + +// Contribute monaco-editor languages for pipeline and task yaml +import './pipeline-yaml-monaco-contribution'; +import './task-yaml-monaco-contribution'; + +export default new ContainerModule(bind => { + // add your contribution bindings here + bind(LanguageClientContribution).to(ConcourseClientContribution).inSingletonScope(); +}); \ No newline at end of file diff --git a/theia-extensions/theia-concourse/concourse/src/browser/language-client-contribution.ts b/theia-extensions/theia-concourse/concourse/src/browser/language-client-contribution.ts new file mode 100644 index 000000000..dde18880c --- /dev/null +++ b/theia-extensions/theia-concourse/concourse/src/browser/language-client-contribution.ts @@ -0,0 +1,33 @@ +import { injectable, inject } from 'inversify'; +import { BaseLanguageClientContribution, Workspace, Languages, LanguageClientFactory } from '@theia/languages/lib/browser'; +import { + CONCOURSE_PIPELINE_YAML_LANGUAGE_ID, CONCOURSE_SERVER_ID, CONCOURSE_SERVER_NAME, + CONCOURSE_TASK_YAML_LANGUAGE_ID +} from '../common'; + +@injectable() +export class ConcourseClientContribution extends BaseLanguageClientContribution { + + readonly id = CONCOURSE_SERVER_ID; + readonly name = CONCOURSE_SERVER_NAME; + + constructor( + @inject(Workspace) protected readonly workspace: Workspace, + @inject(Languages) protected readonly languages: Languages, + @inject(LanguageClientFactory) protected readonly languageClientFactory: LanguageClientFactory, + ) { + super(workspace, languages, languageClientFactory); + } + + protected get documentSelector() { + return [CONCOURSE_PIPELINE_YAML_LANGUAGE_ID, CONCOURSE_TASK_YAML_LANGUAGE_ID]; + } + + protected get globPatterns() { + return [ + '*pipeline*.yml', + '*task.yml', + '**/tasks/*.yml' + ]; + } +} diff --git a/theia-extensions/theia-concourse/concourse/src/browser/pipeline-yaml-monaco-contribution.ts b/theia-extensions/theia-concourse/concourse/src/browser/pipeline-yaml-monaco-contribution.ts new file mode 100644 index 000000000..642d7e0e2 --- /dev/null +++ b/theia-extensions/theia-concourse/concourse/src/browser/pipeline-yaml-monaco-contribution.ts @@ -0,0 +1,26 @@ +/// +import { + CONCOURSE_PIPELINE_YAML_LANGUAGE_ID, + CONCOURSE_PIPELINE_YAML_LANGUAGE_NAME +} from '../common'; + +// Pipeline .yml file language registration + +let YAML_LANG_MODULE_PROMISE: monaco.Promise; + +monaco.languages.register({ + id: CONCOURSE_PIPELINE_YAML_LANGUAGE_ID, + filenamePatterns: ['*pipeline*.yml'], + aliases: [CONCOURSE_PIPELINE_YAML_LANGUAGE_NAME, CONCOURSE_PIPELINE_YAML_LANGUAGE_ID], + firstLine: '^#(\\s)*pipeline(\\s)*', +}); + +monaco.languages.onLanguage(CONCOURSE_PIPELINE_YAML_LANGUAGE_ID, () => { + if (!YAML_LANG_MODULE_PROMISE) { + YAML_LANG_MODULE_PROMISE = (monaco.languages.getLanguages().find(ext => ext.id === 'yaml')).loader(); + } + return YAML_LANG_MODULE_PROMISE.then(mod => { + monaco.languages.setLanguageConfiguration(CONCOURSE_PIPELINE_YAML_LANGUAGE_ID, mod.conf); + monaco.languages.setMonarchTokensProvider(CONCOURSE_PIPELINE_YAML_LANGUAGE_ID, mod.language); + }) +}); diff --git a/theia-extensions/theia-concourse/concourse/src/browser/task-yaml-monaco-contribution.ts b/theia-extensions/theia-concourse/concourse/src/browser/task-yaml-monaco-contribution.ts new file mode 100644 index 000000000..16bfb30d0 --- /dev/null +++ b/theia-extensions/theia-concourse/concourse/src/browser/task-yaml-monaco-contribution.ts @@ -0,0 +1,26 @@ +/// +import { + CONCOURSE_TASK_YAML_LANGUAGE_ID, + CONCOURSE_TASK_YAML_LANGUAGE_NAME +} from '../common'; + +// Task .yml file language registration + +let YAML_LANG_MODULE_PROMISE: monaco.Promise; + +monaco.languages.register({ + id: CONCOURSE_TASK_YAML_LANGUAGE_ID, + filenamePatterns: ['*task.yml', '**/tasks/*.yml'], + aliases: [CONCOURSE_TASK_YAML_LANGUAGE_NAME, CONCOURSE_TASK_YAML_LANGUAGE_ID], + firstLine: '^#(\\\\s)*task(\\\\s)*', +}); + +monaco.languages.onLanguage(CONCOURSE_TASK_YAML_LANGUAGE_ID, () => { + if (!YAML_LANG_MODULE_PROMISE) { + YAML_LANG_MODULE_PROMISE = (monaco.languages.getLanguages().find(ext => ext.id === 'yaml')).loader(); + } + return YAML_LANG_MODULE_PROMISE.then(mod => { + monaco.languages.setLanguageConfiguration(CONCOURSE_TASK_YAML_LANGUAGE_ID, mod.conf); + monaco.languages.setMonarchTokensProvider(CONCOURSE_TASK_YAML_LANGUAGE_ID, mod.language); + }) +}); diff --git a/theia-extensions/theia-concourse/concourse/src/common/index.ts b/theia-extensions/theia-concourse/concourse/src/common/index.ts new file mode 100644 index 000000000..9863f022d --- /dev/null +++ b/theia-extensions/theia-concourse/concourse/src/common/index.ts @@ -0,0 +1,8 @@ +export const CONCOURSE_SERVER_ID = 'concourse-yaml'; +export const CONCOURSE_SERVER_NAME = 'Concourse YAML'; + +export const CONCOURSE_PIPELINE_YAML_LANGUAGE_ID = 'concourse-pipeline-yaml'; +export const CONCOURSE_PIPELINE_YAML_LANGUAGE_NAME = 'Concourse Pipeline'; + +export const CONCOURSE_TASK_YAML_LANGUAGE_ID = 'concourse-task-yaml'; +export const CONCOURSE_TASK_YAML_LANGUAGE_NAME = 'Concourse Task'; diff --git a/theia-extensions/theia-concourse/concourse/src/node/concourse-backend-module.ts b/theia-extensions/theia-concourse/concourse/src/node/concourse-backend-module.ts new file mode 100644 index 000000000..2f7cc3800 --- /dev/null +++ b/theia-extensions/theia-concourse/concourse/src/node/concourse-backend-module.ts @@ -0,0 +1,7 @@ +import { ContainerModule } from "inversify"; +import { LanguageServerContribution } from "@theia/languages/lib/node"; +import { ConcourseLanguageContribution } from './concourse-language-contribution'; + +export default new ContainerModule(bind => { + bind(LanguageServerContribution).to(ConcourseLanguageContribution).inSingletonScope(); +}); \ No newline at end of file diff --git a/theia-extensions/theia-concourse/concourse/src/node/concourse-language-contribution.ts b/theia-extensions/theia-concourse/concourse/src/node/concourse-language-contribution.ts new file mode 100644 index 000000000..3fa3cbf0c --- /dev/null +++ b/theia-extensions/theia-concourse/concourse/src/node/concourse-language-contribution.ts @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2017 TypeFox and others. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import * as path from 'path'; +import * as glob from 'glob'; +import { injectable } from 'inversify'; +// import { DEBUG_MODE } from '@theia/core/lib/node'; +import { IConnection, BaseLanguageServerContribution } from '@theia/languages/lib/node'; +import { CONCOURSE_SERVER_ID, CONCOURSE_SERVER_NAME } from '../common'; +import { findJvm } from '@pivotal-tools/jvm-launch-utils'; + + +@injectable() +export class ConcourseLanguageContribution extends BaseLanguageServerContribution { + + readonly id = CONCOURSE_SERVER_ID; + readonly name = CONCOURSE_SERVER_NAME; + + start(clientConnection: IConnection): void { + const serverPath = path.resolve(__dirname, '../../server'); + const jarPaths = glob.sync('concourse-language-server*.jar', { cwd: serverPath }); + if (jarPaths.length === 0) { + throw new Error('The Concourse YAML server launcher is not found.'); + } + + const jarPath = path.resolve(serverPath, jarPaths[0]); + findJvm() + .catch(error => { + throw new Error('Error trying to find JVM'); + }) + .then(jvm => { + if (!jvm) { + throw new Error("Couldn't locate java in $JAVA_HOME or $PATH"); + } + + this.startSocketServer().then(server => { + const socket = this.accept(server); + + // this.logInfo('logs at ' + path.resolve(workspacePath, '.metadata', '.log')); + const env = Object.create(process.env); + const addressInfo = server.address(); + if (typeof addressInfo === 'string') { + throw new Error(`Address info was string ${addressInfo}`); + } + env.CLIENT_HOST = addressInfo.address; + env.CLIENT_PORT = addressInfo.port; + const command = jvm.getJavaExecutable(); + const args = [ + '-Dsts.lsp.client=theia', + '-Dlsp.completions.indentation.enable=true', + '-Dlsp.yaml.completions.errors.disable=true', + '-Dorg.slf4j.simpleLogger.logFile=concourse-yaml.log', + `-Dserver.port=${env.CLIENT_PORT}` + ]; + + // if (DEBUG_MODE) { + args.push( + '-Xdebug', + '-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=7999', + '-Dlog.level=ALL' + ); + // } + + args.push( + '-jar', jarPath, + ); + + this.createProcessSocketConnection(socket, socket, command, args, { env }) + .then(serverConnection => this.forward(clientConnection, serverConnection)); + }); + + }); + + } +} \ No newline at end of file diff --git a/theia-extensions/theia-concourse/concourse/tsconfig.json b/theia-extensions/theia-concourse/concourse/tsconfig.json new file mode 100644 index 000000000..7362f7bed --- /dev/null +++ b/theia-extensions/theia-concourse/concourse/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "strict": true, + "experimentalDecorators": true, + "noUnusedLocals": true, + "emitDecoratorMetadata": true, + "downlevelIteration": true, + "module": "commonjs", + "moduleResolution": "node", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "rootDir": "src", + "outDir": "lib" + }, + "include": [ + "src" + ] +} \ No newline at end of file diff --git a/theia-extensions/theia-concourse/electron-app/package.json b/theia-extensions/theia-concourse/electron-app/package.json new file mode 100644 index 000000000..49dc6a5bb --- /dev/null +++ b/theia-extensions/theia-concourse/electron-app/package.json @@ -0,0 +1,32 @@ +{ + "private": true, + "name": "electron-app", + "version": "0.0.0", + "dependencies": { + "@theia/core": "latest", + "@theia/filesystem": "latest", + "@theia/workspace": "latest", + "@theia/preferences": "latest", + "@theia/navigator": "latest", + "@theia/process": "latest", + "@theia/terminal": "latest", + "@theia/editor": "latest", + "@theia/languages": "latest", + "@theia/markers": "latest", + "@theia/monaco": "latest", + "@theia/typescript": "latest", + "@theia/messages": "latest", + "@theia/concourse": "0.0.0" + }, + "devDependencies": { + "@theia/cli": "latest" + }, + "scripts": { + "prepare": "theia build", + "start": "theia start", + "watch": "theia build --watch" + }, + "theia": { + "target": "electron" + } +} \ No newline at end of file diff --git a/theia-extensions/theia-concourse/lerna.json b/theia-extensions/theia-concourse/lerna.json new file mode 100644 index 000000000..10fe79d90 --- /dev/null +++ b/theia-extensions/theia-concourse/lerna.json @@ -0,0 +1,11 @@ +{ + "lerna": "2.4.0", + "version": "0.0.0", + "useWorkspaces": true, + "npmClient": "yarn", + "command": { + "run": { + "stream": true + } + } +} \ No newline at end of file diff --git a/theia-extensions/theia-concourse/package.json b/theia-extensions/theia-concourse/package.json new file mode 100644 index 000000000..f41e91087 --- /dev/null +++ b/theia-extensions/theia-concourse/package.json @@ -0,0 +1,14 @@ +{ + "private": true, + "scripts": { + "prepare": "lerna run prepare", + "rebuild:browser": "theia rebuild:browser", + "rebuild:electron": "theia rebuild:electron" + }, + "devDependencies": { + "lerna": "2.4.0" + }, + "workspaces": [ + "concourse", "browser-app", "electron-app" + ] +} \ No newline at end of file diff --git a/theia-extensions/theia-spring-boot/README.md b/theia-extensions/theia-spring-boot/README.md index eb4299772..021c7578d 100644 --- a/theia-extensions/theia-spring-boot/README.md +++ b/theia-extensions/theia-spring-boot/README.md @@ -16,6 +16,14 @@ Install yarn. npm install -g yarn +## Install dependencies + +Install dependencies and compile the code. + + yarn + +Note: it is also running `yarn rebuild:browser` and `yarn rebuild:electron`, thus one could navigate to the proper folder and launch it + ## Running the browser example yarn rebuild:browser @@ -32,7 +40,7 @@ Open http://localhost:3000 in the browser. ## Developing with the browser example -Start watching of the hello world extension. +Start watching of the extension. cd spring-boot yarn watch @@ -49,7 +57,7 @@ Open http://localhost:3000 in the browser. ## Developing with the Electron example -Start watching of the hello world extension. +Start watching of extension. cd spring-boot yarn watch diff --git a/theia-extensions/theia-spring-boot/spring-boot/package.json b/theia-extensions/theia-spring-boot/spring-boot/package.json index 32258949d..ba4320b63 100644 --- a/theia-extensions/theia-spring-boot/spring-boot/package.json +++ b/theia-extensions/theia-spring-boot/spring-boot/package.json @@ -12,6 +12,7 @@ "dependencies": { "@theia/core": "latest", "@theia/languages": "latest", + "@theia/preferences": "latest", "@theia/editor": "latest", "@theia/monaco": "latest", "@theia/java": "latest", diff --git a/theia-extensions/theia-spring-boot/spring-boot/src/browser/boot-preferences.ts b/theia-extensions/theia-spring-boot/spring-boot/src/browser/boot-preferences.ts new file mode 100644 index 000000000..7edd56671 --- /dev/null +++ b/theia-extensions/theia-spring-boot/spring-boot/src/browser/boot-preferences.ts @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 TypeFox and others. + * + * Licensed under the Apache License, Version 2.0 (the 'License'); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + */ + +import { interfaces } from 'inversify'; +import { createPreferenceProxy, PreferenceProxy, PreferenceService, PreferenceContribution, PreferenceSchema } from '@theia/core/lib/browser'; + +// tslint:disable:max-line-length + +export const BootConfigSchema: PreferenceSchema = { + 'type': 'object', + 'title': 'Spring Boot Java Configuration', + properties: { + 'boot-java.boot-hints.on': { + type: 'boolean', + description: 'Enable/Disable Spring running Boot application live hints decorators in Java source code.', + default: true + }, + 'spring-boot.ls.java.home': { + type: 'string', + description: `Override JAVA_HOME used for launching the spring-boot-language-server JVM process.`, + default: null + }, + 'spring-boot.ls.java.heap': { + type: 'string', + description: `Max JVM heap value, passed via -Xmx argument when launching spring-boot-language-server JVM process.`, + default: null + } + } +}; + +export interface BootConfiguration { + 'boot-java.boot-hints.on': boolean; + 'spring-boot.ls.java.home': string | null; + 'spring-boot.ls.java.heap': string | null; +} + +export const BootPreferences = Symbol('BootJavaPreferences'); +export type BootPreferences = PreferenceProxy; + +export function createBootPreferences(preferences: PreferenceService): BootPreferences { + return createPreferenceProxy(preferences, BootConfigSchema); +} + +export function bindBootPreferences(bind: interfaces.Bind): void { + bind(BootPreferences).toDynamicValue(ctx => { + const preferences = ctx.container.get(PreferenceService); + return createBootPreferences(preferences); + }); + bind(PreferenceContribution).toConstantValue({ schema: BootConfigSchema }); +} diff --git a/theia-extensions/theia-spring-boot/spring-boot/src/browser/language-client-contribution.ts b/theia-extensions/theia-spring-boot/spring-boot/src/browser/language-client-contribution.ts index 99d690890..d6d621802 100644 --- a/theia-extensions/theia-spring-boot/spring-boot/src/browser/language-client-contribution.ts +++ b/theia-extensions/theia-spring-boot/spring-boot/src/browser/language-client-contribution.ts @@ -1,4 +1,4 @@ -import { injectable, inject } from 'inversify'; +import { injectable, inject, postConstruct } from 'inversify'; import { BaseLanguageClientContribution, Workspace, Languages, LanguageClientFactory } from '@theia/languages/lib/browser'; import { SPRING_BOOT_SERVER_ID, @@ -10,6 +10,13 @@ import { DocumentSelector } from '@theia/languages/lib/common'; import { JAVA_LANGUAGE_ID } from '@theia/java/lib/common'; import { HighlightService} from './highlight-service'; import { ClasspathService } from './classpath-service'; +import { BootPreferences } from './boot-preferences'; +import { NotificationType } from 'vscode-jsonrpc'; +import { DidChangeConfigurationParams } from 'vscode-base-languageclient/lib/base'; +import { Utils } from './utils'; + +const CONFIG_CHANGED_NOTIFICATION_TYPE = new NotificationType('workspace/didChangeConfiguration'); + @injectable() export class SpringBootClientContribution extends BaseLanguageClientContribution { @@ -22,15 +29,35 @@ export class SpringBootClientContribution extends BaseLanguageClientContribution @inject(Languages) protected readonly languages: Languages, @inject(LanguageClientFactory) protected readonly languageClientFactory: LanguageClientFactory, @inject(HighlightService) protected readonly highlightService: HighlightService, - @inject(ClasspathService) protected readonly classpathService: ClasspathService + @inject(ClasspathService) protected readonly classpathService: ClasspathService, + @inject(BootPreferences) protected readonly preferences: BootPreferences ) { super(workspace, languages, languageClientFactory); + } + + @postConstruct() + protected async init() { + await this.preferences.ready; + + // Send settings to LS + this.sendConfig(); + this.preferences.onPreferenceChanged(() => this.sendConfig()); + this.languageClient.then(client => { this.highlightService.attach(client); // this.classpathService.attach(client); }); } + private sendConfig() { + return this.languageClient.then(client => { + const params = Utils.convertDotToNested(Object.assign({}, this.preferences)); + return client.sendNotification(CONFIG_CHANGED_NOTIFICATION_TYPE, { + settings: params + }); + }) + } + protected get documentSelector(): DocumentSelector | undefined { return [JAVA_LANGUAGE_ID, BOOT_PROPERTIES_YAML_LANGUAGE_ID, BOOT_PROPERTIES_LANGUAGE_ID]; } diff --git a/theia-extensions/theia-spring-boot/spring-boot/src/browser/spring-boot-frontend-module.ts b/theia-extensions/theia-spring-boot/spring-boot/src/browser/spring-boot-frontend-module.ts index c07f97fb2..82b85ea11 100644 --- a/theia-extensions/theia-spring-boot/spring-boot/src/browser/spring-boot-frontend-module.ts +++ b/theia-extensions/theia-spring-boot/spring-boot/src/browser/spring-boot-frontend-module.ts @@ -6,9 +6,11 @@ import './monaco-yaml-contribution'; import './monaco-properties-contribution'; import { HighlightService } from './highlight-service'; import { ClasspathService } from './classpath-service'; +import { bindBootPreferences } from './boot-preferences'; export default new ContainerModule(bind => { // add your contribution bindings here + bindBootPreferences(bind); bind(LanguageClientContribution).to(SpringBootClientContribution).inSingletonScope(); bind(HighlightService).toSelf().inSingletonScope(); bind(ClasspathService).toSelf().inSingletonScope(); diff --git a/theia-extensions/theia-spring-boot/spring-boot/src/browser/utils.ts b/theia-extensions/theia-spring-boot/spring-boot/src/browser/utils.ts new file mode 100644 index 000000000..5b5f929c2 --- /dev/null +++ b/theia-extensions/theia-spring-boot/spring-boot/src/browser/utils.ts @@ -0,0 +1,27 @@ +export class Utils { + + private static setNestedValue(properties: string[], value: any, obj: any){ + if (properties.length > 1) { + // The property doesn't exists OR is not an object (and so we overwritte it) so we create it + if (!obj.hasOwnProperty(properties[0]) || typeof obj[properties[0]] !== 'object') { + obj[properties[0]] = {}; + } + Utils.setNestedValue(properties.slice(1), value, obj[properties[0]]); + } else { + obj[properties[0]] = value; + } + } + + public static convertDotToNested(source: any): any { + const result = {}; + Object.keys(source).forEach(property => { + const properties = property.split('.'); + if (source[property] && typeof source[property] === 'object') { + Utils.setNestedValue(properties, Utils.convertDotToNested(source[property]), result); + } else { + Utils.setNestedValue(properties, source[property], result); + } + }); + return result; + } +} \ No newline at end of file diff --git a/theia-extensions/theia-spring-boot/spring-boot/src/node/spring-boot-ls-contribution.ts b/theia-extensions/theia-spring-boot/spring-boot/src/node/spring-boot-ls-contribution.ts index 058158653..2a95f3ee7 100644 --- a/theia-extensions/theia-spring-boot/spring-boot/src/node/spring-boot-ls-contribution.ts +++ b/theia-extensions/theia-spring-boot/spring-boot/src/node/spring-boot-ls-contribution.ts @@ -56,8 +56,7 @@ export class SpringBootLsContribution extends BaseLanguageServerContribution { '-Dsts.lsp.client=theia', '-Dlsp.completions.indentation.enable=true', '-Dlsp.yaml.completions.errors.disable=true', - '-Dorg.slf4j.simpleLogger.logFile=boot-java.log', - '-Dorg.slf4j.simpleLogger.defaultLogLevel=debug' + '-Dorg.slf4j.simpleLogger.logFile=boot-java.log' ]; args.push(`-Dserver.port=${env.CLIENT_PORT}`);