diff --git a/build/yarn.lock b/build/yarn.lock
index b33452a884..bbb907bc75 100644
--- a/build/yarn.lock
+++ b/build/yarn.lock
@@ -3614,9 +3614,9 @@ vsce@1.48.0:
yazl "^2.2.2"
vscode-ripgrep@^1.4.0:
- version "1.5.4"
- resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.4.tgz#dae1c3eef350513299341cdf96e622c00b548eff"
- integrity sha512-Bs8SvFAkR0QHf09J46VgNo19yRikOtj/f0zHzK3AM3ICjCGNN/BNoG9of6zGVHUTO+6Mk1RbKglyOHLKr8D1lg==
+ version "1.5.5"
+ resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.5.tgz#24c0e9cb356cf889c98e15ecb58f9cf654a1d961"
+ integrity sha512-OrPrAmcun4+uZAuNcQvE6CCPskh+5AsjANod/Q3zRcJcGNxgoOSGlQN9RPtatkUNmkN8Nn8mZBnS1jMylu/dKg==
vscode-telemetry-extractor@1.4.3:
version "1.4.3"
diff --git a/extensions/azurecore/resources/dark/refresh_inverse.svg b/extensions/azurecore/resources/dark/refresh_inverse.svg
index d79fdaa4e8..ec0c43f0bc 100644
--- a/extensions/azurecore/resources/dark/refresh_inverse.svg
+++ b/extensions/azurecore/resources/dark/refresh_inverse.svg
@@ -1 +1,4 @@
-
\ No newline at end of file
+
diff --git a/extensions/azurecore/resources/light/refresh.svg b/extensions/azurecore/resources/light/refresh.svg
index e034574819..a5b88123a0 100644
--- a/extensions/azurecore/resources/light/refresh.svg
+++ b/extensions/azurecore/resources/light/refresh.svg
@@ -1 +1,4 @@
-
\ No newline at end of file
+
diff --git a/extensions/configuration-editing/src/extension.ts b/extensions/configuration-editing/src/extension.ts
index 0b69def737..0d051856c2 100644
--- a/extensions/configuration-editing/src/extension.ts
+++ b/extensions/configuration-editing/src/extension.ts
@@ -63,11 +63,20 @@ function registerVariableCompletions(pattern: string): vscode.Disposable {
const indexOf$ = document.lineAt(position.line).text.indexOf('$');
const startPosition = indexOf$ >= 0 ? new vscode.Position(position.line, indexOf$) : position;
- return [{ label: 'workspaceFolder', detail: localize('workspaceFolder', "The path of the folder opened in VS Code") }, { label: 'workspaceFolderBasename', detail: localize('workspaceFolderBasename', "The name of the folder opened in VS Code without any slashes (/)") },
- { label: 'relativeFile', detail: localize('relativeFile', "The current opened file relative to ${workspaceFolder}") }, { label: 'file', detail: localize('file', "The current opened file") }, { label: 'cwd', detail: localize('cwd', "The task runner's current working directory on startup") },
- { label: 'lineNumber', detail: localize('lineNumber', "The current selected line number in the active file") }, { label: 'selectedText', detail: localize('selectedText', "The current selected text in the active file") },
- { label: 'fileDirname', detail: localize('fileDirname', "The current opened file's dirname") }, { label: 'fileExtname', detail: localize('fileExtname', "The current opened file's extension") }, { label: 'fileBasename', detail: localize('fileBasename', "The current opened file's basename") },
- { label: 'fileBasenameNoExtension', detail: localize('fileBasenameNoExtension', "The current opened file's basename with no file extension") }].map(variable => ({
+ return [
+ { label: 'workspaceFolder', detail: localize('workspaceFolder', "The path of the folder opened in VS Code") },
+ { label: 'workspaceFolderBasename', detail: localize('workspaceFolderBasename', "The name of the folder opened in VS Code without any slashes (/)") },
+ { label: 'relativeFile', detail: localize('relativeFile', "The current opened file relative to ${workspaceFolder}") },
+ { label: 'relativeFileDirname', detail: localize('relativeFileDirname', "The current opened file's dirname relative to ${workspaceFolder}") },
+ { label: 'file', detail: localize('file', "The current opened file") },
+ { label: 'cwd', detail: localize('cwd', "The task runner's current working directory on startup") },
+ { label: 'lineNumber', detail: localize('lineNumber', "The current selected line number in the active file") },
+ { label: 'selectedText', detail: localize('selectedText', "The current selected text in the active file") },
+ { label: 'fileDirname', detail: localize('fileDirname', "The current opened file's dirname") },
+ { label: 'fileExtname', detail: localize('fileExtname', "The current opened file's extension") },
+ { label: 'fileBasename', detail: localize('fileBasename', "The current opened file's basename") },
+ { label: 'fileBasenameNoExtension', detail: localize('fileBasenameNoExtension', "The current opened file's basename with no file extension") }
+ ].map(variable => ({
label: '${' + variable.label + '}',
range: new vscode.Range(startPosition, position),
detail: variable.detail
diff --git a/extensions/json-language-features/server/README.md b/extensions/json-language-features/server/README.md
index 9b02dc24ef..5ca997d9e1 100644
--- a/extensions/json-language-features/server/README.md
+++ b/extensions/json-language-features/server/README.md
@@ -21,6 +21,8 @@ The server implements the following capabilities of the language server protocol
- [Document Symbols](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol) for quick navigation to properties in the document.
- [Document Colors](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentColor) for showing color decorators on values representing colors and [Color Presentation](https://microsoft.github.io/language-server-protocol/specification#textDocument_colorPresentation) for color presentation information to support color pickers. The location of colors is defined by the document's [JSON schema](http://json-schema.org/). All values marked with `"format": "color-hex"` (VSCode specific, non-standard JSON Schema extension) are considered color values. The supported color formats are `#rgb[a]` and `#rrggbb[aa]`.
- [Code Formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_rangeFormatting) supporting ranges and formatting the whole document.
+- [Folding Ranges](https://microsoft.github.io/language-server-protocol/specification#textDocument_foldingRange) for all folding ranges in the document.
+- Semantic Selection for semantic selection for one or multiple cursor positions.
- [Diagnostics (Validation)](https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics) are pushed for all open documents
- syntax errors
- structural validation based on the document's [JSON schema](http://json-schema.org/).
@@ -90,10 +92,39 @@ To find the schema for a given JSON document, the server uses the following mech
- The settings define a schema association based on the documents URL. Settings can either associate a schema URL to a file or path pattern, and they can directly provide a schema.
- Additionally, schema associations can also be provided by a custom 'schemaAssociations' configuration call.
-Schemas are identified by URLs. To load the content of a schema, the JSON language server tries to load from that URL or path. The following URL schemas are supported:
+Schemas are identified by URLs. To load the content of a schema, the JSON language server either tries to load from that URI or path itself, or delegates to the client.
+
+The `initializationOptions.handledSchemaProtocols` initialization option defines which URLs are handled by the server. Requests for all other URIs are send to the client.
+
+`handledSchemaProtocols` is part of the initialization options and can't be changed while the server is running.
+
+```ts
+let clientOptions: LanguageClientOptions = {
+ initializationOptions: {
+ handledSchemaProtocols: ['file'] // language server should only try to load file URLs
+ }
+ ...
+}
+```
+
+If `handledSchemaProtocols` is not set, the JSON language server will load the following URLs itself:
+
- `http`, `https`: Loaded using NodeJS's HTTP support. Proxies can be configured through the settings.
- `file`: Loaded using NodeJS's `fs` support.
-- `vscode`: Loaded by an LSP call to the client.
+
+#### Schema content request
+
+Requests for schemas with URLs not handled by the server are forwarded to the client through an LSP request. This request is a JSON language server specific, non-standardized, extension to the LSP.
+
+Request:
+- method: 'vscode/content'
+- params: `string` - The schema URL to request.
+- response: `string` - The content of the schema with the given URL
+
+#### Schema content change notification
+
+When the client is aware that a schema content has changed, it will notify the server through a notification. This notification is a JSON language server specific, non-standardized, extension to the LSP.
+The server will, as a response, clear the schema content from the cache and reload the schema content when required again.
#### Schema associations notification
@@ -111,20 +142,6 @@ interface ISchemaAssociations {
- keys: a file names or file path (separated by `/`). `*` can be used as a wildcard.
- values: An array of schema URLs
-#### Schema content request
-
-The schema content for schema URLs that start with `vscode://` will be requested from the client through an LSP request. This request is a JSON language server specific, non-standardized, extension to the LSP.
-
-Request:
-- method: 'vscode/content'
-- params: `string` - The schema URL to request. The server will only ask for URLs that start with `vscode://`
-- response: `string` - The content of the schema with the given URL
-
-#### Schema content change notification
-
-When the client is aware that a schema content has changed, it will notify the server through a notification. This notification is a JSON language server specific, non-standardized, extension to the LSP.
-The server will, as a response, clear the schema content from the cache and reload the schema content when required again.
-
Notification:
- method: 'json/schemaContent'
- params: `string` the URL of the schema that has changed.
diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json
index 68b639c2aa..c07dca1e44 100644
--- a/extensions/json-language-features/server/package.json
+++ b/extensions/json-language-features/server/package.json
@@ -1,7 +1,7 @@
{
"name": "vscode-json-languageserver",
"description": "JSON language server",
- "version": "1.0.1",
+ "version": "1.2.0",
"author": "Microsoft Corporation",
"license": "MIT",
"engines": {
diff --git a/extensions/theme-seti/build/update-icon-theme.js b/extensions/theme-seti/build/update-icon-theme.js
index 3686307f7d..69d945693c 100644
--- a/extensions/theme-seti/build/update-icon-theme.js
+++ b/extensions/theme-seti/build/update-icon-theme.js
@@ -10,7 +10,7 @@ let fs = require('fs');
let https = require('https');
let url = require('url');
-// list of languagesIs not shipped with VSCode. The information is used to associate an icon with a langauge association
+// list of languagesIs not shipped with VSCode. The information is used to associate an icon with a language association
let nonBuiltInLanguages = { // { fileNames, extensions }
"r": { extensions: ['r', 'rhistory', 'rprofile', 'rt'] },
"argdown": { extensions: ['ad', 'adown', 'argdown', 'argdn'] },
@@ -35,7 +35,7 @@ let nonBuiltInLanguages = { // { fileNames, extensions }
"todo": { fileNames: ['todo'] }
};
-let FROM_DISK = false; // set to true to take content from a repo checkedout next to the vscode repo
+let FROM_DISK = true; // set to true to take content from a repo checked out next to the vscode repo
let font, fontMappingsFile, fileAssociationFile, colorsFile;
if (!FROM_DISK) {
diff --git a/extensions/theme-seti/cgmanifest.json b/extensions/theme-seti/cgmanifest.json
index 2b449830f5..c742c019ea 100644
--- a/extensions/theme-seti/cgmanifest.json
+++ b/extensions/theme-seti/cgmanifest.json
@@ -6,7 +6,7 @@
"git": {
"name": "seti-ui",
"repositoryUrl": "https://github.com/jesseweed/seti-ui",
- "commitHash": "89175d7f9e0c70cd325b80a18a3c77fc8eb7c798"
+ "commitHash": "904c16acced1134a81b31d71d60293288c31334b"
}
},
"version": "0.1.0"
diff --git a/extensions/theme-seti/icons/seti.woff b/extensions/theme-seti/icons/seti.woff
index e590d77f68..b85727d01e 100644
Binary files a/extensions/theme-seti/icons/seti.woff and b/extensions/theme-seti/icons/seti.woff differ
diff --git a/extensions/theme-seti/icons/vs-seti-icon-theme.json b/extensions/theme-seti/icons/vs-seti-icon-theme.json
index 193c22fe61..d5a05b60ff 100644
--- a/extensions/theme-seti/icons/vs-seti-icon-theme.json
+++ b/extensions/theme-seti/icons/vs-seti-icon-theme.json
@@ -206,6 +206,14 @@
"fontCharacter": "\\E017",
"fontColor": "#a074c4"
},
+ "_cpp_2_light": {
+ "fontCharacter": "\\E017",
+ "fontColor": "#b7b73b"
+ },
+ "_cpp_2": {
+ "fontCharacter": "\\E017",
+ "fontColor": "#cbcb41"
+ },
"_crystal_light": {
"fontCharacter": "\\E018",
"fontColor": "#bfc2c1"
@@ -246,999 +254,1103 @@
"fontCharacter": "\\E01C",
"fontColor": "#cc3e44"
},
- "_db_light": {
+ "_dart_light": {
"fontCharacter": "\\E01D",
+ "fontColor": "#498ba7"
+ },
+ "_dart": {
+ "fontCharacter": "\\E01D",
+ "fontColor": "#519aba"
+ },
+ "_db_light": {
+ "fontCharacter": "\\E01E",
"fontColor": "#dd4b78"
},
"_db": {
- "fontCharacter": "\\E01D",
+ "fontCharacter": "\\E01E",
"fontColor": "#f55385"
},
"_default_light": {
- "fontCharacter": "\\E01E",
+ "fontCharacter": "\\E01F",
"fontColor": "#bfc2c1"
},
"_default": {
- "fontCharacter": "\\E01E",
+ "fontCharacter": "\\E01F",
"fontColor": "#d4d7d6"
},
"_docker_light": {
- "fontCharacter": "\\E020",
+ "fontCharacter": "\\E021",
"fontColor": "#498ba7"
},
"_docker": {
- "fontCharacter": "\\E020",
+ "fontCharacter": "\\E021",
"fontColor": "#519aba"
},
"_docker_1_light": {
- "fontCharacter": "\\E020",
+ "fontCharacter": "\\E021",
"fontColor": "#455155"
},
"_docker_1": {
- "fontCharacter": "\\E020",
+ "fontCharacter": "\\E021",
"fontColor": "#4d5a5e"
},
"_docker_2_light": {
- "fontCharacter": "\\E020",
+ "fontCharacter": "\\E021",
"fontColor": "#7fae42"
},
"_docker_2": {
- "fontCharacter": "\\E020",
+ "fontCharacter": "\\E021",
"fontColor": "#8dc149"
},
"_docker_3_light": {
- "fontCharacter": "\\E020",
+ "fontCharacter": "\\E021",
"fontColor": "#dd4b78"
},
"_docker_3": {
- "fontCharacter": "\\E020",
+ "fontCharacter": "\\E021",
"fontColor": "#f55385"
},
"_ejs_light": {
- "fontCharacter": "\\E022",
+ "fontCharacter": "\\E023",
"fontColor": "#b7b73b"
},
"_ejs": {
- "fontCharacter": "\\E022",
+ "fontCharacter": "\\E023",
"fontColor": "#cbcb41"
},
"_elixir_light": {
- "fontCharacter": "\\E023",
+ "fontCharacter": "\\E024",
"fontColor": "#9068b0"
},
"_elixir": {
- "fontCharacter": "\\E023",
+ "fontCharacter": "\\E024",
"fontColor": "#a074c4"
},
"_elixir_script_light": {
- "fontCharacter": "\\E024",
+ "fontCharacter": "\\E025",
"fontColor": "#9068b0"
},
"_elixir_script": {
- "fontCharacter": "\\E024",
+ "fontCharacter": "\\E025",
"fontColor": "#a074c4"
},
"_elm_light": {
- "fontCharacter": "\\E025",
+ "fontCharacter": "\\E026",
"fontColor": "#498ba7"
},
"_elm": {
- "fontCharacter": "\\E025",
+ "fontCharacter": "\\E026",
"fontColor": "#519aba"
},
"_eslint_light": {
- "fontCharacter": "\\E027",
+ "fontCharacter": "\\E028",
"fontColor": "#9068b0"
},
"_eslint": {
- "fontCharacter": "\\E027",
+ "fontCharacter": "\\E028",
"fontColor": "#a074c4"
},
"_eslint_1_light": {
- "fontCharacter": "\\E027",
+ "fontCharacter": "\\E028",
"fontColor": "#455155"
},
"_eslint_1": {
- "fontCharacter": "\\E027",
+ "fontCharacter": "\\E028",
"fontColor": "#4d5a5e"
},
"_ethereum_light": {
- "fontCharacter": "\\E028",
+ "fontCharacter": "\\E029",
"fontColor": "#498ba7"
},
"_ethereum": {
- "fontCharacter": "\\E028",
+ "fontCharacter": "\\E029",
"fontColor": "#519aba"
},
"_f-sharp_light": {
- "fontCharacter": "\\E029",
+ "fontCharacter": "\\E02A",
"fontColor": "#498ba7"
},
"_f-sharp": {
- "fontCharacter": "\\E029",
+ "fontCharacter": "\\E02A",
"fontColor": "#519aba"
},
"_favicon_light": {
- "fontCharacter": "\\E02A",
+ "fontCharacter": "\\E02B",
"fontColor": "#b7b73b"
},
"_favicon": {
- "fontCharacter": "\\E02A",
+ "fontCharacter": "\\E02B",
"fontColor": "#cbcb41"
},
"_firebase_light": {
- "fontCharacter": "\\E02B",
+ "fontCharacter": "\\E02C",
"fontColor": "#cc6d2e"
},
"_firebase": {
- "fontCharacter": "\\E02B",
+ "fontCharacter": "\\E02C",
"fontColor": "#e37933"
},
"_firefox_light": {
- "fontCharacter": "\\E02C",
+ "fontCharacter": "\\E02D",
"fontColor": "#cc6d2e"
},
"_firefox": {
- "fontCharacter": "\\E02C",
+ "fontCharacter": "\\E02D",
"fontColor": "#e37933"
},
"_font_light": {
- "fontCharacter": "\\E02E",
+ "fontCharacter": "\\E02F",
"fontColor": "#b8383d"
},
"_font": {
- "fontCharacter": "\\E02E",
+ "fontCharacter": "\\E02F",
"fontColor": "#cc3e44"
},
"_git_light": {
- "fontCharacter": "\\E02F",
+ "fontCharacter": "\\E030",
"fontColor": "#3b4b52"
},
"_git": {
- "fontCharacter": "\\E02F",
+ "fontCharacter": "\\E030",
"fontColor": "#41535b"
},
"_go_light": {
- "fontCharacter": "\\E033",
+ "fontCharacter": "\\E034",
"fontColor": "#498ba7"
},
"_go": {
- "fontCharacter": "\\E033",
+ "fontCharacter": "\\E034",
"fontColor": "#519aba"
},
"_go2_light": {
- "fontCharacter": "\\E034",
+ "fontCharacter": "\\E035",
"fontColor": "#498ba7"
},
"_go2": {
- "fontCharacter": "\\E034",
+ "fontCharacter": "\\E035",
"fontColor": "#519aba"
},
"_gradle_light": {
- "fontCharacter": "\\E035",
+ "fontCharacter": "\\E036",
"fontColor": "#7fae42"
},
"_gradle": {
- "fontCharacter": "\\E035",
+ "fontCharacter": "\\E036",
"fontColor": "#8dc149"
},
"_grails_light": {
- "fontCharacter": "\\E036",
+ "fontCharacter": "\\E037",
"fontColor": "#7fae42"
},
"_grails": {
- "fontCharacter": "\\E036",
+ "fontCharacter": "\\E037",
"fontColor": "#8dc149"
},
+ "_graphql_light": {
+ "fontCharacter": "\\E038",
+ "fontColor": "#dd4b78"
+ },
+ "_graphql": {
+ "fontCharacter": "\\E038",
+ "fontColor": "#f55385"
+ },
"_grunt_light": {
- "fontCharacter": "\\E037",
+ "fontCharacter": "\\E039",
"fontColor": "#cc6d2e"
},
"_grunt": {
- "fontCharacter": "\\E037",
+ "fontCharacter": "\\E039",
"fontColor": "#e37933"
},
"_gulp_light": {
- "fontCharacter": "\\E038",
+ "fontCharacter": "\\E03A",
"fontColor": "#b8383d"
},
"_gulp": {
- "fontCharacter": "\\E038",
+ "fontCharacter": "\\E03A",
"fontColor": "#cc3e44"
},
"_haml_light": {
- "fontCharacter": "\\E03A",
+ "fontCharacter": "\\E03C",
"fontColor": "#b8383d"
},
"_haml": {
- "fontCharacter": "\\E03A",
+ "fontCharacter": "\\E03C",
"fontColor": "#cc3e44"
},
+ "_happenings_light": {
+ "fontCharacter": "\\E03D",
+ "fontColor": "#498ba7"
+ },
+ "_happenings": {
+ "fontCharacter": "\\E03D",
+ "fontColor": "#519aba"
+ },
"_haskell_light": {
- "fontCharacter": "\\E03B",
+ "fontCharacter": "\\E03E",
"fontColor": "#9068b0"
},
"_haskell": {
- "fontCharacter": "\\E03B",
+ "fontCharacter": "\\E03E",
"fontColor": "#a074c4"
},
"_haxe_light": {
- "fontCharacter": "\\E03C",
+ "fontCharacter": "\\E03F",
"fontColor": "#cc6d2e"
},
"_haxe": {
- "fontCharacter": "\\E03C",
+ "fontCharacter": "\\E03F",
"fontColor": "#e37933"
},
"_haxe_1_light": {
- "fontCharacter": "\\E03C",
+ "fontCharacter": "\\E03F",
"fontColor": "#b7b73b"
},
"_haxe_1": {
- "fontCharacter": "\\E03C",
+ "fontCharacter": "\\E03F",
"fontColor": "#cbcb41"
},
"_haxe_2_light": {
- "fontCharacter": "\\E03C",
+ "fontCharacter": "\\E03F",
"fontColor": "#498ba7"
},
"_haxe_2": {
- "fontCharacter": "\\E03C",
+ "fontCharacter": "\\E03F",
"fontColor": "#519aba"
},
"_haxe_3_light": {
- "fontCharacter": "\\E03C",
+ "fontCharacter": "\\E03F",
"fontColor": "#9068b0"
},
"_haxe_3": {
- "fontCharacter": "\\E03C",
+ "fontCharacter": "\\E03F",
"fontColor": "#a074c4"
},
"_heroku_light": {
- "fontCharacter": "\\E03D",
+ "fontCharacter": "\\E040",
"fontColor": "#9068b0"
},
"_heroku": {
- "fontCharacter": "\\E03D",
+ "fontCharacter": "\\E040",
"fontColor": "#a074c4"
},
"_hex_light": {
- "fontCharacter": "\\E03E",
+ "fontCharacter": "\\E041",
"fontColor": "#b8383d"
},
"_hex": {
- "fontCharacter": "\\E03E",
+ "fontCharacter": "\\E041",
"fontColor": "#cc3e44"
},
"_html_light": {
- "fontCharacter": "\\E03F",
- "fontColor": "#cc6d2e"
+ "fontCharacter": "\\E042",
+ "fontColor": "#498ba7"
},
"_html": {
- "fontCharacter": "\\E03F",
+ "fontCharacter": "\\E042",
+ "fontColor": "#519aba"
+ },
+ "_html_1_light": {
+ "fontCharacter": "\\E042",
+ "fontColor": "#7fae42"
+ },
+ "_html_1": {
+ "fontCharacter": "\\E042",
+ "fontColor": "#8dc149"
+ },
+ "_html_2_light": {
+ "fontCharacter": "\\E042",
+ "fontColor": "#b7b73b"
+ },
+ "_html_2": {
+ "fontCharacter": "\\E042",
+ "fontColor": "#cbcb41"
+ },
+ "_html_3_light": {
+ "fontCharacter": "\\E042",
+ "fontColor": "#cc6d2e"
+ },
+ "_html_3": {
+ "fontCharacter": "\\E042",
"fontColor": "#e37933"
},
"_html_erb_light": {
- "fontCharacter": "\\E040",
+ "fontCharacter": "\\E043",
"fontColor": "#b8383d"
},
"_html_erb": {
- "fontCharacter": "\\E040",
+ "fontCharacter": "\\E043",
"fontColor": "#cc3e44"
},
"_ignored_light": {
- "fontCharacter": "\\E041",
+ "fontCharacter": "\\E044",
"fontColor": "#3b4b52"
},
"_ignored": {
- "fontCharacter": "\\E041",
+ "fontCharacter": "\\E044",
"fontColor": "#41535b"
},
"_illustrator_light": {
- "fontCharacter": "\\E042",
+ "fontCharacter": "\\E045",
"fontColor": "#b7b73b"
},
"_illustrator": {
- "fontCharacter": "\\E042",
+ "fontCharacter": "\\E045",
"fontColor": "#cbcb41"
},
"_image_light": {
- "fontCharacter": "\\E043",
+ "fontCharacter": "\\E046",
"fontColor": "#9068b0"
},
"_image": {
- "fontCharacter": "\\E043",
+ "fontCharacter": "\\E046",
"fontColor": "#a074c4"
},
"_info_light": {
- "fontCharacter": "\\E044",
+ "fontCharacter": "\\E047",
"fontColor": "#498ba7"
},
"_info": {
- "fontCharacter": "\\E044",
+ "fontCharacter": "\\E047",
"fontColor": "#519aba"
},
"_ionic_light": {
- "fontCharacter": "\\E045",
+ "fontCharacter": "\\E048",
"fontColor": "#498ba7"
},
"_ionic": {
- "fontCharacter": "\\E045",
+ "fontCharacter": "\\E048",
"fontColor": "#519aba"
},
"_jade_light": {
- "fontCharacter": "\\E046",
+ "fontCharacter": "\\E049",
"fontColor": "#b8383d"
},
"_jade": {
- "fontCharacter": "\\E046",
+ "fontCharacter": "\\E049",
"fontColor": "#cc3e44"
},
"_java_light": {
- "fontCharacter": "\\E047",
+ "fontCharacter": "\\E04A",
"fontColor": "#b8383d"
},
"_java": {
- "fontCharacter": "\\E047",
+ "fontCharacter": "\\E04A",
"fontColor": "#cc3e44"
},
"_javascript_light": {
- "fontCharacter": "\\E048",
+ "fontCharacter": "\\E04B",
"fontColor": "#b7b73b"
},
"_javascript": {
- "fontCharacter": "\\E048",
+ "fontCharacter": "\\E04B",
"fontColor": "#cbcb41"
},
"_javascript_1_light": {
- "fontCharacter": "\\E048",
+ "fontCharacter": "\\E04B",
"fontColor": "#cc6d2e"
},
"_javascript_1": {
- "fontCharacter": "\\E048",
+ "fontCharacter": "\\E04B",
"fontColor": "#e37933"
},
"_javascript_2_light": {
- "fontCharacter": "\\E048",
+ "fontCharacter": "\\E04B",
"fontColor": "#498ba7"
},
"_javascript_2": {
- "fontCharacter": "\\E048",
+ "fontCharacter": "\\E04B",
"fontColor": "#519aba"
},
"_jenkins_light": {
- "fontCharacter": "\\E049",
+ "fontCharacter": "\\E04C",
"fontColor": "#b8383d"
},
"_jenkins": {
- "fontCharacter": "\\E049",
+ "fontCharacter": "\\E04C",
"fontColor": "#cc3e44"
},
"_jinja_light": {
- "fontCharacter": "\\E04A",
+ "fontCharacter": "\\E04D",
"fontColor": "#b8383d"
},
"_jinja": {
- "fontCharacter": "\\E04A",
+ "fontCharacter": "\\E04D",
"fontColor": "#cc3e44"
},
"_json_light": {
- "fontCharacter": "\\E04C",
+ "fontCharacter": "\\E04F",
"fontColor": "#b7b73b"
},
"_json": {
- "fontCharacter": "\\E04C",
+ "fontCharacter": "\\E04F",
"fontColor": "#cbcb41"
},
"_json_1_light": {
- "fontCharacter": "\\E04C",
+ "fontCharacter": "\\E04F",
"fontColor": "#7fae42"
},
"_json_1": {
- "fontCharacter": "\\E04C",
+ "fontCharacter": "\\E04F",
"fontColor": "#8dc149"
},
"_julia_light": {
- "fontCharacter": "\\E04D",
+ "fontCharacter": "\\E050",
"fontColor": "#9068b0"
},
"_julia": {
- "fontCharacter": "\\E04D",
+ "fontCharacter": "\\E050",
"fontColor": "#a074c4"
},
"_karma_light": {
- "fontCharacter": "\\E04E",
+ "fontCharacter": "\\E051",
"fontColor": "#7fae42"
},
"_karma": {
- "fontCharacter": "\\E04E",
+ "fontCharacter": "\\E051",
"fontColor": "#8dc149"
},
"_kotlin_light": {
- "fontCharacter": "\\E04F",
+ "fontCharacter": "\\E052",
"fontColor": "#cc6d2e"
},
"_kotlin": {
- "fontCharacter": "\\E04F",
+ "fontCharacter": "\\E052",
"fontColor": "#e37933"
},
"_less_light": {
- "fontCharacter": "\\E050",
+ "fontCharacter": "\\E053",
"fontColor": "#498ba7"
},
"_less": {
- "fontCharacter": "\\E050",
+ "fontCharacter": "\\E053",
"fontColor": "#519aba"
},
"_license_light": {
- "fontCharacter": "\\E051",
+ "fontCharacter": "\\E054",
"fontColor": "#b7b73b"
},
"_license": {
- "fontCharacter": "\\E051",
+ "fontCharacter": "\\E054",
"fontColor": "#cbcb41"
},
"_license_1_light": {
- "fontCharacter": "\\E051",
+ "fontCharacter": "\\E054",
"fontColor": "#cc6d2e"
},
"_license_1": {
- "fontCharacter": "\\E051",
+ "fontCharacter": "\\E054",
"fontColor": "#e37933"
},
"_license_2_light": {
- "fontCharacter": "\\E051",
+ "fontCharacter": "\\E054",
"fontColor": "#b8383d"
},
"_license_2": {
- "fontCharacter": "\\E051",
+ "fontCharacter": "\\E054",
"fontColor": "#cc3e44"
},
"_liquid_light": {
- "fontCharacter": "\\E052",
+ "fontCharacter": "\\E055",
"fontColor": "#7fae42"
},
"_liquid": {
- "fontCharacter": "\\E052",
+ "fontCharacter": "\\E055",
"fontColor": "#8dc149"
},
"_livescript_light": {
- "fontCharacter": "\\E053",
+ "fontCharacter": "\\E056",
"fontColor": "#498ba7"
},
"_livescript": {
- "fontCharacter": "\\E053",
+ "fontCharacter": "\\E056",
"fontColor": "#519aba"
},
"_lock_light": {
- "fontCharacter": "\\E054",
+ "fontCharacter": "\\E057",
"fontColor": "#7fae42"
},
"_lock": {
- "fontCharacter": "\\E054",
+ "fontCharacter": "\\E057",
"fontColor": "#8dc149"
},
"_lua_light": {
- "fontCharacter": "\\E055",
+ "fontCharacter": "\\E058",
"fontColor": "#498ba7"
},
"_lua": {
- "fontCharacter": "\\E055",
+ "fontCharacter": "\\E058",
"fontColor": "#519aba"
},
"_makefile_light": {
- "fontCharacter": "\\E056",
+ "fontCharacter": "\\E059",
"fontColor": "#cc6d2e"
},
"_makefile": {
- "fontCharacter": "\\E056",
+ "fontCharacter": "\\E059",
"fontColor": "#e37933"
},
"_makefile_1_light": {
- "fontCharacter": "\\E056",
+ "fontCharacter": "\\E059",
"fontColor": "#9068b0"
},
"_makefile_1": {
- "fontCharacter": "\\E056",
+ "fontCharacter": "\\E059",
"fontColor": "#a074c4"
},
"_makefile_2_light": {
- "fontCharacter": "\\E056",
+ "fontCharacter": "\\E059",
"fontColor": "#627379"
},
"_makefile_2": {
- "fontCharacter": "\\E056",
+ "fontCharacter": "\\E059",
"fontColor": "#6d8086"
},
"_makefile_3_light": {
- "fontCharacter": "\\E056",
+ "fontCharacter": "\\E059",
"fontColor": "#498ba7"
},
"_makefile_3": {
- "fontCharacter": "\\E056",
+ "fontCharacter": "\\E059",
"fontColor": "#519aba"
},
"_markdown_light": {
- "fontCharacter": "\\E057",
+ "fontCharacter": "\\E05A",
"fontColor": "#498ba7"
},
"_markdown": {
- "fontCharacter": "\\E057",
+ "fontCharacter": "\\E05A",
"fontColor": "#519aba"
},
"_maven_light": {
- "fontCharacter": "\\E058",
+ "fontCharacter": "\\E05B",
"fontColor": "#b8383d"
},
"_maven": {
- "fontCharacter": "\\E058",
+ "fontCharacter": "\\E05B",
"fontColor": "#cc3e44"
},
"_mdo_light": {
- "fontCharacter": "\\E059",
+ "fontCharacter": "\\E05C",
"fontColor": "#b8383d"
},
"_mdo": {
- "fontCharacter": "\\E059",
+ "fontCharacter": "\\E05C",
"fontColor": "#cc3e44"
},
"_mustache_light": {
- "fontCharacter": "\\E05A",
+ "fontCharacter": "\\E05D",
"fontColor": "#cc6d2e"
},
"_mustache": {
- "fontCharacter": "\\E05A",
+ "fontCharacter": "\\E05D",
"fontColor": "#e37933"
},
"_npm_light": {
- "fontCharacter": "\\E05C",
+ "fontCharacter": "\\E05F",
"fontColor": "#3b4b52"
},
"_npm": {
- "fontCharacter": "\\E05C",
+ "fontCharacter": "\\E05F",
"fontColor": "#41535b"
},
"_npm_1_light": {
- "fontCharacter": "\\E05C",
+ "fontCharacter": "\\E05F",
"fontColor": "#b8383d"
},
"_npm_1": {
- "fontCharacter": "\\E05C",
+ "fontCharacter": "\\E05F",
"fontColor": "#cc3e44"
},
"_npm_ignored_light": {
- "fontCharacter": "\\E05D",
+ "fontCharacter": "\\E060",
"fontColor": "#3b4b52"
},
"_npm_ignored": {
- "fontCharacter": "\\E05D",
+ "fontCharacter": "\\E060",
"fontColor": "#41535b"
},
"_nunjucks_light": {
- "fontCharacter": "\\E05E",
+ "fontCharacter": "\\E061",
"fontColor": "#7fae42"
},
"_nunjucks": {
- "fontCharacter": "\\E05E",
+ "fontCharacter": "\\E061",
"fontColor": "#8dc149"
},
"_ocaml_light": {
- "fontCharacter": "\\E05F",
+ "fontCharacter": "\\E062",
"fontColor": "#cc6d2e"
},
"_ocaml": {
- "fontCharacter": "\\E05F",
+ "fontCharacter": "\\E062",
"fontColor": "#e37933"
},
"_odata_light": {
- "fontCharacter": "\\E060",
+ "fontCharacter": "\\E063",
"fontColor": "#cc6d2e"
},
"_odata": {
- "fontCharacter": "\\E060",
+ "fontCharacter": "\\E063",
"fontColor": "#e37933"
},
+ "_pddl_light": {
+ "fontCharacter": "\\E064",
+ "fontColor": "#9068b0"
+ },
+ "_pddl": {
+ "fontCharacter": "\\E064",
+ "fontColor": "#a074c4"
+ },
"_pdf_light": {
- "fontCharacter": "\\E061",
+ "fontCharacter": "\\E065",
"fontColor": "#b8383d"
},
"_pdf": {
- "fontCharacter": "\\E061",
+ "fontCharacter": "\\E065",
"fontColor": "#cc3e44"
},
"_perl_light": {
- "fontCharacter": "\\E062",
+ "fontCharacter": "\\E066",
"fontColor": "#498ba7"
},
"_perl": {
- "fontCharacter": "\\E062",
+ "fontCharacter": "\\E066",
"fontColor": "#519aba"
},
"_photoshop_light": {
- "fontCharacter": "\\E063",
+ "fontCharacter": "\\E067",
"fontColor": "#498ba7"
},
"_photoshop": {
- "fontCharacter": "\\E063",
+ "fontCharacter": "\\E067",
"fontColor": "#519aba"
},
"_php_light": {
- "fontCharacter": "\\E064",
+ "fontCharacter": "\\E068",
"fontColor": "#9068b0"
},
"_php": {
- "fontCharacter": "\\E064",
+ "fontCharacter": "\\E068",
"fontColor": "#a074c4"
},
+ "_plan_light": {
+ "fontCharacter": "\\E069",
+ "fontColor": "#7fae42"
+ },
+ "_plan": {
+ "fontCharacter": "\\E069",
+ "fontColor": "#8dc149"
+ },
+ "_platformio_light": {
+ "fontCharacter": "\\E06A",
+ "fontColor": "#cc6d2e"
+ },
+ "_platformio": {
+ "fontCharacter": "\\E06A",
+ "fontColor": "#e37933"
+ },
"_powershell_light": {
- "fontCharacter": "\\E065",
+ "fontCharacter": "\\E06B",
"fontColor": "#498ba7"
},
"_powershell": {
- "fontCharacter": "\\E065",
+ "fontCharacter": "\\E06B",
"fontColor": "#519aba"
},
"_pug_light": {
- "fontCharacter": "\\E067",
+ "fontCharacter": "\\E06D",
"fontColor": "#b8383d"
},
"_pug": {
- "fontCharacter": "\\E067",
+ "fontCharacter": "\\E06D",
"fontColor": "#cc3e44"
},
"_puppet_light": {
- "fontCharacter": "\\E068",
+ "fontCharacter": "\\E06E",
"fontColor": "#b7b73b"
},
"_puppet": {
- "fontCharacter": "\\E068",
+ "fontCharacter": "\\E06E",
"fontColor": "#cbcb41"
},
"_python_light": {
- "fontCharacter": "\\E069",
+ "fontCharacter": "\\E06F",
"fontColor": "#498ba7"
},
"_python": {
- "fontCharacter": "\\E069",
+ "fontCharacter": "\\E06F",
"fontColor": "#519aba"
},
"_react_light": {
- "fontCharacter": "\\E06B",
+ "fontCharacter": "\\E071",
"fontColor": "#498ba7"
},
"_react": {
- "fontCharacter": "\\E06B",
+ "fontCharacter": "\\E071",
"fontColor": "#519aba"
},
+ "_react_1_light": {
+ "fontCharacter": "\\E071",
+ "fontColor": "#cc6d2e"
+ },
+ "_react_1": {
+ "fontCharacter": "\\E071",
+ "fontColor": "#e37933"
+ },
+ "_react_2_light": {
+ "fontCharacter": "\\E071",
+ "fontColor": "#b7b73b"
+ },
+ "_react_2": {
+ "fontCharacter": "\\E071",
+ "fontColor": "#cbcb41"
+ },
+ "_reasonml_light": {
+ "fontCharacter": "\\E072",
+ "fontColor": "#b8383d"
+ },
+ "_reasonml": {
+ "fontCharacter": "\\E072",
+ "fontColor": "#cc3e44"
+ },
"_rollup_light": {
- "fontCharacter": "\\E06C",
+ "fontCharacter": "\\E073",
"fontColor": "#b8383d"
},
"_rollup": {
- "fontCharacter": "\\E06C",
+ "fontCharacter": "\\E073",
"fontColor": "#cc3e44"
},
"_ruby_light": {
- "fontCharacter": "\\E06D",
+ "fontCharacter": "\\E074",
"fontColor": "#b8383d"
},
"_ruby": {
- "fontCharacter": "\\E06D",
+ "fontCharacter": "\\E074",
"fontColor": "#cc3e44"
},
"_rust_light": {
- "fontCharacter": "\\E06E",
+ "fontCharacter": "\\E075",
"fontColor": "#627379"
},
"_rust": {
- "fontCharacter": "\\E06E",
+ "fontCharacter": "\\E075",
"fontColor": "#6d8086"
},
"_salesforce_light": {
- "fontCharacter": "\\E06F",
+ "fontCharacter": "\\E076",
"fontColor": "#498ba7"
},
"_salesforce": {
- "fontCharacter": "\\E06F",
+ "fontCharacter": "\\E076",
"fontColor": "#519aba"
},
"_sass_light": {
- "fontCharacter": "\\E070",
+ "fontCharacter": "\\E077",
"fontColor": "#dd4b78"
},
"_sass": {
- "fontCharacter": "\\E070",
+ "fontCharacter": "\\E077",
"fontColor": "#f55385"
},
"_sbt_light": {
- "fontCharacter": "\\E071",
+ "fontCharacter": "\\E078",
"fontColor": "#498ba7"
},
"_sbt": {
- "fontCharacter": "\\E071",
+ "fontCharacter": "\\E078",
"fontColor": "#519aba"
},
"_scala_light": {
- "fontCharacter": "\\E072",
+ "fontCharacter": "\\E079",
"fontColor": "#b8383d"
},
"_scala": {
- "fontCharacter": "\\E072",
+ "fontCharacter": "\\E079",
"fontColor": "#cc3e44"
},
"_shell_light": {
- "fontCharacter": "\\E075",
+ "fontCharacter": "\\E07C",
"fontColor": "#455155"
},
"_shell": {
- "fontCharacter": "\\E075",
+ "fontCharacter": "\\E07C",
"fontColor": "#4d5a5e"
},
"_slim_light": {
- "fontCharacter": "\\E076",
+ "fontCharacter": "\\E07D",
"fontColor": "#cc6d2e"
},
"_slim": {
- "fontCharacter": "\\E076",
+ "fontCharacter": "\\E07D",
"fontColor": "#e37933"
},
"_smarty_light": {
- "fontCharacter": "\\E077",
+ "fontCharacter": "\\E07E",
"fontColor": "#b7b73b"
},
"_smarty": {
- "fontCharacter": "\\E077",
+ "fontCharacter": "\\E07E",
"fontColor": "#cbcb41"
},
"_spring_light": {
- "fontCharacter": "\\E078",
+ "fontCharacter": "\\E07F",
"fontColor": "#7fae42"
},
"_spring": {
- "fontCharacter": "\\E078",
+ "fontCharacter": "\\E07F",
"fontColor": "#8dc149"
},
"_stylelint_light": {
- "fontCharacter": "\\E079",
+ "fontCharacter": "\\E080",
"fontColor": "#bfc2c1"
},
"_stylelint": {
- "fontCharacter": "\\E079",
+ "fontCharacter": "\\E080",
"fontColor": "#d4d7d6"
},
"_stylelint_1_light": {
- "fontCharacter": "\\E079",
+ "fontCharacter": "\\E080",
"fontColor": "#455155"
},
"_stylelint_1": {
- "fontCharacter": "\\E079",
+ "fontCharacter": "\\E080",
"fontColor": "#4d5a5e"
},
"_stylus_light": {
- "fontCharacter": "\\E07A",
+ "fontCharacter": "\\E081",
"fontColor": "#7fae42"
},
"_stylus": {
- "fontCharacter": "\\E07A",
+ "fontCharacter": "\\E081",
"fontColor": "#8dc149"
},
"_sublime_light": {
- "fontCharacter": "\\E07B",
+ "fontCharacter": "\\E082",
"fontColor": "#cc6d2e"
},
"_sublime": {
- "fontCharacter": "\\E07B",
+ "fontCharacter": "\\E082",
"fontColor": "#e37933"
},
"_svg_light": {
- "fontCharacter": "\\E07C",
+ "fontCharacter": "\\E083",
"fontColor": "#9068b0"
},
"_svg": {
- "fontCharacter": "\\E07C",
+ "fontCharacter": "\\E083",
"fontColor": "#a074c4"
},
"_svg_1_light": {
- "fontCharacter": "\\E07C",
+ "fontCharacter": "\\E083",
"fontColor": "#498ba7"
},
"_svg_1": {
- "fontCharacter": "\\E07C",
+ "fontCharacter": "\\E083",
"fontColor": "#519aba"
},
"_swift_light": {
- "fontCharacter": "\\E07D",
+ "fontCharacter": "\\E084",
"fontColor": "#cc6d2e"
},
"_swift": {
- "fontCharacter": "\\E07D",
+ "fontCharacter": "\\E084",
"fontColor": "#e37933"
},
"_terraform_light": {
- "fontCharacter": "\\E07E",
+ "fontCharacter": "\\E085",
"fontColor": "#9068b0"
},
"_terraform": {
- "fontCharacter": "\\E07E",
+ "fontCharacter": "\\E085",
"fontColor": "#a074c4"
},
"_tex_light": {
- "fontCharacter": "\\E07F",
+ "fontCharacter": "\\E086",
"fontColor": "#498ba7"
},
"_tex": {
- "fontCharacter": "\\E07F",
+ "fontCharacter": "\\E086",
"fontColor": "#519aba"
},
"_tex_1_light": {
- "fontCharacter": "\\E07F",
+ "fontCharacter": "\\E086",
"fontColor": "#b7b73b"
},
"_tex_1": {
- "fontCharacter": "\\E07F",
+ "fontCharacter": "\\E086",
"fontColor": "#cbcb41"
},
"_tex_2_light": {
- "fontCharacter": "\\E07F",
+ "fontCharacter": "\\E086",
"fontColor": "#cc6d2e"
},
"_tex_2": {
- "fontCharacter": "\\E07F",
+ "fontCharacter": "\\E086",
"fontColor": "#e37933"
},
"_tex_3_light": {
- "fontCharacter": "\\E07F",
+ "fontCharacter": "\\E086",
"fontColor": "#bfc2c1"
},
"_tex_3": {
- "fontCharacter": "\\E07F",
+ "fontCharacter": "\\E086",
"fontColor": "#d4d7d6"
},
"_todo": {
- "fontCharacter": "\\E081"
+ "fontCharacter": "\\E088"
+ },
+ "_tsconfig_light": {
+ "fontCharacter": "\\E089",
+ "fontColor": "#498ba7"
+ },
+ "_tsconfig": {
+ "fontCharacter": "\\E089",
+ "fontColor": "#519aba"
},
"_twig_light": {
- "fontCharacter": "\\E082",
+ "fontCharacter": "\\E08A",
"fontColor": "#7fae42"
},
"_twig": {
- "fontCharacter": "\\E082",
+ "fontCharacter": "\\E08A",
"fontColor": "#8dc149"
},
"_typescript_light": {
- "fontCharacter": "\\E083",
+ "fontCharacter": "\\E08B",
"fontColor": "#498ba7"
},
"_typescript": {
- "fontCharacter": "\\E083",
+ "fontCharacter": "\\E08B",
"fontColor": "#519aba"
},
"_typescript_1_light": {
- "fontCharacter": "\\E083",
+ "fontCharacter": "\\E08B",
"fontColor": "#b7b73b"
},
"_typescript_1": {
- "fontCharacter": "\\E083",
+ "fontCharacter": "\\E08B",
"fontColor": "#cbcb41"
},
"_vala_light": {
- "fontCharacter": "\\E084",
+ "fontCharacter": "\\E08C",
"fontColor": "#627379"
},
"_vala": {
- "fontCharacter": "\\E084",
+ "fontCharacter": "\\E08C",
"fontColor": "#6d8086"
},
"_video_light": {
- "fontCharacter": "\\E085",
+ "fontCharacter": "\\E08D",
"fontColor": "#dd4b78"
},
"_video": {
- "fontCharacter": "\\E085",
+ "fontCharacter": "\\E08D",
"fontColor": "#f55385"
},
"_vue_light": {
- "fontCharacter": "\\E086",
+ "fontCharacter": "\\E08E",
"fontColor": "#7fae42"
},
"_vue": {
- "fontCharacter": "\\E086",
+ "fontCharacter": "\\E08E",
"fontColor": "#8dc149"
},
"_wasm_light": {
- "fontCharacter": "\\E087",
+ "fontCharacter": "\\E08F",
"fontColor": "#9068b0"
},
"_wasm": {
- "fontCharacter": "\\E087",
+ "fontCharacter": "\\E08F",
"fontColor": "#a074c4"
},
"_wat_light": {
- "fontCharacter": "\\E088",
+ "fontCharacter": "\\E090",
"fontColor": "#9068b0"
},
"_wat": {
- "fontCharacter": "\\E088",
+ "fontCharacter": "\\E090",
"fontColor": "#a074c4"
},
"_webpack_light": {
- "fontCharacter": "\\E089",
+ "fontCharacter": "\\E091",
"fontColor": "#498ba7"
},
"_webpack": {
- "fontCharacter": "\\E089",
+ "fontCharacter": "\\E091",
"fontColor": "#519aba"
},
"_wgt_light": {
- "fontCharacter": "\\E08A",
+ "fontCharacter": "\\E092",
"fontColor": "#498ba7"
},
"_wgt": {
- "fontCharacter": "\\E08A",
+ "fontCharacter": "\\E092",
"fontColor": "#519aba"
},
"_windows_light": {
- "fontCharacter": "\\E08B",
+ "fontCharacter": "\\E093",
"fontColor": "#498ba7"
},
"_windows": {
- "fontCharacter": "\\E08B",
+ "fontCharacter": "\\E093",
"fontColor": "#519aba"
},
"_word_light": {
- "fontCharacter": "\\E08C",
+ "fontCharacter": "\\E094",
"fontColor": "#498ba7"
},
"_word": {
- "fontCharacter": "\\E08C",
+ "fontCharacter": "\\E094",
"fontColor": "#519aba"
},
"_xls_light": {
- "fontCharacter": "\\E08D",
+ "fontCharacter": "\\E095",
"fontColor": "#7fae42"
},
"_xls": {
- "fontCharacter": "\\E08D",
+ "fontCharacter": "\\E095",
"fontColor": "#8dc149"
},
"_xml_light": {
- "fontCharacter": "\\E08E",
+ "fontCharacter": "\\E096",
"fontColor": "#cc6d2e"
},
"_xml": {
- "fontCharacter": "\\E08E",
+ "fontCharacter": "\\E096",
"fontColor": "#e37933"
},
"_yarn_light": {
- "fontCharacter": "\\E08F",
+ "fontCharacter": "\\E097",
"fontColor": "#498ba7"
},
"_yarn": {
- "fontCharacter": "\\E08F",
+ "fontCharacter": "\\E097",
"fontColor": "#519aba"
},
"_yml_light": {
- "fontCharacter": "\\E090",
+ "fontCharacter": "\\E098",
"fontColor": "#9068b0"
},
"_yml": {
- "fontCharacter": "\\E090",
+ "fontCharacter": "\\E098",
"fontColor": "#a074c4"
},
"_zip_light": {
- "fontCharacter": "\\E091",
+ "fontCharacter": "\\E099",
"fontColor": "#b8383d"
},
"_zip": {
- "fontCharacter": "\\E091",
+ "fontCharacter": "\\E099",
"fontColor": "#cc3e44"
},
"_zip_1_light": {
- "fontCharacter": "\\E091",
+ "fontCharacter": "\\E099",
"fontColor": "#627379"
},
"_zip_1": {
- "fontCharacter": "\\E091",
+ "fontCharacter": "\\E099",
"fontColor": "#6d8086"
},
// {{SQL CARBON EDIT}}
@@ -1262,6 +1374,10 @@
"asm": "_asm",
"s": "_asm",
"h": "_c_1",
+ "aspx": "_html",
+ "ascx": "_html_1",
+ "asax": "_html_2",
+ "master": "_html_2",
"hh": "_cpp_1",
"hpp": "_cpp_1",
"hxx": "_cpp_1",
@@ -1299,6 +1415,8 @@
"article": "_go",
"gradle": "_gradle",
"gsp": "_grails",
+ "gql": "_graphql",
+ "graphql": "_graphql",
"haml": "_haml",
"hs": "_haskell",
"lhs": "_haskell",
@@ -1310,6 +1428,7 @@
"classpath": "_java",
"js.map": "_javascript",
"spec.js": "_javascript_1",
+ "test.js": "_javascript_1",
"es": "_javascript",
"es5": "_javascript",
"es7": "_javascript",
@@ -1318,6 +1437,7 @@
"jl": "_julia",
"kt": "_kotlin",
"kts": "_kotlin",
+ "dart": "_dart",
"liquid": "_liquid",
"ls": "_livescript",
"argdown": "_argdown",
@@ -1339,10 +1459,18 @@
"cmxa": "_ocaml",
"odata": "_odata",
"php.inc": "_php",
+ "pddl": "_pddl",
+ "plan": "_plan",
+ "happenings": "_happenings",
"pug": "_pug",
"pp": "_puppet",
"epp": "_puppet",
+ "spec.jsx": "_react_1",
+ "test.jsx": "_react_1",
"cjsx": "_react",
+ "spec.tsx": "_react_2",
+ "test.tsx": "_react_2",
+ "re": "_reasonml",
"r": "_R",
"erb": "_html_erb",
"erb.html": "_html_erb",
@@ -1365,6 +1493,7 @@
"toml": "_config",
"twig": "_twig",
"spec.ts": "_typescript_1",
+ "test.ts": "_typescript_1",
"vala": "_vala",
"vapi": "_vala",
"vue": "_vue",
@@ -1468,6 +1597,7 @@
"gulpfile": "_gulp",
"ionic.config.json": "_ionic",
"ionic.project": "_ionic",
+ "platformio.ini": "_platformio",
"rollup.config.js": "_rollup",
"sass-lint.yml": "_sass",
"stylelint.config.js": "_stylelint",
@@ -1475,6 +1605,9 @@
"yarn.lock": "_yarn",
"webpack.config.js": "_webpack",
"webpack.config.build.js": "_webpack",
+ "webpack.common.js": "_webpack",
+ "webpack.dev.js": "_webpack",
+ "webpack.prod.js": "_webpack",
"license": "_license",
"licence": "_license",
"copying": "_license",
@@ -1494,6 +1627,7 @@
"bat": "_windows",
"clojure": "_clojure",
"coffeescript": "_coffee",
+ "jsonc": "_tsconfig",
"c": "_c",
"cpp": "_cpp",
"csharp": "_c-sharp",
@@ -1503,7 +1637,7 @@
"go": "_go2",
"groovy": "_grails",
"handlebars": "_mustache",
- "html": "_html",
+ "html": "_html_3",
"properties": "_java",
"java": "_java",
"javascriptreact": "_react",
@@ -1514,12 +1648,14 @@
"makefile": "_makefile",
"markdown": "_markdown",
"objective-c": "_c_2",
+ "objective-cpp": "_cpp_2",
"perl": "_perl",
"php": "_php",
"powershell": "_powershell",
"jade": "_jade",
"python": "_python",
"r": "_R",
+ "razor": "_html",
"ruby": "_ruby",
"rust": "_rust",
"scss": "_sass",
@@ -1561,6 +1697,10 @@
"asm": "_asm_light",
"s": "_asm_light",
"h": "_c_1_light",
+ "aspx": "_html_light",
+ "ascx": "_html_1_light",
+ "asax": "_html_2_light",
+ "master": "_html_2_light",
"hh": "_cpp_1_light",
"hpp": "_cpp_1_light",
"hxx": "_cpp_1_light",
@@ -1598,6 +1738,8 @@
"article": "_go_light",
"gradle": "_gradle_light",
"gsp": "_grails_light",
+ "gql": "_graphql_light",
+ "graphql": "_graphql_light",
"haml": "_haml_light",
"hs": "_haskell_light",
"lhs": "_haskell_light",
@@ -1609,6 +1751,7 @@
"classpath": "_java_light",
"js.map": "_javascript_light",
"spec.js": "_javascript_1_light",
+ "test.js": "_javascript_1_light",
"es": "_javascript_light",
"es5": "_javascript_light",
"es7": "_javascript_light",
@@ -1617,6 +1760,7 @@
"jl": "_julia_light",
"kt": "_kotlin_light",
"kts": "_kotlin_light",
+ "dart": "_dart_light",
"liquid": "_liquid_light",
"ls": "_livescript_light",
"argdown": "_argdown_light",
@@ -1638,10 +1782,18 @@
"cmxa": "_ocaml_light",
"odata": "_odata_light",
"php.inc": "_php_light",
+ "pddl": "_pddl_light",
+ "plan": "_plan_light",
+ "happenings": "_happenings_light",
"pug": "_pug_light",
"pp": "_puppet_light",
"epp": "_puppet_light",
+ "spec.jsx": "_react_1_light",
+ "test.jsx": "_react_1_light",
"cjsx": "_react_light",
+ "spec.tsx": "_react_2_light",
+ "test.tsx": "_react_2_light",
+ "re": "_reasonml_light",
"r": "_R_light",
"erb": "_html_erb_light",
"erb.html": "_html_erb_light",
@@ -1664,6 +1816,7 @@
"toml": "_config_light",
"twig": "_twig_light",
"spec.ts": "_typescript_1_light",
+ "test.ts": "_typescript_1_light",
"vala": "_vala_light",
"vapi": "_vala_light",
"vue": "_vue_light",
@@ -1743,6 +1896,7 @@
"bat": "_windows_light",
"clojure": "_clojure_light",
"coffeescript": "_coffee_light",
+ "jsonc": "_tsconfig_light",
"c": "_c_light",
"cpp": "_cpp_light",
"csharp": "_c-sharp_light",
@@ -1752,7 +1906,7 @@
"go": "_go2_light",
"groovy": "_grails_light",
"handlebars": "_mustache_light",
- "html": "_html_light",
+ "html": "_html_3_light",
"properties": "_java_light",
"java": "_java_light",
"javascriptreact": "_react_light",
@@ -1763,12 +1917,14 @@
"makefile": "_makefile_light",
"markdown": "_markdown_light",
"objective-c": "_c_2_light",
+ "objective-cpp": "_cpp_2_light",
"perl": "_perl_light",
"php": "_php_light",
"powershell": "_powershell_light",
"jade": "_jade_light",
"python": "_python_light",
"r": "_R_light",
+ "razor": "_html_light",
"ruby": "_ruby_light",
"rust": "_rust_light",
"scss": "_sass_light",
@@ -1829,6 +1985,7 @@
"gulpfile": "_gulp_light",
"ionic.config.json": "_ionic_light",
"ionic.project": "_ionic_light",
+ "platformio.ini": "_platformio_light",
"rollup.config.js": "_rollup_light",
"sass-lint.yml": "_sass_light",
"stylelint.config.js": "_stylelint_light",
@@ -1836,6 +1993,9 @@
"yarn.lock": "_yarn_light",
"webpack.config.js": "_webpack_light",
"webpack.config.build.js": "_webpack_light",
+ "webpack.common.js": "_webpack_light",
+ "webpack.dev.js": "_webpack_light",
+ "webpack.prod.js": "_webpack_light",
"license": "_license_light",
"licence": "_license_light",
"copying": "_license_light",
@@ -1851,5 +2011,5 @@
"Schema Compare": "scmp"
}
},
- "version": "https://github.com/jesseweed/seti-ui/commit/89175d7f9e0c70cd325b80a18a3c77fc8eb7c798"
+ "version": "https://github.com/jesseweed/seti-ui/commit/904c16acced1134a81b31d71d60293288c31334b"
}
\ No newline at end of file
diff --git a/package.json b/package.json
index 57acd2a2eb..1ff677c50e 100644
--- a/package.json
+++ b/package.json
@@ -73,7 +73,7 @@
"v8-inspect-profiler": "^0.0.20",
"vscode-chokidar": "2.1.7",
"vscode-proxy-agent": "0.4.0",
- "vscode-ripgrep": "^1.5.4",
+ "vscode-ripgrep": "^1.5.5",
"vscode-sqlite3": "4.0.8",
"vscode-textmate": "^4.2.2",
"xterm": "3.15.0-beta71",
@@ -192,4 +192,4 @@
"windows-mutex": "0.3.0",
"windows-process-tree": "0.2.4"
}
-}
\ No newline at end of file
+}
diff --git a/remote/package.json b/remote/package.json
index a4113e1e74..081eb5c607 100644
--- a/remote/package.json
+++ b/remote/package.json
@@ -18,7 +18,7 @@
"spdlog": "^0.9.0",
"vscode-chokidar": "2.1.7",
"vscode-proxy-agent": "0.4.0",
- "vscode-ripgrep": "^1.5.4",
+ "vscode-ripgrep": "^1.5.5",
"vscode-textmate": "^4.2.2",
"xterm": "3.15.0-beta71",
"xterm-addon-search": "0.2.0-beta2",
diff --git a/remote/yarn.lock b/remote/yarn.lock
index 9aa7137893..3ed8f02de3 100644
--- a/remote/yarn.lock
+++ b/remote/yarn.lock
@@ -1123,10 +1123,10 @@ vscode-proxy-agent@0.4.0:
https-proxy-agent "2.2.1"
socks-proxy-agent "4.0.1"
-vscode-ripgrep@^1.5.4:
- version "1.5.4"
- resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.4.tgz#dae1c3eef350513299341cdf96e622c00b548eff"
- integrity sha512-Bs8SvFAkR0QHf09J46VgNo19yRikOtj/f0zHzK3AM3ICjCGNN/BNoG9of6zGVHUTO+6Mk1RbKglyOHLKr8D1lg==
+vscode-ripgrep@^1.5.5:
+ version "1.5.5"
+ resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.5.tgz#24c0e9cb356cf889c98e15ecb58f9cf654a1d961"
+ integrity sha512-OrPrAmcun4+uZAuNcQvE6CCPskh+5AsjANod/Q3zRcJcGNxgoOSGlQN9RPtatkUNmkN8Nn8mZBnS1jMylu/dKg==
vscode-textmate@^4.2.2:
version "4.2.2"
diff --git a/src/sql/media/icons/start.svg b/src/sql/media/icons/start.svg
index 9ef467f2c0..8b0a58eca9 100644
--- a/src/sql/media/icons/start.svg
+++ b/src/sql/media/icons/start.svg
@@ -1 +1,3 @@
-
\ No newline at end of file
+
diff --git a/src/sql/media/icons/start_inverse.svg b/src/sql/media/icons/start_inverse.svg
index 3be0c24f6f..2563bfa114 100644
--- a/src/sql/media/icons/start_inverse.svg
+++ b/src/sql/media/icons/start_inverse.svg
@@ -1 +1,3 @@
-
\ No newline at end of file
+
diff --git a/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts
index e8c1b2b17f..9e196784b7 100644
--- a/src/vs/base/browser/ui/checkbox/checkbox.ts
+++ b/src/vs/base/browser/ui/checkbox/checkbox.ts
@@ -22,10 +22,12 @@ export interface ICheckboxOpts extends ICheckboxStyles {
export interface ICheckboxStyles {
inputActiveOptionBorder?: Color;
+ inputActiveOptionBackground?: Color;
}
const defaultOpts = {
- inputActiveOptionBorder: Color.fromHex('#007ACC')
+ inputActiveOptionBorder: Color.fromHex('#007ACC00'),
+ inputActiveOptionBackground: Color.fromHex('#0E639C50')
};
export class CheckboxActionViewItem extends BaseActionViewItem {
@@ -149,12 +151,16 @@ export class Checkbox extends Widget {
if (styles.inputActiveOptionBorder) {
this._opts.inputActiveOptionBorder = styles.inputActiveOptionBorder;
}
+ if (styles.inputActiveOptionBackground) {
+ this._opts.inputActiveOptionBackground = styles.inputActiveOptionBackground;
+ }
this.applyStyles();
}
protected applyStyles(): void {
if (this.domNode) {
this.domNode.style.borderColor = this._checked && this._opts.inputActiveOptionBorder ? this._opts.inputActiveOptionBorder.toString() : 'transparent';
+ this.domNode.style.backgroundColor = this._checked && this._opts.inputActiveOptionBackground ? this._opts.inputActiveOptionBackground.toString() : 'transparent';
}
}
diff --git a/src/vs/base/browser/ui/findinput/findInput.ts b/src/vs/base/browser/ui/findinput/findInput.ts
index 7af439b18e..d582f39d06 100644
--- a/src/vs/base/browser/ui/findinput/findInput.ts
+++ b/src/vs/base/browser/ui/findinput/findInput.ts
@@ -33,6 +33,7 @@ export interface IFindInputOptions extends IFindInputStyles {
export interface IFindInputStyles extends IInputBoxStyles {
inputActiveOptionBorder?: Color;
+ inputActiveOptionBackground?: Color;
}
const NLS_DEFAULT_LABEL = nls.localize('defaultLabel', "input");
@@ -48,6 +49,7 @@ export class FindInput extends Widget {
private fixFocusOnOptionClickEnabled = true;
private inputActiveOptionBorder?: Color;
+ private inputActiveOptionBackground?: Color;
private inputBackground?: Color;
private inputForeground?: Color;
private inputBorder?: Color;
@@ -97,6 +99,7 @@ export class FindInput extends Widget {
this.label = options.label || NLS_DEFAULT_LABEL;
this.inputActiveOptionBorder = options.inputActiveOptionBorder;
+ this.inputActiveOptionBackground = options.inputActiveOptionBackground;
this.inputBackground = options.inputBackground;
this.inputForeground = options.inputForeground;
this.inputBorder = options.inputBorder;
@@ -173,6 +176,7 @@ export class FindInput extends Widget {
public style(styles: IFindInputStyles): void {
this.inputActiveOptionBorder = styles.inputActiveOptionBorder;
+ this.inputActiveOptionBackground = styles.inputActiveOptionBackground;
this.inputBackground = styles.inputBackground;
this.inputForeground = styles.inputForeground;
this.inputBorder = styles.inputBorder;
@@ -194,6 +198,7 @@ export class FindInput extends Widget {
if (this.domNode) {
const checkBoxStyles: ICheckboxStyles = {
inputActiveOptionBorder: this.inputActiveOptionBorder,
+ inputActiveOptionBackground: this.inputActiveOptionBackground,
};
this.regex.style(checkBoxStyles);
this.wholeWords.style(checkBoxStyles);
@@ -294,7 +299,8 @@ export class FindInput extends Widget {
this.regex = this._register(new RegexCheckbox({
appendTitle: appendRegexLabel,
isChecked: false,
- inputActiveOptionBorder: this.inputActiveOptionBorder
+ inputActiveOptionBorder: this.inputActiveOptionBorder,
+ inputActiveOptionBackground: this.inputActiveOptionBackground
}));
this._register(this.regex.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
@@ -310,7 +316,8 @@ export class FindInput extends Widget {
this.wholeWords = this._register(new WholeWordsCheckbox({
appendTitle: appendWholeWordsLabel,
isChecked: false,
- inputActiveOptionBorder: this.inputActiveOptionBorder
+ inputActiveOptionBorder: this.inputActiveOptionBorder,
+ inputActiveOptionBackground: this.inputActiveOptionBackground
}));
this._register(this.wholeWords.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
@@ -323,7 +330,8 @@ export class FindInput extends Widget {
this.caseSensitive = this._register(new CaseSensitiveCheckbox({
appendTitle: appendCaseSensitiveLabel,
isChecked: false,
- inputActiveOptionBorder: this.inputActiveOptionBorder
+ inputActiveOptionBorder: this.inputActiveOptionBorder,
+ inputActiveOptionBackground: this.inputActiveOptionBackground
}));
this._register(this.caseSensitive.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
diff --git a/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts b/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts
index b4b7fed0b6..46dd9d67aa 100644
--- a/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts
+++ b/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts
@@ -12,6 +12,7 @@ export interface IFindInputCheckboxOpts {
readonly appendTitle: string;
readonly isChecked: boolean;
readonly inputActiveOptionBorder?: Color;
+ readonly inputActiveOptionBackground?: Color;
}
const NLS_CASE_SENSITIVE_CHECKBOX_LABEL = nls.localize('caseDescription', "Match Case");
@@ -24,7 +25,8 @@ export class CaseSensitiveCheckbox extends Checkbox {
actionClassName: 'monaco-case-sensitive',
title: NLS_CASE_SENSITIVE_CHECKBOX_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
- inputActiveOptionBorder: opts.inputActiveOptionBorder
+ inputActiveOptionBorder: opts.inputActiveOptionBorder,
+ inputActiveOptionBackground: opts.inputActiveOptionBackground
});
}
}
@@ -35,7 +37,8 @@ export class WholeWordsCheckbox extends Checkbox {
actionClassName: 'monaco-whole-word',
title: NLS_WHOLE_WORD_CHECKBOX_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
- inputActiveOptionBorder: opts.inputActiveOptionBorder
+ inputActiveOptionBorder: opts.inputActiveOptionBorder,
+ inputActiveOptionBackground: opts.inputActiveOptionBackground
});
}
}
@@ -46,7 +49,8 @@ export class RegexCheckbox extends Checkbox {
actionClassName: 'monaco-regex',
title: NLS_REGEX_CHECKBOX_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
- inputActiveOptionBorder: opts.inputActiveOptionBorder
+ inputActiveOptionBorder: opts.inputActiveOptionBorder,
+ inputActiveOptionBackground: opts.inputActiveOptionBackground
});
}
}
diff --git a/src/vs/base/common/lifecycle.ts b/src/vs/base/common/lifecycle.ts
index abd65d46b4..ca8b49a1f9 100644
--- a/src/vs/base/common/lifecycle.ts
+++ b/src/vs/base/common/lifecycle.ts
@@ -207,6 +207,43 @@ export class MutableDisposable implements IDisposable {
}
}
+/**
+ * Wrapper class that stores a disposable that is not currently "owned" by anyone.
+ *
+ * Example use cases:
+ *
+ * - Express that a function/method will take ownership of a disposable parameter.
+ * - Express that a function returns a disposable that the caller must explicitly take ownership of.
+ */
+export class UnownedDisposable extends Disposable {
+ private _hasBeenAcquired = false;
+ private _value?: T;
+
+ public constructor(value: T) {
+ super();
+ this._value = value;
+ }
+
+ public acquire(): T {
+ if (this._hasBeenAcquired) {
+ throw new Error('This disposable has already been acquired');
+ }
+ this._hasBeenAcquired = true;
+ const value = this._value!;
+ this._value = undefined;
+ return value;
+ }
+
+ public dispose() {
+ super.dispose();
+ if (!this._hasBeenAcquired) {
+ this._hasBeenAcquired = true;
+ this._value!.dispose();
+ this._value = undefined;
+ }
+ }
+}
+
export interface IReference extends IDisposable {
readonly object: T;
}
diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts
index e055e81897..e15d8b414a 100644
--- a/src/vs/editor/common/config/commonEditorConfig.ts
+++ b/src/vs/editor/common/config/commonEditorConfig.ts
@@ -460,7 +460,7 @@ const editorConfiguration: IConfigurationNode = {
'editor.fastScrollSensitivity': {
'type': 'number',
'default': EDITOR_DEFAULTS.viewInfo.scrollbar.fastScrollSensitivity,
- 'markdownDescription': nls.localize('fastScrollSensitivity', "Scrolling speed mulitiplier when pressing `Alt`.")
+ 'markdownDescription': nls.localize('fastScrollSensitivity', "Scrolling speed multiplier when pressing `Alt`.")
},
'editor.multiCursorModifier': {
'type': 'string',
diff --git a/src/vs/editor/contrib/find/findModel.ts b/src/vs/editor/contrib/find/findModel.ts
index 17505c4f34..70846107cc 100644
--- a/src/vs/editor/contrib/find/findModel.ts
+++ b/src/vs/editor/contrib/find/findModel.ts
@@ -5,7 +5,7 @@
import { RunOnceScheduler, TimeoutTimer } from 'vs/base/common/async';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
-import { IDisposable, dispose } from 'vs/base/common/lifecycle';
+import { dispose, DisposableStore } from 'vs/base/common/lifecycle';
import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';
import { ReplaceCommand, ReplaceCommandThatPreservesSelection } from 'vs/editor/common/commands/replaceCommand';
import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
@@ -71,7 +71,7 @@ export class FindModelBoundToEditorModel {
private readonly _editor: IActiveCodeEditor;
private readonly _state: FindReplaceState;
- private _toDispose: IDisposable[];
+ private readonly _toDispose = new DisposableStore();
private readonly _decorations: FindDecorations;
private _ignoreModelContentChanged: boolean;
private readonly _startSearchingTimer: TimeoutTimer;
@@ -82,17 +82,16 @@ export class FindModelBoundToEditorModel {
constructor(editor: IActiveCodeEditor, state: FindReplaceState) {
this._editor = editor;
this._state = state;
- this._toDispose = [];
this._isDisposed = false;
this._startSearchingTimer = new TimeoutTimer();
this._decorations = new FindDecorations(editor);
- this._toDispose.push(this._decorations);
+ this._toDispose.add(this._decorations);
this._updateDecorationsScheduler = new RunOnceScheduler(() => this.research(false), 100);
- this._toDispose.push(this._updateDecorationsScheduler);
+ this._toDispose.add(this._updateDecorationsScheduler);
- this._toDispose.push(this._editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => {
+ this._toDispose.add(this._editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => {
if (
e.reason === CursorChangeReason.Explicit
|| e.reason === CursorChangeReason.Undo
@@ -103,7 +102,7 @@ export class FindModelBoundToEditorModel {
}));
this._ignoreModelContentChanged = false;
- this._toDispose.push(this._editor.onDidChangeModelContent((e) => {
+ this._toDispose.add(this._editor.onDidChangeModelContent((e) => {
if (this._ignoreModelContentChanged) {
return;
}
@@ -115,7 +114,7 @@ export class FindModelBoundToEditorModel {
this._updateDecorationsScheduler.schedule();
}));
- this._toDispose.push(this._state.onFindReplaceStateChange((e) => this._onStateChanged(e)));
+ this._toDispose.add(this._state.onFindReplaceStateChange((e) => this._onStateChanged(e)));
this.research(false, this._state.searchScope);
}
@@ -123,7 +122,7 @@ export class FindModelBoundToEditorModel {
public dispose(): void {
this._isDisposed = true;
dispose(this._startSearchingTimer);
- this._toDispose = dispose(this._toDispose);
+ this._toDispose.dispose();
}
private _onStateChanged(e: FindReplaceStateChangedEvent): void {
diff --git a/src/vs/editor/contrib/find/findOptionsWidget.ts b/src/vs/editor/contrib/find/findOptionsWidget.ts
index 68594813e4..eeb61ffa09 100644
--- a/src/vs/editor/contrib/find/findOptionsWidget.ts
+++ b/src/vs/editor/contrib/find/findOptionsWidget.ts
@@ -11,7 +11,7 @@ import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPosit
import { FIND_IDS } from 'vs/editor/contrib/find/findModel';
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
-import { contrastBorder, editorWidgetBackground, inputActiveOptionBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
+import { contrastBorder, editorWidgetBackground, inputActiveOptionBorder, inputActiveOptionBackground, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
export class FindOptionsWidget extends Widget implements IOverlayWidget {
@@ -47,11 +47,13 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget {
this._domNode.setAttribute('aria-hidden', 'true');
const inputActiveOptionBorderColor = themeService.getTheme().getColor(inputActiveOptionBorder);
+ const inputActiveOptionBackgroundColor = themeService.getTheme().getColor(inputActiveOptionBackground);
this.caseSensitive = this._register(new CaseSensitiveCheckbox({
appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleCaseSensitiveCommand),
isChecked: this._state.matchCase,
- inputActiveOptionBorder: inputActiveOptionBorderColor
+ inputActiveOptionBorder: inputActiveOptionBorderColor,
+ inputActiveOptionBackground: inputActiveOptionBackgroundColor
}));
this._domNode.appendChild(this.caseSensitive.domNode);
this._register(this.caseSensitive.onChange(() => {
@@ -63,7 +65,8 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget {
this.wholeWords = this._register(new WholeWordsCheckbox({
appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleWholeWordCommand),
isChecked: this._state.wholeWord,
- inputActiveOptionBorder: inputActiveOptionBorderColor
+ inputActiveOptionBorder: inputActiveOptionBorderColor,
+ inputActiveOptionBackground: inputActiveOptionBackgroundColor
}));
this._domNode.appendChild(this.wholeWords.domNode);
this._register(this.wholeWords.onChange(() => {
@@ -75,7 +78,8 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget {
this.regex = this._register(new RegexCheckbox({
appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleRegexCommand),
isChecked: this._state.isRegex,
- inputActiveOptionBorder: inputActiveOptionBorderColor
+ inputActiveOptionBorder: inputActiveOptionBorderColor,
+ inputActiveOptionBackground: inputActiveOptionBackgroundColor
}));
this._domNode.appendChild(this.regex.domNode);
this._register(this.regex.onChange(() => {
@@ -179,7 +183,10 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget {
}
private _applyTheme(theme: ITheme) {
- let inputStyles = { inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder) };
+ let inputStyles = {
+ inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder),
+ inputActiveOptionBackground: theme.getColor(inputActiveOptionBackground)
+ };
this.caseSensitive.style(inputStyles);
this.wholeWords.style(inputStyles);
this.regex.style(inputStyles);
diff --git a/src/vs/editor/contrib/find/findWidget.css b/src/vs/editor/contrib/find/findWidget.css
index 5644623d0c..d1aa36c7ff 100644
--- a/src/vs/editor/contrib/find/findWidget.css
+++ b/src/vs/editor/contrib/find/findWidget.css
@@ -289,10 +289,6 @@
background-color: rgba(255, 255, 255, 0.1);
}
-.monaco-editor.vs-dark .find-widget .monaco-checkbox .checkbox:checked + .label {
- background-color: rgba(255, 255, 255, 0.1);
-}
-
.monaco-editor.hc-black .find-widget .close-fw,
.monaco-editor.vs-dark .find-widget .close-fw {
background-image: url('images/close-dark.svg');
diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts
index f0d8174565..279d107d9b 100644
--- a/src/vs/editor/contrib/find/findWidget.ts
+++ b/src/vs/editor/contrib/find/findWidget.ts
@@ -27,7 +27,7 @@ import { CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_REPLACE_INPUT_FOCUSED, FIND_IDS, MA
import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
-import { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatchHighlight, editorFindMatchHighlightBorder, editorFindRangeHighlight, editorFindRangeHighlightBorder, editorWidgetBackground, editorWidgetBorder, editorWidgetResizeBorder, errorForeground, inputActiveOptionBorder, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry';
+import { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatchHighlight, editorFindMatchHighlightBorder, editorFindRangeHighlight, editorFindRangeHighlightBorder, editorWidgetBackground, editorWidgetBorder, editorWidgetResizeBorder, errorForeground, inputActiveOptionBorder, inputActiveOptionBackground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry';
import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget';
import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
@@ -560,6 +560,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas
private _applyTheme(theme: ITheme) {
let inputStyles: IFindInputStyles = {
inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder),
+ inputActiveOptionBackground: theme.getColor(inputActiveOptionBackground),
inputBackground: theme.getColor(inputBackground),
inputForeground: theme.getColor(inputForeground),
inputBorder: theme.getColor(inputBorder),
@@ -1217,4 +1218,9 @@ registerThemingParticipant((theme, collector) => {
if (inputActiveBorder) {
collector.addRule(`.monaco-editor .find-widget .monaco-checkbox .checkbox:checked + .label { border: 1px solid ${inputActiveBorder.toString()}; }`);
}
+
+ const inputActiveBackground = theme.getColor(inputActiveOptionBackground);
+ if (inputActiveBackground) {
+ collector.addRule(`.monaco-editor .find-widget .monaco-checkbox .checkbox:checked + .label { background-color: ${inputActiveBackground.toString()}; }`);
+ }
});
diff --git a/src/vs/editor/contrib/find/simpleFindWidget.ts b/src/vs/editor/contrib/find/simpleFindWidget.ts
index 954cdf81b2..6807fe2424 100644
--- a/src/vs/editor/contrib/find/simpleFindWidget.ts
+++ b/src/vs/editor/contrib/find/simpleFindWidget.ts
@@ -15,7 +15,7 @@ import { IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBo
import { SimpleButton } from 'vs/editor/contrib/find/findWidget';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
-import { editorWidgetBackground, inputActiveOptionBorder, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
+import { editorWidgetBackground, inputActiveOptionBorder, inputActiveOptionBackground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
import { ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { ContextScopedFindInput } from 'vs/platform/browser/contextScopedHistoryWidget';
@@ -180,6 +180,7 @@ export abstract class SimpleFindWidget extends Widget {
public updateTheme(theme: ITheme): void {
const inputStyles: IFindInputStyles = {
inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder),
+ inputActiveOptionBackground: theme.getColor(inputActiveOptionBackground),
inputBackground: theme.getColor(inputBackground),
inputForeground: theme.getColor(inputForeground),
inputBorder: theme.getColor(inputBorder),
diff --git a/src/vs/editor/contrib/gotoError/gotoError.ts b/src/vs/editor/contrib/gotoError/gotoError.ts
index ee221e2732..68eb858450 100644
--- a/src/vs/editor/contrib/gotoError/gotoError.ts
+++ b/src/vs/editor/contrib/gotoError/gotoError.ts
@@ -6,7 +6,7 @@
import * as nls from 'vs/nls';
import { Emitter } from 'vs/base/common/event';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
-import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle';
+import { DisposableStore } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IMarker, IMarkerService, MarkerSeverity } from 'vs/platform/markers/common/markers';
@@ -32,7 +32,7 @@ class MarkerModel {
private readonly _editor: ICodeEditor;
private _markers: IMarker[];
private _nextIdx: number;
- private _toUnbind: IDisposable[];
+ private readonly _toUnbind = new DisposableStore();
private _ignoreSelectionChange: boolean;
private readonly _onCurrentMarkerChanged: Emitter;
private readonly _onMarkerSetChanged: Emitter;
@@ -41,15 +41,14 @@ class MarkerModel {
this._editor = editor;
this._markers = [];
this._nextIdx = -1;
- this._toUnbind = [];
this._ignoreSelectionChange = false;
this._onCurrentMarkerChanged = new Emitter();
this._onMarkerSetChanged = new Emitter();
this.setMarkers(markers);
// listen on editor
- this._toUnbind.push(this._editor.onDidDispose(() => this.dispose()));
- this._toUnbind.push(this._editor.onDidChangeCursorPosition(() => {
+ this._toUnbind.add(this._editor.onDidDispose(() => this.dispose()));
+ this._toUnbind.add(this._editor.onDidChangeCursorPosition(() => {
if (this._ignoreSelectionChange) {
return;
}
@@ -190,7 +189,7 @@ class MarkerModel {
}
public dispose(): void {
- this._toUnbind = dispose(this._toUnbind);
+ this._toUnbind.dispose();
}
}
diff --git a/src/vs/platform/diagnostics/node/diagnosticsService.ts b/src/vs/platform/diagnostics/node/diagnosticsService.ts
index 917d81b4c2..ecd08b4a35 100644
--- a/src/vs/platform/diagnostics/node/diagnosticsService.ts
+++ b/src/vs/platform/diagnostics/node/diagnosticsService.ts
@@ -520,10 +520,14 @@ export class DiagnosticsService implements IDiagnosticsService {
if (folderUri.scheme === 'file') {
const folder = folderUri.fsPath;
collectWorkspaceStats(folder, ['node_modules', '.git']).then(stats => {
+ type WorkspaceStatItemClassification = {
+ name: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
+ count: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
+ };
type WorkspaceStatsClassification = {
- fileTypes: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
- configTypes: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
- launchConfigs: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true };
+ fileTypes: WorkspaceStatItemClassification;
+ configTypes: WorkspaceStatItemClassification;
+ launchConfigs: WorkspaceStatItemClassification;
};
type WorkspaceStatsEvent = {
fileTypes: WorkspaceStatItem[];
diff --git a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts
index 02f066378e..5138f4a42d 100644
--- a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts
+++ b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts
@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import { ResolvedAuthority, IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
+import { ResolvedAuthority, IRemoteAuthorityResolverService, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverService {
@@ -12,12 +12,16 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS
constructor() {
}
- resolveAuthority(authority: string): Promise {
+ resolveAuthority(authority: string): Promise {
if (authority.indexOf(':') >= 0) {
const pieces = authority.split(':');
- return Promise.resolve({ authority, host: pieces[0], port: parseInt(pieces[1], 10) });
+ return Promise.resolve({
+ authority: { authority, host: pieces[0], port: parseInt(pieces[1], 10) }
+ });
}
- return Promise.resolve({ authority, host: authority, port: 80 });
+ return Promise.resolve({
+ authority: { authority, host: authority, port: 80 }
+ });
}
clearResolvedAuthority(authority: string): void {
diff --git a/src/vs/platform/remote/common/remoteAgentConnection.ts b/src/vs/platform/remote/common/remoteAgentConnection.ts
index dd59ae9e7c..1e98f9510c 100644
--- a/src/vs/platform/remote/common/remoteAgentConnection.ts
+++ b/src/vs/platform/remote/common/remoteAgentConnection.ts
@@ -163,6 +163,7 @@ export interface IRemoteExtensionHostStartParams {
debugId?: string;
break?: boolean;
port?: number | null;
+ env?: { [key: string]: string | null };
}
interface IExtensionHostConnectionResult {
diff --git a/src/vs/platform/remote/common/remoteAuthorityResolver.ts b/src/vs/platform/remote/common/remoteAuthorityResolver.ts
index 34c0934ac1..80fc027183 100644
--- a/src/vs/platform/remote/common/remoteAuthorityResolver.ts
+++ b/src/vs/platform/remote/common/remoteAuthorityResolver.ts
@@ -13,6 +13,15 @@ export interface ResolvedAuthority {
readonly port: number;
}
+export interface ResolvedOptions {
+ readonly extensionHostEnv?: { [key: string]: string | null };
+}
+
+export interface ResolverResult {
+ authority: ResolvedAuthority;
+ options?: ResolvedOptions;
+}
+
export enum RemoteAuthorityResolverErrorCode {
Unknown = 'Unknown',
NotAvailable = 'NotAvailable',
@@ -61,9 +70,9 @@ export interface IRemoteAuthorityResolverService {
_serviceBrand: any;
- resolveAuthority(authority: string): Promise;
+ resolveAuthority(authority: string): Promise;
clearResolvedAuthority(authority: string): void;
- setResolvedAuthority(resolvedAuthority: ResolvedAuthority): void;
+ setResolvedAuthority(resolvedAuthority: ResolvedAuthority, resolvedOptions?: ResolvedOptions): void;
setResolvedAuthorityError(authority: string, err: any): void;
}
diff --git a/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts
index 131a211cb7..1f648271d8 100644
--- a/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts
+++ b/src/vs/platform/remote/electron-browser/remoteAuthorityResolverService.ts
@@ -3,15 +3,15 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import { ResolvedAuthority, IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
+import { ResolvedAuthority, IRemoteAuthorityResolverService, ResolverResult, ResolvedOptions } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { ipcRenderer as ipc } from 'electron';
import * as errors from 'vs/base/common/errors';
class PendingResolveAuthorityRequest {
constructor(
- public readonly resolve: (value: ResolvedAuthority) => void,
+ public readonly resolve: (value: ResolverResult) => void,
public readonly reject: (err: any) => void,
- public readonly promise: Promise,
+ public readonly promise: Promise,
) {
}
}
@@ -26,11 +26,11 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS
this._resolveAuthorityRequests = Object.create(null);
}
- resolveAuthority(authority: string): Promise {
+ resolveAuthority(authority: string): Promise {
if (!this._resolveAuthorityRequests[authority]) {
- let resolve: (value: ResolvedAuthority) => void;
+ let resolve: (value: ResolverResult) => void;
let reject: (err: any) => void;
- let promise = new Promise((_resolve, _reject) => {
+ let promise = new Promise((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
});
@@ -46,11 +46,11 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS
}
}
- setResolvedAuthority(resolvedAuthority: ResolvedAuthority) {
+ setResolvedAuthority(resolvedAuthority: ResolvedAuthority, options?: ResolvedOptions) {
if (this._resolveAuthorityRequests[resolvedAuthority.authority]) {
let request = this._resolveAuthorityRequests[resolvedAuthority.authority];
ipc.send('vscode:remoteAuthorityResolved', resolvedAuthority);
- request.resolve(resolvedAuthority);
+ request.resolve({ authority: resolvedAuthority, options });
}
}
diff --git a/src/vs/platform/telemetry/common/telemetryService.ts b/src/vs/platform/telemetry/common/telemetryService.ts
index 371b7cd376..d9493cfb1b 100644
--- a/src/vs/platform/telemetry/common/telemetryService.ts
+++ b/src/vs/platform/telemetry/common/telemetryService.ts
@@ -10,7 +10,7 @@ import { ITelemetryAppender } from 'vs/platform/telemetry/common/telemetryUtils'
import { optional } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
-import { IDisposable, dispose } from 'vs/base/common/lifecycle';
+import { DisposableStore } from 'vs/base/common/lifecycle';
import { cloneAndChange, mixin } from 'vs/base/common/objects';
import { Registry } from 'vs/platform/registry/common/platform';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
@@ -35,7 +35,7 @@ export class TelemetryService implements ITelemetryService {
private _userOptIn: boolean;
private _enabled: boolean;
- private _disposables: IDisposable[] = [];
+ private readonly _disposables = new DisposableStore();
private _cleanupPatterns: RegExp[] = [];
constructor(
@@ -113,7 +113,7 @@ export class TelemetryService implements ITelemetryService {
}
dispose(): void {
- this._disposables = dispose(this._disposables);
+ this._disposables.dispose();
}
publicLog(eventName: string, data?: ITelemetryData, anonymizeFilePaths?: boolean): Promise {
diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts
index 5dec8a1d57..07b9fe0e86 100644
--- a/src/vs/platform/theme/common/colorRegistry.ts
+++ b/src/vs/platform/theme/common/colorRegistry.ts
@@ -205,7 +205,8 @@ export const widgetShadow = registerColor('widget.shadow', { dark: '#000000', li
export const inputBackground = registerColor('input.background', { dark: '#3C3C3C', light: Color.white, hc: Color.black }, nls.localize('inputBoxBackground', "Input box background."));
export const inputForeground = registerColor('input.foreground', { dark: foreground, light: foreground, hc: foreground }, nls.localize('inputBoxForeground', "Input box foreground."));
export const inputBorder = registerColor('input.border', { dark: null, light: null, hc: contrastBorder }, nls.localize('inputBoxBorder', "Input box border."));
-export const inputActiveOptionBorder = registerColor('inputOption.activeBorder', { dark: '#007ACC', light: '#007ACC', hc: activeContrastBorder }, nls.localize('inputBoxActiveOptionBorder', "Border color of activated options in input fields."));
+export const inputActiveOptionBorder = registerColor('inputOption.activeBorder', { dark: '#007ACC00', light: '#007ACC00', hc: contrastBorder }, nls.localize('inputBoxActiveOptionBorder', "Border color of activated options in input fields."));
+export const inputActiveOptionBackground = registerColor('inputOption.activeBackground', { dark: transparent(focusBorder, 0.5), light: transparent(focusBorder, 0.3), hc: null }, nls.localize('inputOption.activeBackground', "Background color of activated options in input fields."));
export const inputPlaceholderForeground = registerColor('input.placeholderForeground', { light: transparent(foreground, 0.5), dark: transparent(foreground, 0.5), hc: transparent(foreground, 0.7) }, nls.localize('inputPlaceholderForeground', "Input box foreground color for placeholder text."));
export const inputValidationInfoBackground = registerColor('inputValidation.infoBackground', { dark: '#063B49', light: '#D6ECF2', hc: Color.black }, nls.localize('inputValidationInfoBackground', "Input validation background color for information severity."));
diff --git a/src/vs/platform/theme/common/styler.ts b/src/vs/platform/theme/common/styler.ts
index 1c37120f8c..36db6d057f 100644
--- a/src/vs/platform/theme/common/styler.ts
+++ b/src/vs/platform/theme/common/styler.ts
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService';
-import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry';
+import { focusBorder, inputBackground, inputForeground, ColorIdentifier, selectForeground, selectBackground, selectListBackground, selectBorder, inputBorder, foreground, editorBackground, contrastBorder, inputActiveOptionBorder, inputActiveOptionBackground, listFocusBackground, listFocusForeground, listActiveSelectionBackground, listActiveSelectionForeground, listInactiveSelectionForeground, listInactiveSelectionBackground, listInactiveFocusBackground, listHoverBackground, listHoverForeground, listDropBackground, pickerGroupBorder, pickerGroupForeground, widgetShadow, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationErrorBorder, inputValidationErrorBackground, activeContrastBorder, buttonForeground, buttonBackground, buttonHoverBackground, ColorFunction, badgeBackground, badgeForeground, progressBarBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, breadcrumbsBackground, editorWidgetBorder, inputValidationInfoForeground, inputValidationWarningForeground, inputValidationErrorForeground, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuBorder, menuSeparatorBackground, darken, listFilterWidgetOutline, listFilterWidgetNoMatchesOutline, listFilterWidgetBackground, editorWidgetBackground, treeIndentGuidesStroke, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Color } from 'vs/base/common/color';
import { mixin } from 'vs/base/common/objects';
@@ -59,11 +59,13 @@ export function attachStyler(themeService: IThemeServic
export interface ICheckboxStyleOverrides extends IStyleOverrides {
inputActiveOptionBorderColor?: ColorIdentifier;
+ inputActiveOptionBackgroundColor?: ColorIdentifier;
}
export function attachCheckboxStyler(widget: IThemable, themeService: IThemeService, style?: ICheckboxStyleOverrides): IDisposable {
return attachStyler(themeService, {
- inputActiveOptionBorder: (style && style.inputActiveOptionBorderColor) || inputActiveOptionBorder
+ inputActiveOptionBorder: (style && style.inputActiveOptionBorderColor) || inputActiveOptionBorder,
+ inputActiveOptionBackground: (style && style.inputActiveOptionBackgroundColor) || inputActiveOptionBackground
} as ICheckboxStyleOverrides, widget);
}
@@ -85,6 +87,7 @@ export interface IInputBoxStyleOverrides extends IStyleOverrides {
inputForeground?: ColorIdentifier;
inputBorder?: ColorIdentifier;
inputActiveOptionBorder?: ColorIdentifier;
+ inputActiveOptionBackground?: ColorIdentifier;
inputValidationInfoBorder?: ColorIdentifier;
inputValidationInfoBackground?: ColorIdentifier;
inputValidationInfoForeground?: ColorIdentifier;
@@ -146,6 +149,7 @@ export function attachFindInputBoxStyler(widget: IThemable, themeService: ITheme
inputForeground: (style && style.inputForeground) || inputForeground,
inputBorder: (style && style.inputBorder) || inputBorder,
inputActiveOptionBorder: (style && style.inputActiveOptionBorder) || inputActiveOptionBorder,
+ inputActiveOptionBackground: (style && style.inputActiveOptionBackground) || inputActiveOptionBackground,
inputValidationInfoBorder: (style && style.inputValidationInfoBorder) || inputValidationInfoBorder,
inputValidationInfoBackground: (style && style.inputValidationInfoBackground) || inputValidationInfoBackground,
inputValidationInfoForeground: (style && style.inputValidationInfoForeground) || inputValidationInfoForeground,
diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts
index 4f66d1891a..b39f4b1c89 100644
--- a/src/vs/vscode.proposed.d.ts
+++ b/src/vs/vscode.proposed.d.ts
@@ -94,6 +94,12 @@ declare module 'vscode' {
constructor(host: string, port: number);
}
+ export interface ResolvedOptions {
+ extensionHostEnv?: { [key: string]: string | null };
+ }
+
+ export type ResolverResult = ResolvedAuthority & ResolvedOptions;
+
export class RemoteAuthorityResolverError extends Error {
static NotAvailable(message?: string, handled?: boolean): RemoteAuthorityResolverError;
static TemporarilyNotAvailable(message?: string): RemoteAuthorityResolverError;
@@ -102,7 +108,7 @@ declare module 'vscode' {
}
export interface RemoteAuthorityResolver {
- resolve(authority: string, context: RemoteAuthorityResolverContext): ResolvedAuthority | Thenable;
+ resolve(authority: string, context: RemoteAuthorityResolverContext): ResolverResult | Thenable;
}
export interface ResourceLabelFormatter {
diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts
index 4762748dc4..fd158d3ea2 100644
--- a/src/vs/workbench/api/common/extHost.protocol.ts
+++ b/src/vs/workbench/api/common/extHost.protocol.ts
@@ -31,7 +31,7 @@ import { LogLevel } from 'vs/platform/log/common/log';
import { IMarkerData } from 'vs/platform/markers/common/markers';
import { IProgressOptions, IProgressStep } from 'vs/platform/progress/common/progress';
import * as quickInput from 'vs/platform/quickinput/common/quickInput';
-import { RemoteAuthorityResolverErrorCode, ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver';
+import { RemoteAuthorityResolverErrorCode, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
import * as statusbar from 'vs/platform/statusbar/common/statusbar';
import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
@@ -859,7 +859,7 @@ export interface IResolveAuthorityErrorResult {
export interface IResolveAuthorityOKResult {
type: 'ok';
- value: ResolvedAuthority;
+ value: ResolverResult;
}
export type IResolveAuthorityResult = IResolveAuthorityErrorResult | IResolveAuthorityOKResult;
diff --git a/src/vs/workbench/api/common/extHostSCM.ts b/src/vs/workbench/api/common/extHostSCM.ts
index d1813f1295..86451374b4 100644
--- a/src/vs/workbench/api/common/extHostSCM.ts
+++ b/src/vs/workbench/api/common/extHostSCM.ts
@@ -6,7 +6,7 @@
import { URI, UriComponents } from 'vs/base/common/uri';
import { Event, Emitter } from 'vs/base/common/event';
import { debounce } from 'vs/base/common/decorators';
-import { dispose, IDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
+import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
import { asPromise } from 'vs/base/common/async';
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext, ExtHostSCMShape, CommandDto } from './extHost.protocol';
@@ -263,7 +263,6 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
}
readonly handle = ExtHostSourceControlResourceGroup._handlePool++;
- private _disposables: IDisposable[] = [];
constructor(
private _proxy: MainThreadSCMShape,
@@ -353,7 +352,6 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
dispose(): void {
this._proxy.$unregisterGroup(this._sourceControlHandle, this.handle);
- this._disposables = dispose(this._disposables);
this._onDidDispose.fire();
}
}
diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts
index d8c28fc3d9..5b2fe81ba1 100644
--- a/src/vs/workbench/api/node/extHostExtensionService.ts
+++ b/src/vs/workbench/api/node/extHostExtensionService.ts
@@ -36,6 +36,7 @@ import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento';
import { ExtensionStoragePaths } from 'vs/workbench/api/node/extHostStoragePaths';
import { RemoteAuthorityResolverError, ExtensionExecutionContext } from 'vs/workbench/api/common/extHostTypes';
import { IURITransformer } from 'vs/base/common/uriIpc';
+import { ResolvedAuthority, ResolvedOptions } from 'vs/platform/remote/common/remoteAuthorityResolver';
interface ITestRunner {
/** Old test runner API, as exported from `vscode/lib/testrunner` */
@@ -680,12 +681,22 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape {
try {
const result = await resolver.resolve(remoteAuthority, { resolveAttempt });
+
+ // Split merged API result into separate authority/options
+ const authority: ResolvedAuthority = {
+ authority: remoteAuthority,
+ host: result.host,
+ port: result.port
+ };
+ const options: ResolvedOptions = {
+ extensionHostEnv: result.extensionHostEnv
+ };
+
return {
type: 'ok',
value: {
- authority: remoteAuthority,
- host: result.host,
- port: result.port,
+ authority,
+ options
}
};
} catch (err) {
diff --git a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts
index 1945492d4a..ff8abe09a6 100644
--- a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts
+++ b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts
@@ -20,10 +20,10 @@ export class CommentsDataSource implements IDataSource {
return 'root';
}
if (element instanceof ResourceWithCommentThreads) {
- return element.id;
+ return `${element.owner}-${element.id}`;
}
if (element instanceof CommentNode) {
- return `${element.resource.toString()}-${element.comment.uniqueIdInThread}`;
+ return `${element.owner}-${element.resource.toString()}-${element.threadId}-${element.comment.uniqueIdInThread}`;
}
return '';
}
diff --git a/src/vs/workbench/contrib/comments/common/commentModel.ts b/src/vs/workbench/contrib/comments/common/commentModel.ts
index 2716606952..2b6ecd70b5 100644
--- a/src/vs/workbench/contrib/comments/common/commentModel.ts
+++ b/src/vs/workbench/contrib/comments/common/commentModel.ts
@@ -15,13 +15,15 @@ export interface ICommentThreadChangedEvent extends CommentThreadChangedEvent {
}
export class CommentNode {
+ owner: string;
threadId: string;
range: IRange;
comment: Comment;
replies: CommentNode[] = [];
resource: URI;
- constructor(threadId: string, resource: URI, comment: Comment, range: IRange) {
+ constructor(owner: string, threadId: string, resource: URI, comment: Comment, range: IRange) {
+ this.owner = owner;
this.threadId = threadId;
this.comment = comment;
this.resource = resource;
@@ -35,18 +37,20 @@ export class CommentNode {
export class ResourceWithCommentThreads {
id: string;
+ owner: string;
commentThreads: CommentNode[]; // The top level comments on the file. Replys are nested under each node.
resource: URI;
- constructor(resource: URI, commentThreads: CommentThread[]) {
+ constructor(owner: string, resource: URI, commentThreads: CommentThread[]) {
+ this.owner = owner;
this.id = resource.toString();
this.resource = resource;
- this.commentThreads = commentThreads.filter(thread => thread.comments && thread.comments.length).map(thread => ResourceWithCommentThreads.createCommentNode(resource, thread));
+ this.commentThreads = commentThreads.filter(thread => thread.comments && thread.comments.length).map(thread => ResourceWithCommentThreads.createCommentNode(owner, resource, thread));
}
- public static createCommentNode(resource: URI, commentThread: CommentThread): CommentNode {
+ public static createCommentNode(owner: string, resource: URI, commentThread: CommentThread): CommentNode {
const { threadId, comments, range } = commentThread;
- const commentNodes: CommentNode[] = comments!.map(comment => new CommentNode(threadId!, resource, comment, range));
+ const commentNodes: CommentNode[] = comments!.map(comment => new CommentNode(owner, threadId!, resource, comment, range));
if (commentNodes.length > 1) {
commentNodes[0].replies = commentNodes.slice(1, commentNodes.length);
}
@@ -65,7 +69,7 @@ export class CommentsModel {
}
public setCommentThreads(owner: string, commentThreads: CommentThread[]): void {
- this.commentThreadsMap.set(owner, this.groupByResource(commentThreads));
+ this.commentThreadsMap.set(owner, this.groupByResource(owner, commentThreads));
this.resourceCommentThreads = flatten(values(this.commentThreadsMap));
}
@@ -97,9 +101,9 @@ export class CommentsModel {
// Find comment node on resource that is that thread and replace it
const index = firstIndex(matchingResourceData.commentThreads, (commentThread) => commentThread.threadId === thread.threadId);
if (index >= 0) {
- matchingResourceData.commentThreads[index] = ResourceWithCommentThreads.createCommentNode(URI.parse(matchingResourceData.id), thread);
+ matchingResourceData.commentThreads[index] = ResourceWithCommentThreads.createCommentNode(owner, URI.parse(matchingResourceData.id), thread);
} else if (thread.comments && thread.comments.length) {
- matchingResourceData.commentThreads.push(ResourceWithCommentThreads.createCommentNode(URI.parse(matchingResourceData.id), thread));
+ matchingResourceData.commentThreads.push(ResourceWithCommentThreads.createCommentNode(owner, URI.parse(matchingResourceData.id), thread));
}
});
@@ -108,10 +112,10 @@ export class CommentsModel {
if (existingResource.length) {
const resource = existingResource[0];
if (thread.comments && thread.comments.length) {
- resource.commentThreads.push(ResourceWithCommentThreads.createCommentNode(resource.resource, thread));
+ resource.commentThreads.push(ResourceWithCommentThreads.createCommentNode(owner, resource.resource, thread));
}
} else {
- threadsForOwner.push(new ResourceWithCommentThreads(URI.parse(thread.resource!), [thread]));
+ threadsForOwner.push(new ResourceWithCommentThreads(owner, URI.parse(thread.resource!), [thread]));
}
});
@@ -133,11 +137,11 @@ export class CommentsModel {
}
}
- private groupByResource(commentThreads: CommentThread[]): ResourceWithCommentThreads[] {
+ private groupByResource(owner: string, commentThreads: CommentThread[]): ResourceWithCommentThreads[] {
const resourceCommentThreads: ResourceWithCommentThreads[] = [];
const commentThreadsByResource = new Map();
for (const group of groupBy(commentThreads, CommentsModel._compareURIs)) {
- commentThreadsByResource.set(group[0].resource!, new ResourceWithCommentThreads(URI.parse(group[0].resource!), group));
+ commentThreadsByResource.set(group[0].resource!, new ResourceWithCommentThreads(owner, URI.parse(group[0].resource!), group));
}
commentThreadsByResource.forEach((v, i, m) => {
diff --git a/src/vs/workbench/contrib/experiments/electron-browser/experimentService.ts b/src/vs/workbench/contrib/experiments/electron-browser/experimentService.ts
index 3bc4966f70..a24a9f35fd 100644
--- a/src/vs/workbench/contrib/experiments/electron-browser/experimentService.ts
+++ b/src/vs/workbench/contrib/experiments/electron-browser/experimentService.ts
@@ -10,17 +10,17 @@ import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { language } from 'vs/base/common/platform';
-import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
+import { Disposable } from 'vs/base/common/lifecycle';
import { match } from 'vs/base/common/glob';
import { IRequestService, asJson } from 'vs/platform/request/common/request';
import { Emitter, Event } from 'vs/base/common/event';
import { ITextFileService, StateChange } from 'vs/workbench/services/textfile/common/textfiles';
-import { WorkspaceStats } from 'vs/workbench/contrib/stats/electron-browser/workspaceStats';
import { CancellationToken } from 'vs/base/common/cancellation';
import { distinct } from 'vs/base/common/arrays';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { ExperimentState, IExperimentAction, IExperimentService, IExperiment, ExperimentActionType, IExperimentActionPromptProperties } from 'vs/workbench/contrib/experiments/common/experimentService';
import { IProductService } from 'vs/platform/product/common/product';
+import { IWorkspaceStatsService } from 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService';
interface IExperimentStorageState {
enabled: boolean;
@@ -60,7 +60,6 @@ export class ExperimentService extends Disposable implements IExperimentService
private _experiments: IExperiment[] = [];
private _loadExperimentsPromise: Promise;
private _curatedMapping = Object.create(null);
- private _disposables: IDisposable[] = [];
private readonly _onExperimentEnabled = this._register(new Emitter());
onExperimentEnabled: Event = this._onExperimentEnabled.event;
@@ -74,7 +73,8 @@ export class ExperimentService extends Disposable implements IExperimentService
@ILifecycleService private readonly lifecycleService: ILifecycleService,
@IRequestService private readonly requestService: IRequestService,
@IConfigurationService private readonly configurationService: IConfigurationService,
- @IProductService private readonly productService: IProductService
+ @IProductService private readonly productService: IProductService,
+ @IWorkspaceStatsService private readonly workspaceStatsService: IWorkspaceStatsService
) {
super();
@@ -355,7 +355,7 @@ export class ExperimentService extends Disposable implements IExperimentService
onSaveHandler.dispose();
return;
}
- e.forEach(event => {
+ e.forEach(async event => {
if (event.kind !== StateChange.SAVED
|| latestExperimentState.state !== ExperimentState.Evaluating
|| date === latestExperimentState.lastEditedDate
@@ -370,10 +370,12 @@ export class ExperimentService extends Disposable implements IExperimentService
filePathCheck = match(fileEdits.filePathPattern, event.resource.fsPath);
}
if (Array.isArray(fileEdits.workspaceIncludes) && fileEdits.workspaceIncludes.length) {
- workspaceCheck = !!WorkspaceStats.TAGS && fileEdits.workspaceIncludes.some(x => !!WorkspaceStats.TAGS[x]);
+ const tags = await this.workspaceStatsService.getTags();
+ workspaceCheck = !!tags && fileEdits.workspaceIncludes.some(x => !!tags[x]);
}
if (workspaceCheck && Array.isArray(fileEdits.workspaceExcludes) && fileEdits.workspaceExcludes.length) {
- workspaceCheck = !!WorkspaceStats.TAGS && !fileEdits.workspaceExcludes.some(x => !!WorkspaceStats.TAGS[x]);
+ const tags = await this.workspaceStatsService.getTags();
+ workspaceCheck = !!tags && !fileEdits.workspaceExcludes.some(x => !!tags[x]);
}
if (filePathCheck && workspaceCheck) {
latestExperimentState.editCount = (latestExperimentState.editCount || 0) + 1;
@@ -389,14 +391,10 @@ export class ExperimentService extends Disposable implements IExperimentService
}
}
});
- this._disposables.push(onSaveHandler);
+ this._register(onSaveHandler);
return ExperimentState.Evaluating;
});
}
-
- dispose() {
- this._disposables = dispose(this._disposables);
- }
}
diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
index ee1807b12d..6f8a93ff97 100644
--- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
+++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts
@@ -17,7 +17,7 @@ import { dispose, Disposable } from 'vs/base/common/lifecycle';
import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, AutoUpdateConfigurationKey, IExtensionContainer, EXTENSIONS_CONFIG, ExtensionsPolicy, ExtensionsPolicyKey } from 'vs/workbench/contrib/extensions/common/extensions';
import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate';
import { ExtensionsLabel, IGalleryExtension, IExtensionGalleryService, INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE, IGalleryExtensionVersion, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
-import { IExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionTipsService, IExtensionRecommendation, IExtensionsConfigContent } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
+import { IExtensionEnablementService, EnablementState, IExtensionManagementServerService, IExtensionTipsService, IExtensionRecommendation, IExtensionsConfigContent, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { ExtensionType, ExtensionIdentifier, IExtensionDescription, IExtensionManifest, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
@@ -176,19 +176,22 @@ export class InstallAction extends ExtensionAction {
}
update(): void {
- if (!this.extension || this.extension.type === ExtensionType.System || this.extension.state === ExtensionState.Installed) {
- this.enabled = false;
- this.class = InstallAction.Class;
- this.label = InstallAction.INSTALL_LABEL;
- return;
- }
this.enabled = false;
- if (this.extensionsWorkbenchService.canInstall(this.extension)) {
- const local = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier))[0];
- this.enabled = !local || (!!local.local && isLanguagePackExtension(local.local.manifest));
+ this.class = InstallAction.Class;
+ this.label = InstallAction.INSTALL_LABEL;
+ if (this.extension && this.extension.type === ExtensionType.User) {
+ if (this.extension.state === ExtensionState.Uninstalled && this.extensionsWorkbenchService.canInstall(this.extension)) {
+ this.enabled = true;
+ this.updateLabel();
+ return;
+ }
+ if (this.extension.state === ExtensionState.Installing) {
+ this.enabled = false;
+ this.updateLabel();
+ this.class = this.extension.state === ExtensionState.Installing ? InstallAction.InstallingClass : InstallAction.Class;
+ return;
+ }
}
- this.class = this.extension.state === ExtensionState.Installing ? InstallAction.InstallingClass : InstallAction.Class;
- this.updateLabel();
}
private updateLabel(): void {
@@ -283,60 +286,55 @@ export class InstallAction extends ExtensionAction {
}
}
-export class RemoteInstallAction extends ExtensionAction {
+export class InstallInOtherServerAction extends ExtensionAction {
- private static INSTALL_LABEL = localize('install', "Install");
- private static INSTALLING_LABEL = localize('installing', "Installing");
+ protected static INSTALL_LABEL = localize('install', "Install");
+ protected static INSTALLING_LABEL = localize('installing', "Installing");
private static readonly Class = 'extension-action prominent install';
private static readonly InstallingClass = 'extension-action install installing';
updateWhenCounterExtensionChanges: boolean = true;
- private installing: boolean = false;
+ protected installing: boolean = false;
constructor(
+ id: string,
+ private readonly server: IExtensionManagementServer | null,
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
- @ILabelService private readonly labelService: ILabelService,
- @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
- @IConfigurationService private readonly configurationService: IConfigurationService,
- @IProductService private readonly productService: IProductService,
) {
- super(`extensions.remoteinstall`, RemoteInstallAction.INSTALL_LABEL, RemoteInstallAction.Class, false);
- this._register(this.labelService.onDidChangeFormatters(() => this.updateLabel(), this));
+ super(id, InstallInOtherServerAction.INSTALL_LABEL, InstallInOtherServerAction.Class, false);
this.updateLabel();
this.update();
}
private updateLabel(): void {
- if (this.installing) {
- this.label = RemoteInstallAction.INSTALLING_LABEL;
- this.tooltip = this.label;
- return;
- }
- const remoteServer = this.extensionManagementServerService.remoteExtensionManagementServer;
- if (remoteServer) {
- this.label = `${RemoteInstallAction.INSTALL_LABEL} on ${remoteServer.label}`;
- this.tooltip = this.label;
- return;
- }
+ this.label = this.getLabel();
+ this.tooltip = this.label;
+ }
+
+ protected getLabel(): string {
+ return this.installing ? InstallInOtherServerAction.INSTALLING_LABEL :
+ this.server ? `${InstallInOtherServerAction.INSTALL_LABEL} on ${this.server.label}`
+ : InstallInOtherServerAction.INSTALL_LABEL;
+
}
update(): void {
this.enabled = false;
- this.class = RemoteInstallAction.Class;
+ this.class = InstallInOtherServerAction.Class;
if (this.installing) {
this.enabled = true;
- this.class = RemoteInstallAction.InstallingClass;
+ this.class = InstallInOtherServerAction.InstallingClass;
this.updateLabel();
return;
}
- if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer
- // Installed User Extension
- && this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed
- // Local Workspace Extension
- && this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || !isUIExtension(this.extension.local.manifest, this.productService, this.configurationService))
- // Extension does not exist in remote
- && !this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)
+
+ if (
+ this.extension && this.extension.local && this.server && this.extension.state === ExtensionState.Installed
+ // disabled by extension kind or it is a language pack extension
+ && (this.extension.enablementState === EnablementState.DisabledByExtensionKind || isLanguagePackExtension(this.extension.local.manifest))
+ // Not installed in other server and can install in other server
+ && !this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.server)
&& this.extensionsWorkbenchService.canInstall(this.extension)
) {
this.enabled = true;
@@ -346,13 +344,13 @@ export class RemoteInstallAction extends ExtensionAction {
}
async run(): Promise {
- if (this.extensionManagementServerService.remoteExtensionManagementServer && !this.installing) {
+ if (this.server && !this.installing) {
this.installing = true;
this.update();
this.extensionsWorkbenchService.open(this.extension);
alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName));
if (this.extension.gallery) {
- await this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.installFromGallery(this.extension.gallery);
+ await this.server.extensionManagementService.installFromGallery(this.extension.gallery);
this.installing = false;
this.update();
}
@@ -360,77 +358,30 @@ export class RemoteInstallAction extends ExtensionAction {
}
}
-export class LocalInstallAction extends ExtensionAction {
-
- private static INSTALL_LABEL = localize('install locally', "Install Locally");
- private static INSTALLING_LABEL = localize('installing', "Installing");
-
- private static readonly Class = 'extension-action prominent install';
- private static readonly InstallingClass = 'extension-action install installing';
-
- updateWhenCounterExtensionChanges: boolean = true;
- private installing: boolean = false;
+export class RemoteInstallAction extends InstallInOtherServerAction {
constructor(
- @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
- @ILabelService private readonly labelService: ILabelService,
- @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService,
- @IConfigurationService private readonly configurationService: IConfigurationService,
- @IProductService private readonly productService: IProductService,
+ @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
+ @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService
) {
- super(`extensions.localinstall`, LocalInstallAction.INSTALL_LABEL, LocalInstallAction.Class, false);
- this._register(this.labelService.onDidChangeFormatters(() => this.updateLabel(), this));
- this.updateLabel();
- this.update();
+ super(`extensions.remoteinstall`, extensionManagementServerService.remoteExtensionManagementServer, extensionsWorkbenchService);
}
- private updateLabel(): void {
- if (this.installing) {
- this.label = LocalInstallAction.INSTALLING_LABEL;
- this.tooltip = this.label;
- return;
- }
- this.label = `${LocalInstallAction.INSTALL_LABEL}`;
- this.tooltip = this.label;
+}
+
+export class LocalInstallAction extends InstallInOtherServerAction {
+
+ constructor(
+ @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService,
+ @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService
+ ) {
+ super(`extensions.localinstall`, extensionManagementServerService.localExtensionManagementServer, extensionsWorkbenchService);
}
- update(): void {
- this.enabled = false;
- this.class = LocalInstallAction.Class;
- if (this.installing) {
- this.enabled = true;
- this.class = LocalInstallAction.InstallingClass;
- this.updateLabel();
- return;
- }
- if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer
- // Installed User Extension
- && this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed
- // Remote UI or Language pack Extension
- && this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || isUIExtension(this.extension.local.manifest, this.productService, this.configurationService))
- // Extension does not exist in local
- && !this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.localExtensionManagementServer)
- && this.extensionsWorkbenchService.canInstall(this.extension)
- ) {
- this.enabled = true;
- this.updateLabel();
- return;
- }
+ protected getLabel(): string {
+ return this.installing ? InstallInOtherServerAction.INSTALLING_LABEL : localize('install locally', "Install Locally");
}
- async run(): Promise {
- if (this.extensionManagementServerService.localExtensionManagementServer && !this.installing) {
- this.installing = true;
- this.update();
- this.extensionsWorkbenchService.open(this.extension);
- alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName));
- if (this.extension.gallery) {
- await this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(this.extension.gallery);
- this.installing = false;
- this.update();
- }
- }
- }
}
export class UninstallAction extends ExtensionAction {
diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts
index c0915495e1..ee002a91eb 100644
--- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts
+++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts
@@ -64,8 +64,8 @@ class Extension implements IExtension {
@IProductService private readonly productService: IProductService
) { }
- get type(): ExtensionType | undefined {
- return this.local ? this.local.type : undefined;
+ get type(): ExtensionType {
+ return this.local ? this.local.type : ExtensionType.User;
}
get name(): string {
diff --git a/src/vs/workbench/contrib/extensions/common/extensions.ts b/src/vs/workbench/contrib/extensions/common/extensions.ts
index f55e9ec640..35a6987037 100644
--- a/src/vs/workbench/contrib/extensions/common/extensions.ts
+++ b/src/vs/workbench/contrib/extensions/common/extensions.ts
@@ -34,7 +34,7 @@ export const enum ExtensionState {
}
export interface IExtension {
- readonly type?: ExtensionType;
+ readonly type: ExtensionType;
readonly state: ExtensionState;
readonly name: string;
readonly displayName: string;
diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts
index 891fbb0883..5291d1e70e 100644
--- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts
+++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts
@@ -21,7 +21,7 @@ import { TestExtensionEnablementService } from 'vs/workbench/services/extensionM
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
import { IURLService } from 'vs/platform/url/common/url';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
-import { Emitter } from 'vs/base/common/event';
+import { Emitter, Event } from 'vs/base/common/event';
import { IPager } from 'vs/base/common/paging';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
@@ -42,6 +42,9 @@ import { CancellationToken } from 'vs/base/common/cancellation';
import { ILabelService } from 'vs/platform/label/common/label';
import { ExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService';
import { IProductService } from 'vs/platform/product/common/product';
+import { Schemas } from 'vs/base/common/network';
+import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
+import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
suite('ExtensionsActions Test', () => {
@@ -53,7 +56,7 @@ suite('ExtensionsActions Test', () => {
didUninstallEvent: Emitter;
- suiteSetup(() => {
+ setup(async () => {
installEvent = new Emitter();
didInstallEvent = new Emitter();
uninstallEvent = new Emitter();
@@ -91,9 +94,7 @@ suite('ExtensionsActions Test', () => {
instantiationService.set(IExtensionTipsService, instantiationService.createInstance(ExtensionTipsService));
instantiationService.stub(IURLService, URLService);
- });
- setup(async () => {
instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', []);
instantiationService.stubPromise(IExtensionManagementService, 'getExtensionsReport', []);
instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage());
@@ -1357,6 +1358,682 @@ suite('ExtensionsActions Test', () => {
assert.ok(!testObject.enabled);
});
+ test('Test remote install action is enabled for local workspace extension', async () => {
+ // multi server setup
+ const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.enabled);
+ assert.equal('Install on remote', testObject.label);
+ assert.equal('extension-action prominent install', testObject.class);
+ });
+
+ test('Test remote install action when installing local workspace extension', async (done) => {
+ // multi server setup
+ const remoteExtensionManagementService: IExtensionManagementService = createExtensionManagementService();
+ const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension]), remoteExtensionManagementService);
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.stub(IExtensionsWorkbenchService, workbenchService, 'open', undefined);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.enabled);
+ assert.equal('Install on remote', testObject.label);
+ assert.equal('extension-action prominent install', testObject.class);
+
+ remoteExtensionManagementService.installFromGallery = () => new Promise(c => c(aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) })));
+ const disposable = testObject.onDidChange(() => {
+ if (testObject.label === 'Installing' && testObject.enabled) {
+ disposable.dispose();
+ done();
+ }
+ });
+ testObject.run();
+ });
+
+ test('Test remote install action when installing local workspace extension is finished', async (done) => {
+ // multi server setup
+ const remoteExtensionManagementService: IExtensionManagementService = createExtensionManagementService();
+ const onDidInstallEvent = new Emitter();
+ remoteExtensionManagementService.onDidInstallExtension = onDidInstallEvent.event;
+ const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension]), remoteExtensionManagementService);
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.stub(IExtensionsWorkbenchService, workbenchService, 'open', undefined);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.enabled);
+ assert.equal('Install on remote', testObject.label);
+ assert.equal('extension-action prominent install', testObject.class);
+
+ const installedExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ remoteExtensionManagementService.installFromGallery = () => new Promise(c => c(installedExtension));
+ await testObject.run();
+ assert.ok(testObject.enabled);
+ assert.equal('Install on remote', testObject.label);
+
+ const disposable = testObject.onDidChange(() => {
+ if (testObject.label === 'Install on remote' && !testObject.enabled) {
+ disposable.dispose();
+ done();
+ }
+ });
+ onDidInstallEvent.fire({ identifier: installedExtension.identifier, local: installedExtension, operation: InstallOperation.Install });
+ });
+
+ test('Test remote install action is enabled for disabled local workspace extension', async () => {
+ // multi server setup
+ const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ await instantiationService.get(IExtensionEnablementService).setEnablement([localWorkspaceExtension], EnablementState.DisabledGlobally);
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.enabled);
+ assert.equal('Install on remote', testObject.label);
+ assert.equal('extension-action prominent install', testObject.class);
+ });
+
+ test('Test remote install action is disabled when extension is not set', async () => {
+ // multi server setup
+ const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension]));
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test remote install action is disabled for extension which is not installed', async () => {
+ // multi server setup
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService);
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a')));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const pager = await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = pager.firstPage[0];
+ assert.ok(testObject.extension);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test remote install action is disabled for local workspace extension which is disabled in env', async () => {
+ // multi server setup
+ const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension]));
+ instantiationService.stub(IWorkbenchEnvironmentService, { disableExtensions: true } as IWorkbenchEnvironmentService);
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.extension);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test remote install action is disabled when remote server is not available', async () => {
+ // single server setup
+ const workbenchService = instantiationService.get(IExtensionsWorkbenchService);
+ const extensionManagementServerService = instantiationService.get(IExtensionManagementServerService);
+ const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) });
+ instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [localWorkspaceExtension]);
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.extension);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test remote install action is disabled for local workspace extension if it is uninstalled locally', async () => {
+ // multi server setup
+ const extensionManagementService = instantiationService.get(IExtensionManagementService);
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, extensionManagementService);
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) });
+ instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [localWorkspaceExtension]);
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.enabled);
+ assert.equal('Install on remote', testObject.label);
+
+ uninstallEvent.fire(localWorkspaceExtension.identifier);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test remote install action is disabled for local workspace extension if it is installed in remote', async () => {
+ // multi server setup
+ const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) });
+ const remoteWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension]), createExtensionManagementService([remoteWorkspaceExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.extension);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test remote install action is disabled for local workspace extension if it cannot be installed', async () => {
+ // multi server setup
+ const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.extension);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test remote install action is disabled for local ui extension if it is not installed in remote', async () => {
+ // multi server setup
+ const localUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localUIExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localUIExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.extension);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test remote install action is disabled for local ui extension if it is also installed in remote', async () => {
+ // multi server setup
+ const localUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) });
+ const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localUIExtension]), createExtensionManagementService([remoteUIExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localUIExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.extension);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test remote install action is enabled for locally installed language pack extension', async () => {
+ // multi server setup
+ const languagePackExtension = aLocalExtension('a', { contributes: { localizations: [{ languageId: 'de', translations: [] }] } }, { location: URI.file(`pub.a`) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([languagePackExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: languagePackExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.enabled);
+ assert.equal('Install on remote', testObject.label);
+ assert.equal('extension-action prominent install', testObject.class);
+ });
+
+ test('Test remote install action is disabled if local language pack extension is uninstalled', async () => {
+ // multi server setup
+ const extensionManagementService = instantiationService.get(IExtensionManagementService);
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, extensionManagementService);
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const languagePackExtension = aLocalExtension('a', { contributes: { localizations: [{ languageId: 'de', translations: [] }] } }, { location: URI.file(`pub.a`) });
+ instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [languagePackExtension]);
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: languagePackExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.enabled);
+ assert.equal('Install on remote', testObject.label);
+
+ uninstallEvent.fire(languagePackExtension.identifier);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test local install action is enabled for remote ui extension', async () => {
+ // multi server setup
+ const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteUIExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.enabled);
+ assert.equal('Install Locally', testObject.label);
+ assert.equal('extension-action prominent install', testObject.class);
+ });
+
+ test('Test local install action when installing remote ui extension', async (done) => {
+ // multi server setup
+ const localExtensionManagementService: IExtensionManagementService = createExtensionManagementService();
+ const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, localExtensionManagementService, createExtensionManagementService([remoteUIExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.stub(IExtensionsWorkbenchService, workbenchService, 'open', undefined);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.enabled);
+ assert.equal('Install Locally', testObject.label);
+ assert.equal('extension-action prominent install', testObject.class);
+
+ localExtensionManagementService.installFromGallery = () => new Promise(c => c(aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) })));
+ const disposable = testObject.onDidChange(() => {
+ if (testObject.label === 'Installing' && testObject.enabled) {
+ disposable.dispose();
+ done();
+ }
+ });
+ testObject.run();
+ });
+
+ test('Test local install action when installing remote ui extension is finished', async (done) => {
+ // multi server setup
+ const localExtensionManagementService: IExtensionManagementService = createExtensionManagementService();
+ const onDidInstallEvent = new Emitter();
+ localExtensionManagementService.onDidInstallExtension = onDidInstallEvent.event;
+ const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, localExtensionManagementService, createExtensionManagementService([remoteUIExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.stub(IExtensionsWorkbenchService, workbenchService, 'open', undefined);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.enabled);
+ assert.equal('Install Locally', testObject.label);
+ assert.equal('extension-action prominent install', testObject.class);
+
+ const installedExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) });
+ localExtensionManagementService.installFromGallery = () => new Promise(c => c(installedExtension));
+ await testObject.run();
+ assert.ok(testObject.enabled);
+ assert.equal('Install Locally', testObject.label);
+
+ const disposable = testObject.onDidChange(() => {
+ if (testObject.label === 'Install Locally' && !testObject.enabled) {
+ disposable.dispose();
+ done();
+ }
+ });
+ onDidInstallEvent.fire({ identifier: installedExtension.identifier, local: installedExtension, operation: InstallOperation.Install });
+ });
+
+ test('Test local install action is enabled for disabled remote ui extension', async () => {
+ // multi server setup
+ const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteUIExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ await instantiationService.get(IExtensionEnablementService).setEnablement([remoteUIExtension], EnablementState.DisabledGlobally);
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.enabled);
+ assert.equal('Install Locally', testObject.label);
+ assert.equal('extension-action prominent install', testObject.class);
+ });
+
+ test('Test local install action is disabled when extension is not set', async () => {
+ // multi server setup
+ const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteUIExtension]));
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test local install action is disabled for extension which is not installed', async () => {
+ // multi server setup
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService);
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a')));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const pager = await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = pager.firstPage[0];
+ assert.ok(testObject.extension);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test local install action is disabled for remote ui extension which is disabled in env', async () => {
+ // multi server setup
+ const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ instantiationService.stub(IWorkbenchEnvironmentService, { disableExtensions: true } as IWorkbenchEnvironmentService);
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteUIExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.extension);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test local install action is disabled when local server is not available', async () => {
+ // single server setup
+ const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ const extensionManagementServerService = aSingleRemoteExtensionManagementServerService(instantiationService, createExtensionManagementService([remoteUIExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.extension);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test local install action is disabled for remote ui extension if it is installed in local', async () => {
+ // multi server setup
+ const localUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) });
+ const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localUIExtension]), createExtensionManagementService([remoteUIExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localUIExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.extension);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test local install action is disabled for remoteUI extension if it is uninstalled locally', async () => {
+ // multi server setup
+ const extensionManagementService = instantiationService.get(IExtensionManagementService);
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), extensionManagementService);
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [remoteUIExtension]);
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.enabled);
+ assert.equal('Install Locally', testObject.label);
+
+ uninstallEvent.fire(remoteUIExtension.identifier);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test local install action is disabled for remote UI extension if it cannot be installed', async () => {
+ // multi server setup
+ const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteUIExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.extension);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test local install action is disabled for remote workspace extension if it is not installed in local', async () => {
+ // multi server setup
+ const remoteWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteWorkspaceExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteWorkspaceExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.extension);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test local install action is disabled for remote workspace extension if it is also installed in local', async () => {
+ // multi server setup
+ const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspae' }, { location: URI.file(`pub.a`) });
+ const remoteWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension]), createExtensionManagementService([remoteWorkspaceExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.extension);
+ assert.ok(!testObject.enabled);
+ });
+
+ test('Test local install action is enabled for remotely installed language pack extension', async () => {
+ // multi server setup
+ const languagePackExtension = aLocalExtension('a', { contributes: { localizations: [{ languageId: 'de', translations: [] }] } }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([languagePackExtension]));
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: languagePackExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.enabled);
+ assert.equal('Install Locally', testObject.label);
+ assert.equal('extension-action prominent install', testObject.class);
+ });
+
+ test('Test local install action is disabled if remote language pack extension is uninstalled', async () => {
+ // multi server setup
+ const extensionManagementService = instantiationService.get(IExtensionManagementService);
+ const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), extensionManagementService);
+ instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService);
+ instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService));
+ const languagePackExtension = aLocalExtension('a', { contributes: { localizations: [{ languageId: 'de', translations: [] }] } }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) });
+ instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [languagePackExtension]);
+ const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService);
+ instantiationService.set(IExtensionsWorkbenchService, workbenchService);
+
+ instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: languagePackExtension.identifier })));
+ const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction);
+ instantiationService.createInstance(ExtensionContainers, [testObject]);
+
+ const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!);
+ await workbenchService.queryGallery(CancellationToken.None);
+ testObject.extension = extensions[0];
+ assert.ok(testObject.enabled);
+ assert.equal('Install Locally', testObject.label);
+
+ uninstallEvent.fire(languagePackExtension.identifier);
+ assert.ok(!testObject.enabled);
+ });
test(`RecommendToFolderAction`, () => {
// TODO: Implement test
@@ -1386,4 +2063,61 @@ suite('ExtensionsActions Test', () => {
return { firstPage: objects, total: objects.length, pageSize: objects.length, getPage: () => null! };
}
+ function aSingleRemoteExtensionManagementServerService(instantiationService: TestInstantiationService, remoteExtensionManagementService?: IExtensionManagementService): IExtensionManagementServerService {
+ const remoteExtensionManagementServer: IExtensionManagementServer = {
+ authority: 'vscode-remote',
+ label: 'remote',
+ extensionManagementService: remoteExtensionManagementService || createExtensionManagementService()
+ };
+ return {
+ _serviceBrand: {},
+ localExtensionManagementServer: null,
+ remoteExtensionManagementServer,
+ getExtensionManagementServer: (location: URI) => {
+ if (location.scheme === REMOTE_HOST_SCHEME) {
+ return remoteExtensionManagementServer;
+ }
+ return null;
+ }
+ };
+ }
+
+ function aMultiExtensionManagementServerService(instantiationService: TestInstantiationService, localExtensionManagementService?: IExtensionManagementService, remoteExtensionManagementService?: IExtensionManagementService): IExtensionManagementServerService {
+ const localExtensionManagementServer: IExtensionManagementServer = {
+ authority: 'vscode-local',
+ label: 'local',
+ extensionManagementService: localExtensionManagementService || createExtensionManagementService()
+ };
+ const remoteExtensionManagementServer: IExtensionManagementServer = {
+ authority: 'vscode-remote',
+ label: 'remote',
+ extensionManagementService: remoteExtensionManagementService || createExtensionManagementService()
+ };
+ return {
+ _serviceBrand: {},
+ localExtensionManagementServer,
+ remoteExtensionManagementServer,
+ getExtensionManagementServer: (location: URI) => {
+ if (location.scheme === Schemas.file) {
+ return localExtensionManagementServer;
+ }
+ if (location.scheme === REMOTE_HOST_SCHEME) {
+ return remoteExtensionManagementServer;
+ }
+ return null;
+ }
+ };
+ }
+
+ function createExtensionManagementService(installed: ILocalExtension[] = []): IExtensionManagementService {
+ return {
+ onInstallExtension: Event.None,
+ onDidInstallExtension: Event.None,
+ onUninstallExtension: Event.None,
+ onDidUninstallExtension: Event.None,
+ getInstalled: () => Promise.resolve(installed),
+ installFromGallery: (extension: IGalleryExtension) => Promise.reject(new Error('not supported'))
+ };
+ }
+
});
diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts
index 2476525146..b2b2c388e9 100644
--- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts
+++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts
@@ -112,7 +112,7 @@ suite('ExtensionsWorkbenchServiceTest', () => {
test('test gallery extension', async () => {
const expected = aGalleryExtension('expectedName', {
displayName: 'expectedDisplayName',
- version: '1.5',
+ version: '1.5.0',
publisherId: 'expectedPublisherId',
publisher: 'expectedPublisher',
publisherDisplayName: 'expectedPublisherDisplayName',
@@ -140,14 +140,14 @@ suite('ExtensionsWorkbenchServiceTest', () => {
assert.equal(1, pagedResponse.firstPage.length);
const actual = pagedResponse.firstPage[0];
- assert.equal(null, actual.type);
+ assert.equal(ExtensionType.User, actual.type);
assert.equal('expectedName', actual.name);
assert.equal('expectedDisplayName', actual.displayName);
assert.equal('expectedpublisher.expectedname', actual.identifier.id);
assert.equal('expectedPublisher', actual.publisher);
assert.equal('expectedPublisherDisplayName', actual.publisherDisplayName);
- assert.equal('1.5', actual.version);
- assert.equal('1.5', actual.latestVersion);
+ assert.equal('1.5.0', actual.version);
+ assert.equal('1.5.0', actual.latestVersion);
assert.equal('expectedDescription', actual.description);
assert.equal('uri:icon', actual.iconUrl);
assert.equal('fallback:icon', actual.iconUrlFallback);
diff --git a/src/vs/workbench/contrib/files/common/explorerService.ts b/src/vs/workbench/contrib/files/common/explorerService.ts
index d15394848c..40741dded7 100644
--- a/src/vs/workbench/contrib/files/common/explorerService.ts
+++ b/src/vs/workbench/contrib/files/common/explorerService.ts
@@ -5,7 +5,7 @@
import { Event, Emitter } from 'vs/base/common/event';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
-import { IDisposable, dispose } from 'vs/base/common/lifecycle';
+import { DisposableStore } from 'vs/base/common/lifecycle';
import { IExplorerService, IEditableData, IFilesConfiguration, SortOrder, SortOrderConfiguration } from 'vs/workbench/contrib/files/common/files';
import { ExplorerItem, ExplorerModel } from 'vs/workbench/contrib/files/common/explorerModel';
import { URI } from 'vs/base/common/uri';
@@ -36,7 +36,7 @@ export class ExplorerService implements IExplorerService {
private _onDidChangeEditable = new Emitter();
private _onDidSelectResource = new Emitter<{ resource?: URI, reveal?: boolean }>();
private _onDidCopyItems = new Emitter<{ items: ExplorerItem[], cut: boolean, previouslyCutItems: ExplorerItem[] | undefined }>();
- private disposables: IDisposable[] = [];
+ private readonly disposables = new DisposableStore();
private editable: { stat: ExplorerItem, data: IEditableData } | undefined;
private _sortOrder: SortOrder;
private cutItems: ExplorerItem[] | undefined;
@@ -88,18 +88,18 @@ export class ExplorerService implements IExplorerService {
(root?: URI) => getFileEventsExcludes(this.configurationService, root),
(event: IConfigurationChangeEvent) => event.affectsConfiguration(FILES_EXCLUDE_CONFIG)
);
- this.disposables.push(fileEventsFilter);
+ this.disposables.add(fileEventsFilter);
return fileEventsFilter;
}
@memoize get model(): ExplorerModel {
const model = new ExplorerModel(this.contextService);
- this.disposables.push(model);
- this.disposables.push(this.fileService.onAfterOperation(e => this.onFileOperation(e)));
- this.disposables.push(this.fileService.onFileChanges(e => this.onFileChanges(e)));
- this.disposables.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getValue())));
- this.disposables.push(this.fileService.onDidChangeFileSystemProviderRegistrations(e => {
+ this.disposables.add(model);
+ this.disposables.add(this.fileService.onAfterOperation(e => this.onFileOperation(e)));
+ this.disposables.add(this.fileService.onFileChanges(e => this.onFileChanges(e)));
+ this.disposables.add(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getValue())));
+ this.disposables.add(this.fileService.onDidChangeFileSystemProviderRegistrations(e => {
if (e.added && this.fileSystemProviderSchemes.has(e.scheme)) {
// A file system provider got re-registered, we should update all file stats since they might change (got read-only)
this.model.roots.forEach(r => r.forgetChildren());
@@ -108,7 +108,7 @@ export class ExplorerService implements IExplorerService {
this.fileSystemProviderSchemes.add(e.scheme);
}
}));
- this.disposables.push(model.onDidChangeRoots(() => this._onDidChangeRoots.fire()));
+ this.disposables.add(model.onDidChangeRoots(() => this._onDidChangeRoots.fire()));
return model;
}
@@ -380,6 +380,6 @@ export class ExplorerService implements IExplorerService {
}
dispose(): void {
- dispose(this.disposables);
+ this.disposables.dispose();
}
}
diff --git a/src/vs/workbench/contrib/output/browser/outputActions.ts b/src/vs/workbench/contrib/output/browser/outputActions.ts
index 8c85b35f09..902d2b5805 100644
--- a/src/vs/workbench/contrib/output/browser/outputActions.ts
+++ b/src/vs/workbench/contrib/output/browser/outputActions.ts
@@ -11,7 +11,6 @@ import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { TogglePanelAction } from 'vs/workbench/browser/panel';
-import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { attachSelectBoxStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
@@ -67,11 +66,9 @@ export class ToggleOrSetOutputScrollLockAction extends Action {
public static readonly ID = 'workbench.output.action.toggleOutputScrollLock';
public static readonly LABEL = nls.localize({ key: 'toggleOutputScrollLock', comment: ['Turn on / off automatic output scrolling'] }, "Toggle Output Scroll Lock");
- private toDispose: IDisposable[] = [];
-
constructor(id: string, label: string, @IOutputService private readonly outputService: IOutputService) {
super(id, label, 'output-action output-scroll-unlock');
- this.toDispose.push(this.outputService.onActiveOutputChannel(channel => {
+ this._register(this.outputService.onActiveOutputChannel(channel => {
const activeChannel = this.outputService.getActiveChannel();
if (activeChannel) {
this.setClassAndLabel(activeChannel.scrollLock);
@@ -104,11 +101,6 @@ export class ToggleOrSetOutputScrollLockAction extends Action {
this.label = nls.localize('outputScrollOff', "Turn Auto Scrolling Off");
}
}
-
- public dispose() {
- super.dispose();
- this.toDispose = dispose(this.toDispose);
- }
}
export class SwitchOutputAction extends Action {
@@ -188,15 +180,13 @@ export class OpenLogOutputFile extends Action {
public static readonly ID = 'workbench.output.action.openLogOutputFile';
public static readonly LABEL = nls.localize('openInLogViewer', "Open Log File");
- private disposables: IDisposable[] = [];
-
constructor(
@IOutputService private readonly outputService: IOutputService,
@IEditorService private readonly editorService: IEditorService,
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
super(OpenLogOutputFile.ID, OpenLogOutputFile.LABEL, 'output-action open-log-file');
- this.outputService.onActiveOutputChannel(this.update, this, this.disposables);
+ this._register(this.outputService.onActiveOutputChannel(this.update, this));
this.update();
}
diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts
index 71e7df9d2f..122594b1fd 100644
--- a/src/vs/workbench/contrib/search/browser/searchView.ts
+++ b/src/vs/workbench/contrib/search/browser/searchView.ts
@@ -1151,6 +1151,10 @@ export class SearchView extends ViewletPanel {
}
onQueryChanged(preserveFocus?: boolean): void {
+ if (!this.searchWidget.searchInput.inputBox.isInputValid()) {
+ return;
+ }
+
const isRegex = this.searchWidget.searchInput.getRegex();
const isWholeWords = this.searchWidget.searchInput.getWholeWords();
const isCaseSensitive = this.searchWidget.searchInput.getCaseSensitive();
diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts b/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts
index 3c01869a7a..f6b387c526 100644
--- a/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts
+++ b/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts
@@ -3,25 +3,18 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
-import { localize } from 'vs/nls';
import * as crypto from 'crypto';
import { onUnexpectedError } from 'vs/base/common/errors';
import { URI } from 'vs/base/common/uri';
-import { IFileService, IFileStat, IResolveFileResult } from 'vs/platform/files/common/files';
+import { IFileService, IFileStat } from 'vs/platform/files/common/files';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
-import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
-import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
-import { IWindowConfiguration, IWindowService } from 'vs/platform/windows/common/windows';
+import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
+import { IWindowService } from 'vs/platform/windows/common/windows';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { endsWith } from 'vs/base/common/strings';
-import { Schemas } from 'vs/base/common/network';
-import { INotificationService, Severity, IPromptChoice } from 'vs/platform/notification/common/notification';
-import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
-import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
-import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
-import { joinPath } from 'vs/base/common/resources';
-import { ITextFileService, ITextFileContent } from 'vs/workbench/services/textfile/common/textfiles';
+import { ITextFileService, } from 'vs/workbench/services/textfile/common/textfiles';
import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService';
+import { IWorkspaceStatsService, Tags } from 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService';
const SshProtocolMatcher = /^([^@:]+@)?([^:]+):/;
const SshUrlMatcher = /^([^@:]+@)?([^:]+):(.+)$/;
@@ -43,60 +36,6 @@ const SecondLevelDomainWhitelist = [
'rhcloud.com',
'google.com'
];
-const ModulesToLookFor = [
- // Packages that suggest a node server
- 'express',
- 'sails',
- 'koa',
- 'hapi',
- 'socket.io',
- 'restify',
- // JS frameworks
- 'react',
- 'react-native',
- 'rnpm-plugin-windows',
- '@angular/core',
- '@ionic',
- 'vue',
- 'tns-core-modules',
- // Other interesting packages
- 'aws-sdk',
- 'aws-amplify',
- 'azure',
- 'azure-storage',
- 'firebase',
- '@google-cloud/common',
- 'heroku-cli'
-];
-const PyModulesToLookFor = [
- 'azure',
- 'azure-storage-common',
- 'azure-storage-blob',
- 'azure-storage-file',
- 'azure-storage-queue',
- 'azure-shell',
- 'azure-cosmos',
- 'azure-devtools',
- 'azure-elasticluster',
- 'azure-eventgrid',
- 'azure-functions',
- 'azure-graphrbac',
- 'azure-keyvault',
- 'azure-loganalytics',
- 'azure-monitor',
- 'azure-servicebus',
- 'azure-servicefabric',
- 'azure-storage',
- 'azure-translator',
- 'azure-iothub-device-client',
- 'adal',
- 'pydocumentdb',
- 'botbuilder-core',
- 'botbuilder-schema',
- 'botframework-connector'
-];
-
-type Tags = { [index: string]: boolean | number | string | undefined };
function stripLowLevelDomains(domain: string): string | null {
const match = domain.match(SecondLevelDomainMatcher);
@@ -212,21 +151,14 @@ export function getHashedRemotesFromUri(workspaceUri: URI, fileService: IFileSer
export class WorkspaceStats implements IWorkbenchContribution {
- static TAGS: Tags;
-
- private static DISABLE_WORKSPACE_PROMPT_KEY = 'workspaces.dontPromptToOpen';
-
constructor(
@IFileService private readonly fileService: IFileService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
- @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IWindowService private readonly windowService: IWindowService,
- @INotificationService private readonly notificationService: INotificationService,
- @IQuickInputService private readonly quickInputService: IQuickInputService,
- @IStorageService private readonly storageService: IStorageService,
@ITextFileService private readonly textFileService: ITextFileService,
- @ISharedProcessService private readonly sharedProcessService: ISharedProcessService
+ @ISharedProcessService private readonly sharedProcessService: ISharedProcessService,
+ @IWorkspaceStatsService private readonly workspaceStatsService: IWorkspaceStatsService
) {
this.report();
}
@@ -234,7 +166,7 @@ export class WorkspaceStats implements IWorkbenchContribution {
private report(): void {
// Workspace Stats
- this.resolveWorkspaceTags(this.environmentService.configuration, rootFiles => this.handleWorkspaceFiles(rootFiles))
+ this.workspaceStatsService.getTags()
.then(tags => this.reportWorkspaceTags(tags), error => onUnexpectedError(error));
// Cloud Stats
@@ -246,372 +178,7 @@ export class WorkspaceStats implements IWorkbenchContribution {
diagnosticsChannel.call('reportWorkspaceStats', this.contextService.getWorkspace());
}
- private static searchArray(arr: string[], regEx: RegExp): boolean | undefined {
- return arr.some(v => v.search(regEx) > -1) || undefined;
- }
- /* __GDPR__FRAGMENT__
- "WorkspaceTags" : {
- "workbench.filesToOpenOrCreate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workbench.filesToDiff" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
- "workspace.roots" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.empty" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.grunt" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.gulp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.jake" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.tsconfig" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.jsconfig" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.config.xml" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.vsc.extension" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.asp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.sln" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.unity" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.express" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.sails" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.koa" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.hapi" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.socket.io" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.restify" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.rnpm-plugin-windows" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.react" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.@angular/core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.vue" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.aws-sdk" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.aws-amplify-sdk" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.azure-storage" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.@google-cloud/common" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.firebase" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.npm.heroku-cli" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.bower" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.yeoman.code.ext" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.cordova.high" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.cordova.low" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.xamarin.android" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.xamarin.ios" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.android.cpp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.reactNative" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.ionic" : { "classification" : "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": "true" },
- "workspace.nativeScript" : { "classification" : "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": "true" },
- "workspace.java.pom" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.requirements" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.requirements.star" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.Pipfile" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.conda" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.any-azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-storage-common" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-storage-blob" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-storage-file" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-storage-queue" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-mgmt" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-shell" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.pulumi-azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-cosmos" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-devtools" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-elasticluster" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-eventgrid" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-functions" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-graphrbac" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-keyvault" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-loganalytics" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-monitor" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-servicebus" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-servicefabric" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-storage" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-translator" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-iothub-device-client" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-ml" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.azure-cognitiveservices" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.adal" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.pydocumentdb" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.botbuilder-core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.botbuilder-schema" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
- "workspace.py.botframework-connector" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }
-
- }
- */
- private resolveWorkspaceTags(configuration: IWindowConfiguration, participant?: (rootFiles: string[]) => void): Promise {
- const tags: Tags = Object.create(null);
-
- const state = this.contextService.getWorkbenchState();
- const workspace = this.contextService.getWorkspace();
-
- function createHash(uri: URI): string {
- return crypto.createHash('sha1').update(uri.scheme === Schemas.file ? uri.fsPath : uri.toString()).digest('hex');
- }
-
- let workspaceId: string | undefined;
- switch (state) {
- case WorkbenchState.EMPTY:
- workspaceId = undefined;
- break;
- case WorkbenchState.FOLDER:
- workspaceId = createHash(workspace.folders[0].uri);
- break;
- case WorkbenchState.WORKSPACE:
- if (workspace.configuration) {
- workspaceId = createHash(workspace.configuration);
- }
- }
-
- tags['workspace.id'] = workspaceId;
-
- const { filesToOpenOrCreate, filesToDiff } = configuration;
- tags['workbench.filesToOpenOrCreate'] = filesToOpenOrCreate && filesToOpenOrCreate.length || 0;
- tags['workbench.filesToDiff'] = filesToDiff && filesToDiff.length || 0;
-
- const isEmpty = state === WorkbenchState.EMPTY;
- tags['workspace.roots'] = isEmpty ? 0 : workspace.folders.length;
- tags['workspace.empty'] = isEmpty;
-
- const folders = !isEmpty ? workspace.folders.map(folder => folder.uri) : this.environmentService.appQuality !== 'stable' && this.findFolders(configuration);
- if (!folders || !folders.length || !this.fileService) {
- return Promise.resolve(tags);
- }
-
- return this.fileService.resolveAll(folders.map(resource => ({ resource }))).then((files: IResolveFileResult[]) => {
- const names = ([]).concat(...files.map(result => result.success ? (result.stat!.children || []) : [])).map(c => c.name);
- const nameSet = names.reduce((s, n) => s.add(n.toLowerCase()), new Set());
-
- if (participant) {
- participant(names);
- }
-
- tags['workspace.grunt'] = nameSet.has('gruntfile.js');
- tags['workspace.gulp'] = nameSet.has('gulpfile.js');
- tags['workspace.jake'] = nameSet.has('jakefile.js');
-
- tags['workspace.tsconfig'] = nameSet.has('tsconfig.json');
- tags['workspace.jsconfig'] = nameSet.has('jsconfig.json');
- tags['workspace.config.xml'] = nameSet.has('config.xml');
- tags['workspace.vsc.extension'] = nameSet.has('vsc-extension-quickstart.md');
-
- tags['workspace.ASP5'] = nameSet.has('project.json') && WorkspaceStats.searchArray(names, /^.+\.cs$/i);
- tags['workspace.sln'] = WorkspaceStats.searchArray(names, /^.+\.sln$|^.+\.csproj$/i);
- tags['workspace.unity'] = nameSet.has('assets') && nameSet.has('library') && nameSet.has('projectsettings');
- tags['workspace.npm'] = nameSet.has('package.json') || nameSet.has('node_modules');
- tags['workspace.bower'] = nameSet.has('bower.json') || nameSet.has('bower_components');
-
- tags['workspace.java.pom'] = nameSet.has('pom.xml');
-
- tags['workspace.yeoman.code.ext'] = nameSet.has('vsc-extension-quickstart.md');
-
- tags['workspace.py.requirements'] = nameSet.has('requirements.txt');
- tags['workspace.py.requirements.star'] = WorkspaceStats.searchArray(names, /^(.*)requirements(.*)\.txt$/i);
- tags['workspace.py.Pipfile'] = nameSet.has('pipfile');
- tags['workspace.py.conda'] = WorkspaceStats.searchArray(names, /^environment(\.yml$|\.yaml$)/i);
-
- const mainActivity = nameSet.has('mainactivity.cs') || nameSet.has('mainactivity.fs');
- const appDelegate = nameSet.has('appdelegate.cs') || nameSet.has('appdelegate.fs');
- const androidManifest = nameSet.has('androidmanifest.xml');
-
- const platforms = nameSet.has('platforms');
- const plugins = nameSet.has('plugins');
- const www = nameSet.has('www');
- const properties = nameSet.has('properties');
- const resources = nameSet.has('resources');
- const jni = nameSet.has('jni');
-
- if (tags['workspace.config.xml'] &&
- !tags['workspace.language.cs'] && !tags['workspace.language.vb'] && !tags['workspace.language.aspx']) {
- if (platforms && plugins && www) {
- tags['workspace.cordova.high'] = true;
- } else {
- tags['workspace.cordova.low'] = true;
- }
- }
-
- if (tags['workspace.config.xml'] &&
- !tags['workspace.language.cs'] && !tags['workspace.language.vb'] && !tags['workspace.language.aspx']) {
-
- if (nameSet.has('ionic.config.json')) {
- tags['workspace.ionic'] = true;
- }
- }
-
- if (mainActivity && properties && resources) {
- tags['workspace.xamarin.android'] = true;
- }
-
- if (appDelegate && resources) {
- tags['workspace.xamarin.ios'] = true;
- }
-
- if (androidManifest && jni) {
- tags['workspace.android.cpp'] = true;
- }
-
- function getFilePromises(filename: string, fileService: IFileService, textFileService: ITextFileService, contentHandler: (content: ITextFileContent) => void): Promise[] {
- return !nameSet.has(filename) ? [] : (folders as URI[]).map(workspaceUri => {
- const uri = workspaceUri.with({ path: `${workspaceUri.path !== '/' ? workspaceUri.path : ''}/${filename}` });
- return fileService.exists(uri).then(exists => {
- if (!exists) {
- return undefined;
- }
-
- return textFileService.read(uri, { acceptTextOnly: true }).then(contentHandler);
- }, err => {
- // Ignore missing file
- });
- });
- }
-
- function addPythonTags(packageName: string): void {
- if (PyModulesToLookFor.indexOf(packageName) > -1) {
- tags['workspace.py.' + packageName] = true;
- }
- // cognitive services has a lot of tiny packages. e.g. 'azure-cognitiveservices-search-autosuggest'
- if (packageName.indexOf('azure-cognitiveservices') > -1) {
- tags['workspace.py.azure-cognitiveservices'] = true;
- }
- if (packageName.indexOf('azure-mgmt') > -1) {
- tags['workspace.py.azure-mgmt'] = true;
- }
- if (packageName.indexOf('azure-ml') > -1) {
- tags['workspace.py.azure-ml'] = true;
- }
- if (!tags['workspace.py.any-azure']) {
- tags['workspace.py.any-azure'] = /azure/i.test(packageName);
- }
- }
-
- const requirementsTxtPromises = getFilePromises('requirements.txt', this.fileService, this.textFileService, content => {
- const dependencies: string[] = content.value.split(/\r\n|\r|\n/);
- for (let dependency of dependencies) {
- // Dependencies in requirements.txt can have 3 formats: `foo==3.1, foo>=3.1, foo`
- const format1 = dependency.split('==');
- const format2 = dependency.split('>=');
- const packageName = (format1.length === 2 ? format1[0] : format2[0]).trim();
- addPythonTags(packageName);
- }
- });
-
- const pipfilePromises = getFilePromises('pipfile', this.fileService, this.textFileService, content => {
- let dependencies: string[] = content.value.split(/\r\n|\r|\n/);
-
- // We're only interested in the '[packages]' section of the Pipfile
- dependencies = dependencies.slice(dependencies.indexOf('[packages]') + 1);
-
- for (let dependency of dependencies) {
- if (dependency.trim().indexOf('[') > -1) {
- break;
- }
- // All dependencies in Pipfiles follow the format: ` = `
- if (dependency.indexOf('=') === -1) {
- continue;
- }
- const packageName = dependency.split('=')[0].trim();
- addPythonTags(packageName);
- }
-
- });
-
- const packageJsonPromises = getFilePromises('package.json', this.fileService, this.textFileService, content => {
- try {
- const packageJsonContents = JSON.parse(content.value);
- let dependencies = packageJsonContents['dependencies'];
- let devDependencies = packageJsonContents['devDependencies'];
- for (let module of ModulesToLookFor) {
- if ('react-native' === module) {
- if ((dependencies && dependencies[module]) || (devDependencies && devDependencies[module])) {
- tags['workspace.reactNative'] = true;
- }
- } else if ('tns-core-modules' === module) {
- if ((dependencies && dependencies[module]) || (devDependencies && devDependencies[module])) {
- tags['workspace.nativescript'] = true;
- }
- } else {
- if ((dependencies && dependencies[module]) || (devDependencies && devDependencies[module])) {
- tags['workspace.npm.' + module] = true;
- }
- }
- }
-
- }
- catch (e) {
- // Ignore errors when resolving file or parsing file contents
- }
- });
- return Promise.all([...packageJsonPromises, ...requirementsTxtPromises, ...pipfilePromises]).then(() => tags);
- });
- }
-
- private handleWorkspaceFiles(rootFiles: string[]): void {
- const state = this.contextService.getWorkbenchState();
- const workspace = this.contextService.getWorkspace();
-
- // Handle top-level workspace files for local single folder workspace
- if (state === WorkbenchState.FOLDER) {
- const workspaceFiles = rootFiles.filter(hasWorkspaceFileExtension);
- if (workspaceFiles.length > 0) {
- this.doHandleWorkspaceFiles(workspace.folders[0].uri, workspaceFiles);
- }
- }
- }
-
- private doHandleWorkspaceFiles(folder: URI, workspaces: string[]): void {
- if (this.storageService.getBoolean(WorkspaceStats.DISABLE_WORKSPACE_PROMPT_KEY, StorageScope.WORKSPACE)) {
- return; // prompt disabled by user
- }
-
- const doNotShowAgain: IPromptChoice = {
- label: localize('never again', "Don't Show Again"),
- isSecondary: true,
- run: () => this.storageService.store(WorkspaceStats.DISABLE_WORKSPACE_PROMPT_KEY, true, StorageScope.WORKSPACE)
- };
-
- // Prompt to open one workspace
- if (workspaces.length === 1) {
- const workspaceFile = workspaces[0];
-
- this.notificationService.prompt(Severity.Info, localize('workspaceFound', "This folder contains a workspace file '{0}'. Do you want to open it? [Learn more]({1}) about workspace files.", workspaceFile, 'https://go.microsoft.com/fwlink/?linkid=2025315'), [{
- label: localize('openWorkspace', "Open Workspace"),
- run: () => this.windowService.openWindow([{ workspaceUri: joinPath(folder, workspaceFile) }])
- }, doNotShowAgain]);
- }
-
- // Prompt to select a workspace from many
- else if (workspaces.length > 1) {
- this.notificationService.prompt(Severity.Info, localize('workspacesFound', "This folder contains multiple workspace files. Do you want to open one? [Learn more]({0}) about workspace files.", 'https://go.microsoft.com/fwlink/?linkid=2025315'), [{
- label: localize('selectWorkspace', "Select Workspace"),
- run: () => {
- this.quickInputService.pick(
- workspaces.map(workspace => ({ label: workspace } as IQuickPickItem)),
- { placeHolder: localize('selectToOpen', "Select a workspace to open") }).then(pick => {
- if (pick) {
- this.windowService.openWindow([{ workspaceUri: joinPath(folder, pick.label) }]);
- }
- });
- }
- }, doNotShowAgain]);
- }
- }
-
- private findFolders(configuration: IWindowConfiguration): URI[] | undefined {
- const folder = this.findFolder(configuration);
- return folder && [folder];
- }
-
- private findFolder({ filesToOpenOrCreate, filesToDiff }: IWindowConfiguration): URI | undefined {
- if (filesToOpenOrCreate && filesToOpenOrCreate.length) {
- return this.parentURI(filesToOpenOrCreate[0].fileUri);
- } else if (filesToDiff && filesToDiff.length) {
- return this.parentURI(filesToDiff[0].fileUri);
- }
- return undefined;
- }
-
- private parentURI(uri: URI | undefined): URI | undefined {
- if (!uri) {
- return undefined;
- }
- const path = uri.path;
- const i = path.lastIndexOf('/');
- return i !== -1 ? uri.with({ path: path.substr(0, i) }) : undefined;
- }
private reportWorkspaceTags(tags: Tags): void {
/* __GDPR__
@@ -622,7 +189,6 @@ export class WorkspaceStats implements IWorkbenchContribution {
}
*/
this.telemetryService.publicLog('workspce.tags', tags);
- WorkspaceStats.TAGS = tags;
}
private reportRemoteDomains(workspaceUris: URI[]): void {
@@ -689,6 +255,10 @@ export class WorkspaceStats implements IWorkbenchContribution {
});
}
+ private static searchArray(arr: string[], regEx: RegExp): boolean | undefined {
+ return arr.some(v => v.search(regEx) > -1) || undefined;
+ }
+
/* __GDPR__FRAGMENT__
"AzureTags" : {
"java" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }
diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts
new file mode 100644
index 0000000000..18be93ac57
--- /dev/null
+++ b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts
@@ -0,0 +1,477 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the Source EULA. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import * as crypto from 'crypto';
+import { IFileService, IResolveFileResult, IFileStat } from 'vs/platform/files/common/files';
+import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
+import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
+import { IWindowService, IWindowConfiguration } from 'vs/platform/windows/common/windows';
+import { INotificationService, IPromptChoice } from 'vs/platform/notification/common/notification';
+import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
+import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
+import { ITextFileService, ITextFileContent } from 'vs/workbench/services/textfile/common/textfiles';
+import { URI } from 'vs/base/common/uri';
+import { Schemas } from 'vs/base/common/network';
+import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
+import { localize } from 'vs/nls';
+import Severity from 'vs/base/common/severity';
+import { joinPath } from 'vs/base/common/resources';
+import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
+
+export type Tags = { [index: string]: boolean | number | string | undefined };
+
+const DISABLE_WORKSPACE_PROMPT_KEY = 'workspaces.dontPromptToOpen';
+
+const ModulesToLookFor = [
+ // Packages that suggest a node server
+ 'express',
+ 'sails',
+ 'koa',
+ 'hapi',
+ 'socket.io',
+ 'restify',
+ // JS frameworks
+ 'react',
+ 'react-native',
+ 'rnpm-plugin-windows',
+ '@angular/core',
+ '@ionic',
+ 'vue',
+ 'tns-core-modules',
+ // Other interesting packages
+ 'aws-sdk',
+ 'aws-amplify',
+ 'azure',
+ 'azure-storage',
+ 'firebase',
+ '@google-cloud/common',
+ 'heroku-cli'
+];
+const PyModulesToLookFor = [
+ 'azure',
+ 'azure-storage-common',
+ 'azure-storage-blob',
+ 'azure-storage-file',
+ 'azure-storage-queue',
+ 'azure-shell',
+ 'azure-cosmos',
+ 'azure-devtools',
+ 'azure-elasticluster',
+ 'azure-eventgrid',
+ 'azure-functions',
+ 'azure-graphrbac',
+ 'azure-keyvault',
+ 'azure-loganalytics',
+ 'azure-monitor',
+ 'azure-servicebus',
+ 'azure-servicefabric',
+ 'azure-storage',
+ 'azure-translator',
+ 'azure-iothub-device-client',
+ 'adal',
+ 'pydocumentdb',
+ 'botbuilder-core',
+ 'botbuilder-schema',
+ 'botframework-connector'
+];
+
+export const IWorkspaceStatsService = createDecorator('workspaceStatsService');
+
+export interface IWorkspaceStatsService {
+ _serviceBrand: any;
+ getTags(): Promise;
+}
+
+
+export class WorkspaceStatsService implements IWorkspaceStatsService {
+ _serviceBrand: any;
+ private _tags: Tags;
+
+ constructor(
+ @IFileService private readonly fileService: IFileService,
+ @IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
+ @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
+ @IWindowService private readonly windowService: IWindowService,
+ @INotificationService private readonly notificationService: INotificationService,
+ @IQuickInputService private readonly quickInputService: IQuickInputService,
+ @IStorageService private readonly storageService: IStorageService,
+ @ITextFileService private readonly textFileService: ITextFileService
+ ) { }
+
+ public async getTags(): Promise {
+ if (!this._tags) {
+ this._tags = await this.resolveWorkspaceTags(this.environmentService.configuration, rootFiles => this.handleWorkspaceFiles(rootFiles));
+ }
+
+ return this._tags;
+ }
+
+ /* __GDPR__FRAGMENT__
+ "WorkspaceTags" : {
+ "workbench.filesToOpenOrCreate" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workbench.filesToDiff" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
+ "workspace.roots" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.empty" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.grunt" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.gulp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.jake" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.tsconfig" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.jsconfig" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.config.xml" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.vsc.extension" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.asp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.sln" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.unity" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.express" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.sails" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.koa" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.hapi" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.socket.io" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.restify" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.rnpm-plugin-windows" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.react" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.@angular/core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.vue" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.aws-sdk" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.aws-amplify-sdk" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.azure-storage" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.@google-cloud/common" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.firebase" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.npm.heroku-cli" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.bower" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.yeoman.code.ext" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.cordova.high" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.cordova.low" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.xamarin.android" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.xamarin.ios" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.android.cpp" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.reactNative" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.ionic" : { "classification" : "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": "true" },
+ "workspace.nativeScript" : { "classification" : "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": "true" },
+ "workspace.java.pom" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.requirements" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.requirements.star" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.Pipfile" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.conda" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.any-azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-storage-common" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-storage-blob" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-storage-file" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-storage-queue" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-mgmt" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-shell" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.pulumi-azure" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-cosmos" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-devtools" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-elasticluster" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-eventgrid" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-functions" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-graphrbac" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-keyvault" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-loganalytics" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-monitor" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-servicebus" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-servicefabric" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-storage" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-translator" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-iothub-device-client" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-ml" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.azure-cognitiveservices" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.adal" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.pydocumentdb" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.botbuilder-core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.botbuilder-schema" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true },
+ "workspace.py.botframework-connector" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }
+
+ }
+ */
+ private resolveWorkspaceTags(configuration: IWindowConfiguration, participant?: (rootFiles: string[]) => void): Promise {
+ const tags: Tags = Object.create(null);
+
+ const state = this.contextService.getWorkbenchState();
+ const workspace = this.contextService.getWorkspace();
+
+ function createHash(uri: URI): string {
+ return crypto.createHash('sha1').update(uri.scheme === Schemas.file ? uri.fsPath : uri.toString()).digest('hex');
+ }
+
+ let workspaceId: string | undefined;
+ switch (state) {
+ case WorkbenchState.EMPTY:
+ workspaceId = undefined;
+ break;
+ case WorkbenchState.FOLDER:
+ workspaceId = createHash(workspace.folders[0].uri);
+ break;
+ case WorkbenchState.WORKSPACE:
+ if (workspace.configuration) {
+ workspaceId = createHash(workspace.configuration);
+ }
+ }
+
+ tags['workspace.id'] = workspaceId;
+
+ const { filesToOpenOrCreate, filesToDiff } = configuration;
+ tags['workbench.filesToOpenOrCreate'] = filesToOpenOrCreate && filesToOpenOrCreate.length || 0;
+ tags['workbench.filesToDiff'] = filesToDiff && filesToDiff.length || 0;
+
+ const isEmpty = state === WorkbenchState.EMPTY;
+ tags['workspace.roots'] = isEmpty ? 0 : workspace.folders.length;
+ tags['workspace.empty'] = isEmpty;
+
+ const folders = !isEmpty ? workspace.folders.map(folder => folder.uri) : this.environmentService.appQuality !== 'stable' && this.findFolders(configuration);
+ if (!folders || !folders.length || !this.fileService) {
+ return Promise.resolve(tags);
+ }
+
+ return this.fileService.resolveAll(folders.map(resource => ({ resource }))).then((files: IResolveFileResult[]) => {
+ const names = ([]).concat(...files.map(result => result.success ? (result.stat!.children || []) : [])).map(c => c.name);
+ const nameSet = names.reduce((s, n) => s.add(n.toLowerCase()), new Set());
+
+ if (participant) {
+ participant(names);
+ }
+
+ tags['workspace.grunt'] = nameSet.has('gruntfile.js');
+ tags['workspace.gulp'] = nameSet.has('gulpfile.js');
+ tags['workspace.jake'] = nameSet.has('jakefile.js');
+
+ tags['workspace.tsconfig'] = nameSet.has('tsconfig.json');
+ tags['workspace.jsconfig'] = nameSet.has('jsconfig.json');
+ tags['workspace.config.xml'] = nameSet.has('config.xml');
+ tags['workspace.vsc.extension'] = nameSet.has('vsc-extension-quickstart.md');
+
+ tags['workspace.ASP5'] = nameSet.has('project.json') && this.searchArray(names, /^.+\.cs$/i);
+ tags['workspace.sln'] = this.searchArray(names, /^.+\.sln$|^.+\.csproj$/i);
+ tags['workspace.unity'] = nameSet.has('assets') && nameSet.has('library') && nameSet.has('projectsettings');
+ tags['workspace.npm'] = nameSet.has('package.json') || nameSet.has('node_modules');
+ tags['workspace.bower'] = nameSet.has('bower.json') || nameSet.has('bower_components');
+
+ tags['workspace.java.pom'] = nameSet.has('pom.xml');
+
+ tags['workspace.yeoman.code.ext'] = nameSet.has('vsc-extension-quickstart.md');
+
+ tags['workspace.py.requirements'] = nameSet.has('requirements.txt');
+ tags['workspace.py.requirements.star'] = this.searchArray(names, /^(.*)requirements(.*)\.txt$/i);
+ tags['workspace.py.Pipfile'] = nameSet.has('pipfile');
+ tags['workspace.py.conda'] = this.searchArray(names, /^environment(\.yml$|\.yaml$)/i);
+
+ const mainActivity = nameSet.has('mainactivity.cs') || nameSet.has('mainactivity.fs');
+ const appDelegate = nameSet.has('appdelegate.cs') || nameSet.has('appdelegate.fs');
+ const androidManifest = nameSet.has('androidmanifest.xml');
+
+ const platforms = nameSet.has('platforms');
+ const plugins = nameSet.has('plugins');
+ const www = nameSet.has('www');
+ const properties = nameSet.has('properties');
+ const resources = nameSet.has('resources');
+ const jni = nameSet.has('jni');
+
+ if (tags['workspace.config.xml'] &&
+ !tags['workspace.language.cs'] && !tags['workspace.language.vb'] && !tags['workspace.language.aspx']) {
+ if (platforms && plugins && www) {
+ tags['workspace.cordova.high'] = true;
+ } else {
+ tags['workspace.cordova.low'] = true;
+ }
+ }
+
+ if (tags['workspace.config.xml'] &&
+ !tags['workspace.language.cs'] && !tags['workspace.language.vb'] && !tags['workspace.language.aspx']) {
+
+ if (nameSet.has('ionic.config.json')) {
+ tags['workspace.ionic'] = true;
+ }
+ }
+
+ if (mainActivity && properties && resources) {
+ tags['workspace.xamarin.android'] = true;
+ }
+
+ if (appDelegate && resources) {
+ tags['workspace.xamarin.ios'] = true;
+ }
+
+ if (androidManifest && jni) {
+ tags['workspace.android.cpp'] = true;
+ }
+
+ function getFilePromises(filename: string, fileService: IFileService, textFileService: ITextFileService, contentHandler: (content: ITextFileContent) => void): Promise[] {
+ return !nameSet.has(filename) ? [] : (folders as URI[]).map(workspaceUri => {
+ const uri = workspaceUri.with({ path: `${workspaceUri.path !== '/' ? workspaceUri.path : ''}/${filename}` });
+ return fileService.exists(uri).then(exists => {
+ if (!exists) {
+ return undefined;
+ }
+
+ return textFileService.read(uri, { acceptTextOnly: true }).then(contentHandler);
+ }, err => {
+ // Ignore missing file
+ });
+ });
+ }
+
+ function addPythonTags(packageName: string): void {
+ if (PyModulesToLookFor.indexOf(packageName) > -1) {
+ tags['workspace.py.' + packageName] = true;
+ }
+ // cognitive services has a lot of tiny packages. e.g. 'azure-cognitiveservices-search-autosuggest'
+ if (packageName.indexOf('azure-cognitiveservices') > -1) {
+ tags['workspace.py.azure-cognitiveservices'] = true;
+ }
+ if (packageName.indexOf('azure-mgmt') > -1) {
+ tags['workspace.py.azure-mgmt'] = true;
+ }
+ if (packageName.indexOf('azure-ml') > -1) {
+ tags['workspace.py.azure-ml'] = true;
+ }
+ if (!tags['workspace.py.any-azure']) {
+ tags['workspace.py.any-azure'] = /azure/i.test(packageName);
+ }
+ }
+
+ const requirementsTxtPromises = getFilePromises('requirements.txt', this.fileService, this.textFileService, content => {
+ const dependencies: string[] = content.value.split(/\r\n|\r|\n/);
+ for (let dependency of dependencies) {
+ // Dependencies in requirements.txt can have 3 formats: `foo==3.1, foo>=3.1, foo`
+ const format1 = dependency.split('==');
+ const format2 = dependency.split('>=');
+ const packageName = (format1.length === 2 ? format1[0] : format2[0]).trim();
+ addPythonTags(packageName);
+ }
+ });
+
+ const pipfilePromises = getFilePromises('pipfile', this.fileService, this.textFileService, content => {
+ let dependencies: string[] = content.value.split(/\r\n|\r|\n/);
+
+ // We're only interested in the '[packages]' section of the Pipfile
+ dependencies = dependencies.slice(dependencies.indexOf('[packages]') + 1);
+
+ for (let dependency of dependencies) {
+ if (dependency.trim().indexOf('[') > -1) {
+ break;
+ }
+ // All dependencies in Pipfiles follow the format: ` = `
+ if (dependency.indexOf('=') === -1) {
+ continue;
+ }
+ const packageName = dependency.split('=')[0].trim();
+ addPythonTags(packageName);
+ }
+
+ });
+
+ const packageJsonPromises = getFilePromises('package.json', this.fileService, this.textFileService, content => {
+ try {
+ const packageJsonContents = JSON.parse(content.value);
+ let dependencies = packageJsonContents['dependencies'];
+ let devDependencies = packageJsonContents['devDependencies'];
+ for (let module of ModulesToLookFor) {
+ if ('react-native' === module) {
+ if ((dependencies && dependencies[module]) || (devDependencies && devDependencies[module])) {
+ tags['workspace.reactNative'] = true;
+ }
+ } else if ('tns-core-modules' === module) {
+ if ((dependencies && dependencies[module]) || (devDependencies && devDependencies[module])) {
+ tags['workspace.nativescript'] = true;
+ }
+ } else {
+ if ((dependencies && dependencies[module]) || (devDependencies && devDependencies[module])) {
+ tags['workspace.npm.' + module] = true;
+ }
+ }
+ }
+
+ }
+ catch (e) {
+ // Ignore errors when resolving file or parsing file contents
+ }
+ });
+ return Promise.all([...packageJsonPromises, ...requirementsTxtPromises, ...pipfilePromises]).then(() => tags);
+ });
+ }
+
+ private handleWorkspaceFiles(rootFiles: string[]): void {
+ const state = this.contextService.getWorkbenchState();
+ const workspace = this.contextService.getWorkspace();
+
+ // Handle top-level workspace files for local single folder workspace
+ if (state === WorkbenchState.FOLDER) {
+ const workspaceFiles = rootFiles.filter(hasWorkspaceFileExtension);
+ if (workspaceFiles.length > 0) {
+ this.doHandleWorkspaceFiles(workspace.folders[0].uri, workspaceFiles);
+ }
+ }
+ }
+
+ private doHandleWorkspaceFiles(folder: URI, workspaces: string[]): void {
+ if (this.storageService.getBoolean(DISABLE_WORKSPACE_PROMPT_KEY, StorageScope.WORKSPACE)) {
+ return; // prompt disabled by user
+ }
+
+ const doNotShowAgain: IPromptChoice = {
+ label: localize('never again', "Don't Show Again"),
+ isSecondary: true,
+ run: () => this.storageService.store(DISABLE_WORKSPACE_PROMPT_KEY, true, StorageScope.WORKSPACE)
+ };
+
+ // Prompt to open one workspace
+ if (workspaces.length === 1) {
+ const workspaceFile = workspaces[0];
+
+ this.notificationService.prompt(Severity.Info, localize('workspaceFound', "This folder contains a workspace file '{0}'. Do you want to open it? [Learn more]({1}) about workspace files.", workspaceFile, 'https://go.microsoft.com/fwlink/?linkid=2025315'), [{
+ label: localize('openWorkspace', "Open Workspace"),
+ run: () => this.windowService.openWindow([{ workspaceUri: joinPath(folder, workspaceFile) }])
+ }, doNotShowAgain]);
+ }
+
+ // Prompt to select a workspace from many
+ else if (workspaces.length > 1) {
+ this.notificationService.prompt(Severity.Info, localize('workspacesFound', "This folder contains multiple workspace files. Do you want to open one? [Learn more]({0}) about workspace files.", 'https://go.microsoft.com/fwlink/?linkid=2025315'), [{
+ label: localize('selectWorkspace', "Select Workspace"),
+ run: () => {
+ this.quickInputService.pick(
+ workspaces.map(workspace => ({ label: workspace } as IQuickPickItem)),
+ { placeHolder: localize('selectToOpen', "Select a workspace to open") }).then(pick => {
+ if (pick) {
+ this.windowService.openWindow([{ workspaceUri: joinPath(folder, pick.label) }]);
+ }
+ });
+ }
+ }, doNotShowAgain]);
+ }
+ }
+
+ private findFolders(configuration: IWindowConfiguration): URI[] | undefined {
+ const folder = this.findFolder(configuration);
+ return folder && [folder];
+ }
+
+ private findFolder({ filesToOpenOrCreate, filesToDiff }: IWindowConfiguration): URI | undefined {
+ if (filesToOpenOrCreate && filesToOpenOrCreate.length) {
+ return this.parentURI(filesToOpenOrCreate[0].fileUri);
+ } else if (filesToDiff && filesToDiff.length) {
+ return this.parentURI(filesToDiff[0].fileUri);
+ }
+ return undefined;
+ }
+
+ private parentURI(uri: URI | undefined): URI | undefined {
+ if (!uri) {
+ return undefined;
+ }
+ const path = uri.path;
+ const i = path.lastIndexOf('/');
+ return i !== -1 ? uri.with({ path: path.substr(0, i) }) : undefined;
+ }
+
+ private searchArray(arr: string[], regEx: RegExp): boolean | undefined {
+ return arr.some(v => v.search(regEx) > -1) || undefined;
+ }
+}
\ No newline at end of file
diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts
index 3841104125..b460eeaf33 100644
--- a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts
+++ b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts
@@ -9,6 +9,7 @@ import { IEditorModel } from 'vs/platform/editor/common/editor';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { EditorInput, EditorModel, GroupIdentifier, IEditorInput } from 'vs/workbench/common/editor';
import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/common/webview';
+import { UnownedDisposable as Unowned } from 'vs/base/common/lifecycle';
class WebviewIconsManager {
private readonly _icons = new Map();
@@ -58,6 +59,7 @@ export class WebviewEditorInput extends EditorInput {
private _name: string;
private _iconPath?: { light: URI, dark: URI };
private _group?: GroupIdentifier;
+ private readonly _webview: WebviewEditorOverlay;
constructor(
public readonly id: string,
@@ -67,14 +69,14 @@ export class WebviewEditorInput extends EditorInput {
readonly location: URI;
readonly id: ExtensionIdentifier;
},
- public readonly webview: WebviewEditorOverlay,
+ webview: Unowned,
) {
super();
this._name = name;
this.extension = extension;
- this._register(webview); // The input owns this webview
+ this._webview = this._register(webview.acquire()); // The input owns this webview
}
public getTypeId(): string {
@@ -105,6 +107,10 @@ export class WebviewEditorInput extends EditorInput {
this._onDidChangeLabel.fire();
}
+ public get webview() {
+ return this._webview;
+ }
+
public get iconPath() {
return this._iconPath;
}
@@ -147,7 +153,7 @@ export class RevivedWebviewEditorInput extends WebviewEditorInput {
readonly id: ExtensionIdentifier
},
private readonly reviver: (input: WebviewEditorInput) => Promise,
- webview: WebviewEditorOverlay,
+ webview: Unowned,
) {
super(id, viewType, name, extension, webview);
}
diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts
index 6d3731fb80..085d9b45dc 100644
--- a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts
+++ b/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { equals } from 'vs/base/common/arrays';
-import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
+import { IDisposable, toDisposable, UnownedDisposable } from 'vs/base/common/lifecycle';
import { values } from 'vs/base/common/map';
import { URI } from 'vs/base/common/uri';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
@@ -144,7 +144,7 @@ export class WebviewEditorService implements IWebviewEditorService {
): WebviewEditorInput {
const webview = this.createWebiew(id, extension, options);
- const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, id, viewType, title, extension, webview);
+ const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, id, viewType, title, extension, new UnownedDisposable(webview));
this._editorService.openEditor(webviewInput, { pinned: true, preserveFocus: showOptions.preserveFocus }, showOptions.group);
return webviewInput;
}
@@ -191,7 +191,7 @@ export class WebviewEditorService implements IWebviewEditorService {
const promise = new Promise(r => { resolve = r; });
this._revivalPool.add(webview, resolve!);
return promise;
- }, webview);
+ }, new UnownedDisposable(webview));
webviewInput.iconPath = iconPath;
diff --git a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts
index 9280fb48bf..7700987a66 100644
--- a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts
+++ b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts
@@ -237,6 +237,13 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe
}
return getFilePath();
+ case 'relativeFileDirname':
+ let dirname = paths.dirname(getFilePath());
+ if (folderUri) {
+ return paths.normalize(paths.relative(getFolderUri().fsPath, dirname));
+ }
+ return dirname;
+
case 'fileDirname':
return paths.dirname(getFilePath());
diff --git a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts
index b1302e920d..9809ef95a4 100644
--- a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts
+++ b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts
@@ -221,7 +221,7 @@ export class FileDialogService implements IFileDialogService {
const schema = this.getFileSystemSchema(options);
if (this.shouldUseSimplified(schema)) {
if (!options.availableFileSystems) {
- options.availableFileSystems = [schema]; // by default only allow saving in the own file system
+ options.availableFileSystems = this.ensureFileSchema(schema); // always allow file as well
}
return this.saveRemoteResource(options);
@@ -239,7 +239,7 @@ export class FileDialogService implements IFileDialogService {
const schema = this.getFileSystemSchema(options);
if (this.shouldUseSimplified(schema)) {
if (!options.availableFileSystems) {
- options.availableFileSystems = [schema]; // by default only allow loading in the own file system
+ options.availableFileSystems = this.ensureFileSchema(schema); // always allow file as well
}
const uri = await this.pickRemoteResource(options);
diff --git a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts
index fad4872759..93b1c12748 100644
--- a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts
+++ b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts
@@ -14,7 +14,7 @@ import { ExtHostCustomersRegistry } from 'vs/workbench/api/common/extHostCustome
import { ExtHostContext, ExtHostExtensionServiceShape, IExtHostContext, MainContext } from 'vs/workbench/api/common/extHost.protocol';
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
import { IRPCProtocolLogger, RPCProtocol, RequestInitiator, ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol';
-import { ResolvedAuthority, RemoteAuthorityResolverError } from 'vs/platform/remote/common/remoteAuthorityResolver';
+import { RemoteAuthorityResolverError, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import * as nls from 'vs/nls';
import { Action } from 'vs/base/common/actions';
@@ -249,15 +249,17 @@ export class ExtensionHostProcessManager extends Disposable {
return this._extensionHostProcessWorker && Boolean(this._extensionHostProcessWorker.getInspectPort());
}
- public async resolveAuthority(remoteAuthority: string): Promise {
+ public async resolveAuthority(remoteAuthority: string): Promise {
const authorityPlusIndex = remoteAuthority.indexOf('+');
if (authorityPlusIndex === -1) {
// This authority does not need to be resolved, simply parse the port number
const pieces = remoteAuthority.split(':');
return Promise.resolve({
- authority: remoteAuthority,
- host: pieces[0],
- port: parseInt(pieces[1], 10)
+ authority: {
+ authority: remoteAuthority,
+ host: pieces[0],
+ port: parseInt(pieces[1], 10)
+ }
});
}
const proxy = await this._getExtensionHostProcessProxy();
diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts
index 9c4bf65afb..434c78f21f 100644
--- a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts
+++ b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts
@@ -76,19 +76,20 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH
webSocketFactory: this._webSocketFactory,
addressProvider: {
getAddress: async () => {
- const { host, port } = await this.remoteAuthorityResolverService.resolveAuthority(this._initDataProvider.remoteAuthority);
- return { host, port };
+ const { authority } = await this.remoteAuthorityResolverService.resolveAuthority(this._initDataProvider.remoteAuthority);
+ return { host: authority.host, port: authority.port };
}
},
signService: this._signService
};
- return this.remoteAuthorityResolverService.resolveAuthority(this._initDataProvider.remoteAuthority).then((resolvedAuthority) => {
+ return this.remoteAuthorityResolverService.resolveAuthority(this._initDataProvider.remoteAuthority).then((resolverResult) => {
const startParams: IRemoteExtensionHostStartParams = {
language: platform.language,
debugId: this._environmentService.debugExtensionHost.debugId,
break: this._environmentService.debugExtensionHost.break,
port: this._environmentService.debugExtensionHost.port,
+ env: resolverResult.options && resolverResult.options.extensionHostEnv
};
const extDevLocs = this._environmentService.extensionDevelopmentLocationURI;
diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts
index ea2c188a24..87cd720218 100644
--- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts
+++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts
@@ -19,7 +19,7 @@ import { IExtensionEnablementService } from 'vs/workbench/services/extensionMana
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IInitDataProvider, RemoteExtensionHostClient } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
-import { IRemoteAuthorityResolverService, ResolvedAuthority, RemoteAuthorityResolverError } from 'vs/platform/remote/common/remoteAuthorityResolver';
+import { IRemoteAuthorityResolverService, RemoteAuthorityResolverError, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil';
import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -424,8 +424,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten
const extensionHost = this._extensionHostProcessManagers[0];
this._remoteAuthorityResolverService.clearResolvedAuthority(remoteAuthority);
try {
- const resolvedAuthority = await extensionHost.resolveAuthority(remoteAuthority);
- this._remoteAuthorityResolverService.setResolvedAuthority(resolvedAuthority);
+ const result = await extensionHost.resolveAuthority(remoteAuthority);
+ this._remoteAuthorityResolverService.setResolvedAuthority(result.authority, result.options);
} catch (err) {
this._remoteAuthorityResolverService.setResolvedAuthorityError(remoteAuthority, err);
}
@@ -446,7 +446,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
localExtensions = localExtensions.filter(extension => this._isEnabled(extension));
if (remoteAuthority) {
- let resolvedAuthority: ResolvedAuthority;
+ let resolvedAuthority: ResolverResult;
try {
resolvedAuthority = await extensionHost.resolveAuthority(remoteAuthority);
@@ -468,7 +468,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten
}
// set the resolved authority
- this._remoteAuthorityResolverService.setResolvedAuthority(resolvedAuthority);
+ this._remoteAuthorityResolverService.setResolvedAuthority(resolvedAuthority.authority, resolvedAuthority.options);
// monitor for breakage
const connection = this._remoteAgentService.getConnection();
diff --git a/src/vs/workbench/services/keybinding/test/browserKeyboardMapper.test.ts b/src/vs/workbench/services/keybinding/test/browserKeyboardMapper.test.ts
index 9d66817e23..eeb15b5d53 100644
--- a/src/vs/workbench/services/keybinding/test/browserKeyboardMapper.test.ts
+++ b/src/vs/workbench/services/keybinding/test/browserKeyboardMapper.test.ts
@@ -12,33 +12,39 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/
import { INotificationService } from 'vs/platform/notification/common/notification';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IStorageService } from 'vs/platform/storage/common/storage';
+import { TestStorageService } from 'vs/workbench/test/workbenchTestServices';
+import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
class TestKeyboardMapperFactory extends BrowserKeyboardMapperFactoryBase {
constructor(notificationService: INotificationService, storageService: IStorageService, commandService: ICommandService) {
super(notificationService, storageService, commandService);
- let keymapInfos: IKeymapInfo[] = KeyboardLayoutContribution.INSTANCE.layoutInfos;
+ const keymapInfos: IKeymapInfo[] = KeyboardLayoutContribution.INSTANCE.layoutInfos;
this._keymapInfos.push(...keymapInfos.map(info => (new KeymapInfo(info.layout, info.secondaryLayouts, info.mapping, info.isUserKeyboardLayout))));
this._mru = this._keymapInfos;
this._initialized = true;
this.onKeyboardLayoutChanged();
+ const usLayout = this.getUSStandardLayout();
+ if (usLayout) {
+ this.setActiveKeyMapping(usLayout.mapping);
+ }
}
}
-
suite('keyboard layout loader', () => {
let instantiationService: TestInstantiationService = new TestInstantiationService();
- let notitifcationService = instantiationService.stub(INotificationService, {});
- let storageService = instantiationService.stub(IStorageService, {});
+ let notitifcationService = instantiationService.stub(INotificationService, new TestNotificationService());
+ let storageService = instantiationService.stub(IStorageService, new TestStorageService());
+
let commandService = instantiationService.stub(ICommandService, {});
let instance = new TestKeyboardMapperFactory(notitifcationService, storageService, commandService);
- test.skip('load default US keyboard layout', () => {
+ test('load default US keyboard layout', () => {
assert.notEqual(instance.activeKeyboardLayout, null);
assert.equal(instance.activeKeyboardLayout!.isUSStandard, true);
});
- test.skip('isKeyMappingActive', () => {
+ test('isKeyMappingActive', () => {
assert.equal(instance.isKeyMappingActive({
KeyA: {
value: 'a',
diff --git a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts
index 0db97264ba..16faf5df17 100644
--- a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts
+++ b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts
@@ -121,8 +121,8 @@ export class RemoteAgentConnection extends Disposable implements IRemoteAgentCon
} else {
this._onReconnecting.fire(undefined);
}
- const { host, port } = await this._remoteAuthorityResolverService.resolveAuthority(this.remoteAuthority);
- return { host, port };
+ const { authority } = await this._remoteAuthorityResolverService.resolveAuthority(this.remoteAuthority);
+ return { host: authority.host, port: authority.port };
}
},
signService: this._signService
diff --git a/src/vs/workbench/services/remote/node/tunnelService.ts b/src/vs/workbench/services/remote/node/tunnelService.ts
index ed6caeb7e5..4251b35597 100644
--- a/src/vs/workbench/services/remote/node/tunnelService.ts
+++ b/src/vs/workbench/services/remote/node/tunnelService.ts
@@ -105,8 +105,8 @@ export class TunnelService implements ITunnelService {
webSocketFactory: nodeWebSocketFactory,
addressProvider: {
getAddress: async () => {
- const { host, port } = await this.remoteAuthorityResolverService.resolveAuthority(remoteAuthority);
- return { host, port };
+ const { authority } = await this.remoteAuthorityResolverService.resolveAuthority(remoteAuthority);
+ return { host: authority.host, port: authority.port };
}
},
signService: this.signService
diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts
index d4bae700c1..55aee3699b 100644
--- a/src/vs/workbench/workbench.main.ts
+++ b/src/vs/workbench/workbench.main.ts
@@ -168,6 +168,7 @@ registerSingleton(IMenubarService, MenubarService);
registerSingleton(IURLService, RelayURLService);
registerSingleton(ITunnelService, TunnelService, true);
registerSingleton(ICredentialsService, KeytarCredentialsService, true);
+registerSingleton(IWorkspaceStatsService, WorkspaceStatsService, true);
//#endregion
@@ -456,6 +457,7 @@ import 'vs/workbench/contrib/experiments/electron-browser/experiments.contributi
// Issues
import 'vs/workbench/contrib/issue/electron-browser/issue.contribution';
+import { IWorkspaceStatsService, WorkspaceStatsService } from 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService';
// {{SQL CARBON EDIT}}
// SQL
diff --git a/yarn.lock b/yarn.lock
index 3751bf6d8d..aa68c2eb4a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9902,10 +9902,10 @@ vscode-proxy-agent@0.4.0:
https-proxy-agent "2.2.1"
socks-proxy-agent "4.0.1"
-vscode-ripgrep@^1.5.4:
- version "1.5.4"
- resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.4.tgz#dae1c3eef350513299341cdf96e622c00b548eff"
- integrity sha512-Bs8SvFAkR0QHf09J46VgNo19yRikOtj/f0zHzK3AM3ICjCGNN/BNoG9of6zGVHUTO+6Mk1RbKglyOHLKr8D1lg==
+vscode-ripgrep@^1.5.5:
+ version "1.5.5"
+ resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.5.tgz#24c0e9cb356cf889c98e15ecb58f9cf654a1d961"
+ integrity sha512-OrPrAmcun4+uZAuNcQvE6CCPskh+5AsjANod/Q3zRcJcGNxgoOSGlQN9RPtatkUNmkN8Nn8mZBnS1jMylu/dKg==
vscode-sqlite3@4.0.8:
version "4.0.8"