From 61aa1006512b475b6dd432c6aafaa504f3f175a4 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 16 Apr 2019 07:03:32 +0800 Subject: [PATCH 0001/1031] Add Code Action: Generate toString()... (#873) Signed-off-by: Jinbo Wang --- README.md | 9 ++++++-- package.json | 48 ++++++++++++++++++++++++++++++++++++++---- src/commands.ts | 6 +++++- src/extension.ts | 3 ++- src/protocol.ts | 19 +++++++++++++++++ src/sourceAction.ts | 46 +++++++++++++++++++++++++++++++++++++++- test/extension.test.ts | 3 ++- 7 files changed, 124 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 12eafedd5..b1629616a 100644 --- a/README.md +++ b/README.md @@ -97,12 +97,17 @@ The following settings are supported: * `java.configuration.checkProjectSettingsExclusions`: Checks if the extension-generated project settings files (`.project`, `.classpath`, `.factorypath`, `.settings/`) should be excluded from the file explorer. Defaults to `true`. * `java.codeGeneration.hashCodeEquals.useJava7Objects`: Use Objects.hash and Objects.equals when generating the hashCode and equals methods. This setting only applies to Java 7 and higher. Defaults to `false`. * `java.codeGeneration.hashCodeEquals.useInstanceof`: Use 'instanceof' to compare types when generating the hashCode and equals methods. Defaults to `false`. -* `java.codeGeneration.hashCodeEquals.useBlocks`: Use blocks in 'if' statements when generating the hashCode and equals methods. Defaults to `false`. -* `java.codeGeneration.hashCodeEquals.generateComments`: Generate method comments when generating the hashCode and equals methods. Defaults to `false`. * `java.foldingRange.enabled`: Enable/disable smart folding range support. If disabled, it will use the default indentation-based folding range provided by VS Code. *New in 0.43.0:* * `java.maven.downloadSources`: Enable/disable eager download of Maven source artifacts. +* `java.codeGeneration.useBlocks`: Use blocks in 'if' statements when generating the methods. Defaults to `false`. +* `java.codeGeneration.generateComments`: Generate method comments when generating the methods. Defaults to `false`. +* `java.codeGeneration.toString.template`: The template for generating the toString method. Defaults to `${object.className} [${member.name()}=${member.value}, ${otherMembers}]`. +* `java.codeGeneration.toString.codeStyle`: The code style for generating the toString method. Defaults to `STRING_CONCATENATION`. +* `java.codeGeneration.toString.skipNullValues`: Skip null values when generating the toString method. Defaults to `false`. +* `java.codeGeneration.toString.listArrayContents`: List contents of arrays instead of using native toString(). Defaults to `true`. +* `java.codeGeneration.toString.limitElements`: Limit number of items in arrays/collections/maps to list, if 0 then list all. Defaults to `0`. Troubleshooting =============== diff --git a/package.json b/package.json index 2dd41f409..b8ed5eb27 100644 --- a/package.json +++ b/package.json @@ -296,17 +296,57 @@ "default": false, "scope": "window" }, - "java.codeGeneration.hashCodeEquals.useBlocks": { + "java.codeGeneration.useBlocks": { "type": "boolean", - "description": "Use blocks in 'if' statements when generating the hashCode and equals methods.", + "description": "Use blocks in 'if' statements when generating the methods.", "default": false, "scope": "window" }, - "java.codeGeneration.hashCodeEquals.generateComments": { + "java.codeGeneration.generateComments": { "type": "boolean", - "description": "Generate method comments when generating the hashCode and equals methods.", + "description": "Generate method comments when generating the methods.", "default": false, "scope": "window" + }, + "java.codeGeneration.toString.template": { + "type": "string", + "description": "The template for generating the toString method.", + "default": "${object.className} [${member.name()}=${member.value}, ${otherMembers}]" + }, + "java.codeGeneration.toString.codeStyle": { + "type": "string", + "enum": [ + "STRING_CONCATENATION", + "STRING_BUILDER", + "STRING_BUILDER_CHAINED", + "STRING_FORMAT" + ], + "enumDescriptions": [ + "String concatenation", + "StringBuilder/StringBuffer", + "StringBuilder/StringBuffer - chained call", + "String.format/MessageFormat" + ], + "description": "The code style for generating the toString method.", + "default": "STRING_CONCATENATION" + }, + "java.codeGeneration.toString.skipNullValues": { + "type": "boolean", + "description": "Skip null values when generating the toString method.", + "default": false, + "scope": "window" + }, + "java.codeGeneration.toString.listArrayContents": { + "type": "boolean", + "description": "List contents of arrays instead of using native toString().", + "default": true, + "scope": "window" + }, + "java.codeGeneration.toString.limitElements": { + "type": "integer", + "description": "Limit number of items in arrays/collections/maps to list, if 0 then list all.", + "default": 0, + "scope": "window" } } }, diff --git a/src/commands.ts b/src/commands.ts index 663dcb72e..71517710a 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -109,7 +109,7 @@ export namespace Commands { /** * Generate hashCode() and equals(). */ - export const HASHCODE_EQUALS_PROMPT = 'java.action.hashCodeEqualsPrompt'; + export const HASHCODE_EQUALS_PROMPT = 'java.action.hashCodeEqualsPrompt'; /** * Open settings.json */ @@ -122,4 +122,8 @@ export namespace Commands { * Choose type to import. */ export const CHOOSE_IMPORTS = "java.action.organizeImports.chooseImports"; + /** + * Generate toString(). + */ + export const GENERATE_TOSTRING_PROMPT = 'java.action.generateToStringPrompt'; } \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index f1446fb83..562275918 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -65,7 +65,8 @@ export function activate(context: ExtensionContext): Promise { classFileContentsSupport:true, overrideMethodsPromptSupport:true, hashCodeEqualsPromptSupport:true, - advancedOrganizeImportsSupport:true + advancedOrganizeImportsSupport:true, + generateToStringPromptSupport:true }, triggerFiles: getTriggerFiles() }, diff --git a/src/protocol.ts b/src/protocol.ts index bb38540c8..b87474ffd 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -187,4 +187,23 @@ export interface ImportCandidate { export interface ImportSelection { candidates: ImportCandidate[]; range: Range; +} + +export interface CheckToStringResponse { + type: string; + fields: VariableField[]; + exists: boolean; +} + +export namespace CheckToStringStatusRequest { + export const type = new RequestType('java/checkToStringStatus'); +} + +export interface GenerateToStringParams { + context: CodeActionParams; + fields: VariableField[]; +} + +export namespace GenerateToStringRequest { + export const type = new RequestType('java/generateToString'); } \ No newline at end of file diff --git a/src/sourceAction.ts b/src/sourceAction.ts index e9f066a90..a7d437291 100644 --- a/src/sourceAction.ts +++ b/src/sourceAction.ts @@ -5,13 +5,14 @@ import { CodeActionParams, LanguageClient } from 'vscode-languageclient'; import { Commands } from './commands'; import { applyWorkspaceEdit } from './extension'; import { ListOverridableMethodsRequest, AddOverridableMethodsRequest, CheckHashCodeEqualsStatusRequest, GenerateHashCodeEqualsRequest, -OrganizeImportsRequest, ImportCandidate, ImportSelection } from './protocol'; +OrganizeImportsRequest, ImportCandidate, ImportSelection, GenerateToStringRequest, CheckToStringStatusRequest, VariableField } from './protocol'; export function registerCommands(languageClient: LanguageClient, context: ExtensionContext) { registerOverrideMethodsCommand(languageClient, context); registerHashCodeEqualsCommand(languageClient, context); registerOrganizeImportsCommand(languageClient, context); registerChooseImportCommand(context); + registerGenerateToStringCommand(languageClient, context); } function registerOverrideMethodsCommand(languageClient: LanguageClient, context: ExtensionContext): void { @@ -158,3 +159,46 @@ function registerChooseImportCommand(context: ExtensionContext): void { return chosen; })); } + +function registerGenerateToStringCommand(languageClient: LanguageClient, context: ExtensionContext): void { + context.subscriptions.push(commands.registerCommand(Commands.GENERATE_TOSTRING_PROMPT, async (params: CodeActionParams) => { + const result = await languageClient.sendRequest(CheckToStringStatusRequest.type, params); + if (!result) { + return; + } + + if (result.exists) { + const ans = await window.showInformationMessage(`Method 'toString()' already exists in the Class '${result.type}'. ` + + 'Do you want to replace the implementation?', 'Replace', 'Cancel'); + if (ans !== 'Replace') { + return; + } + } + + let fields: VariableField[] = []; + if (result.fields && result.fields.length) { + const fieldItems = result.fields.map((field) => { + return { + label: `${field.name}: ${field.type}`, + picked: true, + originalField: field + }; + }); + const selectedFields = await window.showQuickPick(fieldItems, { + canPickMany: true, + placeHolder: 'Select the fields to include in the toString() method.' + }); + if (!selectedFields) { + return; + } + + fields = selectedFields.map((item) => item.originalField); + } + + const workspaceEdit = await languageClient.sendRequest(GenerateToStringRequest.type, { + context: params, + fields, + }); + applyWorkspaceEdit(workspaceEdit, languageClient); + })); +} diff --git a/test/extension.test.ts b/test/extension.test.ts index 12d123cca..c9ad7b20e 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -45,7 +45,8 @@ suite('Java Language Extension', () => { Commands.HASHCODE_EQUALS_PROMPT, Commands.OPEN_JSON_SETTINGS, Commands.ORGANIZE_IMPORTS, - Commands.CHOOSE_IMPORTS + Commands.CHOOSE_IMPORTS, + Commands.GENERATE_TOSTRING_PROMPT ]; let foundJavaCommands = commands.filter(function(value){ return JAVA_COMMANDS.indexOf(value)>=0 || value.startsWith('java.'); From 831f44f4c930b4328622448104b6513a0bbead75 Mon Sep 17 00:00:00 2001 From: Gorkem Ercan Date: Mon, 1 Apr 2019 17:07:35 -0400 Subject: [PATCH 0002/1031] Updates tslint configuration Several changes related to tslint. 1. tslint is now invoked as as a typescript plugin, and the gulp function related to tslint is removed. 2. updated tslint.json with rules. 3. fixed reported tslint error Signed-off-by: Gorkem Ercan --- gulpfile.js | 8 +- package-lock.json | 820 ++++++++++----------------------------- package.json | 7 +- src/buildpath.ts | 2 +- src/extension.ts | 113 +++--- src/javaServerStarter.ts | 38 +- src/plugin.ts | 10 +- src/protocol.ts | 9 +- src/requirements.ts | 22 +- src/settings.ts | 19 +- src/sourceAction.ts | 4 +- test/extension.test.ts | 18 +- tsconfig.json | 5 +- tslint.json | 75 +++- 14 files changed, 380 insertions(+), 770 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index 94e4e40ad..93450e0d2 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,16 +1,10 @@ 'use strict'; const gulp = require('gulp'); -const gulp_tslint = require('gulp-tslint'); const cp = require('child_process'); const decompress = require('gulp-decompress'); const download = require('gulp-download'); const server_dir = '../eclipse.jdt.ls'; //... -gulp.task('tslint', () => { - return gulp.src(['**/*.ts', '!**/*.d.ts', '!node_modules/**']) - .pipe(gulp_tslint()) - .pipe(gulp_tslint.report()); -}); gulp.task('download_server', function(done) { download("http://download.eclipse.org/jdtls/snapshots/jdt-language-server-latest.tar.gz") @@ -34,7 +28,7 @@ gulp.task('dev_server', function(done) { } else if(isMac()){ command += '-Denvironment.os=macosx -Denvironment.ws=cocoa -Denvironment.arch=x86_64'; - } + } else if(isWin()){ command += '-Denvironment.os=win32 -Denvironment.ws=win32 -Denvironment.arch=x86_64'; } diff --git a/package-lock.json b/package-lock.json index 006551bea..3aa44f582 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,12 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@types/fancy-log": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@types/fancy-log/-/fancy-log-1.3.0.tgz", - "integrity": "sha512-mQjDxyOM1Cpocd+vm1kZBP7smwKZ4TNokFeds9LV7OZibmPJFEzY3+xZMrKfUdNT71lv8GoCPD6upKwHxubClw==", - "dev": true - }, "@types/glob": { "version": "5.0.30", "resolved": "http://registry.npmjs.org/@types/glob/-/glob-5.0.30.tgz", @@ -237,6 +231,15 @@ "acorn": "^5.0.0" } }, + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, "ajv": { "version": "6.6.1", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.1.tgz", @@ -270,15 +273,6 @@ "ansi-wrap": "^0.1.0" } }, - "ansi-cyan": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", - "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", - "dev": true, - "requires": { - "ansi-wrap": "0.1.0" - } - }, "ansi-gray": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", @@ -288,15 +282,6 @@ "ansi-wrap": "0.1.0" } }, - "ansi-red": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", - "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", - "dev": true, - "requires": { - "ansi-wrap": "0.1.0" - } - }, "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -472,15 +457,6 @@ } } }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, "array-uniq": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", @@ -493,12 +469,6 @@ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -536,7 +506,7 @@ }, "util": { "version": "0.10.3", - "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { @@ -731,7 +701,7 @@ }, "bl": { "version": "1.2.2", - "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", "dev": true, "requires": { @@ -739,15 +709,6 @@ "safe-buffer": "^5.1.1" } }, - "block-stream": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", - "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", - "dev": true, - "requires": { - "inherits": "~2.0.0" - } - }, "bluebird": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", @@ -812,7 +773,7 @@ }, "browserify-aes": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "dev": true, "requires": { @@ -849,7 +810,7 @@ }, "browserify-rsa": { "version": "4.0.1", - "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "dev": true, "requires": { @@ -1198,7 +1159,7 @@ }, "commander": { "version": "2.8.1", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", "dev": true, "requires": { @@ -1306,7 +1267,7 @@ }, "create-hash": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { @@ -1319,7 +1280,7 @@ }, "create-hmac": { "version": "1.1.7", - "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { @@ -1518,15 +1479,6 @@ "yauzl": "^2.4.2" } }, - "deep-assign": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/deep-assign/-/deep-assign-1.0.0.tgz", - "integrity": "sha1-sJJ0O+hCfcYh6gBnzex+cN0Z83s=", - "dev": true, - "requires": { - "is-obj": "^1.0.0" - } - }, "default-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", @@ -1630,7 +1582,7 @@ }, "diffie-hellman": { "version": "5.0.3", - "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { @@ -1645,12 +1597,6 @@ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", "dev": true }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true - }, "duplexer2": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", @@ -1799,6 +1745,21 @@ "es6-symbol": "^3.1.1" } }, + "es6-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz", + "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, "es6-symbol": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", @@ -1864,29 +1825,6 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, - "event-stream": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", - "dev": true, - "requires": { - "duplexer": "~0.1.1", - "from": "~0", - "map-stream": "~0.1.0", - "pause-stream": "0.0.11", - "split": "0.3", - "stream-combiner": "~0.0.4", - "through": "~2.3.1" - }, - "dependencies": { - "map-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", - "dev": true - } - } - }, "events": { "version": "1.1.1", "resolved": "http://registry.npmjs.org/events/-/events-1.1.1.tgz", @@ -2275,12 +2213,6 @@ "map-cache": "^0.2.2" } }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", - "dev": true - }, "from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", @@ -2325,9 +2257,9 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz", + "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==", "dev": true, "optional": true, "requires": { @@ -2354,7 +2286,7 @@ "optional": true }, "are-we-there-yet": { - "version": "1.1.4", + "version": "1.1.5", "bundled": true, "dev": true, "optional": true, @@ -2380,7 +2312,7 @@ } }, "chownr": { - "version": "1.0.1", + "version": "1.1.1", "bundled": true, "dev": true, "optional": true @@ -2419,7 +2351,7 @@ } }, "deep-extend": { - "version": "0.5.1", + "version": "0.6.0", "bundled": true, "dev": true, "optional": true @@ -2468,7 +2400,7 @@ } }, "glob": { - "version": "7.1.2", + "version": "7.1.3", "bundled": true, "dev": true, "optional": true, @@ -2488,12 +2420,12 @@ "optional": true }, "iconv-lite": { - "version": "0.4.21", + "version": "0.4.24", "bundled": true, "dev": true, "optional": true, "requires": { - "safer-buffer": "^2.1.0" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { @@ -2558,17 +2490,17 @@ "optional": true }, "minipass": { - "version": "2.2.4", + "version": "2.3.5", "bundled": true, "dev": true, "optional": true, "requires": { - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.0" } }, "minizlib": { - "version": "1.1.0", + "version": "1.2.1", "bundled": true, "dev": true, "optional": true, @@ -2592,7 +2524,7 @@ "optional": true }, "needle": { - "version": "2.2.0", + "version": "2.2.4", "bundled": true, "dev": true, "optional": true, @@ -2603,18 +2535,18 @@ } }, "node-pre-gyp": { - "version": "0.10.0", + "version": "0.10.3", "bundled": true, "dev": true, "optional": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", - "needle": "^2.2.0", + "needle": "^2.2.1", "nopt": "^4.0.1", "npm-packlist": "^1.1.6", "npmlog": "^4.0.2", - "rc": "^1.1.7", + "rc": "^1.2.7", "rimraf": "^2.6.1", "semver": "^5.3.0", "tar": "^4" @@ -2631,13 +2563,13 @@ } }, "npm-bundled": { - "version": "1.0.3", + "version": "1.0.5", "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.1.10", + "version": "1.2.0", "bundled": true, "dev": true, "optional": true, @@ -2714,12 +2646,12 @@ "optional": true }, "rc": { - "version": "1.2.7", + "version": "1.2.8", "bundled": true, "dev": true, "optional": true, "requires": { - "deep-extend": "^0.5.1", + "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" @@ -2749,16 +2681,16 @@ } }, "rimraf": { - "version": "2.6.2", + "version": "2.6.3", "bundled": true, "dev": true, "optional": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "safe-buffer": { - "version": "5.1.1", + "version": "5.1.2", "bundled": true, "dev": true, "optional": true @@ -2776,7 +2708,7 @@ "optional": true }, "semver": { - "version": "5.5.0", + "version": "5.6.0", "bundled": true, "dev": true, "optional": true @@ -2829,17 +2761,17 @@ "optional": true }, "tar": { - "version": "4.4.1", + "version": "4.4.8", "bundled": true, "dev": true, "optional": true, "requires": { - "chownr": "^1.0.1", + "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.2" } }, @@ -2850,12 +2782,12 @@ "optional": true }, "wide-align": { - "version": "1.1.2", + "version": "1.1.3", "bundled": true, "dev": true, "optional": true, "requires": { - "string-width": "^1.0.2" + "string-width": "^1.0.2 || 2" } }, "wrappy": { @@ -2865,25 +2797,13 @@ "optional": true }, "yallist": { - "version": "3.0.2", + "version": "3.0.3", "bundled": true, "dev": true, "optional": true } } }, - "fstream": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", - "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - } - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -2898,7 +2818,7 @@ }, "get-stream": { "version": "2.3.1", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", "dev": true, "requires": { @@ -3095,17 +3015,6 @@ } } }, - "gulp-chmod": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/gulp-chmod/-/gulp-chmod-2.0.0.tgz", - "integrity": "sha1-AMOQuSigeZslGsz2MaoJ4BzGKZw=", - "dev": true, - "requires": { - "deep-assign": "^1.0.0", - "stat-mode": "^0.2.0", - "through2": "^2.0.0" - } - }, "gulp-decompress": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/gulp-decompress/-/gulp-decompress-2.0.1.tgz", @@ -3199,250 +3108,6 @@ } } }, - "gulp-filter": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/gulp-filter/-/gulp-filter-5.1.0.tgz", - "integrity": "sha1-oF4Rr/sHz33PQafeHLe2OsN4PnM=", - "dev": true, - "requires": { - "multimatch": "^2.0.0", - "plugin-error": "^0.1.2", - "streamfilter": "^1.0.5" - }, - "dependencies": { - "arr-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", - "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1", - "array-slice": "^0.2.3" - } - }, - "arr-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", - "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=", - "dev": true - }, - "array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", - "dev": true - }, - "extend-shallow": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", - "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", - "dev": true, - "requires": { - "kind-of": "^1.1.0" - } - }, - "kind-of": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", - "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", - "dev": true - }, - "plugin-error": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", - "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", - "dev": true, - "requires": { - "ansi-cyan": "^0.1.1", - "ansi-red": "^0.1.1", - "arr-diff": "^1.0.1", - "arr-union": "^2.0.1", - "extend-shallow": "^1.1.2" - } - } - } - }, - "gulp-gunzip": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulp-gunzip/-/gulp-gunzip-1.0.0.tgz", - "integrity": "sha1-FbdBFF6Dqcb1CIYkG1fMWHHxUak=", - "dev": true, - "requires": { - "through2": "~0.6.5", - "vinyl": "~0.4.6" - }, - "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, - "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", - "dev": true, - "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" - } - } - } - }, - "gulp-remote-src-vscode": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/gulp-remote-src-vscode/-/gulp-remote-src-vscode-0.5.1.tgz", - "integrity": "sha512-mw4OGjtC/jlCWJFhbcAlel4YPvccChlpsl3JceNiB/DLJi24/UPxXt53/N26lgI3dknEqd4ErfdHrO8sJ5bATQ==", - "dev": true, - "requires": { - "event-stream": "3.3.4", - "node.extend": "^1.1.2", - "request": "^2.79.0", - "through2": "^2.0.3", - "vinyl": "^2.0.1" - } - }, - "gulp-tslint": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/gulp-tslint/-/gulp-tslint-8.1.3.tgz", - "integrity": "sha512-KEP350N5B9Jg6o6jnyCyKVBPemJePYpMsGfIQq0G0ErvY7tw4Lrfb/y3L4WRf7ek0OsaE8nnj86w+lcLXW8ovw==", - "dev": true, - "requires": { - "@types/fancy-log": "1.3.0", - "chalk": "2.3.1", - "fancy-log": "1.3.2", - "map-stream": "~0.0.7", - "plugin-error": "1.0.1", - "through": "~2.3.8" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.3.1", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", - "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.2.0" - } - }, - "fancy-log": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", - "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", - "dev": true, - "requires": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "time-stamp": "^1.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "gulp-untar": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/gulp-untar/-/gulp-untar-0.0.7.tgz", - "integrity": "sha512-0QfbCH2a1k2qkTLWPqTX+QO4qNsHn3kC546YhAP3/n0h+nvtyGITDuDrYBMDZeW4WnFijmkOvBWa5HshTic1tw==", - "dev": true, - "requires": { - "event-stream": "~3.3.4", - "streamifier": "~0.1.1", - "tar": "^2.2.1", - "through2": "~2.0.3", - "vinyl": "^1.2.0" - }, - "dependencies": { - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true - }, - "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - } - } - }, "gulp-util": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", @@ -3506,21 +3171,6 @@ } } }, - "gulp-vinyl-zip": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/gulp-vinyl-zip/-/gulp-vinyl-zip-2.1.2.tgz", - "integrity": "sha512-wJn09jsb8PyvUeyFF7y7ImEJqJwYy40BqL9GKfJs6UGpaGW9A+N68Q+ajsIpb9AeR6lAdjMbIdDPclIGo1/b7Q==", - "dev": true, - "requires": { - "event-stream": "3.3.4", - "queue": "^4.2.1", - "through2": "^2.0.3", - "vinyl": "^2.0.2", - "vinyl-fs": "^3.0.3", - "yauzl": "^2.2.1", - "yazl": "^2.2.1" - } - }, "gulplog": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", @@ -3546,15 +3196,6 @@ "har-schema": "^2.0.0" } }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -3669,6 +3310,27 @@ "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -3686,6 +3348,33 @@ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "dev": true }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "dev": true, + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, "ieee754": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", @@ -3752,12 +3441,6 @@ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, - "is": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", - "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==", - "dev": true - }, "is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", @@ -3919,12 +3602,6 @@ } } }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -4013,9 +3690,9 @@ "dev": true }, "js-yaml": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.0.tgz", - "integrity": "sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -4366,12 +4043,6 @@ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true }, - "map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", - "dev": true - }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", @@ -4630,6 +4301,16 @@ } } }, + "mock-require": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/mock-require/-/mock-require-3.0.3.tgz", + "integrity": "sha512-lLzfLHcyc10MKQnNUCv7dMcoY/2Qxd6wJfbqCcVk3LDb8An4hF6ohk5AztrvgKhJCqj36uyzi/p5se+tvyD+Wg==", + "dev": true, + "requires": { + "get-caller-file": "^1.0.2", + "normalize-path": "^2.1.1" + } + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -4650,18 +4331,6 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, - "multimatch": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", - "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", - "dev": true, - "requires": { - "array-differ": "^1.0.0", - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "minimatch": "^3.0.0" - } - }, "multipipe": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", @@ -4760,7 +4429,7 @@ }, "buffer": { "version": "4.9.1", - "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { @@ -4777,16 +4446,6 @@ } } }, - "node.extend": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/node.extend/-/node.extend-1.1.8.tgz", - "integrity": "sha512-L/dvEBwyg3UowwqOUTyDsGBU6kjBQOpOhshio9V3i3BMPv5YUb9+mWNN8MK0IbWqT0AqaTSONZf0aTuMMahWgA==", - "dev": true, - "requires": { - "has": "^1.0.3", - "is": "^3.2.1" - } - }, "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", @@ -5092,7 +4751,7 @@ }, "path-browserify": { "version": "0.0.0", - "resolved": "http://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", "dev": true }, @@ -5150,15 +4809,6 @@ "pinkie-promise": "^2.0.0" } }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", - "dev": true, - "requires": { - "through": "~2.3" - } - }, "pbkdf2": { "version": "3.0.17", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", @@ -5225,18 +4875,6 @@ } } }, - "plugin-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", - "dev": true, - "requires": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" - } - }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -5345,20 +4983,11 @@ "dev": true }, "querystringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz", - "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", "dev": true }, - "queue": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/queue/-/queue-4.5.1.tgz", - "integrity": "sha512-AMD7w5hRXcFSb8s9u38acBZ+309u6GsiibP4/0YacJeaurRshogB7v/ZcVPxP5gD5+zIw6ixRHdutiYUJfwKHw==", - "dev": true, - "requires": { - "inherits": "~2.0.0" - } - }, "randombytes": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", @@ -5743,7 +5372,7 @@ }, "sha.js": { "version": "2.4.11", - "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "dev": true, "requires": { @@ -5966,15 +5595,6 @@ "integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==", "dev": true }, - "split": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", - "dev": true, - "requires": { - "through": "2" - } - }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -6022,12 +5642,6 @@ "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", "dev": true }, - "stat-mode": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.2.tgz", - "integrity": "sha1-5sgLYjEj19gM8TLOU480YokHJQI=", - "dev": true - }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -6059,15 +5673,6 @@ "readable-stream": "^2.0.2" } }, - "stream-combiner": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", - "dev": true, - "requires": { - "duplexer": "~0.1.1" - } - }, "stream-each": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", @@ -6103,21 +5708,6 @@ "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", "dev": true }, - "streamfilter": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/streamfilter/-/streamfilter-1.0.7.tgz", - "integrity": "sha512-Gk6KZM+yNA1JpW0KzlZIhjo3EaBJDkYfXtYSbOwNIQ7Zd6006E6+sCFlW1NDvFG/vnXhKmw6TJJgiEQg/8lXfQ==", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } - }, - "streamifier": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/streamifier/-/streamifier-0.1.1.tgz", - "integrity": "sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8=", - "dev": true - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -6167,7 +5757,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, @@ -6193,17 +5783,6 @@ "integrity": "sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA==", "dev": true }, - "tar": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", - "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", - "dev": true, - "requires": { - "block-stream": "*", - "fstream": "^1.0.2", - "inherits": "2" - } - }, "tar-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", @@ -6287,7 +5866,7 @@ }, "through": { "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, @@ -6543,7 +6122,7 @@ }, "tty-browserify": { "version": "0.0.0", - "resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true }, @@ -6569,11 +6148,22 @@ "dev": true }, "typescript": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.1.tgz", - "integrity": "sha512-jw7P2z/h6aPT4AENXDGjcfHTu5CSqzsbZc6YlUIebTyBAq8XaKp78x7VcSh30xwSCcsu5irZkYZUSFP1MrAMbg==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.1.tgz", + "integrity": "sha512-3NSMb2VzDQm8oBTLH6Nj55VVtUEpe/rgkIzMir0qVoLyjDZlnMBva0U6vDiV3IH+sl/Yu6oP5QwsAQtHPmDd2Q==", "dev": true }, + "typescript-tslint-plugin": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/typescript-tslint-plugin/-/typescript-tslint-plugin-0.3.1.tgz", + "integrity": "sha512-h8HEPBm36UEs901ld1x6m5eY/UFb4mF+A0nvERr4BWMww5wnV5nfcm9ZFt18foYL0GQ5NVMt1Tb3466WUU8dRQ==", + "dev": true, + "requires": { + "minimatch": "^3.0.4", + "mock-require": "^3.0.2", + "vscode-languageserver": "^5.1.0" + } + }, "unbzip2-stream": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.1.tgz", @@ -6756,9 +6346,9 @@ } }, "url-parse": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz", - "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.6.tgz", + "integrity": "sha512-/B8AD9iQ01seoXmXf9z/MjLZQIdOoYl/+gvsQF6+mpnxaTfG9P7srYaiqaDMyKkR36XMXfhqSHss5MyFAO8lew==", "dev": true, "requires": { "querystringify": "^2.0.0", @@ -6873,40 +6463,6 @@ "vinyl-sourcemap": "^1.1.0" } }, - "vinyl-source-stream": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-1.1.2.tgz", - "integrity": "sha1-YrU6E1YQqJbpjKlr7jqH8Aio54A=", - "dev": true, - "requires": { - "through2": "^2.0.3", - "vinyl": "^0.4.3" - }, - "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", - "dev": true, - "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" - } - } - } - }, "vinyl-sourcemap": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", @@ -6924,7 +6480,7 @@ }, "vm-browserify": { "version": "0.0.4", - "resolved": "http://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", "dev": true, "requires": { @@ -6932,25 +6488,18 @@ } }, "vscode": { - "version": "1.1.30", - "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.30.tgz", - "integrity": "sha512-YDj5w0TGOcS8XLIdekT4q6LlLV6hv1ZvuT2aGT3KJll4gMz6dUPDgo2VVAf0i0E8igbbZthwvmaUGRwW9yPIaw==", + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.33.tgz", + "integrity": "sha512-sXedp2oF6y4ZvqrrFiZpeMzaCLSWV+PpYkIxjG/iYquNZ9KrLL2LujltGxPLvzn49xu2sZkyC+avVNFgcJD1Iw==", "dev": true, "requires": { "glob": "^7.1.2", - "gulp-chmod": "^2.0.0", - "gulp-filter": "^5.0.1", - "gulp-gunzip": "1.0.0", - "gulp-remote-src-vscode": "^0.5.1", - "gulp-untar": "^0.0.7", - "gulp-vinyl-zip": "^2.1.2", "mocha": "^4.0.1", "request": "^2.88.0", "semver": "^5.4.1", "source-map-support": "^0.5.0", - "url-parse": "^1.4.3", - "vinyl-fs": "^3.0.3", - "vinyl-source-stream": "^1.1.0" + "url-parse": "^1.4.4", + "vscode-test": "^0.1.4" }, "dependencies": { "browser-stdout": { @@ -7051,6 +6600,34 @@ "vscode-languageserver-protocol": "3.13.0" } }, + "vscode-languageserver": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-5.2.1.tgz", + "integrity": "sha512-GuayqdKZqAwwaCUjDvMTAVRPJOp/SLON3mJ07eGsx/Iq9HjRymhKWztX41rISqDKhHVVyFM+IywICyZDla6U3A==", + "dev": true, + "requires": { + "vscode-languageserver-protocol": "3.14.1", + "vscode-uri": "^1.0.6" + }, + "dependencies": { + "vscode-languageserver-protocol": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz", + "integrity": "sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g==", + "dev": true, + "requires": { + "vscode-jsonrpc": "^4.0.0", + "vscode-languageserver-types": "3.14.0" + } + }, + "vscode-languageserver-types": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz", + "integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A==", + "dev": true + } + } + }, "vscode-languageserver-protocol": { "version": "3.13.0", "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.13.0.tgz", @@ -7065,6 +6642,22 @@ "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.13.0.tgz", "integrity": "sha512-BnJIxS+5+8UWiNKCP7W3g9FlE7fErFw0ofP5BXJe7c2tl0VeWh+nNHFbwAS2vmVC4a5kYxHBjRy0UeOtziemVA==" }, + "vscode-test": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-0.1.5.tgz", + "integrity": "sha512-s+lbF1Dtasc0yXVB9iQTexBe2JK6HJAUJe3fWezHKIjq+xRw5ZwCMEMBaonFIPy7s95qg2HPTRDR5W4h4kbxGw==", + "dev": true, + "requires": { + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1" + } + }, + "vscode-uri": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-1.0.6.tgz", + "integrity": "sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww==", + "dev": true + }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", @@ -7391,15 +6984,6 @@ "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } - }, - "yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3" - } } } } diff --git a/package.json b/package.json index b8ed5eb27..836b13f89 100644 --- a/package.json +++ b/package.json @@ -462,7 +462,6 @@ "test": "node ./node_modules/vscode/bin/test", "build-server": "./node_modules/.bin/gulp build_server", "watch-server": "./node_modules/.bin/gulp watch_server", - "tslint": "./node_modules/.bin/gulp tslint", "webpack": "webpack --mode development" }, "devDependencies": { @@ -472,12 +471,12 @@ "gulp": "^4.0.0", "gulp-decompress": "2.0.1", "gulp-download": "0.0.1", - "gulp-tslint": "^8.1.3", "mocha": "^5.2.0", "ts-loader": "^5.3.1", "tslint": "^5.11.0", - "typescript": "^3.0.3", - "vscode": "^1.1.30", + "typescript": "^3.4.1", + "typescript-tslint-plugin": "^0.3.1", + "vscode": "^1.1.33", "webpack": "^4.27.1", "webpack-cli": "^3.1.2" }, diff --git a/src/buildpath.ts b/src/buildpath.ts index 9a00529aa..3463b04de 100644 --- a/src/buildpath.ts +++ b/src/buildpath.ts @@ -47,7 +47,7 @@ export function registerCommands(context: ExtensionContext) { window.showQuickPick(result.data.map(sourcePath => { return { label: sourcePath.displayPath, - detail: `$(file-directory) ${sourcePath.projectType} Project: ${sourcePath.projectName}`, + detail: `$(file-directory) ${sourcePath.projectType} Project: ${sourcePath.projectName}`, }; }), { placeHolder: 'All Java source directories recognized by the workspace.'}); } diff --git a/src/extension.ts b/src/extension.ts index 562275918..e8523d819 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -9,8 +9,10 @@ import { onExtensionChange, collectJavaExtensions } from './plugin'; import { prepareExecutable, awaitServerConnection } from './javaServerStarter'; import * as requirements from './requirements'; import { Commands } from './commands'; -import { StatusNotification, ClassFileContentsRequest, ProjectConfigurationUpdateRequest, MessageType, ActionableNotification, FeatureStatus, CompileWorkspaceRequest, CompileWorkspaceStatus, ProgressReportNotification, ExecuteClientCommandRequest, SendNotificationRequest, -SourceAttachmentRequest, SourceAttachmentResult, SourceAttachmentAttribute } from './protocol'; +import { + StatusNotification, ClassFileContentsRequest, ProjectConfigurationUpdateRequest, MessageType, ActionableNotification, FeatureStatus, CompileWorkspaceRequest, CompileWorkspaceStatus, ProgressReportNotification, ExecuteClientCommandRequest, SendNotificationRequest, + SourceAttachmentRequest, SourceAttachmentResult, SourceAttachmentAttribute +} from './protocol'; import { ExtensionAPI } from './extension.api'; import * as buildpath from './buildpath'; import * as sourceAction from './sourceAction'; @@ -20,7 +22,7 @@ import { onConfigurationChange, excludeProjectSettingsFiles } from './settings'; let lastStatus; let languageClient: LanguageClient; -let jdtEventEmitter = new EventEmitter(); +const jdtEventEmitter = new EventEmitter(); const cleanWorkspaceFileName = '.cleanWorkspace'; export function activate(context: ExtensionContext): Promise { @@ -28,7 +30,7 @@ export function activate(context: ExtensionContext): Promise { enableJavadocSymbols(); return requirements.resolveRequirements().catch(error => { - //show error + // show error window.showErrorMessage(error.message, error.label).then((selection) => { if (error.label && error.label === selection && error.command) { commands.executeCommand(error.command, error.commandParam); @@ -43,10 +45,10 @@ export function activate(context: ExtensionContext): Promise { if (!storagePath) { storagePath = getTempWorkspace(); } - let workspacePath = path.resolve(storagePath + '/jdt_ws'); + const workspacePath = path.resolve(storagePath + '/jdt_ws'); // Options to control the language client - let clientOptions: LanguageClientOptions = { + const clientOptions: LanguageClientOptions = { // Register the server for java documentSelector: [ { scheme: 'file', language: 'java' }, @@ -60,34 +62,34 @@ export function activate(context: ExtensionContext): Promise { bundles: collectJavaExtensions(extensions.all), workspaceFolders: workspace.workspaceFolders ? workspace.workspaceFolders.map(f => f.uri.toString()) : null, settings: { java: getJavaConfiguration() }, - extendedClientCapabilities:{ + extendedClientCapabilities: { progressReportProvider: getJavaConfiguration().get('progressReports.enabled'), - classFileContentsSupport:true, - overrideMethodsPromptSupport:true, - hashCodeEqualsPromptSupport:true, - advancedOrganizeImportsSupport:true, - generateToStringPromptSupport:true + classFileContentsSupport: true, + overrideMethodsPromptSupport: true, + hashCodeEqualsPromptSupport: true, + advancedOrganizeImportsSupport: true, + generateToStringPromptSupport: true }, triggerFiles: getTriggerFiles() }, revealOutputChannelOn: RevealOutputChannelOn.Never }; - let item = window.createStatusBarItem(StatusBarAlignment.Right, Number.MIN_VALUE); + const item = window.createStatusBarItem(StatusBarAlignment.Right, Number.MIN_VALUE); item.text = '$(rocket)'; item.command = Commands.OPEN_OUTPUT; - let progressBar = window.createStatusBarItem(StatusBarAlignment.Left, Number.MIN_VALUE+1); + const progressBar = window.createStatusBarItem(StatusBarAlignment.Left, Number.MIN_VALUE + 1); let serverOptions; - let port = process.env['SERVER_PORT']; + const port = process.env['SERVER_PORT']; if (!port) { - let lsPort = process.env['JDTLS_CLIENT_PORT']; + const lsPort = process.env['JDTLS_CLIENT_PORT']; if (!lsPort) { serverOptions = prepareExecutable(requirements, workspacePath, getJavaConfiguration()); } else { serverOptions = () => { - let socket = net.connect(lsPort); - let result: StreamInfo = { + const socket = net.connect(lsPort); + const result: StreamInfo = { writer: socket, reader: socket }; @@ -166,9 +168,9 @@ export function activate(context: ExtensionContext): Promise { } const titles = notification.commands.map(a => a.title); show(notification.message, ...titles).then((selection) => { - for (let action of notification.commands) { + for (const action of notification.commands) { if (action.title === selection) { - let args: any[] = (action.arguments) ? action.arguments : []; + const args: any[] = (action.arguments) ? action.arguments : []; commands.executeCommand(action.command, ...args); break; } @@ -215,17 +217,17 @@ export function activate(context: ExtensionContext): Promise { return languageClient.sendRequest(ExecuteCommandRequest.type, params); })); - context.subscriptions.push(commands.registerCommand(Commands.COMPILE_WORKSPACE, (isFullCompile : boolean) => { + context.subscriptions.push(commands.registerCommand(Commands.COMPILE_WORKSPACE, (isFullCompile: boolean) => { return window.withProgress({ location: ProgressLocation.Window }, async p => { if (typeof isFullCompile !== 'boolean') { - const selection = await window.showQuickPick(['Incremental', 'Full'], {'placeHolder' : 'please choose compile type:'}); + const selection = await window.showQuickPick(['Incremental', 'Full'], { placeHolder: 'please choose compile type:' }); isFullCompile = selection !== 'Incremental'; } p.report({ message: 'Compiling workspace...' }); const start = new Date().getTime(); const res = await languageClient.sendRequest(CompileWorkspaceRequest.type, isFullCompile); const elapsed = new Date().getTime() - start; - const humanVisibleDelay = elapsed < 1000? 1000:0; + const humanVisibleDelay = elapsed < 1000 ? 1000 : 0; return new Promise((resolve, reject) => { setTimeout(() => { // set a timeout so user would still see the message when build time is short if (res === CompileWorkspaceStatus.SUCCEED) { @@ -288,7 +290,7 @@ export function activate(context: ExtensionContext): Promise { toggleItem(editor, item); })); - let provider: TextDocumentContentProvider = { + const provider: TextDocumentContentProvider = { onDidChange: jdtEventEmitter.event, provideTextDocumentContent: (uri: Uri, token: CancellationToken): Thenable => { return languageClient.sendRequest(ClassFileContentsRequest.type, { uri: uri.toString() }, token).then((v: string): string => { @@ -297,7 +299,7 @@ export function activate(context: ExtensionContext): Promise { } }; context.subscriptions.push(workspace.registerTextDocumentContentProvider('jdt', provider)); - if (extensions.onDidChange) {//Theia doesn't support this API yet + if (extensions.onDidChange) {// Theia doesn't support this API yet extensions.onDidChange(() => { onExtensionChange(extensions.all); }); @@ -305,12 +307,12 @@ export function activate(context: ExtensionContext): Promise { excludeProjectSettingsFiles(); }); - let cleanWorkspaceExists = fs.existsSync( path.join(workspacePath, cleanWorkspaceFileName)); + const cleanWorkspaceExists = fs.existsSync(path.join(workspacePath, cleanWorkspaceFileName)); if (cleanWorkspaceExists) { try { deleteDirectory(workspacePath); } catch (error) { - window.showErrorMessage('Failed to delete ' + workspacePath + ': ' + error); + window.showErrorMessage(`Failed to delete ${workspacePath}: ${error}`); } } @@ -318,7 +320,7 @@ export function activate(context: ExtensionContext): Promise { // Register commands here to make it available even when the language client fails context.subscriptions.push(commands.registerCommand(Commands.OPEN_SERVER_LOG, () => openServerLogFile(workspacePath))); - let extensionPath = context.extensionPath; + const extensionPath = context.extensionPath; context.subscriptions.push(commands.registerCommand(Commands.OPEN_FORMATTER, async () => openFormatter(extensionPath))); context.subscriptions.push(commands.registerCommand(Commands.CLEAN_WORKSPACE, () => cleanWorkspace(workspacePath))); @@ -389,7 +391,7 @@ function setIncompleteClasspathSeverity(severity: string) { const config = getJavaConfiguration(); const section = 'errors.incompleteClasspath.severity'; config.update(section, severity, true).then( - () => console.log(section + ' globally set to ' + severity), + () => console.log(`${section} globally set to ${severity}`), (error) => console.log(error) ); } @@ -417,7 +419,7 @@ function setProjectConfigurationUpdate(languageClient: LanguageClient, uri: Uri, const st = FeatureStatus[status]; config.update(section, st).then( - () => console.log(section + ' set to ' + st), + () => console.log(`${section} set to ${st}`), (error) => console.log(error) ); if (status !== FeatureStatus.disabled) { @@ -442,16 +444,15 @@ function getTempWorkspace() { } function makeRandomHexString(length) { - let chars = ['0', '1', '2', '3', '4', '5', '6', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; + const chars = ['0', '1', '2', '3', '4', '5', '6', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; let result = ''; for (let i = 0; i < length; i++) { - let idx = Math.floor(chars.length * Math.random()); + const idx = Math.floor(chars.length * Math.random()); result += chars[idx]; } return result; } - async function cleanWorkspace(workspacePath) { const doIt = 'Restart and delete'; window.showWarningMessage('Are you sure you want to clean the Java language server workspace?', 'Cancel', doIt).then(selection => { @@ -465,8 +466,8 @@ async function cleanWorkspace(workspacePath) { function deleteDirectory(dir) { if (fs.existsSync(dir)) { - fs.readdirSync(dir).forEach(function (child) { - let entry = path.join(dir, child); + fs.readdirSync(dir).forEach((child) => { + const entry = path.join(dir, child); if (fs.lstatSync(entry).isDirectory()) { deleteDirectory(entry); } else { @@ -478,7 +479,7 @@ function deleteDirectory(dir) { } function openServerLogFile(workspacePath): Thenable { - let serverLogFile = path.join(workspacePath, '.metadata', '.log'); + const serverLogFile = path.join(workspacePath, '.metadata', '.log'); if (!serverLogFile) { return window.showWarningMessage('Java Language Server has not started logging.').then(() => false); } @@ -501,27 +502,27 @@ function openServerLogFile(workspacePath): Thenable { } async function openFormatter(extensionPath) { - let defaultFormatter = path.join(extensionPath, 'formatters', 'eclipse-formatter.xml'); - let formatterUrl: string = getJavaConfiguration().get('format.settings.url'); + const defaultFormatter = path.join(extensionPath, 'formatters', 'eclipse-formatter.xml'); + const formatterUrl: string = getJavaConfiguration().get('format.settings.url'); if (formatterUrl && formatterUrl.length > 0) { if (isRemote(formatterUrl)) { commands.executeCommand(Commands.OPEN_BROWSER, Uri.parse(formatterUrl)); } else { - let document = getPath(formatterUrl); + const document = getPath(formatterUrl); if (document && fs.existsSync(document)) { return openDocument(extensionPath, document, defaultFormatter, null); } } } - let global = workspace.workspaceFolders === undefined; - let fileName = formatterUrl || 'eclipse-formatter.xml'; + const global = workspace.workspaceFolders === undefined; + const fileName = formatterUrl || 'eclipse-formatter.xml'; let file; let relativePath; if (!global) { file = path.join(workspace.workspaceFolders[0].uri.fsPath, fileName); relativePath = fileName; } else { - let root = path.join(extensionPath, '..', 'redhat.java'); + const root = path.join(extensionPath, '..', 'redhat.java'); if (!fs.existsSync(root)) { fs.mkdirSync(root); } @@ -542,7 +543,7 @@ async function openFormatter(extensionPath) { function getPath(f) { if (workspace.workspaceFolders && !path.isAbsolute(f)) { workspace.workspaceFolders.forEach(wf => { - let file = path.resolve(wf.uri.path, f); + const file = path.resolve(wf.uri.path, f); if (fs.existsSync(file)) { return file; } @@ -585,18 +586,18 @@ async function addFormatter(extensionPath, formatterUrl, defaultFormatter, relat }; await window.showInputBox(options).then(f => { if (f) { - let global = workspace.workspaceFolders === undefined; + const global = workspace.workspaceFolders === undefined; if (isRemote(f)) { commands.executeCommand(Commands.OPEN_BROWSER, Uri.parse(f)); getJavaConfiguration().update('format.settings.url', f, global); } else { if (!path.isAbsolute(f)) { - let fileName = f; + const fileName = f; if (!global) { f = path.join(workspace.workspaceFolders[0].uri.fsPath, fileName); relativePath = fileName; } else { - let root = path.join(extensionPath, '..', 'redhat.java'); + const root = path.join(extensionPath, '..', 'redhat.java'); if (!fs.existsSync(root)) { fs.mkdirSync(root); } @@ -607,14 +608,14 @@ async function addFormatter(extensionPath, formatterUrl, defaultFormatter, relat } getJavaConfiguration().update('format.settings.url', (relativePath !== null ? relativePath : f), global); if (!fs.existsSync(f)) { - let name = relativePath !== null ? relativePath : f; - let msg = '\'' + name + '\' does not exist. Do you want to create it?'; - let action = 'Yes'; + const name = relativePath !== null ? relativePath : f; + const msg = `' ${name} ' does not exist. Do you want to create it?`; + const action = 'Yes'; window.showWarningMessage(msg, action, 'No').then((selection) => { if (action === selection) { fs.createReadStream(defaultFormatter) - .pipe(fs.createWriteStream(f)) - .on('finish', () => openDocument(extensionPath, f, defaultFormatter, relativePath)); + .pipe(fs.createWriteStream(f)) + .on('finish', () => openDocument(extensionPath, f, defaultFormatter, relativePath)); } }); } else { @@ -626,20 +627,20 @@ async function addFormatter(extensionPath, formatterUrl, defaultFormatter, relat } export async function applyWorkspaceEdit(obj, languageClient) { - let edit = languageClient.protocol2CodeConverter.asWorkspaceEdit(obj); + const edit = languageClient.protocol2CodeConverter.asWorkspaceEdit(obj); if (edit) { await workspace.applyEdit(edit); // By executing the range formatting command to correct the indention according to the VS Code editor settings. // More details, see: https://github.com/redhat-developer/vscode-java/issues/557 try { - let currentEditor = window.activeTextEditor; + const currentEditor = window.activeTextEditor; // If the Uri path of the edit change is not equal to that of the active editor, we will skip the range formatting if (currentEditor.document.uri.fsPath !== edit.entries()[0][0].fsPath) { return; } - let cursorPostion = currentEditor.selection.active; + const cursorPostion = currentEditor.selection.active; // Get the array of all the changes - let changes = edit.entries()[0][1]; + const changes = edit.entries()[0][1]; // Get the position information of the first change let startPosition = new Position(changes[0].range.start.line, changes[0].range.start.character); let lineOffsets = changes[0].newText.split(/\r?\n/).length - 1; @@ -662,7 +663,7 @@ export async function applyWorkspaceEdit(obj, languageClient) { } async function executeRangeFormat(editor, startPosition, lineOffset) { - let endPosition = editor.document.positionAt(editor.document.offsetAt(new Position(startPosition.line + lineOffset + 1, 0)) - 1); + const endPosition = editor.document.positionAt(editor.document.offsetAt(new Position(startPosition.line + lineOffset + 1, 0)) - 1); editor.selection = new Selection(startPosition, endPosition); await commands.executeCommand('editor.action.formatSelection'); } diff --git a/src/javaServerStarter.ts b/src/javaServerStarter.ts index 2c226e19f..633001fc9 100644 --- a/src/javaServerStarter.ts +++ b/src/javaServerStarter.ts @@ -11,20 +11,20 @@ declare var v8debug; const DEBUG = (typeof v8debug === 'object') || startedInDebugMode(); export function prepareExecutable(requirements: RequirementsData, workspacePath, javaConfig): Executable { - let executable: Executable = Object.create(null); - let options: ExecutableOptions = Object.create(null); + const executable: Executable = Object.create(null); + const options: ExecutableOptions = Object.create(null); options.env = process.env; options.stdio = 'pipe'; executable.options = options; executable.command = path.resolve(requirements.java_home + '/bin/java'); executable.args = prepareParams(requirements, javaConfig, workspacePath); - console.log('Starting Java server with: ' + executable.command + ' ' + executable.args.join(' ')); + console.log(`Starting Java server with: ${executable.command} ${executable.args.join(' ')}`); return executable; } export function awaitServerConnection(port): Thenable { - let addr = parseInt(port); + const addr = parseInt(port); return new Promise((res, rej) => { - let server = net.createServer(stream => { + const server = net.createServer(stream => { server.close(); console.log('JDT LS connection established on port ' + addr); res({ reader: stream, writer: stream }); @@ -38,9 +38,8 @@ export function awaitServerConnection(port): Thenable { }); } - function prepareParams(requirements: RequirementsData, javaConfiguration, workspacePath): string[] { - let params: string[] = []; + const params: string[] = []; if (DEBUG) { params.push('-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=1044,quiet=y'); // suspend=y is the default. Use this form if you need to debug the server startup code: @@ -61,12 +60,12 @@ function prepareParams(requirements: RequirementsData, javaConfiguration, worksp params.push('-Dlog.level=ALL'); } - let vmargs = javaConfiguration.get('jdt.ls.vmargs', ''); + const vmargs = javaConfiguration.get('jdt.ls.vmargs', ''); const encodingKey = '-Dfile.encoding='; if (vmargs.indexOf(encodingKey) < 0) { params.push(encodingKey + getJavaEncoding()); } - if (os.platform() == 'win32') { + if (os.platform() === 'win32') { const watchParentProcess = '-DwatchParentProcess='; if (vmargs.indexOf(watchParentProcess) < 0) { params.push(watchParentProcess + 'false'); @@ -74,15 +73,15 @@ function prepareParams(requirements: RequirementsData, javaConfiguration, worksp } parseVMargs(params, vmargs); - let server_home: string = path.resolve(__dirname, '../server'); - let launchersFound: Array = glob.sync('**/plugins/org.eclipse.equinox.launcher_*.jar', { cwd: server_home }); + const serverHome: string = path.resolve(__dirname, '../server'); + const launchersFound: Array = glob.sync('**/plugins/org.eclipse.equinox.launcher_*.jar', { cwd: serverHome }); if (launchersFound.length) { - params.push('-jar'); params.push(path.resolve(server_home, launchersFound[0])); + params.push('-jar'); params.push(path.resolve(serverHome, launchersFound[0])); } else { return null; } - //select configuration directory according to OS + // select configuration directory according to OS let configDir = 'config_win'; if (process.platform === 'darwin') { configDir = 'config_mac'; @@ -94,28 +93,27 @@ function prepareParams(requirements: RequirementsData, javaConfiguration, worksp return params; } - function startedInDebugMode(): boolean { - let args = (process as any).execArgv; + const args = (process as any).execArgv; if (args) { return args.some((arg) => /^--debug=?/.test(arg) || /^--debug-brk=?/.test(arg) || /^--inspect-brk=?/.test(arg)); } return false; } -//exported for tests +// exported for tests export function parseVMargs(params: any[], vmargsLine: string) { if (!vmargsLine) { return; } - let vmargs = vmargsLine.match(/(?:[^\s"]+|"[^"]*")+/g); + const vmargs = vmargsLine.match(/(?:[^\s"]+|"[^"]*")+/g); if (vmargs === null) { return; } vmargs.forEach(arg => { - //remove all standalone double quotes - arg = arg.replace(/(\\)?"/g, function ($0, $1) { return ($1 ? $0 : ''); }); - //unescape all escaped double quotes + // remove all standalone double quotes + arg = arg.replace(/(\\)?"/g, ($0, $1) => { return ($1 ? $0 : ''); }); + // unescape all escaped double quotes arg = arg.replace(/(\\)"/g, '"'); if (params.indexOf(arg) < 0) { params.push(arg); diff --git a/src/plugin.ts b/src/plugin.ts index b15cf98df..b930e230e 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -9,12 +9,12 @@ let existingExtensions: Array; export function collectJavaExtensions(extensions: vscode.Extension[]): string[] { const result = []; if (extensions && extensions.length) { - for (let extension of extensions) { - let contributesSection = extension.packageJSON['contributes']; + for (const extension of extensions) { + const contributesSection = extension.packageJSON['contributes']; if (contributesSection) { - let javaExtensions = contributesSection['javaExtensions']; + const javaExtensions = contributesSection['javaExtensions']; if (Array.isArray(javaExtensions) && javaExtensions.length) { - for (let javaExtensionPath of javaExtensions) { + for (const javaExtensionPath of javaExtensions) { result.push(path.resolve(extension.extensionPath, javaExtensionPath)); } } @@ -32,7 +32,7 @@ export function onExtensionChange(extensions: vscode.Extension[]) { } const oldExtensions = new Set(existingExtensions.slice()); const newExtensions = collectJavaExtensions(extensions); - let hasChanged = ( oldExtensions.size != newExtensions.length); + let hasChanged = ( oldExtensions.size !== newExtensions.length); if (!hasChanged) { for (const newExtension of newExtensions) { if (!oldExtensions.has(newExtension)) { diff --git a/src/protocol.ts b/src/protocol.ts index b87474ffd..06e4a9440 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -73,15 +73,15 @@ export interface ActionableMessage { } export namespace StatusNotification { - export const type = new NotificationType('language/status'); + export const type = new NotificationType('language/status'); } export namespace ProgressReportNotification { - export const type = new NotificationType('language/progressReport'); + export const type = new NotificationType('language/progressReport'); } export namespace ClassFileContentsRequest { - export const type= new RequestType ('java/classFileContents'); + export const type = new RequestType ('java/classFileContents'); } export namespace ProjectConfigurationUpdateRequest { @@ -100,7 +100,6 @@ export namespace ExecuteClientCommandRequest { export const type = new RequestType('workspace/executeClientCommand'); } - export namespace SendNotificationRequest { export const type = new RequestType('workspace/notify'); } @@ -206,4 +205,4 @@ export interface GenerateToStringParams { export namespace GenerateToStringRequest { export const type = new RequestType('java/generateToString'); -} \ No newline at end of file +} diff --git a/src/requirements.ts b/src/requirements.ts index 57c2c99c0..0c6a684d0 100644 --- a/src/requirements.ts +++ b/src/requirements.ts @@ -30,9 +30,9 @@ interface ErrorData { * */ export async function resolveRequirements(): Promise { - let java_home = await checkJavaRuntime(); - let javaVersion = await checkJavaVersion(java_home); - return Promise.resolve({ 'java_home': java_home, 'java_version': javaVersion }); + const javaHome = await checkJavaRuntime(); + const javaVersion = await checkJavaVersion(javaHome); + return Promise.resolve({ java_home: javaHome, java_version: javaVersion }); } function checkJavaRuntime(): Promise { @@ -60,14 +60,14 @@ function checkJavaRuntime(): Promise { if (pathExists.sync(path.resolve(javaHome, JAVAC_FILENAME))) { msg = `'bin' should be removed from the ${source} (${javaHome})`; } else { - msg = `The ${source} (${javaHome}) does not point to a JDK.` + msg = `The ${source} (${javaHome}) does not point to a JDK.`; } invalidJavaHome(reject, msg); } return resolve(javaHome); } - //No settings, let's try to detect as last resort. - findJavaHome(function (err, home) { + // No settings, let's try to detect as last resort. + findJavaHome((err, home) => { if (err) { openJDKDownload(reject, 'Java runtime (JDK, not JRE) could not be located'); } @@ -83,10 +83,10 @@ function readJavaConfig(): string { return config.get('java.home', null); } -function checkJavaVersion(java_home: string): Promise { +function checkJavaVersion(javaHome: string): Promise { return new Promise((resolve, reject) => { - cp.execFile(java_home + '/bin/java', ['-version'], {}, (error, stdout, stderr) => { - let javaVersion = parseMajorVersion(stderr); + cp.execFile(javaHome + '/bin/java', ['-version'], {}, (error, stdout, stderr) => { + const javaVersion = parseMajorVersion(stderr); if (javaVersion < 8) { openJDKDownload(reject, 'Java 8 or more recent is required to run. Please download and install a recent JDK'); } else { @@ -103,12 +103,12 @@ export function parseMajorVersion(content: string): number { return 0; } let version = match[1]; - //Ignore '1.' prefix for legacy Java versions + // Ignore '1.' prefix for legacy Java versions if (version.startsWith('1.')) { version = version.substring(2); } - //look into the interesting bits now + // look into the interesting bits now regexp = /\d+/g; match = regexp.exec(version); let javaVersion = 0; diff --git a/src/settings.ts b/src/settings.ts index 4cdafc72a..3cf0b2562 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -5,7 +5,6 @@ import { LanguageClient } from 'vscode-languageclient'; import { Commands } from './commands'; import { getJavaConfiguration } from './utils'; - const DEFAULT_HIDDEN_FILES: string[] = ['**/.classpath', '**/.project', '**/.settings', '**/.factorypath']; const changeItem = { @@ -23,14 +22,14 @@ export function onConfigurationChange() { if (!params.affectsConfiguration('java')) { return; } - let newConfig = getJavaConfiguration(); + const newConfig = getJavaConfiguration(); if (newConfig.get(EXCLUDE_FILE_CONFIG)) { excludeProjectSettingsFiles(); } if (hasJavaConfigChanged(oldConfig, newConfig)) { - let msg = 'Java Language Server configuration changed, please restart VS Code.'; - let action = 'Restart Now'; - let restartId = Commands.RELOAD_WINDOW; + const msg = 'Java Language Server configuration changed, please restart VS Code.'; + const action = 'Restart Now'; + const restartId = Commands.RELOAD_WINDOW; oldConfig = newConfig; window.showWarningMessage(msg, action).then((selection) => { if (action === selection) { @@ -86,7 +85,7 @@ function excludeProjectSettingsFilesForWorkspace(workspaceUri: Uri) { config.update('exclude', excludedInspectedValue.workspaceValue, ConfigurationTarget.Workspace); } else if (result === changeItem.never) { const storeInWorkspace = getJavaConfiguration().inspect(EXCLUDE_FILE_CONFIG).workspaceValue; - getJavaConfiguration().update(EXCLUDE_FILE_CONFIG, false, storeInWorkspace?ConfigurationTarget.Workspace:ConfigurationTarget.Global); + getJavaConfiguration().update(EXCLUDE_FILE_CONFIG, false, storeInWorkspace?ConfigurationTarget.Workspace: ConfigurationTarget.Global); } }); } @@ -105,13 +104,13 @@ function hasConfigKeyChanged(key, oldConfig, newConfig) { export function getJavaEncoding(): string { const config = workspace.getConfiguration(); - const languageConfig = config.get('[java]') + const languageConfig = config.get('[java]'); let javaEncoding = null; - if (languageConfig != null) { + if (languageConfig) { javaEncoding = languageConfig['files.encoding']; } - if (javaEncoding == null) { + if (!javaEncoding) { javaEncoding = config.get('files.encoding', 'UTF-8'); } return javaEncoding; -} \ No newline at end of file +} diff --git a/src/sourceAction.ts b/src/sourceAction.ts index a7d437291..5b9ce55ae 100644 --- a/src/sourceAction.ts +++ b/src/sourceAction.ts @@ -1,6 +1,6 @@ 'use strict'; -import { commands, window, ExtensionContext, Range, ViewColumn, Uri, Disposable} from 'vscode'; +import { commands, window, ExtensionContext, Range, ViewColumn, Uri, Disposable } from 'vscode'; import { CodeActionParams, LanguageClient } from 'vscode-languageclient'; import { Commands } from './commands'; import { applyWorkspaceEdit } from './extension'; @@ -117,7 +117,7 @@ function registerChooseImportCommand(context: ExtensionContext): void { const chosen: ImportCandidate[] = []; const fileUri: Uri = Uri.parse(uri); for (let i = 0; i < selections.length; i++) { - const selection : ImportSelection = selections[i]; + const selection: ImportSelection = selections[i]; // Move the cursor to the code line with ambiguous import choices. await window.showTextDocument(fileUri, { preserveFocus: true, selection: selection.range, viewColumn: ViewColumn.One }); const candidates: ImportCandidate[] = selection.candidates; diff --git a/test/extension.test.ts b/test/extension.test.ts index c9ad7b20e..eac830f1d 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -5,7 +5,7 @@ import * as path from 'path'; import * as plugin from '../src/plugin'; import * as java from '../src/javaServerStarter'; import * as requirements from '../src/requirements'; -import {Commands} from '../src/commands'; +import { Commands } from '../src/commands'; suite('Java Language Extension', () => { @@ -48,16 +48,16 @@ suite('Java Language Extension', () => { Commands.CHOOSE_IMPORTS, Commands.GENERATE_TOSTRING_PROMPT ]; - let foundJavaCommands = commands.filter(function(value){ + const foundJavaCommands = commands.filter(function(value) { return JAVA_COMMANDS.indexOf(value)>=0 || value.startsWith('java.'); }); - assert.equal(foundJavaCommands.length ,JAVA_COMMANDS.length, 'Some Java commands are not registered properly or a new command is not added to the test'); + assert.equal(foundJavaCommands.length , JAVA_COMMANDS.length, 'Some Java commands are not registered properly or a new command is not added to the test'); }); }); test('should parse VM arguments', function () { - let userArgs = '-Xmx512m -noverify -Dfoo=\"something with blank\" '; - let vmArgs = ['-noverify', 'foo']; + const userArgs = '-Xmx512m -noverify -Dfoo=\"something with blank\" '; + const vmArgs = ['-noverify', 'foo']; java.parseVMargs(vmArgs, userArgs); @@ -69,8 +69,8 @@ suite('Java Language Extension', () => { }); test('should parse VM arguments with spaces', function () { - let userArgs = '-javaagent:"C:\\Program Files\\Java\\lombok.jar" -Xbootclasspath/a:"C:\\Program Files\\Java\\lombok.jar" -Dfoo="Some \\"crazy\\" stuff"'; - let vmArgs = []; + const userArgs = '-javaagent:"C:\\Program Files\\Java\\lombok.jar" -Xbootclasspath/a:"C:\\Program Files\\Java\\lombok.jar" -Dfoo="Some \\"crazy\\" stuff"'; + const vmArgs = []; java.parseVMargs(vmArgs, userArgs); @@ -98,7 +98,7 @@ suite('Java Language Extension', () => { }); test('should parse Java version', function () { - //Test boundaries + // Test boundaries assert.equal(requirements.parseMajorVersion(null), 0); assert.equal(requirements.parseMajorVersion(''), 0); assert.equal(requirements.parseMajorVersion('foo'), 0); @@ -106,7 +106,7 @@ suite('Java Language Extension', () => { assert.equal(requirements.parseMajorVersion('version ""'), 0); assert.equal(requirements.parseMajorVersion('version "NaN"'), 0); - //Test the real stuff + // Test the real stuff assert.equal(requirements.parseMajorVersion('version "1.7"'), 7); assert.equal(requirements.parseMajorVersion('version "1.8.0_151"'), 8); assert.equal(requirements.parseMajorVersion('version "9"'), 9); diff --git a/tsconfig.json b/tsconfig.json index 4f5c0d087..e3f76fb10 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,11 +7,12 @@ "module": "commonjs", "moduleResolution": "node", "outDir": "out", - "sourceMap": true + "sourceMap": true, + "plugins": [{ "name": "typescript-tslint-plugin" }] }, "exclude": [ "node_modules", "server", ".vscode-test" ] -} \ No newline at end of file +} diff --git a/tslint.json b/tslint.json index f17c0afe2..7898c2182 100644 --- a/tslint.json +++ b/tslint.json @@ -1,22 +1,57 @@ { - "defaultSeverity": "error", - "rules": { - "no-unused-expression": true, - "no-duplicate-variable": true, - "curly": true, - "class-name": true, - "semicolon": true, - "triple-equals": true, - "quotemark": [true, "single", "avoid-escape"], - "no-debugger": true, - "no-empty": true, - "no-var-keyword": true, - "no-unsafe-finally": true, - "new-parens":true, - "no-duplicate-imports": true, - "deprecation":true, - "no-unsafe-any":true, - "no-string-throw":true, - "no-require-imports": true - } + "rules": { + "encoding": true, + "only-arrow-functions": [ + true, "allow-declarations", "allow-named-functions" + ], + "no-var-keyword": true, + "object-literal-key-quotes": [ + true, "as-needed" + ], + "comment-format": [true, "check-space"], + "curly": [true, "ignore-same-line"], + "triple-equals": true, + "prefer-const": true, + "prefer-for-of": true, + "variable-name": [ + true, + "allow-leading-underscore", + "allow-pascal-case", + "ban-keywords", + "check-format" + ], + "switch-final-break": [true, "always"], + "prefer-template": [true, "allow-single-concat"], + "semicolon": [true, "always"], + "no-consecutive-blank-lines": true, + "no-boolean-literal-compare": true, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-module", + "check-separator", + "check-type", + "check-preblock" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + }, + { + "call-signature": "onespace", + "index-signature": "onespace", + "parameter": "onespace", + "property-declaration": "onespace", + "variable-declaration": "onespace" + } + ], + "no-trailing-whitespace": true, + "no-debugger": true + } } From bc2909b43204a7522329870920078280d29ebce6 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Mon, 15 Apr 2019 23:15:04 -0400 Subject: [PATCH 0003/1031] Add changelog for 0.43.0 Signed-off-by: Fred Bricon --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6afba4244..57bcdb972 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log + +## 0.43.0 (April 16th, 2019) +* enhancement - optimize server initialization. See [#869](https://github.com/redhat-developer/vscode-java/pull/869). +* enhancement - download Java sources lazily for Maven projects. See [#870](https://github.com/redhat-developer/vscode-java/pull/870). +* enhancement - added `Generate toString()...` source action. See [#873](https://github.com/redhat-developer/vscode-java/pull/873). +* bug fix - completion cache resets after file recompilation resulting in slow code completion. See [JLS#847](https://github.com/eclipse/eclipse.jdt.ls/issues/847). + ## 0.42.1 (April 1st, 2019) * bug fix - fixed java.lang.UnsupportedClassVersionError when trying to run/test standalone code. See [#801](https://github.com/redhat-developer/vscode-java/issues/801). From b2db0b14b5fc66585171b8d6ce5e8a146f349f9b Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Tue, 16 Apr 2019 18:22:27 -0400 Subject: [PATCH 0004/1031] Update changelog for the 0.43.0 release Signed-off-by: Fred Bricon --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57bcdb972..17a420e4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,13 @@ # Change Log -## 0.43.0 (April 16th, 2019) +## 0.43.0 (April 17th, 2019) * enhancement - optimize server initialization. See [#869](https://github.com/redhat-developer/vscode-java/pull/869). * enhancement - download Java sources lazily for Maven projects. See [#870](https://github.com/redhat-developer/vscode-java/pull/870). * enhancement - added `Generate toString()...` source action. See [#873](https://github.com/redhat-developer/vscode-java/pull/873). +* enhancement - show more detailed progress report on startup. See [#883](https://github.com/redhat-developer/vscode-java/issues/883). * bug fix - completion cache resets after file recompilation resulting in slow code completion. See [JLS#847](https://github.com/eclipse/eclipse.jdt.ls/issues/847). +* bug fix - fix jar detection on windows, for invisible projects. See [#882](https://github.com/redhat-developer/vscode-java/issues/882). ## 0.42.1 (April 1st, 2019) * bug fix - fixed java.lang.UnsupportedClassVersionError when trying to run/test standalone code. See [#801](https://github.com/redhat-developer/vscode-java/issues/801). From cf34bd31df0918ef38717753298c96d385beba6f Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Mon, 29 Apr 2019 16:49:53 -0400 Subject: [PATCH 0005/1031] Upversion to 0.44.0 Signed-off-by: Fred Bricon --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3aa44f582..f8caad710 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "java", - "version": "0.43.0", + "version": "0.44.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 836b13f89..a121dc879 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "author": "Red Hat", "icon": "icons/icon128.png", "license": "EPL-1.0", - "version": "0.43.0", + "version": "0.44.0", "publisher": "redhat", "bugs": "https://github.com/redhat-developer/vscode-java/issues", "preview": true, From 668699636953a3c644f18154d011164cbd77c4cc Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Mon, 29 Apr 2019 14:09:56 +0800 Subject: [PATCH 0006/1031] Enable advanced "Generate getters and setters..." source action Signed-off-by: Jinbo Wang --- src/commands.ts | 4 ++++ src/extension.ts | 3 ++- src/protocol.ts | 20 ++++++++++++++++++++ src/sourceAction.ts | 40 +++++++++++++++++++++++++++++++++++++++- test/extension.test.ts | 3 ++- 5 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index 71517710a..4f92c2894 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -126,4 +126,8 @@ export namespace Commands { * Generate toString(). */ export const GENERATE_TOSTRING_PROMPT = 'java.action.generateToStringPrompt'; + /** + * Generate Getters and Setters. + */ + export const GENERATE_ACCESSORS_PROMPT = 'java.action.generateAccessorsPrompt'; } \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index e8523d819..c3962cd58 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -68,7 +68,8 @@ export function activate(context: ExtensionContext): Promise { overrideMethodsPromptSupport: true, hashCodeEqualsPromptSupport: true, advancedOrganizeImportsSupport: true, - generateToStringPromptSupport: true + generateToStringPromptSupport: true, + advancedGenerateAccessorsSupport: true, }, triggerFiles: getTriggerFiles() }, diff --git a/src/protocol.ts b/src/protocol.ts index 06e4a9440..3b15c2a2e 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -206,3 +206,23 @@ export interface GenerateToStringParams { export namespace GenerateToStringRequest { export const type = new RequestType('java/generateToString'); } + +export interface AccessorField { + fieldName: string; + isStatic: boolean; + generateGetter: boolean; + generateSetter: boolean; +} + +export namespace ResolveUnimplementedAccessorsRequest { + export const type = new RequestType('java/resolveUnimplementedAccessors'); +} + +export interface GenerateAccessorsParams { + context: CodeActionParams; + accessors: AccessorField[]; +} + +export namespace GenerateAccessorsRequest { + export const type = new RequestType('java/generateAccessors'); +} diff --git a/src/sourceAction.ts b/src/sourceAction.ts index 5b9ce55ae..e5b346030 100644 --- a/src/sourceAction.ts +++ b/src/sourceAction.ts @@ -5,7 +5,7 @@ import { CodeActionParams, LanguageClient } from 'vscode-languageclient'; import { Commands } from './commands'; import { applyWorkspaceEdit } from './extension'; import { ListOverridableMethodsRequest, AddOverridableMethodsRequest, CheckHashCodeEqualsStatusRequest, GenerateHashCodeEqualsRequest, -OrganizeImportsRequest, ImportCandidate, ImportSelection, GenerateToStringRequest, CheckToStringStatusRequest, VariableField } from './protocol'; +OrganizeImportsRequest, ImportCandidate, ImportSelection, GenerateToStringRequest, CheckToStringStatusRequest, VariableField, ResolveUnimplementedAccessorsRequest, GenerateAccessorsRequest } from './protocol'; export function registerCommands(languageClient: LanguageClient, context: ExtensionContext) { registerOverrideMethodsCommand(languageClient, context); @@ -13,6 +13,7 @@ export function registerCommands(languageClient: LanguageClient, context: Extens registerOrganizeImportsCommand(languageClient, context); registerChooseImportCommand(context); registerGenerateToStringCommand(languageClient, context); + registerGenerateAccessorsCommand(languageClient, context); } function registerOverrideMethodsCommand(languageClient: LanguageClient, context: ExtensionContext): void { @@ -202,3 +203,40 @@ function registerGenerateToStringCommand(languageClient: LanguageClient, context applyWorkspaceEdit(workspaceEdit, languageClient); })); } + +function registerGenerateAccessorsCommand(languageClient: LanguageClient, context: ExtensionContext): void { + context.subscriptions.push(commands.registerCommand(Commands.GENERATE_ACCESSORS_PROMPT, async (params: CodeActionParams) => { + const accessors = await languageClient.sendRequest(ResolveUnimplementedAccessorsRequest.type, params); + if (!accessors || !accessors.length) { + return; + } + + const accessorItems = accessors.map((accessor) => { + const description = []; + if (accessor.generateGetter) { + description.push('getter'); + } + if (accessor.generateSetter) { + description.push('setter'); + } + return { + label: accessor.fieldName, + description: (accessor.isStatic?'static ':'')+ description.join(', '), + originalField: accessor, + }; + }); + const selectedAccessors = await window.showQuickPick(accessorItems, { + canPickMany: true, + placeHolder: 'Select the fields to generate getters and setters.' + }); + if (!selectedAccessors.length) { + return; + } + + const workspaceEdit = await languageClient.sendRequest(GenerateAccessorsRequest.type, { + context: params, + accessors: selectedAccessors.map((item) => item.originalField), + }); + applyWorkspaceEdit(workspaceEdit, languageClient); + })); +} diff --git a/test/extension.test.ts b/test/extension.test.ts index eac830f1d..3c963246a 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -46,7 +46,8 @@ suite('Java Language Extension', () => { Commands.OPEN_JSON_SETTINGS, Commands.ORGANIZE_IMPORTS, Commands.CHOOSE_IMPORTS, - Commands.GENERATE_TOSTRING_PROMPT + Commands.GENERATE_TOSTRING_PROMPT, + Commands.GENERATE_ACCESSORS_PROMPT ]; const foundJavaCommands = commands.filter(function(value) { return JAVA_COMMANDS.indexOf(value)>=0 || value.startsWith('java.'); From 5bc3ebc709a535a80a172a14d54d9afe894a43f3 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Thu, 2 May 2019 15:35:23 -0400 Subject: [PATCH 0007/1031] Changelog for the 0.44.0 release Signed-off-by: Fred Bricon --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17a420e4d..96c0fc188 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Change Log +## 0.44.0 (May 2nd, 2019) +* enhancement - show more progress details of workspace jobs. See [#896](https://github.com/redhat-developer/vscode-java/issues/896). +* enhancement - added advanced `Generate getters and setters...` source action. See [#907](https://github.com/redhat-developer/vscode-java/pull/907). +* enhancement - batch Maven project imports when available ram < 1.5GB and number of projects > 50, to reduce memory consumption. See [JLS#982](https://github.com/eclipse/eclipse.jdt.ls/issues/982). +* enhancement - tentative workaround for poor resource refresh performance on Windows. See [JLS#1001](https://github.com/eclipse/eclipse.jdt.ls/pull/1001). +* enhancement - log resource path and line number of build errors. See [JLS#1013](https://github.com/eclipse/eclipse.jdt.ls/issues/1013). +* bug fix - update classpath when jar files are modified. See [#775](https://github.com/redhat-developer/vscode-java/issues/775). +* bug fix - remove ellipsis on `Create getter and setter for` label. See [#908](https://github.com/redhat-developer/vscode-java/issues/908). +* bug fix - fixed NPE when peeking implementation on generic types. See [JLS#1004](https://github.com/eclipse/eclipse.jdt.ls/issues/1004). +* bug fix - only return signature help on method invocation and javadoc reference. See [JLS#1009](https://github.com/eclipse/eclipse.jdt.ls/issues/1009). +* bug fix - properly detect active signature in signature help. See [JLS#1017](https://github.com/eclipse/eclipse.jdt.ls/issues/1017). +* bug fix - use proper kinds for interfaces, enums and constants, in completion and document symbols. See [JLS#1012](https://github.com/eclipse/eclipse.jdt.ls/issues/1012). ## 0.43.0 (April 17th, 2019) * enhancement - optimize server initialization. See [#869](https://github.com/redhat-developer/vscode-java/pull/869). From 5c01423a2cb7cf7eb19a4da40bdcd510f3d12535 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Tue, 7 May 2019 11:33:44 -0400 Subject: [PATCH 0008/1031] Rework command and extension activation conditions - early registration of `open output command`. Fixes #914 - activate extension when .classpath is found at the root - only activate some commands in the palette if the server is started - removed extension activation by commands needing the server to be started in the 1st place - fixed check for non-existing server log, in the `open server log` command Signed-off-by: Fred Bricon --- package.json | 21 ++++++++++++++------- src/extension.ts | 9 +++++---- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index a121dc879..d8442a54b 100644 --- a/package.json +++ b/package.json @@ -27,14 +27,9 @@ ], "activationEvents": [ "onLanguage:java", - "onCommand:java.show.references", - "onCommand:java.show.implementations", - "onCommand:java.open.output", - "onCommand:java.open.serverLog", - "onCommand:java.execute.workspaceCommand", - "onCommand:java.projectConfiguration.update", "workspaceContains:pom.xml", - "workspaceContains:build.gradle" + "workspaceContains:build.gradle", + "workspaceContains:.classpath" ], "main": "./dist/extension", "contributes": { @@ -439,6 +434,18 @@ } ], "commandPalette": [ + { + "command": "java.projectConfiguration.update", + "when": "javaLSReady" + }, + { + "command": "java.workspace.compile", + "when": "javaLSReady" + }, + { + "command": "java.project.listSourcePaths", + "when": "javaLSReady" + }, { "command": "java.project.updateSourceAttachment", "when": "false" diff --git a/src/extension.ts b/src/extension.ts index c3962cd58..90345b1fb 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -105,6 +105,7 @@ export function activate(context: ExtensionContext): Promise { // Create the language client and start the client. languageClient = new LanguageClient('java', 'Language Support for Java', serverOptions, clientOptions); languageClient.registerProposedFeatures(); + languageClient.onReady().then(() => { languageClient.onNotification(StatusNotification.type, (report) => { switch (report.type) { @@ -186,9 +187,6 @@ export function activate(context: ExtensionContext): Promise { return commands.executeCommand(params.command, ...params.arguments); }); - context.subscriptions.push(commands.registerCommand(Commands.OPEN_OUTPUT, () => { - languageClient.outputChannel.show(ViewColumn.Three); - })); context.subscriptions.push(commands.registerCommand(Commands.SHOW_JAVA_REFERENCES, (uri: string, position: LSPosition, locations: LSLocation[]) => { commands.executeCommand(Commands.SHOW_REFERENCES, Uri.parse(uri), languageClient.protocol2CodeConverter.asPosition(position), locations.map(languageClient.protocol2CodeConverter.asLocation)); })); @@ -319,6 +317,9 @@ export function activate(context: ExtensionContext): Promise { languageClient.start(); // Register commands here to make it available even when the language client fails + + context.subscriptions.push(commands.registerCommand(Commands.OPEN_OUTPUT, () => languageClient.outputChannel.show(ViewColumn.Three))); + context.subscriptions.push(commands.registerCommand(Commands.OPEN_SERVER_LOG, () => openServerLogFile(workspacePath))); const extensionPath = context.extensionPath; @@ -481,7 +482,7 @@ function deleteDirectory(dir) { function openServerLogFile(workspacePath): Thenable { const serverLogFile = path.join(workspacePath, '.metadata', '.log'); - if (!serverLogFile) { + if (!fs.existsSync(serverLogFile)) { return window.showWarningMessage('Java Language Server has not started logging.').then(() => false); } From 91e7e42ffeb2f00ae801c124bdfc030d12279ae5 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Thu, 9 May 2019 11:12:37 -0400 Subject: [PATCH 0009/1031] Ensure build uses latest JDK Signed-off-by: Fred Bricon --- Jenkinsfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 2f9fda581..117d3556f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -14,6 +14,11 @@ def buildVscodeExtension(){ node('rhel7'){ stage 'Build JDT LS' + + env.JAVA_HOME="${tool 'openjdk-1.8'}" + env.PATH="${env.JAVA_HOME}/bin:${env.PATH}" + sh 'java -version' + git url: 'https://github.com/eclipse/eclipse.jdt.ls.git' sh "./mvnw clean verify -B -U -e -Pserver-distro -Dtycho.disableP2Mirrors=true -P!jboss-maven-repos,!redhat-ga-repository,!redhat-ea-repository" From a1519cfa0d0231e9fe62df5c1d1301bd31e67a14 Mon Sep 17 00:00:00 2001 From: Snjezana Peco Date: Wed, 8 May 2019 19:33:05 +0200 Subject: [PATCH 0010/1031] Optionally disable loading gradle from gradle wrapper Signed-off-by: Snjezana Peco --- README.md | 4 ++++ package.json | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b1629616a..4d2b5e8b4 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,10 @@ The following settings are supported: * `java.codeGeneration.toString.listArrayContents`: List contents of arrays instead of using native toString(). Defaults to `true`. * `java.codeGeneration.toString.limitElements`: Limit number of items in arrays/collections/maps to list, if 0 then list all. Defaults to `0`. +*New in 0.45.0:* +* `java.import.gradle.wrapper.enabled`: Enable/disable the Gradle wrapper. +* `java.import.gradle.version`: Gradle version, used if the gradle wrapper is missing or disabled. + Troubleshooting =============== 1. Check the status of the language tools on the lower right corner (marked with A on image below). diff --git a/package.json b/package.json index d8442a54b..7a6cd0d17 100644 --- a/package.json +++ b/package.json @@ -114,16 +114,28 @@ "description": "Traces the communication between VS Code and the Java language server.", "scope": "window" }, + "java.import.maven.enabled": { + "type": "boolean", + "default": true, + "description": "Enable/disable the Maven importer.", + "scope": "window" + }, "java.import.gradle.enabled": { "type": "boolean", "default": true, "description": "Enable/disable the Gradle importer.", "scope": "window" }, - "java.import.maven.enabled": { + "java.import.gradle.wrapper.enabled": { "type": "boolean", "default": true, - "description": "Enable/disable the Maven importer.", + "description": "Enable/disable the Gradle wrapper.", + "scope": "window" + }, + "java.import.gradle.version": { + "type": "string", + "default": null, + "description": "Gradle version, used if the gradle wrapper is missing or disabled.", "scope": "window" }, "java.maven.downloadSources": { From b502b193248483380b6c78b5d3c57a59048df34b Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Tue, 14 May 2019 21:16:54 -0400 Subject: [PATCH 0011/1031] Changelog for the 0.45.0 release Signed-off-by: Fred Bricon --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96c0fc188..1c1388271 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## 0.45.0 (May 15th, 2019) +* enhancement - optionally disable loading Gradle from wrapper and use a specific Gradle version. See [#875](https://github.com/redhat-developer/vscode-java/issues/875). +* enhancement - added `Assign parameters to new fields` source actions. See [JLS#167](https://github.com/eclipse/eclipse.jdt.ls/issues/167). +* enhancement - added code action for adding non existing constructor from super class. See [JLS#767](https://github.com/eclipse/eclipse.jdt.ls/issues/767). +* enhancement - use the `java.codeGeneration.generateComments` preference to generate comments for getter and setter. See [JLS#1024](https://github.com/eclipse/eclipse.jdt.ls/pull/1024). +* bug fix - fixed extension activation conditions causing some issues. See [#914](https://github.com/redhat-developer/vscode-java/issues/914) and [#915](https://github.com/redhat-developer/vscode-java/pull/915). +* bug fix - fixed failing build caused by a bad formatter URL. See [#916](https://github.com/redhat-developer/vscode-java/issues/916). +* bug fix - fixed NPE when closing a renamed file. See [JLS#993](https://github.com/eclipse/eclipse.jdt.ls/issues/993). +* bug fix - fixed Signature Help for constructors. See [JLS#1030](https://github.com/eclipse/eclipse.jdt.ls/issues/1030). + ## 0.44.0 (May 2nd, 2019) * enhancement - show more progress details of workspace jobs. See [#896](https://github.com/redhat-developer/vscode-java/issues/896). * enhancement - added advanced `Generate getters and setters...` source action. See [#907](https://github.com/redhat-developer/vscode-java/pull/907). From 3c6c2a5ca92a6ebe6ede990b71aa7d2543a74422 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Wed, 15 May 2019 18:18:12 -0400 Subject: [PATCH 0012/1031] Forgot to upversion to 0.45.0 Signed-off-by: Fred Bricon --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index f8caad710..31158451d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "java", - "version": "0.44.0", + "version": "0.45.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 7a6cd0d17..897edbc9c 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "author": "Red Hat", "icon": "icons/icon128.png", "license": "EPL-1.0", - "version": "0.44.0", + "version": "0.45.0", "publisher": "redhat", "bugs": "https://github.com/redhat-developer/vscode-java/issues", "preview": true, From f3f7d7ef6716e547e8c04aca7997baa8909876bd Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Thu, 16 May 2019 10:56:32 -0400 Subject: [PATCH 0013/1031] Upversion to 0.46.0 Signed-off-by: Fred Bricon --- README.md | 11 ++++------- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4d2b5e8b4..0e0df4500 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,8 @@ The following settings are supported: * `java.format.enabled` : Enable/disable the default Java formatter. * `java.contentProvider.preferred` : Preferred content provider (see 3rd party decompilers available in [vscode-java-decompiler](https://github.com/dgileadi/vscode-java-decompiler)). * `java.import.gradle.enabled` : Enable/disable the Gradle importer. +* `java.import.gradle.wrapper.enabled`: Enable/disable the Gradle wrapper. +* `java.import.gradle.version`: Gradle version, used if the gradle wrapper is missing or disabled. * `java.import.maven.enabled` : Enable/disable the Maven importer. * `java.autobuild.enabled` : Enable/disable the 'auto build'. * `java.maxConcurrentBuilds`: Set max simultaneous project builds. @@ -95,12 +97,10 @@ The following settings are supported: * `java.completion.guessMethodArguments` : When set to true, method arguments are guessed when a method is selected from as list of code assist proposals. * `java.completion.enabled` : Enable/disable code completion support. * `java.configuration.checkProjectSettingsExclusions`: Checks if the extension-generated project settings files (`.project`, `.classpath`, `.factorypath`, `.settings/`) should be excluded from the file explorer. Defaults to `true`. -* `java.codeGeneration.hashCodeEquals.useJava7Objects`: Use Objects.hash and Objects.equals when generating the hashCode and equals methods. This setting only applies to Java 7 and higher. Defaults to `false`. -* `java.codeGeneration.hashCodeEquals.useInstanceof`: Use 'instanceof' to compare types when generating the hashCode and equals methods. Defaults to `false`. * `java.foldingRange.enabled`: Enable/disable smart folding range support. If disabled, it will use the default indentation-based folding range provided by VS Code. - -*New in 0.43.0:* * `java.maven.downloadSources`: Enable/disable eager download of Maven source artifacts. +* `java.codeGeneration.hashCodeEquals.useInstanceof`: Use 'instanceof' to compare types when generating the hashCode and equals methods. Defaults to `false`. +* `java.codeGeneration.hashCodeEquals.useJava7Objects`: Use Objects.hash and Objects.equals when generating the hashCode and equals methods. This setting only applies to Java 7 and higher. Defaults to `false`. * `java.codeGeneration.useBlocks`: Use blocks in 'if' statements when generating the methods. Defaults to `false`. * `java.codeGeneration.generateComments`: Generate method comments when generating the methods. Defaults to `false`. * `java.codeGeneration.toString.template`: The template for generating the toString method. Defaults to `${object.className} [${member.name()}=${member.value}, ${otherMembers}]`. @@ -109,9 +109,6 @@ The following settings are supported: * `java.codeGeneration.toString.listArrayContents`: List contents of arrays instead of using native toString(). Defaults to `true`. * `java.codeGeneration.toString.limitElements`: Limit number of items in arrays/collections/maps to list, if 0 then list all. Defaults to `0`. -*New in 0.45.0:* -* `java.import.gradle.wrapper.enabled`: Enable/disable the Gradle wrapper. -* `java.import.gradle.version`: Gradle version, used if the gradle wrapper is missing or disabled. Troubleshooting =============== diff --git a/package-lock.json b/package-lock.json index 31158451d..4bad5b7c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "java", - "version": "0.45.0", + "version": "0.46.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 897edbc9c..3a01bdb96 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "author": "Red Hat", "icon": "icons/icon128.png", "license": "EPL-1.0", - "version": "0.45.0", + "version": "0.46.0", "publisher": "redhat", "bugs": "https://github.com/redhat-developer/vscode-java/issues", "preview": true, From 8437dbafbb1d3cc9b0aa5e966368f2eed42ded91 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Thu, 16 May 2019 11:11:31 -0400 Subject: [PATCH 0014/1031] Skip jdt.ls tests as it's already tested in jdt.ls's own build process Signed-off-by: Fred Bricon --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 117d3556f..c05591030 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -20,7 +20,7 @@ node('rhel7'){ sh 'java -version' git url: 'https://github.com/eclipse/eclipse.jdt.ls.git' - sh "./mvnw clean verify -B -U -e -Pserver-distro -Dtycho.disableP2Mirrors=true -P!jboss-maven-repos,!redhat-ga-repository,!redhat-ea-repository" + sh "./mvnw clean verify -B -U -e -Pserver-distro -Dtycho.disableP2Mirrors=true -DskipTests -P!jboss-maven-repos,!redhat-ga-repository,!redhat-ea-repository" def files = findFiles(glob: '**/org.eclipse.jdt.ls.product/distro/**.tar.gz') stash name: 'server_distro', includes :files[0].path From e93092ca61cd3e96228b684ad29d7464a47465d7 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 14 May 2019 17:35:25 +0800 Subject: [PATCH 0015/1031] Enable Source Action: Generate Constructors Signed-off-by: Jinbo Wang --- src/commands.ts | 4 +++ src/extension.ts | 1 + src/protocol.ts | 35 +++++++++++++++++++++---- src/sourceAction.ts | 59 ++++++++++++++++++++++++++++++++++++++++-- test/extension.test.ts | 3 ++- 5 files changed, 94 insertions(+), 8 deletions(-) diff --git a/src/commands.ts b/src/commands.ts index 4f92c2894..8ba67a83c 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -130,4 +130,8 @@ export namespace Commands { * Generate Getters and Setters. */ export const GENERATE_ACCESSORS_PROMPT = 'java.action.generateAccessorsPrompt'; + /** + * Generate Constructors. + */ + export const GENERATE_CONSTRUCTORS_PROMPT = 'java.action.generateConstructorsPrompt'; } \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 90345b1fb..524e59217 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -70,6 +70,7 @@ export function activate(context: ExtensionContext): Promise { advancedOrganizeImportsSupport: true, generateToStringPromptSupport: true, advancedGenerateAccessorsSupport: true, + generateConstructorsPromptSupport: true, }, triggerFiles: getTriggerFiles() }, diff --git a/src/protocol.ts b/src/protocol.ts index 3b15c2a2e..9aa562333 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -148,7 +148,7 @@ export namespace AddOverridableMethodsRequest { export const type = new RequestType('java/addOverridableMethods'); } -export interface VariableField { +export interface VariableBinding { bindingKey: string; name: string; type: string; @@ -156,7 +156,7 @@ export interface VariableField { export interface CheckHashCodeEqualsResponse { type: string; - fields: VariableField[]; + fields: VariableBinding[]; existingMethods: string[]; } @@ -166,7 +166,7 @@ export namespace CheckHashCodeEqualsStatusRequest { export interface GenerateHashCodeEqualsParams { context: CodeActionParams; - fields: VariableField[]; + fields: VariableBinding[]; regenerate: boolean; } @@ -190,7 +190,7 @@ export interface ImportSelection { export interface CheckToStringResponse { type: string; - fields: VariableField[]; + fields: VariableBinding[]; exists: boolean; } @@ -200,7 +200,7 @@ export namespace CheckToStringStatusRequest { export interface GenerateToStringParams { context: CodeActionParams; - fields: VariableField[]; + fields: VariableBinding[]; } export namespace GenerateToStringRequest { @@ -226,3 +226,28 @@ export interface GenerateAccessorsParams { export namespace GenerateAccessorsRequest { export const type = new RequestType('java/generateAccessors'); } + +export interface MethodBinding { + bindingKey: string; + name: string; + parameters: string[]; +} + +export interface CheckConstructorsResponse { + constructors: MethodBinding[]; + fields: VariableBinding[]; +} + +export namespace CheckConstructorStatusRequest { + export const type = new RequestType('java/checkConstructorsStatus'); +} + +export interface GenerateConstructorsParams { + context: CodeActionParams; + constructors: MethodBinding[]; + fields: VariableBinding[]; +} + +export namespace GenerateConstructorsRequest { + export const type = new RequestType('java/generateConstructors'); +} diff --git a/src/sourceAction.ts b/src/sourceAction.ts index e5b346030..88bc1b8e9 100644 --- a/src/sourceAction.ts +++ b/src/sourceAction.ts @@ -5,7 +5,7 @@ import { CodeActionParams, LanguageClient } from 'vscode-languageclient'; import { Commands } from './commands'; import { applyWorkspaceEdit } from './extension'; import { ListOverridableMethodsRequest, AddOverridableMethodsRequest, CheckHashCodeEqualsStatusRequest, GenerateHashCodeEqualsRequest, -OrganizeImportsRequest, ImportCandidate, ImportSelection, GenerateToStringRequest, CheckToStringStatusRequest, VariableField, ResolveUnimplementedAccessorsRequest, GenerateAccessorsRequest } from './protocol'; +OrganizeImportsRequest, ImportCandidate, ImportSelection, GenerateToStringRequest, CheckToStringStatusRequest, VariableBinding, ResolveUnimplementedAccessorsRequest, GenerateAccessorsRequest, CheckConstructorStatusRequest, GenerateConstructorsRequest } from './protocol'; export function registerCommands(languageClient: LanguageClient, context: ExtensionContext) { registerOverrideMethodsCommand(languageClient, context); @@ -14,6 +14,7 @@ export function registerCommands(languageClient: LanguageClient, context: Extens registerChooseImportCommand(context); registerGenerateToStringCommand(languageClient, context); registerGenerateAccessorsCommand(languageClient, context); + registerGenerateConstructorsCommand(languageClient, context); } function registerOverrideMethodsCommand(languageClient: LanguageClient, context: ExtensionContext): void { @@ -176,7 +177,7 @@ function registerGenerateToStringCommand(languageClient: LanguageClient, context } } - let fields: VariableField[] = []; + let fields: VariableBinding[] = []; if (result.fields && result.fields.length) { const fieldItems = result.fields.map((field) => { return { @@ -240,3 +241,57 @@ function registerGenerateAccessorsCommand(languageClient: LanguageClient, contex applyWorkspaceEdit(workspaceEdit, languageClient); })); } + +function registerGenerateConstructorsCommand(languageClient: LanguageClient, context: ExtensionContext): void { + context.subscriptions.push(commands.registerCommand(Commands.GENERATE_CONSTRUCTORS_PROMPT, async (params: CodeActionParams) => { + const status = await languageClient.sendRequest(CheckConstructorStatusRequest.type, params); + if (!status || !status.constructors || !status.constructors.length) { + return; + } + + let selectedConstructors = status.constructors; + let selectedFields = []; + if (status.constructors.length > 1) { + const constructorItems = status.constructors.map((constructor) => { + return { + label: `${constructor.name}(${constructor.parameters.join(',')})`, + originalConstructor: constructor, + }; + }); + const selectedConstructorItems = await window.showQuickPick(constructorItems, { + canPickMany: true, + placeHolder: 'Select super class constructor(s).', + }); + if (!selectedConstructorItems || !selectedConstructorItems.length) { + return; + } + + selectedConstructors = selectedConstructorItems.map(item => item.originalConstructor); + } + + if (status.fields.length) { + const fieldItems = status.fields.map((field) => { + return { + label: `${field.name}: ${field.type}`, + originalField: field, + }; + }); + const selectedFieldItems = await window.showQuickPick(fieldItems, { + canPickMany: true, + placeHolder: 'Select fields to initialize by constructor(s).', + }); + if (!selectedFieldItems) { + return; + } + + selectedFields = selectedFieldItems.map(item => item.originalField); + } + + const workspaceEdit = await languageClient.sendRequest(GenerateConstructorsRequest.type, { + context: params, + constructors: selectedConstructors, + fields: selectedFields, + }); + applyWorkspaceEdit(workspaceEdit, languageClient); + })); +} diff --git a/test/extension.test.ts b/test/extension.test.ts index 3c963246a..635b652e6 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -47,7 +47,8 @@ suite('Java Language Extension', () => { Commands.ORGANIZE_IMPORTS, Commands.CHOOSE_IMPORTS, Commands.GENERATE_TOSTRING_PROMPT, - Commands.GENERATE_ACCESSORS_PROMPT + Commands.GENERATE_ACCESSORS_PROMPT, + Commands.GENERATE_CONSTRUCTORS_PROMPT, ]; const foundJavaCommands = commands.filter(function(value) { return JAVA_COMMANDS.indexOf(value)>=0 || value.startsWith('java.'); From c70ba525c77406e9d1940ce56f80042b940a9faa Mon Sep 17 00:00:00 2001 From: Meir Blachman Date: Tue, 21 May 2019 17:10:21 +0300 Subject: [PATCH 0016/1031] add try-resources snippet Signed-off-by: Meir Blachman --- snippets/java.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/snippets/java.json b/snippets/java.json index 2269dcdab..7b3293888 100644 --- a/snippets/java.json +++ b/snippets/java.json @@ -98,6 +98,16 @@ ], "description": "try/catch block" }, + "tryresources": { + "prefix": "try_resources", + "body": [ + "try ($1) {", + "\t$2", + "} catch (${3:Exception} ${4:e}) {", + "\t$5//${0:TODO}: handle exception", + "}" + ] + }, "private_method": { "prefix": "private_method", "body": [ From fd23af542c5e41881b06ebcab435e65cf1ffacaa Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Fri, 17 May 2019 13:58:06 +0800 Subject: [PATCH 0017/1031] update loading icon in status bar Signed-off-by: Yan Zhang --- src/extension.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extension.ts b/src/extension.ts index 524e59217..8e532985d 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -78,7 +78,7 @@ export function activate(context: ExtensionContext): Promise { }; const item = window.createStatusBarItem(StatusBarAlignment.Right, Number.MIN_VALUE); - item.text = '$(rocket)'; + item.text = '$(sync~spin)'; item.command = Commands.OPEN_OUTPUT; const progressBar = window.createStatusBarItem(StatusBarAlignment.Left, Number.MIN_VALUE + 1); From 1012a568fca29979ce4cf6ba6e8edb0a57a79fb9 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Tue, 21 May 2019 16:16:12 -0400 Subject: [PATCH 0018/1031] New 'private field' snippet, triggered by prf Signed-off-by: Fred Bricon --- snippets/java.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/snippets/java.json b/snippets/java.json index 7b3293888..2890ef175 100644 --- a/snippets/java.json +++ b/snippets/java.json @@ -191,5 +191,12 @@ "${0:Object} ${1:foo} = new ${0:Object}();" ], "description": "Create new Object" + }, + "Private field": { + "prefix": "prf", + "body": [ + "private ${1:String} ${2:name};" + ], + "description": "Private field" } } \ No newline at end of file From 0d81470c5fc088fd2cd642c21cff4abd81509cb9 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Fri, 24 May 2019 07:02:10 +0800 Subject: [PATCH 0019/1031] Enable code action: Generate Delegate Methods... (#930) Signed-off-by: Jinbo Wang --- src/commands.ts | 4 +++ src/extension.ts | 1 + src/protocol.ts | 27 ++++++++++++++++++ src/sourceAction.ts | 64 +++++++++++++++++++++++++++++++++++++++++- test/extension.test.ts | 1 + 5 files changed, 96 insertions(+), 1 deletion(-) diff --git a/src/commands.ts b/src/commands.ts index 8ba67a83c..9a94d9ddf 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -134,4 +134,8 @@ export namespace Commands { * Generate Constructors. */ export const GENERATE_CONSTRUCTORS_PROMPT = 'java.action.generateConstructorsPrompt'; + /** + * Generate Delegate Methods. + */ + export const GENERATE_DELEGATE_METHODS_PROMPT = 'java.action.generateDelegateMethodsPrompt'; } \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 8e532985d..750583ed9 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -71,6 +71,7 @@ export function activate(context: ExtensionContext): Promise { generateToStringPromptSupport: true, advancedGenerateAccessorsSupport: true, generateConstructorsPromptSupport: true, + generateDelegateMethodsPromptSupport: true, }, triggerFiles: getTriggerFiles() }, diff --git a/src/protocol.ts b/src/protocol.ts index 9aa562333..ded572394 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -251,3 +251,30 @@ export interface GenerateConstructorsParams { export namespace GenerateConstructorsRequest { export const type = new RequestType('java/generateConstructors'); } + +export interface DelegateField { + field: VariableBinding; + delegateMethods: MethodBinding[]; +} + +export interface CheckDelegateMethodsResponse { + delegateFields: DelegateField[]; +} + +export namespace CheckDelegateMethodsStatusRequest { + export const type = new RequestType('java/checkDelegateMethodsStatus'); +} + +export interface DelegateEntry { + field: VariableBinding; + delegateMethod: MethodBinding; +} + +export interface GenerateDelegateMethodsParams { + context: CodeActionParams; + delegateEntries: DelegateEntry[]; +} + +export namespace GenerateDelegateMethodsRequest { + export const type = new RequestType('java/generateDelegateMethods'); +} diff --git a/src/sourceAction.ts b/src/sourceAction.ts index 88bc1b8e9..21f0c8b9a 100644 --- a/src/sourceAction.ts +++ b/src/sourceAction.ts @@ -5,7 +5,7 @@ import { CodeActionParams, LanguageClient } from 'vscode-languageclient'; import { Commands } from './commands'; import { applyWorkspaceEdit } from './extension'; import { ListOverridableMethodsRequest, AddOverridableMethodsRequest, CheckHashCodeEqualsStatusRequest, GenerateHashCodeEqualsRequest, -OrganizeImportsRequest, ImportCandidate, ImportSelection, GenerateToStringRequest, CheckToStringStatusRequest, VariableBinding, ResolveUnimplementedAccessorsRequest, GenerateAccessorsRequest, CheckConstructorStatusRequest, GenerateConstructorsRequest } from './protocol'; +OrganizeImportsRequest, ImportCandidate, ImportSelection, GenerateToStringRequest, CheckToStringStatusRequest, VariableBinding, ResolveUnimplementedAccessorsRequest, GenerateAccessorsRequest, CheckConstructorStatusRequest, GenerateConstructorsRequest, CheckDelegateMethodsStatusRequest, GenerateDelegateMethodsRequest } from './protocol'; export function registerCommands(languageClient: LanguageClient, context: ExtensionContext) { registerOverrideMethodsCommand(languageClient, context); @@ -15,6 +15,7 @@ export function registerCommands(languageClient: LanguageClient, context: Extens registerGenerateToStringCommand(languageClient, context); registerGenerateAccessorsCommand(languageClient, context); registerGenerateConstructorsCommand(languageClient, context); + registerGenerateDelegateMethodsCommand(languageClient, context); } function registerOverrideMethodsCommand(languageClient: LanguageClient, context: ExtensionContext): void { @@ -295,3 +296,64 @@ function registerGenerateConstructorsCommand(languageClient: LanguageClient, con applyWorkspaceEdit(workspaceEdit, languageClient); })); } + +function registerGenerateDelegateMethodsCommand(languageClient: LanguageClient, context: ExtensionContext): void { + context.subscriptions.push(commands.registerCommand(Commands.GENERATE_DELEGATE_METHODS_PROMPT, async (params: CodeActionParams) => { + const status = await languageClient.sendRequest(CheckDelegateMethodsStatusRequest.type, params); + if (!status || !status.delegateFields || !status.delegateFields.length) { + window.showWarningMessage("All delegatable methods are already implemented."); + return; + } + + let selectedDelegateField = status.delegateFields[0]; + if (status.delegateFields.length > 1) { + const fieldItems = status.delegateFields.map((delegateField) => { + return { + label: `${delegateField.field.name}: ${delegateField.field.type}`, + originalField: delegateField, + }; + }); + const selectedFieldItem = await window.showQuickPick(fieldItems, { + placeHolder: 'Select target to generate delegates for.', + }); + if (!selectedFieldItem) { + return; + } + + selectedDelegateField = selectedFieldItem.originalField; + } + + let delegateEntryItems = selectedDelegateField.delegateMethods.map(delegateMethod => { + return { + label: `${selectedDelegateField.field.name}.${delegateMethod.name}(${delegateMethod.parameters.join(',')})`, + originalField: selectedDelegateField.field, + originalMethod: delegateMethod, + } + }); + + if (!delegateEntryItems.length) { + window.showWarningMessage("All delegatable methods are already implemented."); + return; + } + + const selectedDelegateEntryItems = await window.showQuickPick(delegateEntryItems, { + canPickMany: true, + placeHolder: 'Select methods to generate delegates for.', + }); + if (!selectedDelegateEntryItems || !selectedDelegateEntryItems.length) { + return; + } + + const delegateEntries = selectedDelegateEntryItems.map(item => { + return { + field: item.originalField, + delegateMethod: item.originalMethod, + }; + }); + const workspaceEdit = await languageClient.sendRequest(GenerateDelegateMethodsRequest.type, { + context: params, + delegateEntries, + }); + applyWorkspaceEdit(workspaceEdit, languageClient); + })); +} \ No newline at end of file diff --git a/test/extension.test.ts b/test/extension.test.ts index 635b652e6..3d5904b82 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -49,6 +49,7 @@ suite('Java Language Extension', () => { Commands.GENERATE_TOSTRING_PROMPT, Commands.GENERATE_ACCESSORS_PROMPT, Commands.GENERATE_CONSTRUCTORS_PROMPT, + Commands.GENERATE_DELEGATE_METHODS_PROMPT, ]; const foundJavaCommands = commands.filter(function(value) { return JAVA_COMMANDS.indexOf(value)>=0 || value.startsWith('java.'); From ff8144b0fda3ed6f818008e3b3de140f93dc6ef2 Mon Sep 17 00:00:00 2001 From: Yaohai Zheng Date: Thu, 30 May 2019 10:58:26 +0800 Subject: [PATCH 0020/1031] Enable proposed API. Signed-off-by: Yaohai Zheng --- package-lock.json | 41 +++++++++++------------------------------ package.json | 1 + 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4bad5b7c5..291fe8aa4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2276,8 +2276,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -2298,14 +2297,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2320,20 +2317,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -2450,8 +2444,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -2463,7 +2456,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2478,7 +2470,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2486,14 +2477,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -2512,7 +2501,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -2593,8 +2581,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -2606,7 +2593,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -2692,8 +2678,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -2729,7 +2714,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -2749,7 +2733,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -2793,14 +2776,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, diff --git a/package.json b/package.json index 3a01bdb96..a5394ca17 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "publisher": "redhat", "bugs": "https://github.com/redhat-developer/vscode-java/issues", "preview": true, + "enableProposedApi": true, "engines": { "vscode": "^1.31.0" }, From 3b0fdfd708f2f9da428ae223857451dd48826ca8 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Mon, 3 Jun 2019 22:21:48 -0400 Subject: [PATCH 0021/1031] Changelog for 0.46.0 release Signed-off-by: Fred Bricon --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c1388271..4a5327b58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## 0.46.0 (June 5th, 2019) +* enhancement - new 'try with resources' snippet, triggered by `try_resources`. See [#932](https://github.com/redhat-developer/vscode-java/pull/932). +* enhancement - new 'private field' snippet, triggered by `prf`. See [#933](https://github.com/redhat-developer/vscode-java/pull/933). +* enhancement - new spinning icon in status bar, when server is loading. Good bye rocket. See [#929](https://github.com/redhat-developer/vscode-java/pull/929). +* enhancement - enabled proposed API. See [#942](https://github.com/redhat-developer/vscode-java/pull/942). +* enhancement - added code action to generate constructors. See [#921](https://github.com/redhat-developer/vscode-java/pull/921). +* enhancement - added code action to generate delegate methods. See [#930](https://github.com/redhat-developer/vscode-java/pull/930). +* enhancement - updated buildship to 3.1.0. See [Buildship changelog](https://discuss.gradle.org/t/buildship-3-1-is-now-available/31600). +* enhancement - updated m2e to 1.12 (now embeds Maven 3.6.1). See [m2e changelog](https://projects.eclipse.org/projects/technology.m2e/releases/1.12/bugs). +* enhancement - provide more info on hover for constant fields. See [JLS#1049](https://github.com/eclipse/eclipse.jdt.ls/issues/1049). +* bug fix - fixed Signature Help not matching active parameter per type. See [JLS#1037](https://github.com/eclipse/eclipse.jdt.ls/issues/1037). +* bug fix - fixed disabling Gradle wrapper in certain cases. See [JLS#1044](https://github.com/eclipse/eclipse.jdt.ls/issues/1044). + ## 0.45.0 (May 15th, 2019) * enhancement - optionally disable loading Gradle from wrapper and use a specific Gradle version. See [#875](https://github.com/redhat-developer/vscode-java/issues/875). * enhancement - added `Assign parameters to new fields` source actions. See [JLS#167](https://github.com/eclipse/eclipse.jdt.ls/issues/167). From c945683b1266b925cc89a520973712995b76ef1e Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Wed, 5 Jun 2019 14:47:31 -0400 Subject: [PATCH 0022/1031] Revert #942 - Enable proposed API The VS Code Marketplace prevents extensions from publishing with enableProposedApi:true: ERROR Extensions using proposed API (enableProposedApi: true) can't be published to the Marketplace Signed-off-by: Fred Bricon --- CHANGELOG.md | 1 - package.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a5327b58..c51fb8838 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,6 @@ * enhancement - new 'try with resources' snippet, triggered by `try_resources`. See [#932](https://github.com/redhat-developer/vscode-java/pull/932). * enhancement - new 'private field' snippet, triggered by `prf`. See [#933](https://github.com/redhat-developer/vscode-java/pull/933). * enhancement - new spinning icon in status bar, when server is loading. Good bye rocket. See [#929](https://github.com/redhat-developer/vscode-java/pull/929). -* enhancement - enabled proposed API. See [#942](https://github.com/redhat-developer/vscode-java/pull/942). * enhancement - added code action to generate constructors. See [#921](https://github.com/redhat-developer/vscode-java/pull/921). * enhancement - added code action to generate delegate methods. See [#930](https://github.com/redhat-developer/vscode-java/pull/930). * enhancement - updated buildship to 3.1.0. See [Buildship changelog](https://discuss.gradle.org/t/buildship-3-1-is-now-available/31600). diff --git a/package.json b/package.json index a5394ca17..997dd1c62 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "publisher": "redhat", "bugs": "https://github.com/redhat-developer/vscode-java/issues", "preview": true, - "enableProposedApi": true, + "enableProposedApi": false, "engines": { "vscode": "^1.31.0" }, From 2c7f35a50e85937c2a6f293c81c4c0949a96ca3c Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Wed, 5 Jun 2019 19:48:03 -0400 Subject: [PATCH 0023/1031] Upversion to 0.47.0 Signed-off-by: Fred Bricon --- package-lock.json | 43 +++++++++++++++++++++++++++++++------------ package.json | 2 +- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 291fe8aa4..a5f87e500 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "java", - "version": "0.46.0", + "version": "0.47.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2276,7 +2276,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -2297,12 +2298,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2317,17 +2320,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -2444,7 +2450,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -2456,6 +2463,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2470,6 +2478,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2477,12 +2486,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -2501,6 +2512,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -2581,7 +2593,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -2593,6 +2606,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -2678,7 +2692,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -2714,6 +2729,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -2733,6 +2749,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -2776,12 +2793,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, diff --git a/package.json b/package.json index 997dd1c62..77a9a45f3 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "author": "Red Hat", "icon": "icons/icon128.png", "license": "EPL-1.0", - "version": "0.46.0", + "version": "0.47.0", "publisher": "redhat", "bugs": "https://github.com/redhat-developer/vscode-java/issues", "preview": true, From 0eab5e43a59f6c95114556b91ceb667f9f53e98a Mon Sep 17 00:00:00 2001 From: Snjezana Peco Date: Mon, 17 Jun 2019 20:42:18 +0200 Subject: [PATCH 0024/1031] Cannot set up dev environment following contributing instruction Signed-off-by: Snjezana Peco --- CONTRIBUTING.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 26380678e..2dba41456 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,18 +48,29 @@ This will build and place the binaries under the `server` folder. Alternately yo While developing the language server and the extension, you don't need to deploy the server every time to try out changes. Instead you can run the language server out of its Eclipse workspace: +### _Launch Extension - Remote Server_ + - Open VSCode on the `vscode-java` folder - In the debug viewlet, run the launch _Launch Extension - Remote Server_ - The extension will open a socket on port 3333 and will wait for the JDT language server to connect - In Eclipse, run the JDT language server as an Eclipse application. - - Create a debug configuration of type _Eclipse Application_. + - Create a debug configuration of type _Eclipse Application_. - in the main tab of the debug configuration set the product to `org.eclipse.jdt.ls.core.product`. - in the Environment tab, define a variable `CLIENT_PORT` with value `3333`. - if your workspace contains 'org.eclipse.jdt.ui', use the Plug-Ins tab in the debug configuration to exclude the plug-in. The presence of 'org.eclipse.jdt.ui' will cause the language server to hang. + - You can also use the `jdt.ls.remote.server` launch configuration. + - In the debug console of VSCode you can see if the connection was successful. - When the server is running breakpoints can be reached and hot code replace can be used to make fixes without restarting the server. - You can modify `launch.json` to use a different port: - - Modify `SERVER_PORT` to specify the port the JST LS server should connect to. + - Modify `SERVER_PORT` to specify the port the JDT LS server should connect to. + +### _Launch Extension - JDTLS Client_ + +- start the `jdt.ls.socket-stream` launch configuration in Eclipse +- start the _Launch Extension - JDTLS Client_ in VS Code +- You can modify `launch.json` to use a different port: + - Modify `JDTLS_CLIENT_PORT` to specify the port VS Code should connect to. ## Sideloading From d5d77cb7c26672d3f909ef4b724079e2f6654261 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Thu, 27 Jun 2019 15:26:47 +0800 Subject: [PATCH 0025/1031] Add rename after 'extract to variable/constant/method' refactoring (#965) Signed-off-by: Jinbo Wang --- src/commands.ts | 8 +++++ src/extension.ts | 3 ++ src/protocol.ts | 23 +++++++++++++- src/refactorAction.ts | 69 ++++++++++++++++++++++++++++++++++++++++++ test/extension.test.ts | 2 ++ 5 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 src/refactorAction.ts diff --git a/src/commands.ts b/src/commands.ts index 9a94d9ddf..a2ab5f6f0 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -138,4 +138,12 @@ export namespace Commands { * Generate Delegate Methods. */ export const GENERATE_DELEGATE_METHODS_PROMPT = 'java.action.generateDelegateMethodsPrompt'; + /** + * Apply Refactoring Command. + */ + export const APPLY_REFACTORING_COMMAND = 'java.action.applyRefactoringCommand'; + /** + * Rename Command. + */ + export const RENAME_COMMAND = 'java.action.rename'; } \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 750583ed9..e91c7a79f 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -16,6 +16,7 @@ import { import { ExtensionAPI } from './extension.api'; import * as buildpath from './buildpath'; import * as sourceAction from './sourceAction'; +import * as refactorAction from './refactorAction'; import * as net from 'net'; import { getJavaConfiguration } from './utils'; import { onConfigurationChange, excludeProjectSettingsFiles } from './settings'; @@ -72,6 +73,7 @@ export function activate(context: ExtensionContext): Promise { advancedGenerateAccessorsSupport: true, generateConstructorsPromptSupport: true, generateDelegateMethodsPromptSupport: true, + advancedExtractRefactoringSupport: true, }, triggerFiles: getTriggerFiles() }, @@ -286,6 +288,7 @@ export function activate(context: ExtensionContext): Promise { buildpath.registerCommands(context); sourceAction.registerCommands(languageClient, context); + refactorAction.registerCommands(languageClient, context); context.subscriptions.push(window.onDidChangeActiveTextEditor((editor) => { toggleItem(editor, item); diff --git a/src/protocol.ts b/src/protocol.ts index ded572394..bf0de4dc6 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -1,6 +1,6 @@ 'use strict'; -import { RequestType, NotificationType, TextDocumentIdentifier, ExecuteCommandParams, CodeActionParams, WorkspaceEdit } from 'vscode-languageclient'; +import { RequestType, NotificationType, TextDocumentIdentifier, ExecuteCommandParams, CodeActionParams, WorkspaceEdit, FormattingOptions } from 'vscode-languageclient'; import { Command, Range } from 'vscode'; /** @@ -278,3 +278,24 @@ export interface GenerateDelegateMethodsParams { export namespace GenerateDelegateMethodsRequest { export const type = new RequestType('java/generateDelegateMethods'); } + +export interface RenamePosition { + uri: string; + offset: number; + length: number; +} + +export interface RefactorWorkspaceEdit { + edit: WorkspaceEdit; + command?: Command; +} + +export interface GetRefactorEditParams { + command: string; + context: CodeActionParams; + options: FormattingOptions; +} + +export namespace GetRefactorEditRequest { + export const type = new RequestType('java/getRefactorEdit'); +} diff --git a/src/refactorAction.ts b/src/refactorAction.ts new file mode 100644 index 000000000..220011dbe --- /dev/null +++ b/src/refactorAction.ts @@ -0,0 +1,69 @@ +'use strict'; + +import { commands, window, ExtensionContext, workspace, Position, Uri, TextDocument } from 'vscode'; +import { LanguageClient, FormattingOptions } from 'vscode-languageclient'; +import { Commands as javaCommands } from './commands'; +import { GetRefactorEditRequest, RefactorWorkspaceEdit, RenamePosition } from './protocol'; + +export function registerCommands(languageClient: LanguageClient, context: ExtensionContext) { + registerApplyRefactorCommand(languageClient, context); +} + +function registerApplyRefactorCommand(languageClient: LanguageClient, context: ExtensionContext): void { + context.subscriptions.push(commands.registerCommand(javaCommands.RENAME_COMMAND, async (position: RenamePosition) => { + try { + const uri: Uri = Uri.parse(position.uri); + const document: TextDocument = await workspace.openTextDocument(uri); + if (document == null) { + return; + } + + const renamePosition: Position = document.positionAt(position.offset); + await commands.executeCommand('editor.action.rename', [ + document.uri, + renamePosition, + ]); + } catch (error) { + // do nothing. + } + })); + + context.subscriptions.push(commands.registerCommand(javaCommands.APPLY_REFACTORING_COMMAND, async (command: string, params: any) => { + if (command === 'extractVariable' + || command === 'extractVariableAllOccurrence' + || command === 'extractConstant' + || command === 'extractMethod') { + const currentEditor = window.activeTextEditor; + if (!currentEditor || !currentEditor.options) { + return; + } + + const formattingOptions: FormattingOptions = { + tabSize: currentEditor.options.tabSize, + insertSpaces: currentEditor.options.insertSpaces, + }; + const result: RefactorWorkspaceEdit = await languageClient.sendRequest(GetRefactorEditRequest.type, { + command, + context: params, + options: formattingOptions, + }); + + if (!result || !result.edit) { + return; + } + + const edit = languageClient.protocol2CodeConverter.asWorkspaceEdit(result.edit); + if (edit) { + await workspace.applyEdit(edit); + } + + if (result.command) { + if (result.command.arguments) { + await commands.executeCommand(result.command.command, ...result.command.arguments); + } else { + await commands.executeCommand(result.command.command); + } + } + } + })); +} diff --git a/test/extension.test.ts b/test/extension.test.ts index 3d5904b82..79bb155c8 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -50,6 +50,8 @@ suite('Java Language Extension', () => { Commands.GENERATE_ACCESSORS_PROMPT, Commands.GENERATE_CONSTRUCTORS_PROMPT, Commands.GENERATE_DELEGATE_METHODS_PROMPT, + Commands.APPLY_REFACTORING_COMMAND, + Commands.RENAME_COMMAND ]; const foundJavaCommands = commands.filter(function(value) { return JAVA_COMMANDS.indexOf(value)>=0 || value.startsWith('java.'); From d8d86ee838740438456f5e00dbe5290efcce0ab5 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Wed, 3 Jul 2019 11:12:01 +0800 Subject: [PATCH 0026/1031] Enable refactoring: Extract to field Signed-off-by: Jinbo Wang --- src/protocol.ts | 1 + src/refactorAction.ts | 28 ++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/protocol.ts b/src/protocol.ts index bf0de4dc6..aad0512cb 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -294,6 +294,7 @@ export interface GetRefactorEditParams { command: string; context: CodeActionParams; options: FormattingOptions; + commandArguments: any[]; } export namespace GetRefactorEditRequest { diff --git a/src/refactorAction.ts b/src/refactorAction.ts index 220011dbe..658e8e082 100644 --- a/src/refactorAction.ts +++ b/src/refactorAction.ts @@ -28,11 +28,13 @@ function registerApplyRefactorCommand(languageClient: LanguageClient, context: E } })); - context.subscriptions.push(commands.registerCommand(javaCommands.APPLY_REFACTORING_COMMAND, async (command: string, params: any) => { + context.subscriptions.push(commands.registerCommand(javaCommands.APPLY_REFACTORING_COMMAND, async (command: string, params: any, commandInfo: any) => { if (command === 'extractVariable' || command === 'extractVariableAllOccurrence' || command === 'extractConstant' - || command === 'extractMethod') { + || command === 'extractMethod' + || command === 'extractField' + || command === 'convertVariableToField') { const currentEditor = window.activeTextEditor; if (!currentEditor || !currentEditor.options) { return; @@ -42,10 +44,32 @@ function registerApplyRefactorCommand(languageClient: LanguageClient, context: E tabSize: currentEditor.options.tabSize, insertSpaces: currentEditor.options.insertSpaces, }; + const commandArguments: any[] = []; + if (command === 'extractField' || command === 'convertVariableToField') { + if (commandInfo.initializedScopes && Array.isArray(commandInfo.initializedScopes)) { + const scopes: any[] = commandInfo.initializedScopes; + let initializeIn: string; + if (scopes.length === 1) { + initializeIn = scopes[0]; + } else if (scopes.length > 1) { + initializeIn = await window.showQuickPick(scopes, { + placeHolder: "Initialize the field in", + }); + + if (!initializeIn) { + return; + } + } + + commandArguments.push(initializeIn); + } + } + const result: RefactorWorkspaceEdit = await languageClient.sendRequest(GetRefactorEditRequest.type, { command, context: params, options: formattingOptions, + commandArguments, }); if (!result || !result.edit) { From 21bdfec66fd6d2726582410c41cdd6fac0a191fd Mon Sep 17 00:00:00 2001 From: Snjezana Peco Date: Mon, 8 Jul 2019 17:45:09 +0200 Subject: [PATCH 0027/1031] Add additional Gradle preferences Signed-off-by: Snjezana Peco --- README.md | 6 ++++++ package.json | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/README.md b/README.md index 0e0df4500..205b5a496 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,12 @@ The following settings are supported: * `java.codeGeneration.toString.listArrayContents`: List contents of arrays instead of using native toString(). Defaults to `true`. * `java.codeGeneration.toString.limitElements`: Limit number of items in arrays/collections/maps to list, if 0 then list all. Defaults to `0`. +*New in 0.47.0* + +* `java.import.gradle.arguments`: Arguments to pass to Gradle. +* `java.import.gradle.jvmArguments`: JVM arguments to pass to Gradle. +* `java.import.gradle.home`: setting for GRADLE_HOME. + Troubleshooting =============== diff --git a/package.json b/package.json index 77a9a45f3..8ce3587cd 100644 --- a/package.json +++ b/package.json @@ -139,6 +139,24 @@ "description": "Gradle version, used if the gradle wrapper is missing or disabled.", "scope": "window" }, + "java.import.gradle.arguments": { + "type": "string", + "default": null, + "description": "Arguments to pass to Gradle.", + "scope": "window" + }, + "java.import.gradle.jvmArguments": { + "type": "string", + "default": null, + "description": "JVM arguments to pass to Gradle.", + "scope": "window" + }, + "java.import.gradle.home": { + "type": "string", + "default": null, + "description": "Setting for GRADLE_HOME.", + "scope": "window" + }, "java.maven.downloadSources": { "type": "boolean", "default": false, From 89d3921d6bea902ac4f8626bff165e120c534c25 Mon Sep 17 00:00:00 2001 From: Rome Li Date: Fri, 12 Jul 2019 16:52:04 +0800 Subject: [PATCH 0028/1031] Support "textDocument/selectionRange" (#976) Signed-off-by: Rome Li --- README.md | 3 +- package-lock.json | 168 +++++++++++++--------------------------------- package.json | 12 +++- 3 files changed, 57 insertions(+), 126 deletions(-) diff --git a/README.md b/README.md index 205b5a496..6bf5cbaa0 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ The following settings are supported: * `java.completion.enabled` : Enable/disable code completion support. * `java.configuration.checkProjectSettingsExclusions`: Checks if the extension-generated project settings files (`.project`, `.classpath`, `.factorypath`, `.settings/`) should be excluded from the file explorer. Defaults to `true`. * `java.foldingRange.enabled`: Enable/disable smart folding range support. If disabled, it will use the default indentation-based folding range provided by VS Code. +* `java.selectionRange.enabled`: Enable/disable Smart Selection support for Java. Disabling this option will not affect the VS Code built-in word-based and bracket-based smart selection. * `java.maven.downloadSources`: Enable/disable eager download of Maven source artifacts. * `java.codeGeneration.hashCodeEquals.useInstanceof`: Use 'instanceof' to compare types when generating the hashCode and equals methods. Defaults to `false`. * `java.codeGeneration.hashCodeEquals.useJava7Objects`: Use Objects.hash and Objects.equals when generating the hashCode and equals methods. This setting only applies to Java 7 and higher. Defaults to `false`. @@ -114,7 +115,7 @@ The following settings are supported: * `java.import.gradle.arguments`: Arguments to pass to Gradle. * `java.import.gradle.jvmArguments`: JVM arguments to pass to Gradle. * `java.import.gradle.home`: setting for GRADLE_HOME. - +* `java.selectionRange.enabled`: Setting for Smart Selection support for Java. When it's on, Expand/Shrink Selection works better for Java code. Troubleshooting =============== diff --git a/package-lock.json b/package-lock.json index a5f87e500..b043500b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -232,9 +232,9 @@ } }, "agent-base": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", - "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, "requires": { "es6-promisify": "^5.0.0" @@ -1746,9 +1746,9 @@ } }, "es6-promise": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz", - "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==", + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", "dev": true }, "es6-promisify": { @@ -3349,12 +3349,12 @@ "dev": true }, "https-proxy-agent": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", - "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", + "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", "dev": true, "requires": { - "agent-base": "^4.1.0", + "agent-base": "^4.3.0", "debug": "^3.1.0" }, "dependencies": { @@ -3368,9 +3368,9 @@ } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true } } @@ -6346,12 +6346,12 @@ } }, "url-parse": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.6.tgz", - "integrity": "sha512-/B8AD9iQ01seoXmXf9z/MjLZQIdOoYl/+gvsQF6+mpnxaTfG9P7srYaiqaDMyKkR36XMXfhqSHss5MyFAO8lew==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", "dev": true, "requires": { - "querystringify": "^2.0.0", + "querystringify": "^2.1.1", "requires-port": "^1.0.0" } }, @@ -6488,116 +6488,33 @@ } }, "vscode": { - "version": "1.1.33", - "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.33.tgz", - "integrity": "sha512-sXedp2oF6y4ZvqrrFiZpeMzaCLSWV+PpYkIxjG/iYquNZ9KrLL2LujltGxPLvzn49xu2sZkyC+avVNFgcJD1Iw==", + "version": "1.1.35", + "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.35.tgz", + "integrity": "sha512-xPnxzQU40LOS2yPyzWW+WKpTV6qA3z16TcgpZ9O38UWLA157Zz4GxUx5H7Gd07pxzw0GqvusbF4D+5GBgNxvEQ==", "dev": true, "requires": { "glob": "^7.1.2", - "mocha": "^4.0.1", + "mocha": "^5.2.0", "request": "^2.88.0", "semver": "^5.4.1", "source-map-support": "^0.5.0", "url-parse": "^1.4.4", - "vscode-test": "^0.1.4" - }, - "dependencies": { - "browser-stdout": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", - "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", - "dev": true - }, - "commander": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", - "dev": true - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "diff": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", - "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", - "dev": true - }, - "growl": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", - "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", - "dev": true - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", - "dev": true - }, - "mocha": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz", - "integrity": "sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==", - "dev": true, - "requires": { - "browser-stdout": "1.3.0", - "commander": "2.11.0", - "debug": "3.1.0", - "diff": "3.3.1", - "escape-string-regexp": "1.0.5", - "glob": "7.1.2", - "growl": "1.10.3", - "he": "1.1.1", - "mkdirp": "0.5.1", - "supports-color": "4.4.0" - }, - "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "dev": true, - "requires": { - "has-flag": "^2.0.0" - } - } + "vscode-test": "^0.4.1" } }, "vscode-jsonrpc": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz", - "integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg==" + "integrity": "sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg==", + "dev": true }, "vscode-languageclient": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-5.1.1.tgz", - "integrity": "sha512-jMxshi+BPRQFNG8GB00dJv7ldqMda0be26laYYll/udtJuHbog6RqK10GSxHWDN0PgY0b0m5fePyTk3bq8a0TA==", + "version": "5.3.0-next.6", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-5.3.0-next.6.tgz", + "integrity": "sha512-DxT8+gkenjCjJV6ArcP75/AQfx6HP6m6kHIbacPCpffMeoE1YMLKj6ZixA9J87yr0fMtBmqumLmDeGe7MIF2bw==", "requires": { "semver": "^5.5.0", - "vscode-languageserver-protocol": "3.13.0" + "vscode-languageserver-protocol": "^3.15.0-next.6" } }, "vscode-languageserver": { @@ -6629,23 +6546,30 @@ } }, "vscode-languageserver-protocol": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.13.0.tgz", - "integrity": "sha512-2ZGKwI+P2ovQll2PGAp+2UfJH+FK9eait86VBUdkPd9HRlm8e58aYT9pV/NYanHOcp3pL6x2yTLVCFMcTer0mg==", + "version": "3.15.0-next.6", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.6.tgz", + "integrity": "sha512-/yDpYlWyNs26mM23mT73xmOFsh1iRfgZfBdHmfAxwDKwpQKLoOSqVidtYfxlK/pD3IEKGcAVnT4WXTsguxxAMQ==", "requires": { - "vscode-jsonrpc": "^4.0.0", - "vscode-languageserver-types": "3.13.0" + "vscode-jsonrpc": "^4.1.0-next.2", + "vscode-languageserver-types": "^3.15.0-next.2" + }, + "dependencies": { + "vscode-jsonrpc": { + "version": "4.1.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.1.0-next.2.tgz", + "integrity": "sha512-GsBLjP9DxQ42yl1mW9GEIlnSc0+R8mfzhaebwmmTPEJjezD5SPoAo3DFrIAFZha9yvQ1nzZfZlhtVpGQmgxtXg==" + } } }, "vscode-languageserver-types": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.13.0.tgz", - "integrity": "sha512-BnJIxS+5+8UWiNKCP7W3g9FlE7fErFw0ofP5BXJe7c2tl0VeWh+nNHFbwAS2vmVC4a5kYxHBjRy0UeOtziemVA==" + "version": "3.15.0-next.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.2.tgz", + "integrity": "sha512-2JkrMWWUi2rlVLSo9OFR2PIGUzdiowEM8NgNYiwLKnXTjpwpjjIrJbNNxDik7Rv4oo9KtikcFQZKXbrKilL/MQ==" }, "vscode-test": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-0.1.5.tgz", - "integrity": "sha512-s+lbF1Dtasc0yXVB9iQTexBe2JK6HJAUJe3fWezHKIjq+xRw5ZwCMEMBaonFIPy7s95qg2HPTRDR5W4h4kbxGw==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-0.4.3.tgz", + "integrity": "sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w==", "dev": true, "requires": { "http-proxy-agent": "^2.1.0", diff --git a/package.json b/package.json index 8ce3587cd..e7d6734d4 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "preview": true, "enableProposedApi": false, "engines": { - "vscode": "^1.31.0" + "vscode": "^1.33.0" }, "repository": { "type": "git", @@ -373,6 +373,12 @@ "description": "Limit number of items in arrays/collections/maps to list, if 0 then list all.", "default": 0, "scope": "window" + }, + "java.selectionRange.enabled": { + "type": "boolean", + "default": true, + "description": "Enable/disable Smart Selection support for Java. Disabling this option will not affect the VS Code built-in word-based and bracket-based smart selection.", + "scope": "window" } } }, @@ -514,12 +520,12 @@ "tslint": "^5.11.0", "typescript": "^3.4.1", "typescript-tslint-plugin": "^0.3.1", - "vscode": "^1.1.33", + "vscode": "^1.1.35", "webpack": "^4.27.1", "webpack-cli": "^3.1.2" }, "dependencies": { - "vscode-languageclient": "~5.1.1", + "vscode-languageclient": "5.3.0-next.6", "find-java-home": "0.2.0", "tmp": "^0.0.33", "path-exists": "^3.0.0", From cf1fbe19f4317f574f996421d89577cf114b2ab9 Mon Sep 17 00:00:00 2001 From: Rome Li Date: Wed, 17 Jul 2019 17:01:56 +0800 Subject: [PATCH 0029/1031] Migrate to 'vscode-test' (#981) Signed-off-by: Rome Li --- .vscode/launch.json | 4 ++-- package-lock.json | 49 ++++++++---------------------------------- package.json | 14 ++++++------ src/plugin.ts | 4 ++-- test/extension.test.ts | 15 +++++++------ test/index.ts | 49 +++++++++++++++++++++++++++++++----------- test/runtest.ts | 23 ++++++++++++++++++++ 7 files changed, 88 insertions(+), 70 deletions(-) create mode 100644 test/runtest.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 14f578dcd..3a337dd88 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -49,8 +49,8 @@ "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], "stopOnEntry": false, "sourceMaps": true, - "outFiles": ["${workspaceRoot}/out/test/**"], + "outFiles": ["${workspaceRoot}/out/**/*.js"], "preLaunchTask": "npm: compile" } ] -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index b043500b8..854cf57f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,12 @@ "integrity": "sha512-JWB3xaVfsfnFY8Ofc9rTB/op0fqqTSqy4vBcVk1LuRJvta7KTX+D//fCkiTMeLGhdr2EbFZzQjC97gvmPilk9Q==", "dev": true }, + "@types/vscode": { + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.36.0.tgz", + "integrity": "sha512-SbHR3Q5g/C3N+Ila3KrRf1rSZiyHxWdOZ7X3yFHXzw6HrvRLuVZrxnwEX0lTBMRpH9LkwZdqRTgXW+D075jxkg==", + "dev": true + }, "@webassemblyjs/ast": { "version": "1.7.11", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz", @@ -4982,12 +4988,6 @@ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", "dev": true }, - "querystringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", - "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", - "dev": true - }, "randombytes": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", @@ -5186,12 +5186,6 @@ "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, "resolve": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", @@ -6345,16 +6339,6 @@ } } }, - "url-parse": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", - "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -6487,21 +6471,6 @@ "indexof": "0.0.1" } }, - "vscode": { - "version": "1.1.35", - "resolved": "https://registry.npmjs.org/vscode/-/vscode-1.1.35.tgz", - "integrity": "sha512-xPnxzQU40LOS2yPyzWW+WKpTV6qA3z16TcgpZ9O38UWLA157Zz4GxUx5H7Gd07pxzw0GqvusbF4D+5GBgNxvEQ==", - "dev": true, - "requires": { - "glob": "^7.1.2", - "mocha": "^5.2.0", - "request": "^2.88.0", - "semver": "^5.4.1", - "source-map-support": "^0.5.0", - "url-parse": "^1.4.4", - "vscode-test": "^0.4.1" - } - }, "vscode-jsonrpc": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz", @@ -6567,9 +6536,9 @@ "integrity": "sha512-2JkrMWWUi2rlVLSo9OFR2PIGUzdiowEM8NgNYiwLKnXTjpwpjjIrJbNNxDik7Rv4oo9KtikcFQZKXbrKilL/MQ==" }, "vscode-test": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-0.4.3.tgz", - "integrity": "sha512-EkMGqBSefZH2MgW65nY05rdRSko15uvzq4VAPM5jVmwYuFQKE7eikKXNJDRxL+OITXHB6pI+a3XqqD32Y3KC5w==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.0.0.tgz", + "integrity": "sha512-RnZUhxEXYCozHtBAQwX/UISlw0JPqlv1I9LLl4++vcPDIvjs2Zfz2Inp8haxixS1sOTftHJ9kiecrwWF9S3taQ==", "dev": true, "requires": { "http-proxy-agent": "^2.1.0", diff --git a/package.json b/package.json index e7d6734d4..6e6f42ab7 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "preview": true, "enableProposedApi": false, "engines": { - "vscode": "^1.33.0" + "vscode": "^1.36.0" }, "repository": { "type": "git", @@ -500,18 +500,18 @@ }, "scripts": { "vscode:prepublish": "webpack --mode production", - "compile": "tsc -p ./", + "compile": "tsc -p ./&webpack --mode development", "watch": "webpack --mode development --watch --info-verbosity verbose", - "postinstall": "node ./node_modules/vscode/bin/install", - "test": "node ./node_modules/vscode/bin/test", + "pretest": "npm run compile", + "test": "node ./out/test/runtest.js", "build-server": "./node_modules/.bin/gulp build_server", - "watch-server": "./node_modules/.bin/gulp watch_server", - "webpack": "webpack --mode development" + "watch-server": "./node_modules/.bin/gulp watch_server" }, "devDependencies": { "@types/glob": "5.0.30", "@types/mocha": "^5.2.5", "@types/node": "^6.0.40", + "@types/vscode": "^1.36.0", "gulp": "^4.0.0", "gulp-decompress": "2.0.1", "gulp-download": "0.0.1", @@ -520,7 +520,7 @@ "tslint": "^5.11.0", "typescript": "^3.4.1", "typescript-tslint-plugin": "^0.3.1", - "vscode": "^1.1.35", + "vscode-test": "^1.0.0", "webpack": "^4.27.1", "webpack-cli": "^3.1.2" }, diff --git a/src/plugin.ts b/src/plugin.ts index b930e230e..a88b1f58e 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -6,7 +6,7 @@ import { Commands } from './commands'; let existingExtensions: Array; -export function collectJavaExtensions(extensions: vscode.Extension[]): string[] { +export function collectJavaExtensions(extensions: readonly vscode.Extension[]): string[] { const result = []; if (extensions && extensions.length) { for (const extension of extensions) { @@ -26,7 +26,7 @@ export function collectJavaExtensions(extensions: vscode.Extension[]): stri return result; } -export function onExtensionChange(extensions: vscode.Extension[]) { +export function onExtensionChange(extensions: readonly vscode.Extension[]) { if (!existingExtensions) { return; } diff --git a/test/extension.test.ts b/test/extension.test.ts index 79bb155c8..687048186 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -20,7 +20,7 @@ suite('Java Language Extension', () => { }); }); - test('should register all java commands', function () { + test('should register all java commands', () => { return vscode.commands.getCommands(true).then((commands) => { const JAVA_COMMANDS = [ @@ -53,14 +53,14 @@ suite('Java Language Extension', () => { Commands.APPLY_REFACTORING_COMMAND, Commands.RENAME_COMMAND ]; - const foundJavaCommands = commands.filter(function(value) { + const foundJavaCommands = commands.filter((value) => { return JAVA_COMMANDS.indexOf(value)>=0 || value.startsWith('java.'); }); assert.equal(foundJavaCommands.length , JAVA_COMMANDS.length, 'Some Java commands are not registered properly or a new command is not added to the test'); }); }); - test('should parse VM arguments', function () { + test('should parse VM arguments', () => { const userArgs = '-Xmx512m -noverify -Dfoo=\"something with blank\" '; const vmArgs = ['-noverify', 'foo']; @@ -73,7 +73,7 @@ suite('Java Language Extension', () => { assert.equal('-Dfoo=something with blank', vmArgs[3]); }); - test('should parse VM arguments with spaces', function () { + test('should parse VM arguments with spaces', () => { const userArgs = '-javaagent:"C:\\Program Files\\Java\\lombok.jar" -Xbootclasspath/a:"C:\\Program Files\\Java\\lombok.jar" -Dfoo="Some \\"crazy\\" stuff"'; const vmArgs = []; @@ -85,7 +85,7 @@ suite('Java Language Extension', () => { assert.equal(vmArgs[2], '-Dfoo=Some "crazy" stuff'); }); - test('should collect java extensions', function () { + test('should collect java extensions', () => { const packageJSON = JSON.parse(fs.readFileSync(path.join(__dirname, '../../test/resources/packageExample.json'), 'utf8')); const fakedExtension = { id: 'test', @@ -93,7 +93,8 @@ suite('Java Language Extension', () => { isActive: true, packageJSON, exports: '', - activate: null + activate: null, + extensionKind: vscode.ExtensionKind.Workspace }; const extensions = [fakedExtension]; @@ -102,7 +103,7 @@ suite('Java Language Extension', () => { assert(result[0].endsWith(path.normalize('./bin/java.extend.jar'))); }); - test('should parse Java version', function () { + test('should parse Java version', () => { // Test boundaries assert.equal(requirements.parseMajorVersion(null), 0); assert.equal(requirements.parseMajorVersion(''), 0); diff --git a/test/index.ts b/test/index.ts index f38dc9ddd..8275646bf 100644 --- a/test/index.ts +++ b/test/index.ts @@ -1,23 +1,48 @@ -// -// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING +// +// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING // // This file is providing the test runner to use when running extension tests. // By default the test runner in use is Mocha based. -// +// // You can provide your own test runner if you want to override it by exporting // a function run(testRoot: string, clb: (error:Error) => void) that the extension // host can call to run the tests. The test runner is expected to use console.log // to report the results back to the caller. When the tests are finished, return // a possible error to the callback or null if none. -// tslint:disable-next-line:no-require-imports -let testRunner = require('vscode/lib/testrunner'); +import * as path from 'path'; +import * as Mocha from 'mocha'; +import * as glob from 'glob'; + +export function run(): Promise { + const mocha = new Mocha({ + ui: 'tdd', + useColors: true + }); + + const testsRoot = path.resolve(__dirname, '..'); + + return new Promise((c, e) => { + glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { + if (err) { + return e(err); + } -// You can directly control Mocha options by uncommenting the following lines -// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info -testRunner.configure({ - ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.) - useColors: true // colored output from test results -}); + // Add files to the test suite + files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); -module.exports = testRunner; \ No newline at end of file + try { + // Run the mocha test + mocha.run(failures => { + if (failures > 0) { + e(new Error(`${failures} tests failed.`)); + } else { + c(); + } + }); + } catch (err) { + e(err); + } + }); + }); +} diff --git a/test/runtest.ts b/test/runtest.ts new file mode 100644 index 000000000..e48da460f --- /dev/null +++ b/test/runtest.ts @@ -0,0 +1,23 @@ +import * as path from 'path'; + +import { runTests } from 'vscode-test'; + +async function main() { + try { + // The folder containing the Extension Manifest package.json + // Passed to `--extensionDevelopmentPath` + const extensionDevelopmentPath = path.resolve(__dirname, '../..'); + + // The path to the extension test script + // Passed to --extensionTestsPath + const extensionTestsPath = path.resolve(__dirname, './'); + + // Download VS Code, unzip it and run the integration test + await runTests({ extensionDevelopmentPath, extensionTestsPath }); + } catch (err) { + console.error('Failed to run tests'); + process.exit(1); + } +} + +main(); From 1445ee101e611c9c567cfa0a91a7f9b93841b8ed Mon Sep 17 00:00:00 2001 From: Rome Li Date: Wed, 17 Jul 2019 21:21:23 +0800 Subject: [PATCH 0030/1031] Log file to record client errors Signed-off-by: Rome Li --- package-lock.json | 213 +++++++++++++++++++++++++++++++++++---- package.json | 4 +- src/extension.ts | 22 ++-- src/javaServerStarter.ts | 7 +- src/log.ts | 21 ++++ 5 files changed, 235 insertions(+), 32 deletions(-) create mode 100644 src/log.ts diff --git a/package-lock.json b/package-lock.json index 854cf57f5..804c2b5e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,6 +38,15 @@ "integrity": "sha512-SbHR3Q5g/C3N+Ila3KrRf1rSZiyHxWdOZ7X3yFHXzw6HrvRLuVZrxnwEX0lTBMRpH9LkwZdqRTgXW+D075jxkg==", "dev": true }, + "@types/winston": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/winston/-/winston-2.4.4.tgz", + "integrity": "sha512-BVGCztsypW8EYwJ+Hq+QNYiT/MUyCif0ouBH+flrY66O5W+KIXAMML6E/0fJpm7VjIzgangahl5S03bJJQGrZw==", + "dev": true, + "requires": { + "winston": "*" + } + }, "@webassemblyjs/ast": { "version": "1.7.11", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz", @@ -533,6 +542,14 @@ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", "dev": true }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "requires": { + "lodash": "^4.17.14" + } + }, "async-done": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.1.tgz", @@ -1133,11 +1150,19 @@ "object-visit": "^1.0.0" } }, + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -1145,8 +1170,16 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } }, "color-support": { "version": "1.1.3", @@ -1154,6 +1187,25 @@ "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true }, + "colornames": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", + "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" + }, + "colors": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", + "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==" + }, + "colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + } + }, "combined-stream": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", @@ -1258,8 +1310,7 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "create-ecdh": { "version": "4.0.3", @@ -1580,6 +1631,16 @@ "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", "dev": true }, + "diagnostics": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", + "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", + "requires": { + "colorspace": "1.1.x", + "enabled": "1.0.x", + "kuler": "1.0.x" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -1691,6 +1752,14 @@ "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", "dev": true }, + "enabled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", + "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", + "requires": { + "env-variable": "0.0.x" + } + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -1711,6 +1780,11 @@ "tapable": "^1.0.0" } }, + "env-variable": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", + "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==" + }, "errno": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", @@ -2041,6 +2115,11 @@ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "dev": true }, + "fast-safe-stringify": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", + "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==" + }, "fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -2050,6 +2129,11 @@ "pend": "~1.2.0" } }, + "fecha": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", + "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" + }, "figgy-pudding": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", @@ -3629,8 +3713,7 @@ "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "is-typedarray": { "version": "1.0.0", @@ -3668,8 +3751,7 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", @@ -3780,6 +3862,14 @@ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true }, + "kuler": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", + "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", + "requires": { + "colornames": "^1.1.1" + } + }, "last-run": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", @@ -3873,6 +3963,11 @@ "path-exists": "^3.0.0" } }, + "lodash": { + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", + "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==" + }, "lodash._basecopy": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", @@ -3998,6 +4093,25 @@ "lodash.escape": "^3.0.0" } }, + "logform": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz", + "integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==", + "requires": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^2.3.3", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -4616,6 +4730,11 @@ "wrappy": "1" } }, + "one-time": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", + "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=" + }, "ordered-read-streams": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", @@ -5032,7 +5151,6 @@ "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -5046,8 +5164,7 @@ "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" } } }, @@ -5272,8 +5389,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safe-regex": { "version": "1.1.0", @@ -5395,6 +5511,21 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -5633,8 +5764,7 @@ "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", - "dev": true + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, "static-extend": { "version": "0.1.2", @@ -5717,7 +5847,6 @@ "version": "1.1.1", "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "requires": { "safe-buffer": "~5.1.0" } @@ -5852,6 +5981,11 @@ } } }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", @@ -5998,6 +6132,11 @@ } } }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, "ts-loader": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-5.3.1.tgz", @@ -6357,8 +6496,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "uuid": { "version": "3.3.2", @@ -6796,6 +6934,43 @@ "resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.4.tgz", "integrity": "sha1-ugZWKbepJRMOFXeRCM9UCZDpjRs=" }, + "winston": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz", + "integrity": "sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==", + "requires": { + "async": "^2.6.1", + "diagnostics": "^1.1.1", + "is-stream": "^1.1.0", + "logform": "^2.1.1", + "one-time": "0.0.4", + "readable-stream": "^3.1.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.3.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "winston-transport": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", + "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", + "requires": { + "readable-stream": "^2.3.6", + "triple-beam": "^1.2.0" + } + }, "worker-farm": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", diff --git a/package.json b/package.json index 6e6f42ab7..8985efb82 100644 --- a/package.json +++ b/package.json @@ -512,6 +512,7 @@ "@types/mocha": "^5.2.5", "@types/node": "^6.0.40", "@types/vscode": "^1.36.0", + "@types/winston": "^2.4.4", "gulp": "^4.0.0", "gulp-decompress": "2.0.1", "gulp-download": "0.0.1", @@ -530,6 +531,7 @@ "tmp": "^0.0.33", "path-exists": "^3.0.0", "expand-home-dir": "^0.0.3", - "glob": "^7.1.3" + "glob": "^7.1.3", + "winston": "^3.2.1" } } diff --git a/src/extension.ts b/src/extension.ts index e91c7a79f..16f28279a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -20,6 +20,7 @@ import * as refactorAction from './refactorAction'; import * as net from 'net'; import { getJavaConfiguration } from './utils'; import { onConfigurationChange, excludeProjectSettingsFiles } from './settings'; +import { logger, initializeLogFile } from './log'; let lastStatus; let languageClient: LanguageClient; @@ -28,6 +29,13 @@ const cleanWorkspaceFileName = '.cleanWorkspace'; export function activate(context: ExtensionContext): Promise { + let storagePath = context.storagePath; + if (!storagePath) { + storagePath = getTempWorkspace(); + } + + initializeLogFile(path.join(storagePath, 'client.log')); + enableJavadocSymbols(); return requirements.resolveRequirements().catch(error => { @@ -42,10 +50,6 @@ export function activate(context: ExtensionContext): Promise { }).then(requirements => { return window.withProgress({ location: ProgressLocation.Window }, p => { return new Promise((resolve, reject) => { - let storagePath = context.storagePath; - if (!storagePath) { - storagePath = getTempWorkspace(); - } const workspacePath = path.resolve(storagePath + '/jdt_ws'); // Options to control the language client @@ -390,7 +394,7 @@ function enableJavadocSymbols() { function logNotification(message: string, ...items: string[]) { return new Promise((resolve, reject) => { - console.log(message); + logger.verbose(message); }); } @@ -398,8 +402,8 @@ function setIncompleteClasspathSeverity(severity: string) { const config = getJavaConfiguration(); const section = 'errors.incompleteClasspath.severity'; config.update(section, severity, true).then( - () => console.log(`${section} globally set to ${severity}`), - (error) => console.log(error) + () => logger.info(`${section} globally set to ${severity}`), + (error) => logger.error(error) ); } @@ -426,8 +430,8 @@ function setProjectConfigurationUpdate(languageClient: LanguageClient, uri: Uri, const st = FeatureStatus[status]; config.update(section, st).then( - () => console.log(`${section} set to ${st}`), - (error) => console.log(error) + () => logger.info(`${section} set to ${st}`), + (error) => logger.error(error) ); if (status !== FeatureStatus.disabled) { projectConfigurationUpdate(languageClient, uri); diff --git a/src/javaServerStarter.ts b/src/javaServerStarter.ts index 633001fc9..5e02d8c6e 100644 --- a/src/javaServerStarter.ts +++ b/src/javaServerStarter.ts @@ -6,6 +6,7 @@ import * as os from 'os'; import { StreamInfo, Executable, ExecutableOptions } from 'vscode-languageclient'; import { RequirementsData } from './requirements'; import { getJavaEncoding } from './settings'; +import { logger } from './log'; declare var v8debug; const DEBUG = (typeof v8debug === 'object') || startedInDebugMode(); @@ -18,7 +19,7 @@ export function prepareExecutable(requirements: RequirementsData, workspacePath, executable.options = options; executable.command = path.resolve(requirements.java_home + '/bin/java'); executable.args = prepareParams(requirements, javaConfig, workspacePath); - console.log(`Starting Java server with: ${executable.command} ${executable.args.join(' ')}`); + logger.info(`Starting Java server with: ${executable.command} ${executable.args.join(' ')}`); return executable; } export function awaitServerConnection(port): Thenable { @@ -26,13 +27,13 @@ export function awaitServerConnection(port): Thenable { return new Promise((res, rej) => { const server = net.createServer(stream => { server.close(); - console.log('JDT LS connection established on port ' + addr); + logger.info('JDT LS connection established on port ' + addr); res({ reader: stream, writer: stream }); }); server.on('error', rej); server.listen(addr, () => { server.removeListener('error', rej); - console.log('Awaiting JDT LS connection on port ' + addr); + logger.info('Awaiting JDT LS connection on port ' + addr); }); return server; }); diff --git a/src/log.ts b/src/log.ts new file mode 100644 index 000000000..e8f4432c1 --- /dev/null +++ b/src/log.ts @@ -0,0 +1,21 @@ +import { createLogger, format, transports } from 'winston'; + +export function initializeLogFile(filename: string) { + logger.add(new transports.File({ + filename: filename, + maxsize: 100 * 1024, // 100k max size per file + maxFiles: 2 // the last 100k of logs are always available + })); +} + +export const logger = createLogger({ + format: format.combine( + format.timestamp({ + format: 'YYYY-MM-DD HH:mm:ss.SSS' + }), + format.prettyPrint() + ), + transports: [ + new transports.Console() + ] +}); From 6cd52cfb06d358ebb7511a54c356795e146ebab0 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Wed, 17 Jul 2019 18:08:35 +0200 Subject: [PATCH 0031/1031] Add 'Open Java extension log file' command Signed-off-by: Fred Bricon --- package.json | 7 ++++++- src/commands.ts | 6 ++++++ src/extension.ts | 24 ++++++++++++++++++------ test/extension.test.ts | 1 + 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 8985efb82..e8a2c4981 100644 --- a/package.json +++ b/package.json @@ -390,7 +390,12 @@ }, { "command": "java.open.serverLog", - "title": "Open Java Language Server log file", + "title": "Open Java language server log file", + "category": "Java" + }, + { + "command": "java.open.clientLog", + "title": "Open Java extension log file", "category": "Java" }, { diff --git a/src/commands.ts b/src/commands.ts index a2ab5f6f0..3ac381cdd 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -74,6 +74,12 @@ export namespace Commands { */ export const OPEN_SERVER_LOG = 'java.open.serverLog'; + /** + * Open Java client Log file + */ + export const OPEN_CLIENT_LOG = 'java.open.clientLog'; + + /** * Open Java formatter settings */ diff --git a/src/extension.ts b/src/extension.ts index 16f28279a..2c4cf280c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -26,6 +26,7 @@ let lastStatus; let languageClient: LanguageClient; const jdtEventEmitter = new EventEmitter(); const cleanWorkspaceFileName = '.cleanWorkspace'; +let clientLogFile; export function activate(context: ExtensionContext): Promise { @@ -33,8 +34,8 @@ export function activate(context: ExtensionContext): Promise { if (!storagePath) { storagePath = getTempWorkspace(); } - - initializeLogFile(path.join(storagePath, 'client.log')); + clientLogFile = path.join(storagePath, 'client.log'); + initializeLogFile(clientLogFile); enableJavadocSymbols(); @@ -331,6 +332,8 @@ export function activate(context: ExtensionContext): Promise { context.subscriptions.push(commands.registerCommand(Commands.OPEN_SERVER_LOG, () => openServerLogFile(workspacePath))); + context.subscriptions.push(commands.registerCommand(Commands.OPEN_CLIENT_LOG, () => openClientLogFile(clientLogFile))); + const extensionPath = context.extensionPath; context.subscriptions.push(commands.registerCommand(Commands.OPEN_FORMATTER, async () => openFormatter(extensionPath))); @@ -491,11 +494,20 @@ function deleteDirectory(dir) { function openServerLogFile(workspacePath): Thenable { const serverLogFile = path.join(workspacePath, '.metadata', '.log'); - if (!fs.existsSync(serverLogFile)) { - return window.showWarningMessage('Java Language Server has not started logging.').then(() => false); + return openLogFile(serverLogFile, 'Could not open Java Language Server log file'); +} + +function openClientLogFile(logFile): Thenable { + return openLogFile(logFile, 'Could not open Java extension log file'); +} + + +function openLogFile(logFile, openingFailureWarning:string ): Thenable { + if (!fs.existsSync(logFile)) { + return window.showWarningMessage('No log file available').then(() => false); } - return workspace.openTextDocument(serverLogFile) + return workspace.openTextDocument(logFile) .then(doc => { if (!doc) { return false; @@ -506,7 +518,7 @@ function openServerLogFile(workspacePath): Thenable { }, () => false) .then(didOpen => { if (!didOpen) { - window.showWarningMessage('Could not open Java Language Server log file'); + window.showWarningMessage(openingFailureWarning); } return didOpen; }); diff --git a/test/extension.test.ts b/test/extension.test.ts index 687048186..3e3db1976 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -34,6 +34,7 @@ suite('Java Language Extension', () => { Commands.APPLY_WORKSPACE_EDIT, Commands.EXECUTE_WORKSPACE_COMMAND, Commands.OPEN_SERVER_LOG, + Commands.OPEN_CLIENT_LOG, Commands.COMPILE_WORKSPACE, Commands.OPEN_FORMATTER, Commands.CLEAN_WORKSPACE, From 8fda1d0e6a78dc3e0ee4343fdf1b755352c4aa39 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Wed, 17 Jul 2019 19:28:06 +0200 Subject: [PATCH 0032/1031] Changelog for the 0.47.0 release Signed-off-by: Fred Bricon --- CHANGELOG.md | 16 ++++++++++++++++ README.md | 7 ++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c51fb8838..f0d04c203 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Change Log +## 0.47.0 (July 19th, 2019) +* enhancement - trigger client autorename after 'extract to variable/constant/method'. See [#333](https://github.com/redhat-developer/vscode-java/issues/333). +* enhancement - added support for semantic selection. See [#780](https://github.com/redhat-developer/vscode-java/issues/780). +* enhancement - Maven projects use the latest Execution Environment when source/target is not yet supported. See [#951](https://github.com/redhat-developer/vscode-java/issues/951). +* enhancement - added code action to convert a local variable to a field. See [#971](https://github.com/redhat-developer/vscode-java/pull/971). +* enhancement - added additional Gradle preferences. See [#973](https://github.com/redhat-developer/vscode-java/pull/973). +* enhancement - added new command to open the Java extension log. See [#985](https://github.com/redhat-developer/vscode-java/issues/985). +* enhancement - prevented aggressive classpath updates when jars don't change. See [JLS#1078](https://github.com/eclipse/eclipse.jdt.ls/pull/1078). +* enhancement - new extension point to register static commands during JDT LS initialization . See [JLS#1084](https://github.com/eclipse/eclipse.jdt.ls/issues/1084). +* bug fix - fixed "Extract Variable" returning a wrong cursor position. See [#952](https://github.com/redhat-developer/vscode-java/issues/952). +* bug fix - use the default `GRADLE_USER_HOME` env var if possible, for Gradle wrappers and modules. See [JLS#1072](https://github.com/eclipse/eclipse.jdt.ls/pull/1072). +* bug fix - fixed signature help returning the wrong active parameter. See [JLS#1039](https://github.com/eclipse/eclipse.jdt.ls/issues/1039). +* bug fix - fixed signature help stopped working after using a lambda. See [JLS#1086](https://github.com/eclipse/eclipse.jdt.ls/issues/1086). +* debt - replaced vscode package with @types/vscode. See [#977](https://github.com/redhat-developer/vscode-java/issues/977). +* documentation - setup the project for development. See [#949](https://github.com/redhat-developer/vscode-java/issues/949.) + ## 0.46.0 (June 5th, 2019) * enhancement - new 'try with resources' snippet, triggered by `try_resources`. See [#932](https://github.com/redhat-developer/vscode-java/pull/932). * enhancement - new 'private field' snippet, triggered by `prf`. See [#933](https://github.com/redhat-developer/vscode-java/pull/933). diff --git a/README.md b/README.md index 6bf5cbaa0..583c0ea53 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ Features * Code formatting (on-type/selection/file) * Code snippets * Annotation processing support (automatic for Maven projects) +* Semantic selection Please note that [Gradle-based Android projects are not supported](https://github.com/redhat-developer/vscode-java/issues/10#issuecomment-268834749). @@ -58,7 +59,8 @@ Available commands ========================== The following commands are available: - `Java:Update Project configuration` (`Shift+Alt+U`): is available when the editor is focused on a Maven pom.xml or a Gradle file. It forces project configuration / classpath updates (eg. dependency changes or Java compilation level), according to the project build descriptor. -- `Java:Open Java Language Server log file`: opens the Java Language Server log file, useful for troubleshooting problems. +- `Java:Open Java language server log file`: opens the Java Language Server log file, useful for troubleshooting problems. +- `Java:Open Java extension log file`: opens the Java extension log file, useful for troubleshooting problems. - `Java:Force Java compilation` (`Shift+Alt+B`): manually triggers compilation of the workspace. - `Java:Open Java formatter settings`: Open the Eclipse formatter settings. Creates a new settings file if none exists. - `Java:Clean the Java language server workspace`: Clean the Java language server workspace. @@ -98,7 +100,6 @@ The following settings are supported: * `java.completion.enabled` : Enable/disable code completion support. * `java.configuration.checkProjectSettingsExclusions`: Checks if the extension-generated project settings files (`.project`, `.classpath`, `.factorypath`, `.settings/`) should be excluded from the file explorer. Defaults to `true`. * `java.foldingRange.enabled`: Enable/disable smart folding range support. If disabled, it will use the default indentation-based folding range provided by VS Code. -* `java.selectionRange.enabled`: Enable/disable Smart Selection support for Java. Disabling this option will not affect the VS Code built-in word-based and bracket-based smart selection. * `java.maven.downloadSources`: Enable/disable eager download of Maven source artifacts. * `java.codeGeneration.hashCodeEquals.useInstanceof`: Use 'instanceof' to compare types when generating the hashCode and equals methods. Defaults to `false`. * `java.codeGeneration.hashCodeEquals.useJava7Objects`: Use Objects.hash and Objects.equals when generating the hashCode and equals methods. This setting only applies to Java 7 and higher. Defaults to `false`. @@ -115,7 +116,7 @@ The following settings are supported: * `java.import.gradle.arguments`: Arguments to pass to Gradle. * `java.import.gradle.jvmArguments`: JVM arguments to pass to Gradle. * `java.import.gradle.home`: setting for GRADLE_HOME. -* `java.selectionRange.enabled`: Setting for Smart Selection support for Java. When it's on, Expand/Shrink Selection works better for Java code. +* `java.selectionRange.enabled`: Enable/disable Smart Selection support for Java. Disabling this option will not affect the VS Code built-in word-based and bracket-based smart selection. Troubleshooting =============== From 418334b7093670ce4ceb7f83c89b5e4741d0d34a Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Wed, 17 Jul 2019 19:47:42 +0200 Subject: [PATCH 0033/1031] npm audit fix Signed-off-by: Fred Bricon --- package-lock.json | 43 ++++++++++--------------------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/package-lock.json b/package-lock.json index 804c2b5e0..ede9eb961 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4325,9 +4325,9 @@ } }, "mixin-deep": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", "dev": true, "requires": { "for-in": "^1.0.2", @@ -5452,9 +5452,9 @@ "dev": true }, "set-value": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -6337,38 +6337,15 @@ "dev": true }, "union-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", - "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", - "set-value": "^0.4.3" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "set-value": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", - "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.1", - "to-object-path": "^0.3.0" - } - } + "set-value": "^2.0.1" } }, "unique-filename": { From 13235c83d581564c5b442477938d5af906e381ea Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Thu, 18 Jul 2019 15:09:34 +0200 Subject: [PATCH 0034/1031] Fix typo and update release date in changelog Signed-off-by: Fred Bricon --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0d04c203..21a83f078 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log -## 0.47.0 (July 19th, 2019) +## 0.47.0 (July 18th, 2019) * enhancement - trigger client autorename after 'extract to variable/constant/method'. See [#333](https://github.com/redhat-developer/vscode-java/issues/333). * enhancement - added support for semantic selection. See [#780](https://github.com/redhat-developer/vscode-java/issues/780). * enhancement - Maven projects use the latest Execution Environment when source/target is not yet supported. See [#951](https://github.com/redhat-developer/vscode-java/issues/951). @@ -14,7 +14,7 @@ * bug fix - fixed signature help returning the wrong active parameter. See [JLS#1039](https://github.com/eclipse/eclipse.jdt.ls/issues/1039). * bug fix - fixed signature help stopped working after using a lambda. See [JLS#1086](https://github.com/eclipse/eclipse.jdt.ls/issues/1086). * debt - replaced vscode package with @types/vscode. See [#977](https://github.com/redhat-developer/vscode-java/issues/977). -* documentation - setup the project for development. See [#949](https://github.com/redhat-developer/vscode-java/issues/949.) +* documentation - setup the project for development. See [#949](https://github.com/redhat-developer/vscode-java/issues/949). ## 0.46.0 (June 5th, 2019) * enhancement - new 'try with resources' snippet, triggered by `try_resources`. See [#932](https://github.com/redhat-developer/vscode-java/pull/932). From b811c79f3acd199bbe7aafe9a3127550fda5844e Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Thu, 18 Jul 2019 19:02:29 +0200 Subject: [PATCH 0035/1031] Upversion to 0.48.0 Signed-off-by: Fred Bricon --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ede9eb961..98e649e22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "java", - "version": "0.47.0", + "version": "0.48.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e8a2c4981..16061205b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "author": "Red Hat", "icon": "icons/icon128.png", "license": "EPL-1.0", - "version": "0.47.0", + "version": "0.48.0", "publisher": "redhat", "bugs": "https://github.com/redhat-developer/vscode-java/issues", "preview": true, From 00200318212b439036861513899f352149e1d55c Mon Sep 17 00:00:00 2001 From: Rome Li Date: Thu, 18 Jul 2019 11:38:41 +0800 Subject: [PATCH 0036/1031] Rotate client log file daily Signed-off-by: Rome Li --- package-lock.json | 72 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 +- src/extension.ts | 18 ++++++++++-- src/log.ts | 8 ++++-- 4 files changed, 95 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 98e649e22..d15dd5172 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1392,6 +1392,11 @@ "randomfill": "^1.0.3" } }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" + }, "cyclist": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", @@ -2140,6 +2145,14 @@ "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", "dev": true }, + "file-stream-rotator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.4.1.tgz", + "integrity": "sha512-W3aa3QJEc8BS2MmdVpQiYLKHj3ijpto1gMDlsgCRSKfIUe6MwkcpODGPQ3vZfb0XvCeCqlu9CBQTN7oQri2TZQ==", + "requires": { + "moment": "^2.11.2" + } + }, "file-type": { "version": "3.9.0", "resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", @@ -4431,6 +4444,11 @@ "normalize-path": "^2.1.1" } }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -4654,6 +4672,11 @@ } } }, + "object-hash": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", + "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==" + }, "object-keys": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", @@ -6939,6 +6962,55 @@ } } }, + "winston-compat": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/winston-compat/-/winston-compat-0.1.4.tgz", + "integrity": "sha512-mMEfFsSm6GmkFF+f4/0UJtG4N1vSaczGmXLVJYmS/+u2zUaIPcw2ZRuwUg2TvVBjswgiraN+vNnAG8z4fRUZ4w==", + "requires": { + "cycle": "~1.0.3", + "logform": "^1.6.0", + "triple-beam": "^1.2.0" + }, + "dependencies": { + "logform": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-1.10.0.tgz", + "integrity": "sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==", + "requires": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^2.3.3", + "ms": "^2.1.1", + "triple-beam": "^1.2.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "winston-daily-rotate-file": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-3.10.0.tgz", + "integrity": "sha512-KO8CfbI2CvdR3PaFApEH02GPXiwJ+vbkF1mCkTlvRIoXFI8EFlf1ACcuaahXTEiDEKCii6cNe95gsL4ZkbnphA==", + "requires": { + "file-stream-rotator": "^0.4.1", + "object-hash": "^1.3.0", + "semver": "^6.2.0", + "triple-beam": "^1.3.0", + "winston-compat": "^0.1.4", + "winston-transport": "^4.2.0" + }, + "dependencies": { + "semver": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.2.0.tgz", + "integrity": "sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A==" + } + } + }, "winston-transport": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", diff --git a/package.json b/package.json index 16061205b..66445cf4a 100644 --- a/package.json +++ b/package.json @@ -537,6 +537,7 @@ "path-exists": "^3.0.0", "expand-home-dir": "^0.0.3", "glob": "^7.1.3", - "winston": "^3.2.1" + "winston": "^3.2.1", + "winston-daily-rotate-file": "^3.10.0" } } diff --git a/src/extension.ts b/src/extension.ts index 2c4cf280c..c003cfd9b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -21,6 +21,7 @@ import * as net from 'net'; import { getJavaConfiguration } from './utils'; import { onConfigurationChange, excludeProjectSettingsFiles } from './settings'; import { logger, initializeLogFile } from './log'; +import glob = require('glob'); let lastStatus; let languageClient: LanguageClient; @@ -497,8 +498,21 @@ function openServerLogFile(workspacePath): Thenable { return openLogFile(serverLogFile, 'Could not open Java Language Server log file'); } -function openClientLogFile(logFile): Thenable { - return openLogFile(logFile, 'Could not open Java extension log file'); +function openClientLogFile(logFile: string): Thenable { + return new Promise((resolve) => { + const filename = path.basename(logFile); + const dirname = path.dirname(logFile); + + // find out the newest one + glob(filename + '.*', { cwd: dirname }, (err, files) => { + if (!err && files.length > 0) { + files.sort(); + logFile = path.join(dirname, files[files.length - 1]); + } + + openLogFile(logFile, 'Could not open Java extension log file').then((result) => resolve(result)); + }); + }); } diff --git a/src/log.ts b/src/log.ts index e8f4432c1..3f248e953 100644 --- a/src/log.ts +++ b/src/log.ts @@ -1,10 +1,12 @@ import { createLogger, format, transports } from 'winston'; +import * as DailyRotateFile from 'winston-daily-rotate-file'; export function initializeLogFile(filename: string) { - logger.add(new transports.File({ + logger.add(new DailyRotateFile({ filename: filename, - maxsize: 100 * 1024, // 100k max size per file - maxFiles: 2 // the last 100k of logs are always available + datePattern: 'YYYY-MM-DD', + maxSize: '100k', // 100k max size per file + maxFiles: '2d' // retain logs of the last two days })); } From 6690072208bdf423b0a0dc3eff9f47c40341372f Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Tue, 23 Jul 2019 10:13:07 +0800 Subject: [PATCH 0037/1031] Enable the 'invert local variable' fix Signed-off-by: Sheng Chen --- src/refactorAction.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/refactorAction.ts b/src/refactorAction.ts index 658e8e082..913b829ae 100644 --- a/src/refactorAction.ts +++ b/src/refactorAction.ts @@ -14,7 +14,7 @@ function registerApplyRefactorCommand(languageClient: LanguageClient, context: E try { const uri: Uri = Uri.parse(position.uri); const document: TextDocument = await workspace.openTextDocument(uri); - if (document == null) { + if (document === null) { return; } @@ -34,7 +34,8 @@ function registerApplyRefactorCommand(languageClient: LanguageClient, context: E || command === 'extractConstant' || command === 'extractMethod' || command === 'extractField' - || command === 'convertVariableToField') { + || command === 'convertVariableToField' + || command === 'invertVariable') { const currentEditor = window.activeTextEditor; if (!currentEditor || !currentEditor.options) { return; @@ -80,7 +81,7 @@ function registerApplyRefactorCommand(languageClient: LanguageClient, context: E if (edit) { await workspace.applyEdit(edit); } - + if (result.command) { if (result.command.arguments) { await commands.executeCommand(result.command.command, ...result.command.arguments); From 1f57f69597eec81767f94b03708454d48d802cdf Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Thu, 1 Aug 2019 18:10:33 +0800 Subject: [PATCH 0038/1031] Can find Oracle JDK from Windows Registry (#1010) Update to find-java-home@1.0.0 Signed-off-by: Yan Zhang --- package-lock.json | 52 ++++++++++++++++++++++----------------------- package.json | 2 +- src/requirements.ts | 2 +- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index d15dd5172..31cde6811 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "dependencies": { "@types/glob": { "version": "5.0.30", - "resolved": "http://registry.npmjs.org/@types/glob/-/glob-5.0.30.tgz", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.30.tgz", "integrity": "sha1-ECZAnFYlqGiQdGAoCNCCsoZ7ilE=", "dev": true, "requires": { @@ -281,7 +281,7 @@ }, "ansi-colors": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", "dev": true, "requires": { @@ -382,7 +382,7 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", "dev": true }, "arr-map": { @@ -867,7 +867,7 @@ }, "buffer": { "version": "3.6.0", - "resolved": "http://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", "dev": true, "requires": { @@ -995,7 +995,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -1473,7 +1473,7 @@ "decompress-tar": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", - "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "integrity": "sha1-cYy9P8sWIJcW5womuE57pFkuWvE=", "dev": true, "requires": { "file-type": "^5.2.0", @@ -1492,7 +1492,7 @@ "decompress-tarbz2": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", - "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "integrity": "sha1-MIKluIDqQEOBY0nzeLVsUWvho5s=", "dev": true, "requires": { "decompress-tar": "^4.1.0", @@ -1505,7 +1505,7 @@ "file-type": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", - "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", + "integrity": "sha1-5QzXXTVv/tTjBtxPW89Sp5kDqRk=", "dev": true } } @@ -1513,7 +1513,7 @@ "decompress-targz": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", - "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "integrity": "sha1-wJvDXE0R894J8tLaU+neI+fOHu4=", "dev": true, "requires": { "decompress-tar": "^4.1.1", @@ -2155,7 +2155,7 @@ }, "file-type": { "version": "3.9.0", - "resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", "dev": true }, @@ -2194,9 +2194,9 @@ } }, "find-java-home": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/find-java-home/-/find-java-home-0.2.0.tgz", - "integrity": "sha512-nq5PFOHxE1VSEbdDVkLoA2bAcRnG4ETqJO8ipFq3glIWA52hdWCXYX3emuUyMAQfaqFU4Ea85gqcgaPmOApEPA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-java-home/-/find-java-home-1.0.0.tgz", + "integrity": "sha512-eqC9OCUT3stF1zfDJ/g0Uz9XFPi5X+2ZAv84Y+itA2x5scCe6GCF585re8YjjoJeIOipjNMRMM7s2E3ige+6+w==", "requires": { "which": "~1.0.5", "winreg": "~1.2.2" @@ -3194,7 +3194,7 @@ }, "through": { "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, @@ -3592,7 +3592,7 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", "dev": true }, "is-builtin-module": { @@ -3708,7 +3708,7 @@ "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "dev": true, "requires": { "isobject": "^3.0.1" @@ -4296,14 +4296,14 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -4360,7 +4360,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -4369,7 +4369,7 @@ "dependencies": { "minimist": { "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true } @@ -4784,7 +4784,7 @@ }, "os-tmpdir": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "p-defer": { @@ -4916,7 +4916,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-key": { @@ -4984,7 +4984,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, @@ -5031,7 +5031,7 @@ }, "pretty-hrtime": { "version": "1.0.3", - "resolved": "http://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, @@ -5876,7 +5876,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -5895,7 +5895,7 @@ "strip-dirs": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", - "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "integrity": "sha1-SYdzYmT8NEzyD2w0rKnRPR1O1sU=", "dev": true, "requires": { "is-natural-number": "^4.0.1" diff --git a/package.json b/package.json index 66445cf4a..42eb3b6e3 100644 --- a/package.json +++ b/package.json @@ -532,7 +532,7 @@ }, "dependencies": { "vscode-languageclient": "5.3.0-next.6", - "find-java-home": "0.2.0", + "find-java-home": "1.0.0", "tmp": "^0.0.33", "path-exists": "^3.0.0", "expand-home-dir": "^0.0.3", diff --git a/src/requirements.ts b/src/requirements.ts index 0c6a684d0..81cc13def 100644 --- a/src/requirements.ts +++ b/src/requirements.ts @@ -5,7 +5,7 @@ import * as cp from 'child_process'; import * as path from 'path'; import * as pathExists from 'path-exists'; import * as expandHomeDir from 'expand-home-dir'; -import * as findJavaHome from 'find-java-home'; +import findJavaHome = require("find-java-home"); import { Commands } from './commands'; const isWindows = process.platform.indexOf('win') === 0; From 0783074164d74daf9207a377f496fc0088f86f1f Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Fri, 2 Aug 2019 18:50:31 +0800 Subject: [PATCH 0039/1031] Enable 'Move...' in Refactor menu (#979) Signed-off-by: Jinbo Wang --- src/extension.ts | 1 + src/protocol.ts | 30 +++++++ src/refactorAction.ts | 178 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 196 insertions(+), 13 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index c003cfd9b..75266d701 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -80,6 +80,7 @@ export function activate(context: ExtensionContext): Promise { generateConstructorsPromptSupport: true, generateDelegateMethodsPromptSupport: true, advancedExtractRefactoringSupport: true, + moveRefactoringSupport: true, }, triggerFiles: getTriggerFiles() }, diff --git a/src/protocol.ts b/src/protocol.ts index aad0512cb..01850e976 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -288,6 +288,7 @@ export interface RenamePosition { export interface RefactorWorkspaceEdit { edit: WorkspaceEdit; command?: Command; + errorMessage?: string; } export interface GetRefactorEditParams { @@ -300,3 +301,32 @@ export interface GetRefactorEditParams { export namespace GetRefactorEditRequest { export const type = new RequestType('java/getRefactorEdit'); } + +export interface PackageNode { + displayName: string; + uri: string; + path: string; + project: string; + isDefaultPackage: boolean; + isParentOfSelectedFile: boolean; +} + +export interface MoveParams { + moveKind: string; + sourceUris: string[]; + params: CodeActionParams; + destination?: any; + updateReferences?: boolean; +} + +export interface MoveDestinationsResponse { + destinations: any[]; +} + +export namespace GetMoveDestinationsRequest { + export const type = new RequestType('java/getMoveDestinations'); +} + +export namespace MoveRequest { + export const type = new RequestType('java/move'); +} diff --git a/src/refactorAction.ts b/src/refactorAction.ts index 913b829ae..dadc8c2ef 100644 --- a/src/refactorAction.ts +++ b/src/refactorAction.ts @@ -1,9 +1,11 @@ 'use strict'; -import { commands, window, ExtensionContext, workspace, Position, Uri, TextDocument } from 'vscode'; -import { LanguageClient, FormattingOptions } from 'vscode-languageclient'; +import { existsSync } from 'fs'; +import * as path from 'path'; +import { commands, ExtensionContext, Position, TextDocument, Uri, window, workspace } from 'vscode'; +import { FormattingOptions, LanguageClient, WorkspaceEdit, CreateFile, RenameFile, DeleteFile, TextDocumentEdit } from 'vscode-languageclient'; import { Commands as javaCommands } from './commands'; -import { GetRefactorEditRequest, RefactorWorkspaceEdit, RenamePosition } from './protocol'; +import { GetRefactorEditRequest, MoveRequest, RefactorWorkspaceEdit, RenamePosition, GetMoveDestinationsRequest } from './protocol'; export function registerCommands(languageClient: LanguageClient, context: ExtensionContext) { registerApplyRefactorCommand(languageClient, context); @@ -73,22 +75,172 @@ function registerApplyRefactorCommand(languageClient: LanguageClient, context: E commandArguments, }); - if (!result || !result.edit) { + await applyRefactorEdit(languageClient, result); + } else if (command === 'moveFile') { + if (!commandInfo || !commandInfo.uri) { return; } - const edit = languageClient.protocol2CodeConverter.asWorkspaceEdit(result.edit); - if (edit) { - await workspace.applyEdit(edit); + await moveFile(languageClient, [Uri.parse(commandInfo.uri)]); + } + })); +} + +async function applyRefactorEdit(languageClient: LanguageClient, refactorEdit: RefactorWorkspaceEdit) { + if (!refactorEdit) { + return; + } + + if (refactorEdit.errorMessage) { + window.showErrorMessage(refactorEdit.errorMessage); + return; + } + + if (refactorEdit.edit) { + const edit = languageClient.protocol2CodeConverter.asWorkspaceEdit(refactorEdit.edit); + if (edit) { + await workspace.applyEdit(edit); + } + } + + if (refactorEdit.command) { + if (refactorEdit.command.arguments) { + await commands.executeCommand(refactorEdit.command.command, ...refactorEdit.command.arguments); + } else { + await commands.executeCommand(refactorEdit.command.command); + } + } +} + +async function moveFile(languageClient: LanguageClient, fileUris: Uri[]) { + if (!hasCommonParent(fileUris)) { + window.showErrorMessage("Moving files from different directories are not supported. Please make sure they are from the same directory."); + return; + } + + const moveDestinations = await languageClient.sendRequest(GetMoveDestinationsRequest.type, { + moveKind: 'moveResource', + sourceUris: fileUris.map(uri => uri.toString()) + }); + if (!moveDestinations || !moveDestinations.destinations || !moveDestinations.destinations.length) { + window.showErrorMessage("Cannot find available Java packages to move the selected files to."); + return; + } + + const packageNodeItems = moveDestinations.destinations.map((packageNode) => { + const packageUri: Uri = packageNode.uri ? Uri.parse(packageNode.uri) : null; + const displayPath: string = packageUri ? workspace.asRelativePath(packageUri, true) : packageNode.path; + return { + label: (packageNode.isParentOfSelectedFile ? '* ' : '') + packageNode.displayName, + description: displayPath, + packageNode, + } + }); + + let placeHolder = (fileUris.length === 1) ? `Choose the target package for ${getFileNameFromUri(fileUris[0])}.` + : `Choose the target package for ${fileUris.length} selected files.`; + let selectPackageNodeItem = await window.showQuickPick(packageNodeItems, { + placeHolder, + }); + if (!selectPackageNodeItem) { + return; + } + + const packageUri: Uri = selectPackageNodeItem.packageNode.uri ? Uri.parse(selectPackageNodeItem.packageNode.uri) : null; + if (packageUri && packageUri.fsPath) { + const duplicatedFiles: string[] = []; + const moveUris: Uri[] = []; + for (const uri of fileUris) { + const fileName: string = getFileNameFromUri(uri); + if (existsSync(path.join(packageUri.fsPath, fileName))) { + duplicatedFiles.push(fileName); + } else { + moveUris.push(uri); } + } + + if (duplicatedFiles.length) { + window.showWarningMessage(`The files '${duplicatedFiles.join(',')}' already exist in the package '${selectPackageNodeItem.packageNode.displayName}'. The move operation will ignore them.`); + } + + if (!moveUris.length) { + return; + } + + fileUris = moveUris; + } + + const refactorEdit: RefactorWorkspaceEdit = await languageClient.sendRequest(MoveRequest.type, { + moveKind: 'moveResource', + sourceUris: fileUris.map(uri => uri.toString()), + params: null, + destination: selectPackageNodeItem.packageNode, + updateReferences: true, + }); + + await applyRefactorEdit(languageClient, refactorEdit); + if (refactorEdit && refactorEdit.edit) { + await saveEdit(refactorEdit.edit); + } +} + +function getFileNameFromUri(uri: Uri): string { + return uri.fsPath.replace(/^.*[\\\/]/, ''); +} + +function hasCommonParent(uris: Uri[]): boolean { + if (uris == null || uris.length <= 1) { + return true; + } + + const firstParent: string = path.dirname(uris[0].fsPath); + for (let i = 1; i < uris.length; i++) { + const parent = path.dirname(uris[i].fsPath); + if (path.relative(firstParent, parent) !== '.') { + return false; + } + } - if (result.command) { - if (result.command.arguments) { - await commands.executeCommand(result.command.command, ...result.command.arguments); - } else { - await commands.executeCommand(result.command.command); + return true; +} + +async function saveEdit(edit: WorkspaceEdit) { + if (!edit) { + return; + } + + const touchedFiles: Set = new Set(); + if (edit.changes) { + for (const uri of Object.keys(edit.changes)) { + touchedFiles.add(uri); + } + } + + if (edit.documentChanges) { + for (const change of edit.documentChanges) { + const kind = ( change).kind; + if (kind === 'rename') { + if (touchedFiles.has(( change).oldUri)) { + touchedFiles.delete(( change).oldUri); + touchedFiles.add(( change).newUri); } + } else if (kind === 'delete') { + if (touchedFiles.has(( change).uri)) { + touchedFiles.delete(( change).uri); + } + } else if (!kind) { + touchedFiles.add(( change).textDocument.uri); } } - })); + } + + for (const fileUri of touchedFiles) { + const uri: Uri = Uri.parse(fileUri); + const document: TextDocument = await workspace.openTextDocument(uri); + if (document == null) { + continue; + } + + await document.save(); + } } From 56138b677f11b3a308aa409368113f3e49d39912 Mon Sep 17 00:00:00 2001 From: Yan Zhang Date: Thu, 1 Aug 2019 12:46:17 +0800 Subject: [PATCH 0040/1031] Fix tslint Signed-off-by: Yan Zhang --- .travis.yml | 1 + package.json | 3 ++- src/commands.ts | 3 +-- src/extension.ts | 3 +-- src/sourceAction.ts | 8 ++++---- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index d606e7068..b9d6b9c92 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,4 +31,5 @@ install: - ls -ll java-*vsix script: +- npm run tslint - npm test --silent diff --git a/package.json b/package.json index 42eb3b6e3..a262f62f5 100644 --- a/package.json +++ b/package.json @@ -510,7 +510,8 @@ "pretest": "npm run compile", "test": "node ./out/test/runtest.js", "build-server": "./node_modules/.bin/gulp build_server", - "watch-server": "./node_modules/.bin/gulp watch_server" + "watch-server": "./node_modules/.bin/gulp watch_server", + "tslint": "tslint -p ." }, "devDependencies": { "@types/glob": "5.0.30", diff --git a/src/commands.ts b/src/commands.ts index 3ac381cdd..a22f8542e 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -79,7 +79,6 @@ export namespace Commands { */ export const OPEN_CLIENT_LOG = 'java.open.clientLog'; - /** * Open Java formatter settings */ @@ -152,4 +151,4 @@ export namespace Commands { * Rename Command. */ export const RENAME_COMMAND = 'java.action.rename'; -} \ No newline at end of file +} diff --git a/src/extension.ts b/src/extension.ts index 75266d701..48d8d2ee6 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -516,8 +516,7 @@ function openClientLogFile(logFile: string): Thenable { }); } - -function openLogFile(logFile, openingFailureWarning:string ): Thenable { +function openLogFile(logFile, openingFailureWarning: string): Thenable { if (!fs.existsSync(logFile)) { return window.showWarningMessage('No log file available').then(() => false); } diff --git a/src/sourceAction.ts b/src/sourceAction.ts index 21f0c8b9a..404286b62 100644 --- a/src/sourceAction.ts +++ b/src/sourceAction.ts @@ -223,7 +223,7 @@ function registerGenerateAccessorsCommand(languageClient: LanguageClient, contex } return { label: accessor.fieldName, - description: (accessor.isStatic?'static ':'')+ description.join(', '), + description: (accessor.isStatic ? 'static ' : '')+ description.join(', '), originalField: accessor, }; }); @@ -323,12 +323,12 @@ function registerGenerateDelegateMethodsCommand(languageClient: LanguageClient, selectedDelegateField = selectedFieldItem.originalField; } - let delegateEntryItems = selectedDelegateField.delegateMethods.map(delegateMethod => { + const delegateEntryItems = selectedDelegateField.delegateMethods.map(delegateMethod => { return { label: `${selectedDelegateField.field.name}.${delegateMethod.name}(${delegateMethod.parameters.join(',')})`, originalField: selectedDelegateField.field, originalMethod: delegateMethod, - } + }; }); if (!delegateEntryItems.length) { @@ -356,4 +356,4 @@ function registerGenerateDelegateMethodsCommand(languageClient: LanguageClient, }); applyWorkspaceEdit(workspaceEdit, languageClient); })); -} \ No newline at end of file +} From 9359130e281c3e80ee550b8e5cc6434c16ac6ff3 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Fri, 2 Aug 2019 12:54:35 +0200 Subject: [PATCH 0041/1031] Switch recommended tslint extension to ms-vscode.vscode-typescript-tslint-plugin Signed-off-by: Fred Bricon --- .vscode/extensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index ad475c77a..c81530615 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,7 +3,7 @@ // for the documentation about the extensions.json format "recommendations": [ // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp - "eg2.tslint", + "ms-vscode.vscode-typescript-tslint-plugin", "EditorConfig.EditorConfig" ] } \ No newline at end of file From 0c6d585ee969f09b7c5c7e07b52140af6ff9876e Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Fri, 2 Aug 2019 13:04:49 +0200 Subject: [PATCH 0042/1031] Fix tslint issues Signed-off-by: Fred Bricon --- src/refactorAction.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/refactorAction.ts b/src/refactorAction.ts index dadc8c2ef..2a725645c 100644 --- a/src/refactorAction.ts +++ b/src/refactorAction.ts @@ -130,16 +130,16 @@ async function moveFile(languageClient: LanguageClient, fileUris: Uri[]) { const packageNodeItems = moveDestinations.destinations.map((packageNode) => { const packageUri: Uri = packageNode.uri ? Uri.parse(packageNode.uri) : null; const displayPath: string = packageUri ? workspace.asRelativePath(packageUri, true) : packageNode.path; - return { - label: (packageNode.isParentOfSelectedFile ? '* ' : '') + packageNode.displayName, - description: displayPath, - packageNode, - } + return { + label: (packageNode.isParentOfSelectedFile ? '* ' : '') + packageNode.displayName, + description: displayPath, + packageNode, + }; }); - let placeHolder = (fileUris.length === 1) ? `Choose the target package for ${getFileNameFromUri(fileUris[0])}.` + const placeHolder = (fileUris.length === 1) ? `Choose the target package for ${getFileNameFromUri(fileUris[0])}.` : `Choose the target package for ${fileUris.length} selected files.`; - let selectPackageNodeItem = await window.showQuickPick(packageNodeItems, { + const selectPackageNodeItem = await window.showQuickPick(packageNodeItems, { placeHolder, }); if (!selectPackageNodeItem) { @@ -189,7 +189,7 @@ function getFileNameFromUri(uri: Uri): string { } function hasCommonParent(uris: Uri[]): boolean { - if (uris == null || uris.length <= 1) { + if (uris === null || uris.length <= 1) { return true; } @@ -237,7 +237,7 @@ async function saveEdit(edit: WorkspaceEdit) { for (const fileUri of touchedFiles) { const uri: Uri = Uri.parse(fileUri); const document: TextDocument = await workspace.openTextDocument(uri); - if (document == null) { + if (document === null) { continue; } From 2e4dbb975f81d153ea4a89fc5a502000d5e55fef Mon Sep 17 00:00:00 2001 From: Rome Li Date: Mon, 5 Aug 2019 21:46:09 +0800 Subject: [PATCH 0043/1031] Log language client failures (#1015) Signed-off-by: Rome Li --- src/extension.ts | 50 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 48d8d2ee6..501ff4781 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -4,7 +4,7 @@ import * as path from 'path'; import * as os from 'os'; import * as fs from 'fs'; import { workspace, extensions, ExtensionContext, window, StatusBarAlignment, commands, ViewColumn, Uri, CancellationToken, TextDocumentContentProvider, TextEditor, WorkspaceConfiguration, languages, IndentAction, ProgressLocation, InputBoxOptions, Selection, Position, EventEmitter } from 'vscode'; -import { ExecuteCommandParams, ExecuteCommandRequest, LanguageClient, LanguageClientOptions, RevealOutputChannelOn, Position as LSPosition, Location as LSLocation, StreamInfo, VersionedTextDocumentIdentifier } from 'vscode-languageclient'; +import { ExecuteCommandParams, ExecuteCommandRequest, LanguageClient, LanguageClientOptions, RevealOutputChannelOn, Position as LSPosition, Location as LSLocation, StreamInfo, VersionedTextDocumentIdentifier, ErrorHandler, Message, ErrorAction, CloseAction, InitializationFailedHandler } from 'vscode-languageclient'; import { onExtensionChange, collectJavaExtensions } from './plugin'; import { prepareExecutable, awaitServerConnection } from './javaServerStarter'; import * as requirements from './requirements'; @@ -27,8 +27,47 @@ let lastStatus; let languageClient: LanguageClient; const jdtEventEmitter = new EventEmitter(); const cleanWorkspaceFileName = '.cleanWorkspace'; +const extensionName = 'Language Support for Java'; let clientLogFile; +class ClientErrorHandler implements ErrorHandler { + private restarts: number[]; + + constructor(private name: string) { + this.restarts = []; + } + + public error(_error: Error, _message: Message, count: number): ErrorAction { + if (count && count <= 3) { + logger.error(`${this.name} server encountered error: ${_message}, ${_error && _error.toString()}`); + return ErrorAction.Continue; + } + + logger.error(`${this.name} server encountered error and will shut down: ${_message}, ${_error && _error.toString()}`); + return ErrorAction.Shutdown; + } + + public closed(): CloseAction { + this.restarts.push(Date.now()); + if (this.restarts.length < 5) { + logger.error(`The ${this.name} server crashed and will restart.`); + return CloseAction.Restart; + } else { + const diff = this.restarts[this.restarts.length - 1] - this.restarts[0]; + if (diff <= 3 * 60 * 1000) { + const message = `The ${this.name} server crashed 5 times in the last 3 minutes. The server will not be restarted.`; + logger.error(message); + window.showErrorMessage(message); + return CloseAction.DoNotRestart; + } + + logger.error(`The ${this.name} server crashed and will restart.`); + this.restarts.shift(); + return CloseAction.Restart; + } + } +} + export function activate(context: ExtensionContext): Promise { let storagePath = context.storagePath; @@ -84,7 +123,12 @@ export function activate(context: ExtensionContext): Promise { }, triggerFiles: getTriggerFiles() }, - revealOutputChannelOn: RevealOutputChannelOn.Never + revealOutputChannelOn: RevealOutputChannelOn.Never, + errorHandler: new ClientErrorHandler(extensionName), + initializationFailedHandler: error => { + logger.error(`Failed to initialize ${extensionName} due to ${error && error.toString()}`); + return true; + } }; const item = window.createStatusBarItem(StatusBarAlignment.Right, Number.MIN_VALUE); @@ -114,7 +158,7 @@ export function activate(context: ExtensionContext): Promise { } // Create the language client and start the client. - languageClient = new LanguageClient('java', 'Language Support for Java', serverOptions, clientOptions); + languageClient = new LanguageClient('java', extensionName, serverOptions, clientOptions); languageClient.registerProposedFeatures(); languageClient.onReady().then(() => { From ebd8d06b50cabdac5279e5ed0966f275de508058 Mon Sep 17 00:00:00 2001 From: Rome Li Date: Thu, 8 Aug 2019 17:14:06 +0800 Subject: [PATCH 0044/1031] Open client/server logs SxS (#1021) Signed-off-by: Rome Li --- package.json | 5 +++++ src/commands.ts | 5 +++++ src/extension.ts | 31 +++++++++++++++++++++---------- test/extension.test.ts | 1 + 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index a262f62f5..007f687d7 100644 --- a/package.json +++ b/package.json @@ -398,6 +398,11 @@ "title": "Open Java extension log file", "category": "Java" }, + { + "command": "java.open.logs", + "title": "Open all log files", + "category": "Java" + }, { "command": "java.workspace.compile", "title": "Force Java compilation", diff --git a/src/commands.ts b/src/commands.ts index a22f8542e..aabdc10f6 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -79,6 +79,11 @@ export namespace Commands { */ export const OPEN_CLIENT_LOG = 'java.open.clientLog'; + /** + * Open Java log files side by side + */ + export const OPEN_LOGS = 'java.open.logs'; + /** * Open Java formatter settings */ diff --git a/src/extension.ts b/src/extension.ts index 501ff4781..6f4c38d30 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -57,7 +57,12 @@ class ClientErrorHandler implements ErrorHandler { if (diff <= 3 * 60 * 1000) { const message = `The ${this.name} server crashed 5 times in the last 3 minutes. The server will not be restarted.`; logger.error(message); - window.showErrorMessage(message); + const action = "Show logs"; + window.showErrorMessage(message, action).then(selection => { + if (selection === action) { + commands.executeCommand(Commands.OPEN_LOGS); + } + }); return CloseAction.DoNotRestart; } @@ -376,9 +381,11 @@ export function activate(context: ExtensionContext): Promise { context.subscriptions.push(commands.registerCommand(Commands.OPEN_OUTPUT, () => languageClient.outputChannel.show(ViewColumn.Three))); - context.subscriptions.push(commands.registerCommand(Commands.OPEN_SERVER_LOG, () => openServerLogFile(workspacePath))); + context.subscriptions.push(commands.registerCommand(Commands.OPEN_SERVER_LOG, (column: ViewColumn) => openServerLogFile(workspacePath, column))); - context.subscriptions.push(commands.registerCommand(Commands.OPEN_CLIENT_LOG, () => openClientLogFile(clientLogFile))); + context.subscriptions.push(commands.registerCommand(Commands.OPEN_CLIENT_LOG, (column: ViewColumn) => openClientLogFile(clientLogFile, column))); + + context.subscriptions.push(commands.registerCommand(Commands.OPEN_LOGS, () => openLogs())); const extensionPath = context.extensionPath; context.subscriptions.push(commands.registerCommand(Commands.OPEN_FORMATTER, async () => openFormatter(extensionPath))); @@ -538,12 +545,12 @@ function deleteDirectory(dir) { } } -function openServerLogFile(workspacePath): Thenable { +function openServerLogFile(workspacePath, column: ViewColumn = ViewColumn.Active): Thenable { const serverLogFile = path.join(workspacePath, '.metadata', '.log'); - return openLogFile(serverLogFile, 'Could not open Java Language Server log file'); + return openLogFile(serverLogFile, 'Could not open Java Language Server log file', column); } -function openClientLogFile(logFile: string): Thenable { +function openClientLogFile(logFile: string, column: ViewColumn = ViewColumn.Active): Thenable { return new Promise((resolve) => { const filename = path.basename(logFile); const dirname = path.dirname(logFile); @@ -555,12 +562,17 @@ function openClientLogFile(logFile: string): Thenable { logFile = path.join(dirname, files[files.length - 1]); } - openLogFile(logFile, 'Could not open Java extension log file').then((result) => resolve(result)); + openLogFile(logFile, 'Could not open Java extension log file', column).then((result) => resolve(result)); }); }); } -function openLogFile(logFile, openingFailureWarning: string): Thenable { +async function openLogs() { + await commands.executeCommand(Commands.OPEN_CLIENT_LOG, ViewColumn.One); + await commands.executeCommand(Commands.OPEN_SERVER_LOG, ViewColumn.Two); +} + +function openLogFile(logFile, openingFailureWarning: string, column: ViewColumn = ViewColumn.Active): Thenable { if (!fs.existsSync(logFile)) { return window.showWarningMessage('No log file available').then(() => false); } @@ -570,8 +582,7 @@ function openLogFile(logFile, openingFailureWarning: string): Thenable if (!doc) { return false; } - return window.showTextDocument(doc, window.activeTextEditor ? - window.activeTextEditor.viewColumn : undefined) + return window.showTextDocument(doc, column) .then(editor => !!editor); }, () => false) .then(didOpen => { diff --git a/test/extension.test.ts b/test/extension.test.ts index 3e3db1976..7c0354768 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -35,6 +35,7 @@ suite('Java Language Extension', () => { Commands.EXECUTE_WORKSPACE_COMMAND, Commands.OPEN_SERVER_LOG, Commands.OPEN_CLIENT_LOG, + Commands.OPEN_LOGS, Commands.COMPILE_WORKSPACE, Commands.OPEN_FORMATTER, Commands.CLEAN_WORKSPACE, From da07c30de49cabfc3f5bb3b023f3f3aa46ec70e4 Mon Sep 17 00:00:00 2001 From: Rome Li Date: Wed, 7 Aug 2019 11:32:24 +0800 Subject: [PATCH 0045/1031] Log info from output channel Signed-off-by: Rome Li --- src/extension.ts | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 6f4c38d30..6871b37fb 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import * as os from 'os'; import * as fs from 'fs'; -import { workspace, extensions, ExtensionContext, window, StatusBarAlignment, commands, ViewColumn, Uri, CancellationToken, TextDocumentContentProvider, TextEditor, WorkspaceConfiguration, languages, IndentAction, ProgressLocation, InputBoxOptions, Selection, Position, EventEmitter } from 'vscode'; +import { workspace, extensions, ExtensionContext, window, StatusBarAlignment, commands, ViewColumn, Uri, CancellationToken, TextDocumentContentProvider, TextEditor, WorkspaceConfiguration, languages, IndentAction, ProgressLocation, InputBoxOptions, Selection, Position, EventEmitter, OutputChannel } from 'vscode'; import { ExecuteCommandParams, ExecuteCommandRequest, LanguageClient, LanguageClientOptions, RevealOutputChannelOn, Position as LSPosition, Location as LSLocation, StreamInfo, VersionedTextDocumentIdentifier, ErrorHandler, Message, ErrorAction, CloseAction, InitializationFailedHandler } from 'vscode-languageclient'; import { onExtensionChange, collectJavaExtensions } from './plugin'; import { prepareExecutable, awaitServerConnection } from './javaServerStarter'; @@ -73,6 +73,42 @@ class ClientErrorHandler implements ErrorHandler { } } +class OutputInfoCollector implements OutputChannel { + private channel: OutputChannel = null; + + constructor(public name: string) { + this.channel = window.createOutputChannel(this.name); + } + + append(value: string): void { + logger.info(value); + this.channel.append(value); + } + + appendLine(value: string): void { + logger.info(value); + this.channel.appendLine(value); + } + + clear(): void { + this.channel.clear(); + } + + show(preserveFocus?: boolean): void; + show(column?: ViewColumn, preserveFocus?: boolean): void; + show(column?: any, preserveFocus?: any) { + this.channel.show(column, preserveFocus); + } + + hide(): void { + this.channel.hide(); + } + + dispose(): void { + this.channel.dispose(); + } +} + export function activate(context: ExtensionContext): Promise { let storagePath = context.storagePath; @@ -133,7 +169,9 @@ export function activate(context: ExtensionContext): Promise { initializationFailedHandler: error => { logger.error(`Failed to initialize ${extensionName} due to ${error && error.toString()}`); return true; - } + }, + outputChannel: new OutputInfoCollector(extensionName), + outputChannelName: extensionName }; const item = window.createStatusBarItem(StatusBarAlignment.Right, Number.MIN_VALUE); From 25c7cd4781497f0cbc3effad151491633731a8d8 Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Fri, 23 Aug 2019 02:15:13 +0800 Subject: [PATCH 0046/1031] Enable move instance method and static member (#1027) Signed-off-by: Jinbo Wang --- src/protocol.ts | 14 +++++- src/refactorAction.ts | 106 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 3 deletions(-) diff --git a/src/protocol.ts b/src/protocol.ts index 01850e976..cef61530e 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -1,6 +1,6 @@ 'use strict'; -import { RequestType, NotificationType, TextDocumentIdentifier, ExecuteCommandParams, CodeActionParams, WorkspaceEdit, FormattingOptions } from 'vscode-languageclient'; +import { RequestType, NotificationType, TextDocumentIdentifier, ExecuteCommandParams, CodeActionParams, WorkspaceEdit, FormattingOptions, WorkspaceSymbolParams, SymbolInformation } from 'vscode-languageclient'; import { Command, Range } from 'vscode'; /** @@ -152,6 +152,7 @@ export interface VariableBinding { bindingKey: string; name: string; type: string; + isField: boolean; } export interface CheckHashCodeEqualsResponse { @@ -320,6 +321,7 @@ export interface MoveParams { } export interface MoveDestinationsResponse { + errorMessage?: string; destinations: any[]; } @@ -330,3 +332,13 @@ export namespace GetMoveDestinationsRequest { export namespace MoveRequest { export const type = new RequestType('java/move'); } + +export interface SearchSymbolParams extends WorkspaceSymbolParams { + projectName: string; + maxResults?: number; + sourceOnly?: boolean; +} + +export namespace SearchSymbols { + export const type = new RequestType('java/searchSymbols'); +} diff --git a/src/refactorAction.ts b/src/refactorAction.ts index 2a725645c..748c454ce 100644 --- a/src/refactorAction.ts +++ b/src/refactorAction.ts @@ -3,9 +3,9 @@ import { existsSync } from 'fs'; import * as path from 'path'; import { commands, ExtensionContext, Position, TextDocument, Uri, window, workspace } from 'vscode'; -import { FormattingOptions, LanguageClient, WorkspaceEdit, CreateFile, RenameFile, DeleteFile, TextDocumentEdit } from 'vscode-languageclient'; +import { FormattingOptions, LanguageClient, WorkspaceEdit, CreateFile, RenameFile, DeleteFile, TextDocumentEdit, CodeActionParams } from 'vscode-languageclient'; import { Commands as javaCommands } from './commands'; -import { GetRefactorEditRequest, MoveRequest, RefactorWorkspaceEdit, RenamePosition, GetMoveDestinationsRequest } from './protocol'; +import { GetRefactorEditRequest, MoveRequest, RefactorWorkspaceEdit, RenamePosition, GetMoveDestinationsRequest, SearchSymbols } from './protocol'; export function registerCommands(languageClient: LanguageClient, context: ExtensionContext) { registerApplyRefactorCommand(languageClient, context); @@ -82,6 +82,10 @@ function registerApplyRefactorCommand(languageClient: LanguageClient, context: E } await moveFile(languageClient, [Uri.parse(commandInfo.uri)]); + } else if (command === 'moveInstanceMethod') { + await moveInstanceMethod(languageClient, params, commandInfo); + } else if (command === 'moveStaticMember') { + await moveStaticMember(languageClient, params, commandInfo); } })); } @@ -244,3 +248,101 @@ async function saveEdit(edit: WorkspaceEdit) { await document.save(); } } + +async function moveInstanceMethod(languageClient: LanguageClient, params: CodeActionParams, commandInfo: any) { + const moveDestinations = await languageClient.sendRequest(GetMoveDestinationsRequest.type, { + moveKind: 'moveInstanceMethod', + sourceUris: [ params.textDocument.uri ], + params + }); + if (moveDestinations && moveDestinations.errorMessage) { + window.showErrorMessage(moveDestinations.errorMessage); + return; + } + + if (!moveDestinations || !moveDestinations.destinations || !moveDestinations.destinations.length) { + window.showErrorMessage("Cannot find possible class targets to move the selected method to."); + return; + } + + const destinationNodeItems = moveDestinations.destinations.map((destination) => { + return { + label: `${destination.type} ${destination.name}`, + description: destination.isField ? "Field" : "Method Parameter", + destination, + }; + }); + const methodName = commandInfo && commandInfo.displayName ? commandInfo.displayName : ''; + const selected = await window.showQuickPick(destinationNodeItems, { + placeHolder: `Select the new class for the instance method ${methodName}.`, + }); + if (!selected) { + return; + } + + const refactorEdit: RefactorWorkspaceEdit = await languageClient.sendRequest(MoveRequest.type, { + moveKind: 'moveInstanceMethod', + sourceUris: [ params.textDocument.uri ], + params, + destination: selected.destination, + }); + await applyRefactorEdit(languageClient, refactorEdit); +} + +async function moveStaticMember(languageClient: LanguageClient, params: CodeActionParams, commandInfo: any) { + const memberName = commandInfo && commandInfo.displayName ? commandInfo.displayName : ''; + const exclude: Set = new Set(); + if (commandInfo.enclosingTypeName) { + exclude.add(commandInfo.enclosingTypeName); + // 55: Type, 71: Enum, 81: AnnotationType + if (commandInfo.memberType === 55 || commandInfo.memeberType === 71 + || commandInfo.memberType === 81) { + exclude.add(`${commandInfo.enclosingTypeName}.${commandInfo.displayName}`); + } + } + const picked = await window.showQuickPick( + languageClient.sendRequest(SearchSymbols.type, { + query: '*', + projectName: commandInfo ? commandInfo.projectName : null, + sourceOnly: true, + }).then(types => { + if (types && types.length) { + return types.filter((type) => { + const typeName = type.containerName ? `${type.containerName}.${type.name}` : type.name; + return !exclude.has(typeName); + }).sort((a, b) => { + if (a.name < b.name) { + return -1; + } else if (a.name > b.name) { + return 1; + } + return 0; + }).map((symbol => { + return { + label: symbol.name, + description: symbol.containerName, + symbolNode: symbol, + }; + })); + } else { + return [{ + label: 'No result found', + alwaysShow: true, + description: '', + symbolNode: null, + }]; + } + }), { + placeHolder: `Select the new class for the static member ${memberName}.` + }); + + if (picked && picked.symbolNode) { + const refactorEdit: RefactorWorkspaceEdit = await languageClient.sendRequest(MoveRequest.type, { + moveKind: 'moveStaticMember', + sourceUris: [ params.textDocument.uri ], + params, + destination: picked.symbolNode, + }); + await applyRefactorEdit(languageClient, refactorEdit); + } +} From 722f2f5815fc0d56717e4ddcf3efe74b4e557e8f Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Fri, 23 Aug 2019 11:19:50 +0200 Subject: [PATCH 0047/1031] Update lodash.template version to fix vulnerability Signed-off-by: Fred Bricon --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 007f687d7..a1e383613 100644 --- a/package.json +++ b/package.json @@ -534,7 +534,8 @@ "typescript-tslint-plugin": "^0.3.1", "vscode-test": "^1.0.0", "webpack": "^4.27.1", - "webpack-cli": "^3.1.2" + "webpack-cli": "^3.1.2", + "lodash.template": ">=4.5.0" }, "dependencies": { "vscode-languageclient": "5.3.0-next.6", From 77b61ab1dafa3a1f82c4f6b00c73bc3f903a85af Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Fri, 23 Aug 2019 11:20:55 +0200 Subject: [PATCH 0048/1031] Update lodash.template version to fix vulnerability - part 2 Signed-off-by: Fred Bricon --- package-lock.json | 62 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 31cde6811..39cb7982a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3178,6 +3178,25 @@ "replace-ext": "0.0.1", "through2": "^2.0.0", "vinyl": "^0.5.0" + }, + "dependencies": { + "lodash.template": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "dev": true, + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash._basetostring": "^3.0.0", + "lodash._basevalues": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.restparam": "^3.0.0", + "lodash.templatesettings": "^3.0.0" + } + } } }, "object-assign": { @@ -3249,6 +3268,23 @@ "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", "dev": true }, + "lodash.template": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", + "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "dev": true, + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash._basetostring": "^3.0.0", + "lodash._basevalues": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash._reinterpolate": "^3.0.0", + "lodash.escape": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.restparam": "^3.0.0", + "lodash.templatesettings": "^3.0.0" + } + }, "object-assign": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", @@ -4080,20 +4116,24 @@ "dev": true }, "lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", "dev": true, "requires": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" + "lodash.templatesettings": "^4.0.0" + }, + "dependencies": { + "lodash.templatesettings": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", + "dev": true, + "requires": { + "lodash._reinterpolate": "^3.0.0" + } + } } }, "lodash.templatesettings": { From b26485a174b0eb7576c196cd763fcb64f1f3284f Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 3 Sep 2019 00:22:13 +0800 Subject: [PATCH 0049/1031] Enable to move type to new file (#1041) Signed-off-by: Jinbo Wang --- src/refactorAction.ts | 86 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 9 deletions(-) diff --git a/src/refactorAction.ts b/src/refactorAction.ts index 748c454ce..8efba2b92 100644 --- a/src/refactorAction.ts +++ b/src/refactorAction.ts @@ -3,7 +3,7 @@ import { existsSync } from 'fs'; import * as path from 'path'; import { commands, ExtensionContext, Position, TextDocument, Uri, window, workspace } from 'vscode'; -import { FormattingOptions, LanguageClient, WorkspaceEdit, CreateFile, RenameFile, DeleteFile, TextDocumentEdit, CodeActionParams } from 'vscode-languageclient'; +import { FormattingOptions, LanguageClient, WorkspaceEdit, CreateFile, RenameFile, DeleteFile, TextDocumentEdit, CodeActionParams, SymbolInformation } from 'vscode-languageclient'; import { Commands as javaCommands } from './commands'; import { GetRefactorEditRequest, MoveRequest, RefactorWorkspaceEdit, RenamePosition, GetMoveDestinationsRequest, SearchSymbols } from './protocol'; @@ -86,6 +86,8 @@ function registerApplyRefactorCommand(languageClient: LanguageClient, context: E await moveInstanceMethod(languageClient, params, commandInfo); } else if (command === 'moveStaticMember') { await moveStaticMember(languageClient, params, commandInfo); + } else if (command === 'moveType') { + await moveType(languageClient, params, commandInfo); } })); } @@ -124,7 +126,8 @@ async function moveFile(languageClient: LanguageClient, fileUris: Uri[]) { const moveDestinations = await languageClient.sendRequest(GetMoveDestinationsRequest.type, { moveKind: 'moveResource', - sourceUris: fileUris.map(uri => uri.toString()) + sourceUris: fileUris.map(uri => uri.toString()), + params: null, }); if (!moveDestinations || !moveDestinations.destinations || !moveDestinations.destinations.length) { window.showErrorMessage("Cannot find available Java packages to move the selected files to."); @@ -300,10 +303,25 @@ async function moveStaticMember(languageClient: LanguageClient, params: CodeActi exclude.add(`${commandInfo.enclosingTypeName}.${commandInfo.displayName}`); } } + + const projectName = commandInfo ? commandInfo.projectName : null; + const picked = await selectTargetClass(languageClient, `Select the new class for the static member ${memberName}.`, projectName, exclude); + if (picked) { + const refactorEdit: RefactorWorkspaceEdit = await languageClient.sendRequest(MoveRequest.type, { + moveKind: 'moveStaticMember', + sourceUris: [ params.textDocument.uri ], + params, + destination: picked, + }); + await applyRefactorEdit(languageClient, refactorEdit); + } +} + +async function selectTargetClass(languageClient: LanguageClient, placeHolder: string, projectName: string, exclude: Set): Promise { const picked = await window.showQuickPick( languageClient.sendRequest(SearchSymbols.type, { query: '*', - projectName: commandInfo ? commandInfo.projectName : null, + projectName, sourceOnly: true, }).then(types => { if (types && types.length) { @@ -333,16 +351,66 @@ async function moveStaticMember(languageClient: LanguageClient, params: CodeActi }]; } }), { - placeHolder: `Select the new class for the static member ${memberName}.` + placeHolder, }); - if (picked && picked.symbolNode) { - const refactorEdit: RefactorWorkspaceEdit = await languageClient.sendRequest(MoveRequest.type, { - moveKind: 'moveStaticMember', + return picked ? picked.symbolNode : null; +} + +async function moveType(languageClient: LanguageClient, params: CodeActionParams, commandInfo: any) { + if (!commandInfo || !commandInfo.supportedDestinationKinds) { + return; + } + + const destinationPickItems: any[] = commandInfo.supportedDestinationKinds.map((kind) => { + if (kind === 'newFile') { + return { + label: `Move type ${commandInfo.displayName} to new file`, + kind, + }; + } else { + return { + label: `Move type ${commandInfo.displayName} to another class`, + kind, + }; + } + }); + + if (!destinationPickItems.length) { + return; + } + + const picked = await window.showQuickPick(destinationPickItems, { + placeHolder: 'What would you like to do?', + }); + if (!picked) { + return; + } + + let refactorEdit: RefactorWorkspaceEdit; + if (picked.kind === 'newFile') { + refactorEdit = await languageClient.sendRequest(MoveRequest.type, { + moveKind: 'moveTypeToNewFile', sourceUris: [ params.textDocument.uri ], params, - destination: picked.symbolNode, }); - await applyRefactorEdit(languageClient, refactorEdit); + } else { + const exclude: Set = new Set(); + if (commandInfo.enclosingTypeName) { + exclude.add(commandInfo.enclosingTypeName); + exclude.add(`${commandInfo.enclosingTypeName}.${commandInfo.displayName}`); + } + + const picked = await selectTargetClass(languageClient, `Select the new class for the type ${commandInfo.displayName}.`, commandInfo.projectName, exclude); + if (picked) { + refactorEdit = await languageClient.sendRequest(MoveRequest.type, { + moveKind: 'moveTypeToClass', + sourceUris: [ params.textDocument.uri ], + params, + destination: picked, + }); + } } + + await applyRefactorEdit(languageClient, refactorEdit); } From 31f44ecef9cdb9a6a83cdb44b971f6bf1f746057 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Tue, 3 Sep 2019 10:03:23 +0200 Subject: [PATCH 0050/1031] Changelog for 0.48.0 Signed-off-by: Fred Bricon --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21a83f078..e6f1a9dcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Change Log +## 0.48.0 (September 4th, 2019) +* enhancement - ignore "Unsupported SuppressWarning" warnings by default. See [#507](https://github.com/redhat-developer/vscode-java/issues/507). +* enhancement - code action to move member to another class. See [#980](https://github.com/redhat-developer/vscode-java/issues/980). +* enhancement - code action to move class to another package. See [#1017](https://github.com/redhat-developer/vscode-java/issues/1017). +* enhancement - code action to move inner types to new class. See [#1027](https://github.com/redhat-developer/vscode-java/pull/1027). +* enhancement - code action to 'Invert local variable'. See [#997](https://github.com/redhat-developer/vscode-java/pull/997). +* enhancement - show client & server logs side by side. See [#1016](https://github.com/redhat-developer/vscode-java/issues/1016). +* enhancement - rotate client logs daily. See [#989](https://github.com/redhat-developer/vscode-java/pull/989). +* enhancement - log language client failures. See [#1015](https://github.com/redhat-developer/vscode-java/pull/1015). +* enhancement - code action to create unresolved types. See [JLS#853](https://github.com/eclipse/eclipse.jdt.ls/issues/853). +* enhancement - properly render @ApiNote in javadoc. See [JLS#1069](https://github.com/eclipse/eclipse.jdt.ls/issues/1069). +* enhancement - code action to convert lambda to anonymous class. See [JLS#1119](https://github.com/eclipse/eclipse.jdt.ls/issues/1119). +* bug fix - fixed "Java runtime could not be located" for Windows + Oracle JDK. See [#836](https://github.com/redhat-developer/vscode-java/issues/836). +* bug fix - fixed go to implementation doesn't work for method invocation. See [#886](https://github.com/redhat-developer/vscode-java/issues/886). +* bug fix - fixed find implementation doesn't work on classes. See [JLS#1098](https://github.com/eclipse/eclipse.jdt.ls/issues/1098). +* bug fix - fixed NavigateToDefinitionHandler should not return null. See [JLS#1143](https://github.com/eclipse/eclipse.jdt.ls/pull/1143). +* bug fix - fixed secondary same-line error not reported. See [JLS#1147](https://github.com/eclipse/eclipse.jdt.ls/issues/1147). + ## 0.47.0 (July 18th, 2019) * enhancement - trigger client autorename after 'extract to variable/constant/method'. See [#333](https://github.com/redhat-developer/vscode-java/issues/333). * enhancement - added support for semantic selection. See [#780](https://github.com/redhat-developer/vscode-java/issues/780). From dc440b1f24419fe3f7f662f3d059b7cee4733c61 Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Wed, 4 Sep 2019 14:13:47 +0200 Subject: [PATCH 0051/1031] Upversion to 0.49.0 Signed-off-by: Fred Bricon --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 39cb7982a..8e4e43161 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "java", - "version": "0.48.0", + "version": "0.49.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a1e383613..772ca6d3c 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "author": "Red Hat", "icon": "icons/icon128.png", "license": "EPL-1.0", - "version": "0.48.0", + "version": "0.49.0", "publisher": "redhat", "bugs": "https://github.com/redhat-developer/vscode-java/issues", "preview": true, From aaef6e8b0bc0a21c0dc4c060a30953e4646efa3a Mon Sep 17 00:00:00 2001 From: Snjezana Peco Date: Sat, 14 Sep 2019 02:55:10 +0200 Subject: [PATCH 0052/1031] Exclude certain packages from autocomplete/autoimport Signed-off-by: Snjezana Peco --- README.md | 7 ++++--- package.json | 9 +++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 583c0ea53..6a6cd2611 100644 --- a/README.md +++ b/README.md @@ -110,14 +110,15 @@ The following settings are supported: * `java.codeGeneration.toString.skipNullValues`: Skip null values when generating the toString method. Defaults to `false`. * `java.codeGeneration.toString.listArrayContents`: List contents of arrays instead of using native toString(). Defaults to `true`. * `java.codeGeneration.toString.limitElements`: Limit number of items in arrays/collections/maps to list, if 0 then list all. Defaults to `0`. - -*New in 0.47.0* - * `java.import.gradle.arguments`: Arguments to pass to Gradle. * `java.import.gradle.jvmArguments`: JVM arguments to pass to Gradle. * `java.import.gradle.home`: setting for GRADLE_HOME. * `java.selectionRange.enabled`: Enable/disable Smart Selection support for Java. Disabling this option will not affect the VS Code built-in word-based and bracket-based smart selection. +*New in 0.49.0* + +* `java.completion.filteredTypes`: Defines the type filters. All types whose fully qualified name matches the selected filter strings will be ignored in content assist or quick fix proposals and when organizing imports. For example 'java.awt.*' will hide all types from the awt packages. + Troubleshooting =============== 1. Check the status of the language tools on the lower right corner (marked with A on image below). diff --git a/package.json b/package.json index 772ca6d3c..4d0a2ac5a 100644 --- a/package.json +++ b/package.json @@ -263,6 +263,15 @@ ], "scope": "window" }, + "java.completion.filteredTypes": { + "type": "array", + "description": "Defines the type filters. All types whose fully qualified name matches the selected filter strings will be ignored in content assist or quick fix proposals and when organizing imports. For example 'java.awt.*' will hide all types from the awt packages.", + "default": [ + "java.awt.*", + "com.sun.*" + ], + "scope": "window" + }, "java.completion.importOrder": { "type": "array", "description": "Defines the sorting order of import statements. A package or type name prefix (e.g. 'org.eclipse') is a valid entry. An import is always added to the most specific group.", From a24c5e4f9d7b3e23fd7bf9630a09d36286a9d867 Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Sun, 15 Sep 2019 14:51:29 +0800 Subject: [PATCH 0053/1031] Support refactoring: Convert anonymous class to nested Signed-off-by: Sheng Chen --- src/refactorAction.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/refactorAction.ts b/src/refactorAction.ts index 8efba2b92..7962e7957 100644 --- a/src/refactorAction.ts +++ b/src/refactorAction.ts @@ -37,7 +37,8 @@ function registerApplyRefactorCommand(languageClient: LanguageClient, context: E || command === 'extractMethod' || command === 'extractField' || command === 'convertVariableToField' - || command === 'invertVariable') { + || command === 'invertVariable' + || command === 'convertAnonymousClassToNestedCommand') { const currentEditor = window.activeTextEditor; if (!currentEditor || !currentEditor.options) { return; From 6671c28cbdaec8764ca2b41e511e72a34bd9046f Mon Sep 17 00:00:00 2001 From: Jinbo Wang Date: Tue, 17 Sep 2019 17:40:41 +0800 Subject: [PATCH 0054/1031] Use hover to support 'Go To Super Implementation' action (#1053) Signed-off-by: Jinbo Wang --- src/commands.ts | 4 ++ src/extension.api.ts | 6 ++ src/extension.ts | 9 ++- src/hoverAction.ts | 125 +++++++++++++++++++++++++++++++++++++++++ src/protocol.ts | 16 +++++- test/extension.test.ts | 3 +- 6 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 src/hoverAction.ts diff --git a/src/commands.ts b/src/commands.ts index aabdc10f6..8e151e7d7 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -156,4 +156,8 @@ export namespace Commands { * Rename Command. */ export const RENAME_COMMAND = 'java.action.rename'; + /** + * Navigate To Super Method Command. + */ + export const NAVIGATE_TO_SUPER_IMPLEMENTATION_COMMAND = 'java.action.navigateToSuperImplementation'; } diff --git a/src/extension.api.ts b/src/extension.api.ts index c269c5dd0..f47c4e835 100644 --- a/src/extension.api.ts +++ b/src/extension.api.ts @@ -1,7 +1,13 @@ import { RequirementsData } from './requirements'; +import { TextDocumentPositionParams } from 'vscode-languageclient'; +import { CancellationToken, Command, ProviderResult } from 'vscode'; + +export type provideHoverCommandFn = (params: TextDocumentPositionParams, token: CancellationToken) => ProviderResult; +export type registerHoverCommand = (callback: provideHoverCommandFn) => void; export interface ExtensionAPI { readonly apiVersion: string; readonly javaRequirement: RequirementsData; readonly status: "Started" | "Error"; + readonly registerHoverCommand: registerHoverCommand; } diff --git a/src/extension.ts b/src/extension.ts index 6871b37fb..2dbc2a04e 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -15,6 +15,7 @@ import { } from './protocol'; import { ExtensionAPI } from './extension.api'; import * as buildpath from './buildpath'; +import * as hoverAction from './hoverAction'; import * as sourceAction from './sourceAction'; import * as refactorAction from './refactorAction'; import * as net from 'net'; @@ -161,6 +162,7 @@ export function activate(context: ExtensionContext): Promise { generateDelegateMethodsPromptSupport: true, advancedExtractRefactoringSupport: true, moveRefactoringSupport: true, + clientHoverProvider: true, }, triggerFiles: getTriggerFiles() }, @@ -203,6 +205,7 @@ export function activate(context: ExtensionContext): Promise { // Create the language client and start the client. languageClient = new LanguageClient('java', extensionName, serverOptions, clientOptions); languageClient.registerProposedFeatures(); + const registerHoverCommand = hoverAction.registerClientHoverProvider(languageClient, context); languageClient.onReady().then(() => { languageClient.onNotification(StatusNotification.type, (report) => { @@ -215,7 +218,8 @@ export function activate(context: ExtensionContext): Promise { resolve({ apiVersion: '0.2', javaRequirement: requirements, - status: report.type + status: report.type, + registerHoverCommand, }); break; case 'Error': @@ -226,7 +230,8 @@ export function activate(context: ExtensionContext): Promise { resolve({ apiVersion: '0.2', javaRequirement: requirements, - status: report.type + status: report.type, + registerHoverCommand, }); break; case 'Starting': diff --git a/src/hoverAction.ts b/src/hoverAction.ts new file mode 100644 index 000000000..d867102a5 --- /dev/null +++ b/src/hoverAction.ts @@ -0,0 +1,125 @@ +'use strict'; + +import { commands, ExtensionContext, HoverProvider, languages, CancellationToken, Hover, Position, TextDocument, MarkdownString, window, Uri, MarkedString, Command } from "vscode"; +import { LanguageClient, TextDocumentPositionParams, HoverRequest } from "vscode-languageclient"; +import { Commands as javaCommands } from "./commands"; +import { FindLinks } from "./protocol"; +import { registerHoverCommand, provideHoverCommandFn } from "./extension.api"; +import { logger } from "./log"; + +export function registerClientHoverProvider(languageClient: LanguageClient, context: ExtensionContext): registerHoverCommand { + const hoverProvider: JavaHoverProvider = new JavaHoverProvider(languageClient); + hoverProvider.registerHoverCommand(async (params: TextDocumentPositionParams, token: CancellationToken) => { + return await provideHoverCommand(languageClient, params, token); + }); + context.subscriptions.push(languages.registerHoverProvider('java', hoverProvider)); + context.subscriptions.push(commands.registerCommand(javaCommands.NAVIGATE_TO_SUPER_IMPLEMENTATION_COMMAND, (location: any) => { + navigateToSuperImplementation(languageClient, location); + })); + + return hoverProvider.registerHoverCommand; +} + +async function provideHoverCommand(languageClient: LanguageClient, params: TextDocumentPositionParams, token: CancellationToken): Promise { + const response = await languageClient.sendRequest(FindLinks.type, { + type: 'superImplementation', + position: params, + }, token); + if (response && response.length) { + const location = response[0]; + let tooltip; + if (location.kind === 'method') { + tooltip = `Go to super method '${location.displayName}'`; + } else { + tooltip = `Go to super implementation '${location.displayName}'`; + } + + return [{ + title: 'Go to Super Implementation', + command: javaCommands.NAVIGATE_TO_SUPER_IMPLEMENTATION_COMMAND, + tooltip, + arguments: [{ + uri: encodeBase64(location.uri), + range: location.range, + }], + }]; + } +} + +function navigateToSuperImplementation(languageClient: LanguageClient, location: any) { + const range = languageClient.protocol2CodeConverter.asRange(location.range); + window.showTextDocument(Uri.parse(decodeBase64(location.uri)), { + preserveFocus: true, + selection: range, + }); +} + +function encodeBase64(text: string): string { + return Buffer.from(text).toString('base64'); +} + +function decodeBase64(text: string): string { + return Buffer.from(text, 'base64').toString('ascii'); +} + +class JavaHoverProvider implements HoverProvider { + private _hoverRegistry: provideHoverCommandFn[] = []; + + constructor(readonly languageClient: LanguageClient) { + } + + async provideHover(document: TextDocument, position: Position, token: CancellationToken): Promise { + const params = { + textDocument: this.languageClient.code2ProtocolConverter.asTextDocumentIdentifier(document), + position: this.languageClient.code2ProtocolConverter.asPosition(position), + }; + + // Fetch the javadoc from Java language server. + const hoverResponse = await this.languageClient.sendRequest(HoverRequest.type, params, token); + const serverHover = this.languageClient.protocol2CodeConverter.asHover(hoverResponse); + + // Fetch the contributed hover commands from third party extensions. + const contributedCommands: Command[] = await this.getContributedHoverCommands(params, token); + if (!contributedCommands.length) { + return serverHover; + } + + const contributed = new MarkdownString(contributedCommands.map((command) => this.convertCommandToMarkdown(command)).join(' | ')); + contributed.isTrusted = true; + let contents: MarkedString[] = [ contributed ]; + let range; + if (serverHover && serverHover.contents) { + contents = contents.concat(serverHover.contents); + range = serverHover.range; + } + return new Hover(contents, range); + } + + registerHoverCommand(callback: provideHoverCommandFn) { + this._hoverRegistry.push(callback); + } + + private async getContributedHoverCommands(params: TextDocumentPositionParams, token: CancellationToken): Promise { + const contributedCommands: Command[] = []; + for (const provideFn of this._hoverRegistry) { + try { + if (token.isCancellationRequested) { + break; + } + + const commands = (await provideFn(params, token)) || []; + commands.forEach((command) => { + contributedCommands.push(command); + }); + } catch (error) { + logger.error(`Failed to provide hover command ${String(error)}`); + } + } + + return contributedCommands; + } + + private convertCommandToMarkdown(command: Command): string { + return `[${command.title}](command:${command.command}?${encodeURIComponent(JSON.stringify(command.arguments || []))} "${command.tooltip || command.command}")`; + } +} diff --git a/src/protocol.ts b/src/protocol.ts index cef61530e..4672501ac 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -1,6 +1,6 @@ 'use strict'; -import { RequestType, NotificationType, TextDocumentIdentifier, ExecuteCommandParams, CodeActionParams, WorkspaceEdit, FormattingOptions, WorkspaceSymbolParams, SymbolInformation } from 'vscode-languageclient'; +import { RequestType, NotificationType, TextDocumentIdentifier, ExecuteCommandParams, CodeActionParams, WorkspaceEdit, FormattingOptions, WorkspaceSymbolParams, SymbolInformation, TextDocumentPositionParams, Location } from 'vscode-languageclient'; import { Command, Range } from 'vscode'; /** @@ -342,3 +342,17 @@ export interface SearchSymbolParams extends WorkspaceSymbolParams { export namespace SearchSymbols { export const type = new RequestType('java/searchSymbols'); } + +export interface FindLinksParams { + type: string; + position: TextDocumentPositionParams; +} + +export interface LinkLocation extends Location { + displayName: string; + kind: string; +} + +export namespace FindLinks { + export const type = new RequestType('java/findLinks'); +} diff --git a/test/extension.test.ts b/test/extension.test.ts index 7c0354768..8b4a6bc8e 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -53,7 +53,8 @@ suite('Java Language Extension', () => { Commands.GENERATE_CONSTRUCTORS_PROMPT, Commands.GENERATE_DELEGATE_METHODS_PROMPT, Commands.APPLY_REFACTORING_COMMAND, - Commands.RENAME_COMMAND + Commands.RENAME_COMMAND, + Commands.NAVIGATE_TO_SUPER_IMPLEMENTATION_COMMAND ]; const foundJavaCommands = commands.filter((value) => { return JAVA_COMMANDS.indexOf(value)>=0 || value.startsWith('java.'); From 1b2a56e75c11e9853939f6bf0dd6517d064238fc Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Tue, 17 Sep 2019 20:02:46 +0200 Subject: [PATCH 0055/1031] Changelog for 0.49.0 Signed-off-by: Fred Bricon --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6f1a9dcf..021817793 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Change Log +## 0.49.0 (September 19th, 2019) +* enhancement - navigate to the super implementation. See [#553](https://github.com/redhat-developer/vscode-java/issues/553). +* enhancement - exclude certain packages from autocomplete/autoimport. See [#710](https://github.com/redhat-developer/vscode-java/issues/710). +* enhancement - code action: create non existing package when package declaration mismatch. See [#1030](https://github.com/redhat-developer/vscode-java/issues/1030). +* enhancement - code action: convert anonymous class to nested class. See [#1060](https://github.com/redhat-developer/vscode-java/pull/1060). +* enhancement - code action: fix non accessible references. See [JLS#440](https://github.com/eclipse/eclipse.jdt.ls/issues/440). +* enhancement - code action: convert for-loop to for-each loop. See [JLS#1166](https://github.com/eclipse/eclipse.jdt.ls/issues/1166). +* bug fix - fixed tables not properly rendered on Javadoc hover. See [#1002](https://github.com/redhat-developer/vscode-java/issues/1002). +* bug fix - extract embedded javadoc images. See [#1007](https://github.com/redhat-developer/vscode-java/issues/1007). +* bug fix - fixed extension never reaching the ready state (always spin). See [#1056](https://github.com/redhat-developer/vscode-java/issues/1056). +* bug fix - fixed wrong completion text for AnonymousDeclarationType. See [JLS#1168](https://github.com/eclipse/eclipse.jdt.ls/issues/1168). +* bug fix - fixed "No delegateCommandHandler for 'xxx'" error. See [JLS#1146](https://github.com/eclipse/eclipse.jdt.ls/issues/1146). +* bug fix - load bundle only once if same bundle occurs multiple times in different locations. See [JLS#1174](https://github.com/eclipse/eclipse.jdt.ls/pull/1174). + ## 0.48.0 (September 4th, 2019) * enhancement - ignore "Unsupported SuppressWarning" warnings by default. See [#507](https://github.com/redhat-developer/vscode-java/issues/507). * enhancement - code action to move member to another class. See [#980](https://github.com/redhat-developer/vscode-java/issues/980). From 8b11961035d71740e4196540ac910f2cdd9f9b4e Mon Sep 17 00:00:00 2001 From: Fred Bricon Date: Tue, 17 Sep 2019 23:33:22 +0200 Subject: [PATCH 0056/1031] Append changelog for 0.49.0 Signed-off-by: Fred Bricon --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 021817793..d47093830 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * bug fix - fixed wrong completion text for AnonymousDeclarationType. See [JLS#1168](https://github.com/eclipse/eclipse.jdt.ls/issues/1168). * bug fix - fixed "No delegateCommandHandler for 'xxx'" error. See [JLS#1146](https://github.com/eclipse/eclipse.jdt.ls/issues/1146). * bug fix - load bundle only once if same bundle occurs multiple times in different locations. See [JLS#1174](https://github.com/eclipse/eclipse.jdt.ls/pull/1174). +* bug fix - fixed incorrect `prepareRename` response when called over import. See [JLS#1175](https://github.com/eclipse/eclipse.jdt.ls/issues/1175). ## 0.48.0 (September 4th, 2019) * enhancement - ignore "Unsupported SuppressWarning" warnings by default. See [#507](https://github.com/redhat-developer/vscode-java/issues/507). From 06793b174437fee55985c62917f08da926f37058 Mon Sep 17 00:00:00 2001 From: Anton Kosyakov Date: Wed, 18 Sep 2019 09:18:20 +0000 Subject: [PATCH 0057/1031] fix #1066: use `vscode.env.appName` instead of hardcoding `VS Code` Signed-off-by: Anton Kosyakov --- src/plugin.ts | 2 +- src/requirements.ts | 4 ++-- src/settings.ts | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugin.ts b/src/plugin.ts index a88b1f58e..af947ca3b 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -43,7 +43,7 @@ export function onExtensionChange(extensions: readonly vscode.Extension[]) } if (hasChanged) { - const msg = 'Extensions to the Java Language Server changed, reloading Visual Studio Code is required for the changes to take effect.'; + const msg = `Extensions to the Java Language Server changed, reloading ${vscode.env.appName} is required for the changes to take effect.`; const action = 'Reload'; const restartId = Commands.RELOAD_WINDOW; vscode.window.showWarningMessage(msg, action).then((selection) => { diff --git a/src/requirements.ts b/src/requirements.ts index 81cc13def..7c827f6e3 100644 --- a/src/requirements.ts +++ b/src/requirements.ts @@ -1,6 +1,6 @@ 'use strict'; -import { workspace, Uri } from 'vscode'; +import { workspace, Uri, env } from 'vscode'; import * as cp from 'child_process'; import * as path from 'path'; import * as pathExists from 'path-exists'; @@ -40,7 +40,7 @@ function checkJavaRuntime(): Promise { let source: string; let javaHome: string = readJavaConfig(); if (javaHome) { - source = 'java.home variable defined in VS Code settings'; + source = `java.home variable defined in ${env.appName} settings`; } else { javaHome = process.env['JDK_HOME']; if (javaHome) { diff --git a/src/settings.ts b/src/settings.ts index 3cf0b2562..b729566bb 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,6 +1,6 @@ 'use strict'; -import { window, Uri, workspace, WorkspaceConfiguration, commands, ConfigurationTarget } from 'vscode'; +import { window, Uri, workspace, WorkspaceConfiguration, commands, ConfigurationTarget, env } from 'vscode'; import { LanguageClient } from 'vscode-languageclient'; import { Commands } from './commands'; import { getJavaConfiguration } from './utils'; @@ -27,7 +27,7 @@ export function onConfigurationChange() { excludeProjectSettingsFiles(); } if (hasJavaConfigChanged(oldConfig, newConfig)) { - const msg = 'Java Language Server configuration changed, please restart VS Code.'; + const msg = `Java Language Server configuration changed, please restart ${env.appName}.`; const action = 'Restart Now'; const restartId = Commands.RELOAD_WINDOW; oldConfig = newConfig; @@ -70,7 +70,7 @@ function excludeProjectSettingsFilesForWorkspace(workspaceUri: Uri) { items.unshift(changeItem.global); } - window.showInformationMessage('Do you want to exclude the VS Code Java project settings files (.classpath, .project. .settings, .factorypath) from the file explorer?', ...items).then((result) => { + window.showInformationMessage(`Do you want to exclude the ${env.appName} Java project settings files (.classpath, .project. .settings, .factorypath) from the file explorer?`, ...items).then((result) => { if (result === changeItem.global) { excludedInspectedValue.globalValue = excludedInspectedValue.globalValue || {}; for (const hiddenFile of needExcludeFiles) { From 51aecc4544effa69e48a8d3e1eb06c41293bb46f Mon Sep 17 00:00:00 2001 From: Nikolas Komonen Date: Tue, 20 Aug 2019 11:20:49 -0400 Subject: [PATCH 0058/1031] Updating CONTRIBUTING with images for setting up remote debugging Signed-off-by: Nikolas Komonen --- CONTRIBUTING.md | 146 +++++++++++++++++--- images/changelog/ChooseProduct.png | Bin 0 -> 39396 bytes images/changelog/ClientPort.png | Bin 0 -> 14470 bytes images/changelog/CreateNewConfiguration.png | Bin 0 -> 11130 bytes images/changelog/DebugConfigurationOpen.png | Bin 0 -> 30601 bytes images/changelog/DebugRemoteServer.png | Bin 0 -> 11894 bytes images/changelog/RemoteServer.png | Bin 0 -> 21323 bytes images/changelog/importMavenProject.png | Bin 0 -> 38424 bytes images/changelog/importProject.png | Bin 0 -> 37128 bytes images/changelog/importedMavenProject.png | Bin 0 -> 87582 bytes images/changelog/loadingTargetPlatform.png | Bin 0 -> 4256 bytes images/changelog/reloadTargetPlatform.png | Bin 0 -> 2767 bytes images/changelog/setTargetPlatform.png | Bin 0 -> 152156 bytes 13 files changed, 124 insertions(+), 22 deletions(-) create mode 100644 images/changelog/ChooseProduct.png create mode 100644 images/changelog/ClientPort.png create mode 100644 images/changelog/CreateNewConfiguration.png create mode 100644 images/changelog/DebugConfigurationOpen.png create mode 100644 images/changelog/DebugRemoteServer.png create mode 100644 images/changelog/RemoteServer.png create mode 100644 images/changelog/importMavenProject.png create mode 100644 images/changelog/importProject.png create mode 100644 images/changelog/importedMavenProject.png create mode 100644 images/changelog/loadingTargetPlatform.png create mode 100644 images/changelog/reloadTargetPlatform.png create mode 100644 images/changelog/setTargetPlatform.png diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2dba41456..b6eacd8b7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,54 +11,156 @@ vscode-java is a Visual Studio Code extension that uses a language server for it smartness. Usually vscode-java features depend on the [Eclipse ™ JDT Language Server](https://github.com/eclipse/eclipse.jdt.ls), (a.k.a. eclipse.jdt.ls) and the contributions should be coordinated between the two repositories. -## First Time Setup -1. Install prerequisites: +# + +## Background Info + +For the whole language server to get up and running it requires +two parts. + + **A)** The Client Side (this repo): [VSCode Java](https://github.com/redhat-developer/vscode-java) + +**B)** The Server Side: [JDT LS](https://github.com/eclipse/eclipse.jdt.ls) + +# + +## Complete Setup Guide + +The following will be a start to finish guide to get the entire language server up and running. + +# + +## **A)** Client Side Setup + +1. Install the required software: * latest [Visual Studio Code](https://code.visualstudio.com/) * [Node.js](https://nodejs.org/) v4.0.0 or higher -2. Fork and clone the repository +2. Fork and clone [this repository](https://github.com/redhat-developer/vscode-java) + + Keep in mind the final directories will look like: + + ``` + PROJECT_FOLDER/ + | + |--- vscode-java/ + |--- eclipse.jdt.ls/ + + ``` + + 3. `cd vscode-java` 4. Install the dependencies: ```bash $ npm install ``` -5. Open the folder in VS Code -## Building Eclipse ™ JDT Language Server +# + +## **B)** Server Side Setup This assumes that you are starting on the `vscode-java` directory 1. `cd ..` 2. Fork and clone the [eclipse.jdt.ls](https://github.com/eclipse/eclipse.jdt.ls) repository + + Ensure the directory looks like: + ``` + PROJECT_FOLDER/ + | + |--- vscode-java/ + |--- eclipse.jdt.ls/ + + ``` 3. Build server ```bash - $ cd ..\vscode-java + $ cd ./vscode-java $ npm run build-server ``` + +**\*Optional:** You can run faster server builds during development by calling `./node_modules/.bin/gulp dev_server` script instead, this will build server binaries that are required by your host OS only. You can also use `npm run watch-server` which will build and place them on the extension for Java changes. These commands run Maven in offline mode, so you might need to run `build-server` at least once, to fetch all the dependencies. This will build and place the binaries under the `server` folder. Alternately you can download and use the latest snapshot build from [Eclipse ™ JDT Language Server](https://github.com/eclipse/eclipse.jdt.ls) project with the following - ```bash - $ cd ..\vscode-java - $ ./node_modules/.bin/gulp download_server - ``` +```bash +$ cd ../vscode-java +$ ./node_modules/.bin/gulp download_server +``` +### Setting up the JDT Language Server in Eclipse + +4. In Eclipse, import a maven project: + + ![Import Project](images/changelog/importProject.png) + + ![Import Project](images/changelog/importMavenProject.png) -## Run with a remote JDT language server + Select the `eclipse.jdt.ls` folder, then click yes/accept to all +following prompts: + + ![Import Project](images/changelog/importedMavenProject.png) + +5) Now we need to use Tycho to download the dependencies, +this will get rid of the errors. + + At the top right arrow it will say `Set Target Platform`, select that and continue. + + ![Import Project](images/changelog/setTargetPlatform.png) + + After it will change to `Reload Target Platform` select that: + + ![Import Project](images/changelog/reloadTargetPlatform.png) + +6) Wait till the bottom right is done loading: + + ![Import Project](images/changelog/loadingTargetPlatform.png) + + once 100%: + + + + The errors should now be gone. + +# +# Running Everything + +## **C)** Run with a remote JDT language server While developing the language server and the extension, you don't need to deploy the server every time to try out changes. Instead you can run the language server out of its Eclipse workspace: -### _Launch Extension - Remote Server_ - -- Open VSCode on the `vscode-java` folder -- In the debug viewlet, run the launch _Launch Extension - Remote Server_ -- The extension will open a socket on port 3333 and will wait for the JDT language server to connect -- In Eclipse, run the JDT language server as an Eclipse application. - - Create a debug configuration of type _Eclipse Application_. - - in the main tab of the debug configuration set the product to `org.eclipse.jdt.ls.core.product`. - - in the Environment tab, define a variable `CLIENT_PORT` with value `3333`. - - if your workspace contains 'org.eclipse.jdt.ui', use the Plug-Ins tab in the debug configuration to exclude the plug-in. The presence of 'org.eclipse.jdt.ui' will cause the language server to hang. - - You can also use the `jdt.ls.remote.server` launch configuration. +### a) _Launch Extension - Client Side_ + +1. Open VSCode on the `vscode-java` folder + +2. In the debug viewlet, run the launch _Launch Extension - Remote Server_ +![Remote Server](images/changelog/RemoteServer.png) + +3. The extension will open a socket on port 3333 and will wait for the JDT language server to connect + + + +### b) _Setup Debug Server - Server Side_ + +[**\*Skip to C if this option exists\***](#c-launch-debug-server---server-side) + +In Eclipse, run the JDT language server as an Eclipse application. + 1) Create a debug configuration of type _Eclipse Application_. + ![Creation Menu](images/changelog/DebugConfigurationOpen.png) + + ![New Configuration](images/changelog/CreateNewConfiguration.png) + 2) in the main tab of the debug configuration set the product to `org.eclipse.jdt.ls.core.product`. + + ![Choose Product](./images/changelog/ChooseProduct.png) + 3) in the Environment tab, define a variable `CLIENT_PORT` with value `3333`. + + ![Define Port](images/changelog/ClientPort.png) + 4) If your workspace contains 'org.eclipse.jdt.ui', use the Plug-Ins tab in the debug configuration to exclude the plug-in. The presence of 'org.eclipse.jdt.ui' will cause the language server to hang. + +### c) _Launch Debug Server - Server Side_ + +- With the client side **(vscode-java) running**, you can start the remote server. + + ![Define Port](images/changelog/DebugRemoteServer.png) - In the debug console of VSCode you can see if the connection was successful. - When the server is running breakpoints can be reached and hot code replace can be used to make fixes without restarting the server. diff --git a/images/changelog/ChooseProduct.png b/images/changelog/ChooseProduct.png new file mode 100644 index 0000000000000000000000000000000000000000..0e7ecacb3d64173e26e7dcc49f14165e758a10e9 GIT binary patch literal 39396 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�%oHDa<_+{3 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 X+TX5|oe~1>?+BwaruwD2nDBoA@E?E) literal 0 HcmV?d00001 diff --git a/images/changelog/ClientPort.png b/images/changelog/ClientPort.png new file mode 100644 index 0000000000000000000000000000000000000000..1512f06cbc1a57a417491e608fb7493b124a1fcd GIT binary patch literal 14470 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

o9n3OTd=3Yde?#v6HWxmbp*9?k?Fd(%(fEV~a zed51Rq@~w#H1yb(1?lcSx!^sd|M7{xu<(2Ki|lRK;ra<Vt&PK69%;vwH!Y$1H^EM;n~kQEc1hc;`5@(-lj9SigIj+Gshdve-fQm5 zb(7%7h=&jB>&f7)2{Bp5vY{_UI)V|Jyu4O#5<8aZ7+>NBp;1lq@c4y)GI*Mw<>25* zfTnIuqoJiClgMv>+clLwSprheE58749^Q!$UIC3>4B4n#ty~SKjlbWF4@}uupHD;T zWSF2mZ)z&#rY(ntIm^+SmGgAwmTBw*!|b@p9(y)Svu6{N5|3v-<=~v3K6ysS9HPjt zhGC-CfUTjeIiA)W^lI=hF7t~o%&(7YjcsLbviSFU0NT_S45sCr;K$NQi!7 zkiTK&)#91rW3krg%aT5GYkXF8;{()?9OrOC zp!hbYYwyaPn<`V~`TAD*gNObOW$*2+qi_s=bocnG@)~Q-b!oP#XcFg@?-c7b$ie!) z-;}ewj9}7eESxn>o~<(1Eo-t_XHCVLAd5-Q{`)FrvI?}d%>{TM(Rsee0lA~;w_ z*PxZvwR!+&dsn9*hZ+&p6*|G%U|UE*snD@w=jGEWm{Cw5jrtVzfnPYtNZP(UX3;EP z8_ALefQI*Ve#=(R;9&8JaL3=M^7N3Sy}ja}S(t%6_ls*G7F)IB26e#2x(4_V><(aH zRH_&UMgalc2)hJA?J%lW5x;sDb(q3`Wx|yt-D4~t`{8KD2qw*lRApyG-y7ErROXY? z9KPN{ApGc+B{0y{y&*x@s>#U`)y2dh-zrNaPHjST; zPJN+&OyxNaVUtf0_v><%g^Mx`CU{U`X>O?+2h!%xJDB z>K+=e7hBj&tIwII8~0cw3M-E~Ul)d~L~AiR=N?40P+r_FKAWvhBH^f=P2FIr*_sn{ z84|is!lh2ZJrjfDNzrJdqa&x$pXIyY4Gi>WDw*5pr5NrCuro@tmQ@qv%~E8|QB{#i z#hizG=${0a;iZ`!MxV)$%Tjtog^0Ba6N{Lby&vTfrUjKLve&7ndOH=@PlBki{1)}pe0@3Lg@47e|0RA33zaT!~-O^!KjMtAI?o0 zxc-Iq-T#L64{Aw(+vSkmSYJ<=xI{19O7PZ551@J#BPA{6AKWc$;BFrOelMpUu8J!M z-03KvY<>%WuDe{A$$m~KMLvfj6K)^efdbb3k&RN&$7^ZHpp$RW_32#Icp=;xol{0g`e#7Mo=WeB*SNNTbGtZbh4?zMvjf17Fr=Wl zThX!dcc%G|W*zZzsL{RTWOL!GhfU5bFN^m5*!B~LD>m*j`-U+w4!PJl2L^k1T$j_M zGDJ4yng;|Diu4+6yvB&~WUl(^&#bjPCk?oKx&@^A(lYAR*$elGV6N z{VH|d4lI{`GPoZZe@Ly3f;;Yte`pe)>piX@QQW_2l8;#Ah=O#U19w41buT&z;gC(o#CQN#1;wzK5H`d^V)E*g1szSS|bfXD4H? zJ2&oOo;rcbU;A{{AO+e0YpIDX?+#5h8=bk{W7O^^OiAgMOZrN}Sw7M~+LBu7HJ*?b zK_e?Gi-K}P`AT5efDMf*;;9I%tB{C@(7@Q7c!Ztq=sa1g=q?&Xf_={o|d84KbmYIoWcFoH;*!w03owbX`O_@r?UMJQ(<) zb;?fVm$?W<8o4*;%1{$Zj_i}?yzrGa3vtNP+$kk>o+V6306u3t*3>bKcdSPC?S{4~ zQcAvVeSd32;0LDIQxO!oEK7*0bk(^{mDTd+y#^NvUoK51T#zvRaa8gRAm1WZrY+LF zyZ)7HCahSbT?Ob}xA}w}-E%tTz{qV1r7fC(v#NDJ9BE|%EajhE<3jF7KG-cLuUHnI zp?2Pn(4fPSei8YuZGc-QA}deN`dLAio^o?yseRu>9=k72uxN{kX&E|aC@k93BNl^% zsM7RqhM2vus4$z4Z`|U75jK)Ft^QSqvx$z{l0No*&~|vVjL9!WM?T}M9lNr!vILuM z1rV<;w{lWJX`Nj=p;`opJKyWQ8o-<4i=Ax_(}0Rx4=QgnU2Y6WRX}_3@bFMjP$=if zjSKR!0cPyiuV1PKYVMw%>epLM79yYqU%26`OCL&(V8#g=_tkm}EdUrDA`!-jSw0j$ zC&a(*_Z>PKp0P&D66}0fElVBpC(*So96fLYX~{@_o*XEz1P@;47O2LS5a7#LB2)j;wRqakfup3$7@& z_2YB#nzzoin5%*%2CuG*Sm8^0<7BT?yO?+UDPYR<3-|&&C<5~yUNM)_z9Ss-^{Rb^ zyStcWi9#nkr%!hsbpxhSt^_)I<2MLK0!Jn6xKbj| zdg|FwWF@TJe5`h1^5>@SmuXYRW+gcjbNb6;>335&dC9uTvvn4fa(rc?U4|nM7DP;o zn_mzAbpG(8M991MMI}lC*1$3Hz6{^|-t4sL5Q9)5GsY8Y&e|W^EqmYG3c3g90PCi# zq_lHusuBVC$WI0zjkj!O_1KK+fB5>w_fEcOdz|dp3)K}6*M%$gw%j54cAC7|*&wYA zMzGl6S{>mgSV1QzWtQKC#8YRbtp;Sm_+wvkK!?6%{zd}`)IZGV|Ijx5tx7_BjM<)B zwmOv3qTuXt>KYZA%K!cR9>lB`?SeivF9PVd?#fBLEhqnrF36M9yj-0FsHMfVVT?~& z{=NSV`}Z!M6-(T?&oAnaBa`7MkVcpvjo&F6Ch@KFiy3qXM6lXV*%Anj1ovk6-40)G zNtOo%9mOf?d)8RFZ*G?1<;a!j0!@;NNO> ztnBgOi_KJ8a9aGd^Y-?ZWl4)$XfJSAQgU#xU|5{2?e*4hNi2m7%CO9e5!05KPM;iz|4$A|F4q7I(6i&xGX2{ ze}G-J@-4;z4m?I zqnT#^eoJ5PjVReXv+O(-Y!Xi3a51i!P80Y72J?wt^VsO<&eG`qT0FZSPMwYq08Lu=krpsw zlDW~QJW|8Wm|$+?k5X3p8<+=BdNK~VvAIDT+yT@oL;bySLvH!rWfrR1^a=keqlzpZj&n8D zQ@6eQq&FZ?t7CJ=((;;}v&jpdZ}C)?(~ylAFu;BAa*e`l8(9E3O*V5@ak+JRQabmI zEo9~cZPa~oZph{9E4zf^4&tUQ13I5h2_`~3VUJ5!?b_3gl0dN=?>iq!bMtPjy>V!i ztxdLDI4pJO!|UiJ@pZd4z5H{G8NH#gdEW69HA~Cesvp@Th)QdA>*Jqiq(&in zEiMjDn|LHEYn!=Q&>2#lwvqPqZMG^ddPwWzc)O~V`TUn5o%J5KT|oZTaEU16yzxsu zUWuxUk5^$B80cF~1llFGigJ9sMSIRmFUN%JbE`!Q1^APwE-16uWWEx}i=Hv*@mkJA z$Li^kVZGWvj6i?JqFVHWVNVSI>2Y>W%xJUjEXl;L|5Tw3OsG_mym1>hw$QxCEc+O8 znCix2`Z75EroqSM@Nih@u0GxTt5OVrL>$9R3MPv^5yz@}K1i0Gi5m00qM6iOqxSg3 z>q^TS4wFt`fYcG2M^UdpqOGE*SDf`VD9GNzqkblJURj&I>^&2#&s~Qis>kc{^61l- zzye*yJ+V*d0VDuSgnerc%&G;F zUkY@yV`+=VoEk3nu_;+`AA_Y2@va3@D^T|;B6;k+D$hNicsLzYTOJ5{f;{`Xu4Vbn zf5^?6RBU_wj%HoA5&hs zBq5HWTk2+RFBt?>d_Y@-O(8JSEHx8yih=QUzMT1w8|&Tfo~~e+H%ZSEPZC0U`POIM=2?Fdwq`rmrof0VS4RE_pM0lOth2Z!;k$5`Y(mz%6_D7=1`lA?H3 zq6K!40`-q!dos84)to&{@3R9$~9w^ zP7xY~NlGfGyzGnx=E_`^^j@FsL?Ik+oo^nF0bM5<)<#d%D~f>x`fPr;(_ihMZ7mEP zZq|Cf6frBuw*fxVGZ`3RXN$%YNZ_ofEdA}|mCwAgFa}I4xO3zW z(6f3pGBT z&a0v~L!q>OR`bmw&W6DHfoAOu^G)Bjov2yhJn52DXr zN#b#Zwk|GCbZJRQYyh~vhdz(N)@Ynb)H7mbWyKfka)Fu%seo5A^p|AOoDhqkx2c&28P!@^h?7=S0Kb9V;>oLUM!1ZnIn zNDWpYrGOl6P-o}Mm+B>pt^1gVixvKG1??0ND ztgkJFCnpwogAQxCoEv;-(w5-TA}C*mP&`%Y2mEkGs-$6lKea*Oi-Y>0i42G7bKm#e%jt^ zauz;$75<;npwhIk76!Z$o}(XC6Xkf$bd}A#$JR)e za9X%hV9(f;wraCqbF)t%7CF#a#>ne7d(}yVQ2;@7eSJL;IBVC~6lqB*X6((@OfF|F zuZAZj@tggA?)c|8LEc`sxSd>QopF*wkl+0nK^C^rqV`}mYBxQz5WL#K>luqQx>RR^ zR5G`H`_RzP`1n~#3$k};XtB&lLQ!!Th{r81(*aNuRd9H5p)SM4$(hVy9;w2hnj8

V&5S9RJ%3?RBi1+#4L4Yf9^8{L(fc5otTw&zpYM9M@eUj&uZJ%BB&j4QJeSO{u zB+}yI6Vlp5L_|zlm1YA8oa)6oXqcGf>?SfFKdu2O8NpD1zdsP*K7GpSw5j0f>1j+4 zh4Gp6$Jw^ro&$XV*t*dQJwwx~wu)c*6cM2aeg(9B+pfHj8&dCDhq6o=CVE0CDZfbE zv`m#3^aPT_5OIEML%n{>$JcoW)pQ@ zY5jy^o&eOsr`oqO<>j1~6AJj__0E>N@~O3erjt#4bGALcBOv?uuZuXlyA#LpjcpB5 z`=al)6J7kBLX09Q&=4Nl+`1WRK;!x00C6sF$x1K*qY8^9*h5kv9-5pyztS19lf?|o zP{4Ux1>6oLC1q8?z=zjN%*+HvalHhqM{anp`YWp5P838DQ(Z zIds8b$N=8bw{VouNL^4^R8*qd;BvV14jmo6s(?903b+M?SMzo-e0@E@&#yn8J!gdA z-DRdqC$&LjoY+wOy2cQI+J}4+d)h)$ zR6_QI%X((4t<3<4kPq_igRKXjK79h33tyN&U3q?H=Gyjn0q9+|u)3+KX?q~bFFcvg zRVr%);DzeJhnS>qGBY!8kkR`9N3K z5`@8@O($T+Hn+AgDFx@cx@ei1t-C|X_4M@gz0Xve#tgs`2jCJvMTyVQAFavNaUaV- ze?M3xgR4j2k>0rMPHm0m6fBsefB5*3!+zx_;$$N*Ft9>{X;(EBAF%j#ORZoRPhDLd zd~K~ik!xsVq+BwJ7A#_BjKhPo9NBER+)+bkgV z83;-^I>1CS3@ojzuz8&RA(1BzECT)flEAG4T?^QjGchp%q~CoomQ;4r(3yDf2-<3D zgruY)y4%VfA6^Fl9fHTH86IBL`Q9v8l~;fawR+RgoSor+Z+k%GWQ{}rZi>*I;_?;feY{rlgWul`N;{z)7E!>NBW$$zf;_tf73 z=I_S-$v6K!^-p8};ncrT=AWznJ@s$<|G&EYza;MeNA><^bJ+jqga6&-KUe*a6#DP` q|LC^pne_x+SH5J)cXe4ML5a^Y>oRkI#gunp&Jq$(!&K<*N>%gxU z?htt`Fc`eBs=5MPVtYvId1yLYdw7|-S%EZdJv}_E+$=)IP(h$KAbBYXE${imEFV35 z*}ML7zoU%%4s~oS@t=6T-ccbik`r2!{d8M#s zi~xbeJwc$d7oc2CGm@%I5kJgWFvtT3k3QO2+Ov<;#OT<_cx0iq(QHY0q7PYxc1)Aw zqn$`;M5L}RI-gSwF&BQykc8V$#fffz*GnDE?&l}Jr-s8+4SD&Vy{YomVd9dKk{^wY z5$m9`eaChu)t_Wj$Sy)7l zr)5i7pPFhiiXE~9PVabj?l0`fgb2)tj3mWJb+S;~sh}5+_jdV3Uebl$+OO%W`ZnEU z3NgwPfV+Te6MZ{u()^NSAzm4!Qe`EiRRj@jPj4qyF~(BX_VKr3ci>f3zFin&Qqyk2)eHaC5FEo8_GxwG->C-{WFzTHl(^dYu^$R zkb_`0q=^N;Ce5&{TxxJyX9$R6Ogc0zqK@Ye)YeQnj_aCo7xPz;Evlhbwq1>eXqg31=>$_k`4~p``FaAOa^<4E7UBYF^yh2P_1Jg6l@~;f%-AU_y z)xx#odAge|(#fY0qN8dH_W9~b85tMr&M7s2V|`CmOYWcktM7!{7~Z=z8zFRUO<6Ck zVv4h%Fa*T3Q5}X$y)omO6GU!h<2L58hv=prk`fp!%j6jNKBnJpvIw1E+i91mPhC*v z?Gs~_gwIR6=O-zs8E==zN{9+Ht6iKF2L?+zu|}vF%t7Z&-#{mvP23!mJ;}!wqCT0> zeyFSK`+mz}!#)9zt*NIA3Gu|EUm@zV{PDKEqw=g{wxKiaR{=>qQP|s%pE&fZu-C-9 z-%|29#bkfsadRL`V}H*5lDw1O@MnK~q(F9lzU8`~3py4;Of%1FbD!Cv`uQX$GSK9R zbFv!;!c>Sx_3i5tzF@?Aemu)*)UwG$etFS&^G$4z{WTmb<)x<2(%Z2NZc-l_C<=UG zOK*ce)z#8eRLDCxObo*68fhxNXXqR{Zr-_N{EQTYYJ#VdmukGQ+RvM$il-dv?^^!c zYs$R(nWjXL|JKPO=Aa{H@{POw#^t%L$-OpH|n(z8s^ z#h`+{kxNi3+4t@WO~Z^e_O;x*{H^`zx6X&pYUIo=OW(v6 z*O#6H<=AJhh@W>>SaOJkfbr8`DT}&Y+#CBDEaD3}!yg1{B|JZSPt4fK!$h^sGnV4e z%bKWL8H$t!hv=A>txa2}_gJfJH1IQ&^$p{vrDg zXn1xV$wqh}^{!3x@S?fEVz66=N`ty*G=JjPi=78^z#swbhn&zd*!f$u#nFm4m$VXJ z0HcFL-VDf8eE9Xb1OF1A?whMbSV*VOI0@*6!1$vA7cORFvIC2YkiJNNcazC9VY)g*47qE zRoKd~SEcY$8!G0R6tY%L&z+A~z?MCb!m!a?F{{@FjDB~PXw+)QNXblPsYR$Cnx^B+ zsPCA4cp1@)|ClEZ`yd)7Cx{;Q7A;=&9uXxBJM3+Ol++}4EVZ1J+ULE>#5k(9UaXf> zd45mY*O-?i&AHdVX9%&a5%nlCl~wedJ~>;{5FYKo1`{8g*HqbeCs<;gE3I}vJTPkuEn+cK0(#J zYmb?EDn%pA2=j&6*A974eh7qD*YgpXg!k*_-u%?|67$|;awIJ0c|16uCE%C4O5di@ z+yYC$L`(PUux5djj?2uOs*mWL1WSr6&2X)(Q=P;YtS0MF)EGSa+*hP}SQIYs>`gMU zu3-?a?P!4}+l z)&jI>>iCy_fq=O;5|z=usU^zh+v>_vp;4XtrAlch-Tk7YDwcPnm1o)~g$lEUcKyV` ztq~}5;QN6?G}&9II2!O&J?g|?($>-JN&a^5mxGea-$(1nUDNB)){Jy7t2o^rg7{kf zb0yANYx{Zw=-9tG9GH=8^muv_3<{c>uix&tf1A16Ef$o1xi77W9RF=&q_Ir3 zc*pOWH(v3lRSc$wub!Ud7cfH<>_F~k1Zg);s0IEe71w?`J!5pf8atK{ zhMD#RwLvgzz+$Rd;8uAh)gc?9&5H6Q!#9P3&5Lu*rJ%PfHE9^g;n;BlTBhxEX^Zt` z-Ppf4H)y?U+R59^%pM#EFK&+?>YQmHZ=d@la`an$rrSr@ZMyyna74@vbX02FvwSZr z(A8o$!4Vic@0`p>NlH0k&*|2#5dINTs+AxeRjyiGCs@*&te^bUgxLKh1}bC&p-jlv zx)j7R?*Ta=GrlZ5wTcfBc*#YP(F^&k^FFblprmM=SY939H=TlB zW%m-?e}SaGT(TY!RwMj3H5Rjsd;6A*AZj4@0*ShHFVDWa!sUCtEBT&necx!&XDMo^ zn&L5vaN?fQO$%m;iYm|IN9PrE3Jg@wbe`7^e@;G_5@xI76h8E@um}8F%OsOGGCGVU zXQjNty7c<0J+thu2Dj$If$)b%zI24n*1oLO7}9iiK%WwfNu}AdSQVIv_W3Giqlta? zv9TLFLB6mK5tTe|3J;n+wik&*)t*sj)3E0)DXG=338t@f7z4}v8#XpX$xmpt$8~RV zyWS|%_Rpzo+yU%dS?ol58BKPS;AeMFEhBY2_P42B5hcwImFJ7H$@r%1Z`csV&Lv6k zt~^>bf6LgoXI{a0zveQSuxv}_nEVu)gvRkm}R{~ zb?0yd`GmQ-&XnY2TOJaAJN)Gbb%8Yjc00I8q6p&d#;J-!mqL z-{xbVcgNY;`g0}-_N>c7YSj}^G@`f&bw3%k4B&N*K0bT%_Poi=nPo=8kc2>H*k z@(nS!MTMT3S&=E}>Cic7-G#rfuu$mZ!Oco2)`}Ej)dwv1`>R7@Vq#-^S3A4Xs3`P^ zZV9k}fIvM{vkl)mvEoknI_T403s#Iw_j`_&VT7@6DR3T*Z0y&hByzF9hnv%NI2;}v z9NhVMwUFW5A@5vKS*ao?_c<;uMUK|6@x$R_tCzaEx{ptDQqt7MK%%j+F%HC_;%coo zDvnZY+Lq_ThYy-XO7U{pH^2L^#2&t6WyN4CsHzrg5@E=2d(8|-7b>PSXdg^h7zX(J z!(gz%!9i*on)~bHXDzz7NrO%c4a%t;UCYaqR32+Rk?HB_v$L}WvT?i%_))a0P>&+O(JoUneCeZyg>wsi_+n7$_-47Zg|+7|cIC-mkB%-S|IM zTl8P}0{ITzN7%&P{@=|htcKyl0h|s;f14Q@8ENHZq@>2$N63Xfrt-d^vdo`t^*WZ3 zm2GWmBAPL`Mx~Co?TaQJ7#L7dQK6%w)7RG@N@4Hk_`Z1r8dDZg;>|cbKF&!_4#%bj z19R#24&kJw?dk3g?Ouh3hr^`uW#cHOrlv#!AH4VeloAjSkYU;YmVWo{T~bogsBQSJ zISLlV!QLLsOs`+zUc~l%gf6vDx|>yms7fZbbqF&=jY}`qFxn6IZcNiilb6dQR!Bhc)Gd* z&JW#3^~Nl7*y3??a>~le;^yL_5b?z)BC>tx!wF!V{PX9}&E1^>EiOhkutNRor-I|r zv9BGhQSqf8FD6w*MMX7AFOC*lU!Y(*Uh;#)39mS$snw;WU)o(T&PaqJ8@GN`W=i61 z4a!PR*3r`|nX<1k?KIKV-QM12h?nyZ2nf2{WoS04oZMAVR7^}vL=Ewl;TF{So<{d@ zw_k-8M$N=zzcrj@1J8^fuyi6v0qroE5|WVk0s#3 zUG6KUuvt~>QBY9i<>f_SQJOS35=Zsg`;dWFMzghQo$J~3e*E-4-<@RW?xx8uL=1WJ z^mrVknk_uX!5)V_-{QG{vf90i>IL$?wPnm~_q!(Pn3~`88gO3j7_sC6Vi4U15!CW6 zVlH}A>^XC2Qze6UL~4Toz$8!l6k5vl5D(_tS21Kc71GP&-2RVEy7QwfyLI8-Gc*jYE>aGOyBD(z%N@|*GasE zK^!P-DfwG}lsTd zp3DmU`?8O&E$BOcK}p9VY?_wP)6>uztHFR{c&og2laOM{Qz4kV!Doo9G3Qy=@5#)# zv7UT~vkd*$hd61*L@(bmk_y8QRx6Gj$tC7Igicjd5y%6_2#GW_gfmdCc&2BCym3Ge59~f44i7h0qpP!~sM#NqaM!sbA8h&bj z>$;GK?#0dzl}W428to&*s3l&b!*(Omtx1aP)Uo%lG+Zx)`W$s`mfs7Uw>k0`qAgAj z)kGA&0_T+m6HKBQ7@QCb)bu%())?v2KtA{XvWQr~I43xpyXl??KV}=SR4`V25wiGF z;nnRS-5gvx`)E27;zN_Qq+{$<*l6Wm{_4T9?EH-?LfDt@DqdH?)VCksg^k_0^qYMA zJGD-(6X$i)Zd6O({JV(^UDQH9)i{?lCtuAsPw;d`p)fr6usNytXus#sslP&JztJRl zk+T2=LD*)>cu0pDYJgUyJwOFz`9VTP<7G;pMM-~56=&U=SPK8xY_h*PQ|IZSN+DDh46As7O)H+g>p8c_9exIpscs^#_nWVvsZ z7TJRT3L5EgPI@yCi3`P!rBWq@FEa=wF?*y0=?1#C3=f1@{q5%2I!?^u5p>&pf*{9E zE4kb(NJXf|ri^9u-9Hw4Hb%yt=RX%OtqjE^gRz9NpxorZV}}c>rgxn4*HhQ#lb*6H1$O zjpDEc6Ldu2s=~vD-i;+Ds%n=88j5OhL+^keFcm44dsCx}goa7I0RSDY^=D&eCcsLD zl*z15d`D7pHazN7NgAgM;#&^rpHisEwl8O!|J5*IXwGb&Zu>?)@9$tA;Md$eir%+g zg^@Z!a(XW^eWJX!CP(Ico6lNrk8}{}+kJ%#=*uCY*n*d0(gz%*%v73{6QLNsKbzos z-t@o(TV!9lx*U3C@Gi_^5ui$A(6?GqROnR9;O)qdPPiG(ET_q8lzi8*>B!pj46+DJt= zENkiVj&+|aYYEqnvwR9Uc83*4VY%tpwN~Q-RT~nucfUkSLz35iPccep?1?OoccDBCyT;BgfU-HY;3MXDMMxva-?N>W_*UjCp z=xGc`X_eLaDiIdH$3wL38%_>-SuC(zxK+cjTav0elB)VRF4C*K*Y_*W@y;zh1rs3d zjoTBUISpIt^j9fu&5gMw28zWkXFSO&>mO ze8>|luHkI!?2-B17GF-X(|7H)n&VeeqP6FWQJqEVa?-uG1>&@76ZOY+F6Ti($|1=%C zR}HJUX*+O;)>zi|5QXFTW))S-$d>H8CLKC(H#NZN`#dv7lX8Oe8h2A__`(+2QS23^WR_8r|maW#5oy%2tx%x==+|J@qU)kWuVdgS~Z11rV z%bc{|O&&%jTwHT%5IZqiz3W#kJK?a_KPQW(X{?Y>d z`(&%C6&rtmV&q25(Mu0^Jj-PGDu-KOe%dq9&^coFKl1b}ekG2DxK#DxfAas%v};!6 zjyaI2|LcGMO=3VLN4=7ox{N~Ads&y1NOy6kmlT}tG6(TAVpD(qq?$r}d<4SHw6(R1 zY5`Wm!^l{=F#no}sL6R*wCPFQlbuM)V)2x&P^g$!wn#lnVI^P-r>i2Xu zZdzK)nMz}kQ(@1aXW0vSYK!h??qMkxSXfeY&B^6t20*$!Fd)7fKr!4nBjFDdA1!EW z8$M~Y8Ku~h7O%3K-DT>QtGCnD>B##aFhsy#Qk=XYdLL2}Sj;bv|seBT1-zlD|5b zv%sE@x`88To64*A@Y#64cMp5c3r^;B6hB8sR@c@J4GgF=CDq!D7U5x02&X0{*1ByD zhM^OtmxwSkI~>l}r?45LVPe96|K@jD5m!_DB0!v9Q1B8_LPiEz0^7Omv@hf(x=NN{ z7`DNW_Y$6-m!+D;nVFfG`!=;YU{{DEg1@=$CE?6kDB@$qpJ z6BGAsc%hfr$Aj5;8d;#q2WVFxKnMM<4u*%7nvEz32zUW*Ib#|`?yrY+<#`t|@G25P zHtr$wvT00;H>oUes_fc8usk!945|i@iLAh<2cP*Fb^O<4WNpBsbriV|vQttRu)$p1 z+zVxmQy9(7&EUL;2Y=torFK7X-o(VjuU`j#l}9Fv&pG9ROcon!NaqdeJro)$WLK6Zh@K+9cD7Z z05Y+({QTr~VlA>Tv&xnySH;PYos(q299#p7ih79{oRvl1zIS-|s8#Rh>r27!0*Do! zKoCAXJ)NGO0xolC{Y9ZriGC6wg7C?5U3TafEv6}39t`9HZBoEeW)>E;=Dlc=3W0&5 zkl%B+k=R@>U%q^SjKQHY*XW!>H7291tlWxB>f-M1(3syHf%Uv^`V6pTjq)jQ-q@I$ zBr>pEzQIGAXSe>r;_vmGY;8d()}rhih7~NLy+4=1-2w=JVyo14Hi9C0K`(ImT7Sw0iS=do)KZD6kc|(UB$m zoph&TIkm5?@5b+VfP$li{bDt2AQSe+mO4`yHZwO;yt-kXG&*kxthSRHTg!XYiN-J@ z*ISEM%5Dvi6*4E~=95C}^V0@gD zn_IKW8BMbhaB$c4zIO|cf1BNbh&54B!DLMh4@XX*jp1%g?;09nW?^ycg}t`2veGE! zVPj(x7XAx3@W==&HMRNaT5lYMh{jv|$jHcxpQuzlmR#4z%gdcX&*KHMLzZ0ggvwch zo~ysY0RDe@c?l>ahFV%$78VwYLnEBCJ#0?eQpe2kav^I)L)gdLG_2=}dv zs<)aKI=1Olluqn@#h0dng4-)QBr0kCumtZt#y!vXkCsm@0&G~DDXFp1OG--0(eXRg zW0u#FK)@YOTtBIxhpnM@9Lc-EU%#k<5l>9G0nieGNsfyawq+@&qC$Wc26!F7gaPda zh&fIVFbW0{hwGXYJA2i|#RV{YQokQPJv~79Lc_vd6B5!u0T`MrR?Rs%aRHFBaXHWr zm=_slf8D0joJC7@h0ez6YBgX=0r#!Xy=(6rriW8GU*J#B1@?Mac5M5OR#tEQDT5uf zy5kb3%aE>n2R9 z#WQo0Gebig-LlBTY4=w<<21X$UxI6DYX1H;VrOUPZv_n(2{Zerya^ocis7_fCv@6s z_Pw($gkXaYuxJz-nP@epBo{V>RAq$!@Y?@U{Qg5>|E~ZD8ly1wOYwiW z>$ct!zLt*j$Me}4%LB;26Q2U^^#U3|i_y{k?F9gNZm@#wt44;O6Hg;y94E^hc*& zV%fe9eP5k&E~j?~l5#eVT6|}|9A3qOp?x21YUL9ip6-uRSoCY07I?h{z}}_)Su(1< zJtFk>Lv2Pr&LgR7M?Hk`HNcG%hNFMsB(+TO@M#@X92^{?@Kye!-CcQ<1qm>a5i!X4 z$G$L#iRE;?$H&L7OX{TSd^n2&R5>6jQgU*Fo}U6Fec!)d@jGtkbK8)s)+58m_c)w? zH@VwaqE&Wt-eG)xW^TD6 z{(H_y8K5vxS;*S_o@QcD&HnaQp?LD~W<3s&%0yjOKoHxdHXk5<27mv~JwKSQ->;uB zDWG{-pWaEg(BNd)?)xrd#H8B17f`Tb_?#A7E+L6|)pB?{gmh87P?(n|_;vq)Th}E>? z0T?4*RPX*wmDk6Qq8|@ZcRkVp&$Z}}1ynvCUtd`7S_~=Q*4CD&_X((yV@06k!^~7` zosD6mvV>o=bu7GY50g?9uq!P-8Yf0nTwHNz)Eg)Pt3h4Rb6|yzAAl(H^9GX8xP~** z^T+FD#X=36X{J3BYG8ng0K^j!dw!*S;o_%7UVAV2^Ug_{xez2^W#&K(tY zkjHgXWhtKb6cf?&O11{9{^@-&ZGWeW%rP|Ut%n(zCM10OR zDvevMN3%!PPnEX$vSsBJ6nsxsf~kaen%%dfh0^K*ZO_imjEszwiYLdakIKr*qF=0CKQLowe^na(a51789S-yq1v>+3VL}it5|_Y6lkLe|nuU3ft)X5< zQ4%W z&fOn(9&c;_c74(;Rv|{DXiWN$`$FRKlWt;V%<%Pq(AHAez2*AL?z6ExNg5iO<)G)s zBQY{S$aa{ibRy87lM)1_%3n)waZe`*sNs780-cc8k^j@}woCS>lq5oC89fh=i+YEd z=_*s8jM3xg1C>+?@%!JLoWJ|&vb{L$0onm^l)n0(iu~Ump8o|hz~!fH6savg`ZrvZ zC%;OMl3>F#`e;aWp?le=f?PQQbJ4nhZu6Zkj&d>DC)8COff8UK6L#Bo1uB zvm9(}Y@D5+`$(O&bahD&Zcn7*I!^ou7w>h5|*>pJb;Z$!lp@S)jZI$_PM(F4eMsfS+cI_yOv*nu!VEGOh2s zLK*^1f%QkJZNG`Xjb>zG5_DbbfoBN;_IEHdt9G2L0q}?0iJKk({&(*#7o0mi-Q3(f zJs$xzSW`n|a4>!8F)l8S67Y_k(V+c`MoTVzJ3B_B5x`T`ja4IuZImP=5JJ07uC91% zS)Hho6w;LF4}m=*?Y@`!c)Qv{LPEa5v2oT9-3V=a>w@c3Kts_yEhM(jhB_md0zYk( z2p|R_Z`|D7M;sLm^X`p|jW2xz)YWm?(-RXV8GdP_m-(SFG|;bZ#OYFujo%EPdj7{E zK$inRA%DNS>UMlCaO&H`IlBw8ibs&DR734d%VDni{TBEfPXPLJEqbogJ_) zYY7~G1ad?yyUrc|>T>wEf8PNhYXAI%fXAS6adrlDNhn2p>rfYzpht@TZ&F`8S!B;8 z{q);k6%>E_i4BqZ9O36V(!X2>x~Ouln~ z6i!9eZyNwm0N?wyyS8R-4wK$1>8!FUk; zDEL@>vzc$!{9?22buJwHZ>7~=A<)iT+5V3ce>jCSII=$`L5XbLZin?=kg8^UG%=1;Ar8-BZw-T+>O?( zGpMMBQ;CzG*q2rs4~+kLSB3*=J~M}Y>9nY#-?q+<0IWO+hx2~d(bfi-Gf_m5V`muu z-$W!6f~hn{0mHn_0Tf+k?RTao^HJC^OtP7c^ap>Q=39IT9^r>9JFB_rBgJHvIUwUj z;xYWOuh(Jjr}$gI=>Q@YZU*$;ZcbK9OG~qsTr3oo3dU`J zOuy&K$rnR3150=YnLGCuJcnO4n&OUcKg7UFC3bwzwqH}?Mwl|Kn8#g(O zj>Yh#yPs?*-I%hCSH#Vr2c?(osW!X!4h|b;Ac*R`Swk<>@LBJRvCaTeDm+I_l^uw8 z3nCpu!zgSfMn<5vsnKIOT4+4xTlNn%)6>>Y+NH2IoKBZ1)adQ+Z*6Tg)YAhBetZIg ziCxp6$9e#@#orJKxNT$!d0|7T{Pnf@+_#2xUQ}cR)(iJc9WM|c<1<_KqRqj^W+aUs zk%Z|XpL=V)uaJeSe*1HBa^gnP^6^~*f(C%F`}huqbiBO0LPGavn?pcTEa2`U5(cA| v=lU-l0r*Pd(57kNE!|@xiW%4s?HQ{m8`W0ps~E6d6$Fx(R*|ZNybt+5`A_8{ literal 0 HcmV?d00001 diff --git a/images/changelog/DebugConfigurationOpen.png b/images/changelog/DebugConfigurationOpen.png new file mode 100644 index 0000000000000000000000000000000000000000..31efbe144b3942cf25587c6a6c0cdd6683dd2f86 GIT binary patch literal 30601 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 S4Vk+=11T|i(PD_c@BafLI|}~* literal 0 HcmV?d00001 diff --git a/images/changelog/DebugRemoteServer.png b/images/changelog/DebugRemoteServer.png new file mode 100644 index 0000000000000000000000000000000000000000..25c8070138417979b5e421e60ff179ab35a43c4a GIT binary patch literal 11894 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 U6g6M?jvNO-Qi_t*;zr;9A6!C51ONa4 literal 0 HcmV?d00001 diff --git a/images/changelog/RemoteServer.png b/images/changelog/RemoteServer.png new file mode 100644 index 0000000000000000000000000000000000000000..74e87d267a1ae481a90c72d2ddf932675d6a8521 GIT binary patch literal 21323 zcma%jWmr{Fx9$P~Q52*b6a#ljN6jNg-v z%h)kEb44Tc9#u6nDhf;O+*CPo?DO2!Sc}JeaFyuXl@La3FUyC1w0G*4xZU(|xPFN@ z4_2lv45Im#1$XW@>kT$X^@c8Kl?yIB*qNj1gtD@-k8cA6KTki?9XW0sMs#&1t(Gm=`IM~| z_VYN!Yqt$~m^Nm6Be_e|ahUs$x-XLR4jX+m=Gc7i!r`Gc?Ef}o{^&&KLz|B zywJVeT&|YuoJdJY387xS(^V*t1wkRsPWRX4-QC^9?$}mVC+`IOcsw49sJyy5 zJ6X)<%otta0tG3l=+3wg(Jx63rl%Sc6YKr&ptiY8}d|s`h>%sZ@Qp;!Slw(@0H}%&DnC4i!KAQ~W>& zmyn!{^e81MX{*lmq)r+c8;gmG3IkCUzVnU_`p*M;OF}|ILARVLXx~-Sc=WM>6E&}} z@NkC}$tHMfYir)Y!itRm`anfxYGQJmGlO~C&v}$O@gU~4-*nT?FSE9;#qIj$LtgAm z0vltcOl6W>5PpIhfddT>A_B1sQ;5L%^w(W!ZN>2L-X?EiIaT3ATg+4(?2L$eX`-CI#n zQCIiFnI`r^vkfoT{pO`Pr*LRRquZT@Xz%zqkKz0G?<0^Xq^w`L;$Yz8Z*Ole*OszC zA-Ih8Hx-xy{;%9l*)}|$l3^h~KR?!z<&e-&PLD_L2DN$ak9&K2FJ8P55)zUmKO0KU ziW)%qc$yBscij0~B7b6qIZPaB9@&Ux8mzg1*O@nj#lJ)EAM zn_Fw$ulTCFby3Ax*jZ)f>}Y=JYjC@XiAk$FO-4>mPUf=n)oyfb>g*7HKw$7}aaFbE zC;1r3>myNyrCb+B>T)~=HYO(9yBb2xMCoChRMv051oZVc*SaJiK4IbRp6&DXo_11m zbF8`{kEcg&H0upf^Xys(u_;lm2Q#Aw z2M3jg!y)M_5y{EACMGq`lS!CV@$4bQ(}l`(DB;rGMS}srBgC+1`fY zd}4@0LxKp&ROIEw<>jq!L-K95*rbv+*bFZT47b_QDZ=6-Bhy&yI3N`jl_J$<`}Ld) z7M7{ublx*=H(^Q1gPSu$6rzRPPPuNG?~d1hy?lK;!6t%%!4?U@NlUzW9QoN{j)qS3 zs54i!tJ@PMz@gQi*WcFm_4J7Vn?`GAkHe$x;;#%Yu>s9H+E4ZeJ7@0O+O6))27@@O za_TxdzrG?y#Kc?|hYn3lm>ncone3&9jBi)fZdYWd4a9+3<#9T2daBzK!bqgIAT^G| zGUz-%McCip-#P>THmxz!@Au{@B`n)7H9hh!YdBWQ0yn^%eM7Wey^6XcQDG84ZV-n3)xo zloslo+}1h+Qw1l5{-koJ$6Q}d4b5*q{8_BGX^e(@*4EMXJYYRjKL4kT06PJ4{D728 ze9mYiDXsB02_h${Cq+hl zeijkJY^wCG#~XEgvM_!)z4iM_o4a1n1Olc$rhq`ET;@T9(|T)u!J|W4*QPc2z7PRd zokv=*XTn@MxTXx< zT={%1A{6$p0L10J>f*&s{P*_`uVChCX6e+EzIW`C)6fk4)_>IYZeO(`BkO`9lHyDZ zSvi<#s_W}#+udEo#TlUY?>mRnxD6}TpFV$1ubQ7~lvZ+7I{0Df&f)ph%&bDcayo@w z+Udrr_srWP`Ek19)#L>}~(I?QthzN4mePq$KQfpgC*7@%|HP z7y&mm9mO$dN~EL`xNn^bq_qYL$>EB261dd>2~m)f=M)so8BovdR^gJ0zG9gAhet@0o85X?#LbGPuDDNz{Rw|1R4i26;x+*9r$XP}1YIs^f)3teQaDu7yHVP zY*(JVf`Y*9AXq?V<_mBT!SaB<9TF-vC&;kiTvt#)2`)leftb;Gu<_ghdP9J*QS&`A zDG3kRe|%)*jn<_A;)~b2JM4cPP+*pt#GEhhKVF>q1a1x}rCgqHuelchho zz~6Ygs_31Y+fz7QDj<;d2}hAaCY9jM>DJ-8cXhGRzDEwt`pmjiyU~P}3F(1^?7SZ| z(o*f(CDUMKsn<3g-52KFzf!4@U!bk8uM?u9AA*hqnkV#qV<$30q+M4y+==M&ey_Ul zISPU8cbr!1$V> zInnBut3Yq?@EEMtvJ#B?XKf5iG#mHIC)^$yF0|BZP92*9;!*pw@xrSw{&Krq1_lQ+ z;)Gz+{f^j-MS661c3+|4lF9sr@V5X9l( zEO0~Ulzb0XcDdp9c48vNYW-llz7Dnx+|V>07d%|dj}%n+C#QFu#ZOzQt=b2$ zMCNYi>aC~&-e`ADKg+8&#^JK^>Tn>i86V419x<^07GH*2tP1XyH%WL*kKZ0Hx4~y* zoU07JvU~g-o0Ks!Lv#o`vdM=LlP#_MRs&`w5(e>%Ui0_ z($HMM92i*I=)_4B?yx)71=?t{Q}o0Tq3MU#LL?ln8S5!Y3V8S*2udA8$*d8Jr(lER z7-sQ0V<18-ETrTi>2>ZMYS3TKV`75)-nltHL6X?mSRzjMSG&qRp@ghfzcP!84tjov zYiT9Jcn&|88QxTiQ+oaSwQ`A;g~PV$J_`j2$?0&rKzYneTbsWi$!O2~^zm;eZf