diff --git a/.github/classifier.yml b/.github/classifier.yml index 52f6da98912..348242d802a 100644 --- a/.github/classifier.yml +++ b/.github/classifier.yml @@ -7,7 +7,7 @@ api: [], css-less-sass: [], debug: [ isidorn ], - editor: [ alexandrudima ], + editor: [], editor-brackets: [], editor-clipboard: [ rebornix ], editor-colors: [], @@ -39,7 +39,7 @@ php: [ roblourens ], search: [ roblourens ], snippets: [ jrieken ], - tasks: [], + tasks: [ dbaeumer ], typescript: [ mjbvz ], workbench: [ bpasero, isidorn, sandy081] } diff --git a/.github/new_release.yml b/.github/new_release.yml index fae254fcc8a..3877cb6f8a2 100644 --- a/.github/new_release.yml +++ b/.github/new_release.yml @@ -1,5 +1,5 @@ { newReleaseLabel: 'new release', - newReleases: ['1.16'], - perform: false + newReleases: ['1.17'], + perform: true } \ No newline at end of file diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index fe31d24cb18..9f7088b945e 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -45,8 +45,8 @@ const nodeModules = ['electron', 'original-fs'] // Build const builtInExtensions = [ - { name: 'ms-vscode.node-debug', version: '1.17.17' }, - { name: 'ms-vscode.node-debug2', version: '1.17.6' } + { name: 'ms-vscode.node-debug', version: '1.17.18' }, + { name: 'ms-vscode.node-debug2', version: '1.18.1' } ]; const excludedExtensions = [ diff --git a/build/monaco/package.json b/build/monaco/package.json index 4cc3beb09b8..db28b0b9287 100644 --- a/build/monaco/package.json +++ b/build/monaco/package.json @@ -13,10 +13,10 @@ "url": "https://github.com/Microsoft/vscode/issues" }, "devDependencies": { - "@types/minimist": "^1.2.0", - "@types/mocha": "^2.2.39", - "@types/semver": "^5.3.30", - "@types/sinon": "^1.16.34", + "@types/minimist": "1.2.0", + "@types/mocha": "2.2.39", + "@types/semver": "5.3.30", + "@types/sinon": "1.16.34", "debounce": "^1.0.0", "eslint": "^3.4.0", "event-stream": "^3.1.7", diff --git a/build/package.json b/build/package.json index d94f9aad64a..cebb65f3d42 100644 --- a/build/package.json +++ b/build/package.json @@ -2,13 +2,13 @@ "name": "code-oss-dev-build", "version": "1.0.0", "devDependencies": { - "@types/azure": "^0.9.18", - "@types/documentdb": "^1.10.1", - "@types/es6-collections": "^0.5.30", - "@types/es6-promise": "0.0.32", + "@types/azure": "0.9.19", + "@types/documentdb": "1.10.2", + "@types/es6-collections": "0.5.31", + "@types/es6-promise": "0.0.33", "@types/mime": "0.0.29", - "@types/node": "^7.0.13", - "@types/xml2js": "^0.0.33", + "@types/node": "8.0.33", + "@types/xml2js": "0.0.33", "azure-storage": "^2.1.0", "documentdb": "^1.11.0", "mime": "^1.3.4", diff --git a/build/tfs/common/common.sh b/build/tfs/common/common.sh index cdd656676a3..52f53537943 100755 --- a/build/tfs/common/common.sh +++ b/build/tfs/common/common.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash set -e # set agent specific npm cache diff --git a/build/tfs/common/node.sh b/build/tfs/common/node.sh index 67f3f59552f..87f95a5e1d7 100755 --- a/build/tfs/common/node.sh +++ b/build/tfs/common/node.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash set -e # setup nvm diff --git a/build/tfs/linux/build-ia32.sh b/build/tfs/linux/build-ia32.sh index 0d9f98c692d..0b0f1c2a458 100755 --- a/build/tfs/linux/build-ia32.sh +++ b/build/tfs/linux/build-ia32.sh @@ -1,3 +1,3 @@ -#!/usr/bin/env bash +#!/bin/bash set -e ./build/tfs/linux/build.sh ia32 "$@" \ No newline at end of file diff --git a/build/tfs/linux/build-x64.sh b/build/tfs/linux/build-x64.sh index e193a01a5b7..fb5b38e02b3 100755 --- a/build/tfs/linux/build-x64.sh +++ b/build/tfs/linux/build-x64.sh @@ -1,3 +1,3 @@ -#!/usr/bin/env bash +#!/bin/bash set -e ./build/tfs/linux/build.sh x64 "$@" \ No newline at end of file diff --git a/build/tfs/linux/build.sh b/build/tfs/linux/build.sh index cee7821823d..933641afd21 100755 --- a/build/tfs/linux/build.sh +++ b/build/tfs/linux/build.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash . ./build/tfs/common/node.sh . ./scripts/env.sh diff --git a/build/tfs/linux/ia32/run-agent.sh b/build/tfs/linux/ia32/run-agent.sh index efcc96632a3..bcf9017f3cf 100755 --- a/build/tfs/linux/ia32/run-agent.sh +++ b/build/tfs/linux/ia32/run-agent.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash if [ ! -f pat ]; then echo "Error: file pat not found" diff --git a/build/tfs/linux/ia32/xvfb.init b/build/tfs/linux/ia32/xvfb.init index 74f6e3b2522..4d77d253a26 100644 --- a/build/tfs/linux/ia32/xvfb.init +++ b/build/tfs/linux/ia32/xvfb.init @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash # # /etc/rc.d/init.d/xvfbd # diff --git a/build/tfs/linux/release.sh b/build/tfs/linux/release.sh index 114100335a6..958a05f56bd 100755 --- a/build/tfs/linux/release.sh +++ b/build/tfs/linux/release.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash . ./scripts/env.sh . ./build/tfs/common/common.sh diff --git a/build/tfs/linux/smoketest.sh b/build/tfs/linux/smoketest.sh index 558d6082d64..c217e0bd2cb 100644 --- a/build/tfs/linux/smoketest.sh +++ b/build/tfs/linux/smoketest.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash set -e . ./build/tfs/common/node.sh diff --git a/build/tfs/linux/x64/run-agent.sh b/build/tfs/linux/x64/run-agent.sh index 1f122aa40dd..76978ce2b02 100755 --- a/build/tfs/linux/x64/run-agent.sh +++ b/build/tfs/linux/x64/run-agent.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash if [ ! -f pat ]; then echo "Error: file pat not found" diff --git a/build/tfs/linux/x64/xvfb.init b/build/tfs/linux/x64/xvfb.init index 74f6e3b2522..4d77d253a26 100644 --- a/build/tfs/linux/x64/xvfb.init +++ b/build/tfs/linux/x64/xvfb.init @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash # # /etc/rc.d/init.d/xvfbd # diff --git a/extensions/emmet/npm-shrinkwrap.json b/extensions/emmet/npm-shrinkwrap.json index 29ef7947c5e..86365079abd 100644 --- a/extensions/emmet/npm-shrinkwrap.json +++ b/extensions/emmet/npm-shrinkwrap.json @@ -38,9 +38,9 @@ "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz" }, "vscode-emmet-helper": { - "version": "1.1.13", - "from": "vscode-emmet-helper@>=1.1.13 <2.0.0", - "resolved": "https://registry.npmjs.org/vscode-emmet-helper/-/vscode-emmet-helper-1.1.13.tgz" + "version": "1.1.14", + "from": "vscode-emmet-helper@>=1.1.14 <2.0.0", + "resolved": "https://registry.npmjs.org/vscode-emmet-helper/-/vscode-emmet-helper-1.1.14.tgz" }, "vscode-languageserver-types": { "version": "3.3.0", diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index 9251a0cfac0..b768d3c1d90 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -269,7 +269,7 @@ "@emmetio/html-matcher": "^0.3.1", "@emmetio/css-parser": "ramya-rao-a/css-parser#vscode", "@emmetio/math-expression": "^0.1.1", - "vscode-emmet-helper": "^1.1.13", + "vscode-emmet-helper": "^1.1.14", "vscode-languageserver-types": "^3.0.3", "image-size": "^0.5.2", "vscode-nls": "2.0.2" diff --git a/extensions/fsharp/language-configuration.json b/extensions/fsharp/language-configuration.json index 9d684e6f9d9..9cdb97d7912 100644 --- a/extensions/fsharp/language-configuration.json +++ b/extensions/fsharp/language-configuration.json @@ -24,8 +24,8 @@ "folding": { "offSide": true, "markers": { - "start": "^\\s*//#region", - "end": "^\\s*//#endregion" + "start": "^\\s*//\\s*#region|^\\s*\\(\\*\\s*#region(.*)\\*\\)", + "end": "^\\s*//\\s*#endregion|^\\s*\\(\\*\\s*#endregion\\s*\\*\\)" } } } diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index fc66825d924..c41d60d2fbb 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -342,21 +342,35 @@ export class CommandCenter { @command('git.init') async init(): Promise { - const value = workspace.workspaceFolders && workspace.workspaceFolders.length > 0 - ? workspace.workspaceFolders[0].uri.fsPath - : os.homedir(); + const homeUri = Uri.file(os.homedir()); + const defaultUri = workspace.workspaceFolders && workspace.workspaceFolders.length > 0 + ? Uri.file(workspace.workspaceFolders[0].uri.fsPath) + : homeUri; - const path = await window.showInputBox({ - placeHolder: localize('path to init', "Folder path"), - prompt: localize('provide path', "Please provide a folder path to initialize a Git repository"), - value, - ignoreFocusOut: true + const result = await window.showOpenDialog({ + canSelectFiles: false, + canSelectFolders: true, + canSelectMany: false, + defaultUri, + openLabel: localize('init repo', "Initialize Repository") }); - if (!path) { + if (!result || result.length === 0) { return; } + const uri = result[0]; + + if (homeUri.toString().startsWith(uri.toString())) { + const yes = localize('create repo', "Initialize Repository"); + const answer = await window.showWarningMessage(localize('are you sure', "This will create a Git repository in '{0}'. Are you sure you want to continue?", uri.fsPath), yes); + + if (answer !== yes) { + return; + } + } + + const path = uri.fsPath; await this.git.init(path); await this.model.tryOpenRepository(path); } diff --git a/extensions/javascript/package.json b/extensions/javascript/package.json index 4e176f58679..8cc0db74250 100644 --- a/extensions/javascript/package.json +++ b/extensions/javascript/package.json @@ -132,6 +132,6 @@ ] }, "devDependencies": { - "@types/node": "^7.0.4" + "@types/node": "8.0.33" } } diff --git a/extensions/javascript/snippets/javascript.json b/extensions/javascript/snippets/javascript.json index 99723509494..6f13a64c51f 100644 --- a/extensions/javascript/snippets/javascript.json +++ b/extensions/javascript/snippets/javascript.json @@ -22,6 +22,16 @@ ], "description": "For Loop" }, + "For Loop (let)": { + "prefix": "forl", + "body": [ + "for (let ${1:index} = 0; ${1:index} < ${2:array}.length; ${1:index}++) {", + "\tlet ${3:element} = ${2:array}[${1:index}];", + "\t$0", + "}" + ], + "description": "For Loop (let)" + }, "For-Each Loop": { "prefix": "foreach", "body": [ @@ -43,6 +53,15 @@ ], "description": "For-In Loop" }, + "For-Of Loop": { + "prefix": "forof", + "body": [ + "for (let ${1:iterator} of ${2:object}) {", + "\t$0", + "}" + ], + "description": "For-Of Loop" + }, "Function Statement": { "prefix": "function", "body": [ diff --git a/extensions/javascript/snippets/javascriptreact.json b/extensions/javascript/snippets/javascriptreact.json index 044282e4c4f..3801be57a0a 100644 --- a/extensions/javascript/snippets/javascriptreact.json +++ b/extensions/javascript/snippets/javascriptreact.json @@ -22,6 +22,16 @@ ], "description": "For Loop" }, + "For Loop (let)": { + "prefix": "forl", + "body": [ + "for (let ${1:index} = 0; ${1:index} < ${2:array}.length; ${1:index}++) {", + "\tlet ${3:element} = ${2:array}[${1:index}];", + "\t$0", + "}" + ], + "description": "For Loop (let)" + }, "For-Each Loop": { "prefix": "foreach", "body": [ @@ -43,6 +53,15 @@ ], "description": "For-In Loop" }, + "For-Of Loop": { + "prefix": "forof", + "body": [ + "for (let ${1:iterator} of ${2:object}) {", + "\t$0", + "}" + ], + "description": "For-Of Loop" + }, "Function Statement": { "prefix": "function", "body": [ diff --git a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json index 914b3b48909..990df29f8b3 100644 --- a/extensions/javascript/syntaxes/JavaScript.tmLanguage.json +++ b/extensions/javascript/syntaxes/JavaScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/2dea76a2bd6c522cf824168c8a2d3cd05196069d", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/d6ee336bf6047594768a56f955563ba5ce86e7c9", "name": "JavaScript (with React support)", "scopeName": "source.js", "fileTypes": [ @@ -47,20 +47,14 @@ "include": "#declaration" }, { - "include": "#switch-statement" + "include": "#control-statement" }, { - "include": "#for-loop" - }, - { - "include": "#after-operator-block" + "include": "#after-operator-block-as-object-literal" }, { "include": "#decl-block" }, - { - "include": "#control-statement" - }, { "include": "#expression" }, @@ -69,6 +63,164 @@ } ] }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + } + ] + }, + "control-statement": { + "patterns": [ + { + "include": "#switch-statement" + }, + { + "include": "#for-loop" + }, + { + "name": "keyword.control.trycatch.js", + "match": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.js entity.name.function.js" @@ -349,192 +501,342 @@ } ] }, - "ternary-expression": { - "begin": "(\\?)", - "beginCaptures": { - "0": { - "name": "keyword.operator.ternary.js" - } - }, - "end": "(:)", - "endCaptures": { - "0": { - "name": "keyword.operator.ternary.js" - } - }, + "parameter-name": { "patterns": [ { - "include": "#expression" + "match": "\\s*\\b(public|protected|private|readonly)(?=\\s+(public|protected|private|readonly)\\s+)", + "captures": { + "1": { + "name": "storage.modifier.js" + } + } + }, + { + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.js" + }, + "2": { + "name": "keyword.operator.rest.js" + }, + "3": { + "name": "entity.name.function.js variable.language.this.js" + }, + "4": { + "name": "entity.name.function.js" + }, + "5": { + "name": "keyword.operator.optional.js" + } + } + }, + { + "match": "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + }, + { + "name": "meta.definition.property.js variable.object.property.js", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.js", + "match": "\\?" + } + ] + } + ] + }, + "variable-initializer": { + "patterns": [ + { + "begin": "(?)", + "captures": { + "1": { + "name": "storage.modifier.async.js" + }, + "2": { + "name": "variable.parameter.js" + } + } + }, + { + "name": "meta.arrow.js", + "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.js" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.js", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js" + } + }, + "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "patterns": [ + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.js", + "begin": "(?:(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)" - }, - { - "name": "meta.definition.property.js variable.object.property.js", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - }, - { - "name": "keyword.operator.optional.js", - "match": "\\?" - } - ] - } - ] - }, - "method-declaration": { - "patterns": [ - { - "name": "meta.method.declaration.js", - "begin": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)", - "captures": { - "1": { - "name": "storage.modifier.js" - }, - "2": { - "name": "keyword.operator.rest.js" - }, - "3": { - "name": "entity.name.function.js variable.language.this.js" - }, - "4": { - "name": "entity.name.function.js" - }, - "5": { - "name": "keyword.operator.optional.js" - } - } - }, - { - "match": "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - }, - { - "name": "meta.type.annotation.js", - "begin": "(:)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.js" - } - }, - "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - } - ] - }, - "type": { - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#string" - }, - { - "include": "#numeric-literal" - }, - { - "include": "#type-primitive" - }, - { - "include": "#type-builtin-literals" - }, - { - "include": "#type-parameters" - }, - { - "include": "#type-tuple" - }, - { - "include": "#type-object" - }, - { - "include": "#type-operators" - }, - { - "include": "#type-fn-type-parameters" - }, - { - "include": "#type-paren-or-function-parameters" - }, - { - "include": "#type-function-return-type" - }, - { - "include": "#type-name" - } - ] - }, - "function-parameters": { - "name": "meta.parameters.js", - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.definition.parameters.begin.js" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.parameters.end.js" - } - }, - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#decorator" - }, - { - "include": "#destructuring-parameter" - }, - { - "include": "#parameter-name" - }, - { - "include": "#type-annotation" - }, - { - "include": "#variable-initializer" - }, - { - "name": "punctuation.separator.parameter.js", - "match": "," - } - ] - }, - "type-primitive": { - "name": "support.type.primitive.js", - "match": "(?)\n ))\n )\n )\n)", - "end": "(?<=\\))", - "patterns": [ - { - "include": "#function-parameters" - } - ] - } - ] - }, - "type-operators": { - "patterns": [ - { - "include": "#typeof-operator" - }, - { - "begin": "([&|])(?=\\s*\\{)", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.js" - } - }, - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "begin": "[&|]", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.js" - } - }, - "end": "(?=\\S)" - }, - { - "name": "keyword.operator.expression.keyof.js", - "match": "(?)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "storage.type.function.arrow.js" - } - }, - "end": "(?)(?]|//|$)", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - }, - { - "name": "meta.type.function.return.js", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.js" - } - }, - "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - } - ] - }, - "type-function-return-type-core": { - "patterns": [ - { - "include": "#comment" - }, - { - "begin": "(?<==>)(?=\\s*\\{)", - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "include": "#type-predicate-operator" - }, - { - "include": "#type" - } - ] - }, - "type-tuple": { - "name": "meta.type.tuple.js", - "begin": "\\[", - "beginCaptures": { - "0": { - "name": "meta.brace.square.js" - } - }, - "end": "\\]", - "endCaptures": { - "0": { - "name": "meta.brace.square.js" - } - }, - "patterns": [ - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "type-name": { - "patterns": [ - { - "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\.)", - "captures": { - "1": { - "name": "entity.name.type.module.js" - }, - "2": { - "name": "punctuation.accessor.js" - } - } - }, - { - "name": "entity.name.type.js", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - } - ] - }, - "type-parameters": { - "name": "meta.type.parameters.js", - "begin": "(<)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.begin.js" - } - }, - "end": "(>)", - "endCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.end.js" - } - }, - "patterns": [ - { - "include": "#comment" - }, - { - "name": "storage.modifier.js", - "match": "(?)" - }, - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "variable-initializer": { - "patterns": [ - { - "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { + "0": { + "name": "meta.object-literal.key.js" + }, "1": { - "name": "support.class.console.js" - }, - "2": { - "name": "punctuation.accessor.js" - }, - "3": { - "name": "support.function.console.js" + "name": "entity.name.function.js" } } }, { - "match": "(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "captures": { - "1": { - "name": "punctuation.accessor.js" - }, - "2": { - "name": "support.constant.dom.js" - }, - "3": { - "name": "support.variable.property.dom.js" + "name": "meta.object.member.js", + "begin": ":", + "beginCaptures": { + "0": { + "name": "meta.object-literal.key.js punctuation.separator.key-value.js" } - } - }, - { - "name": "support.class.node.js", - "match": "(?x)(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n))", - "captures": { - "1": { - "name": "punctuation.accessor.js" - }, - "2": { - "name": "entity.name.function.js" - } - } - }, - { - "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", - "captures": { - "1": { - "name": "punctuation.accessor.js" - }, - "2": { - "name": "variable.other.constant.property.js" - } - } - }, - { - "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.js" - }, - "2": { - "name": "variable.other.property.js" - } - } - }, - { - "name": "variable.other.constant.js", - "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" - }, - { - "name": "variable.other.readwrite.js", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - } - ] - }, - "object-identifiers": { - "patterns": [ - { - "name": "support.class.js", - "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" - }, - { - "match": "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.js" - }, - "2": { - "name": "variable.other.constant.object.property.js" - }, - "3": { - "name": "variable.other.object.property.js" - } - } - }, - { - "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "variable.other.constant.object.js" - }, - "2": { - "name": "variable.other.object.js" - } - } - } - ] - }, - "cast": { - "patterns": [ - { - "include": "#jsx" - } - ] - }, "new-expr": { "name": "new.expr.js", "begin": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n)))", - "captures": { - "0": { - "name": "meta.object-literal.key.js" - }, - "1": { - "name": "entity.name.function.js" - } - } - }, - { - "name": "meta.object.member.js", - "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", - "captures": { - "0": { - "name": "meta.object-literal.key.js" - } - } - }, - { - "name": "meta.object.member.js", - "begin": "\\.\\.\\.", - "beginCaptures": { - "0": { - "name": "keyword.operator.spread.js" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "name": "meta.object.member.js", - "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", - "captures": { - "1": { - "name": "variable.other.readwrite.js" - } - } - }, - { - "name": "meta.object.member.js", - "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", - "end": "(?=,|\\}|$)", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "include": "#object-member-body" + "include": "#expression" }, { "include": "#punctuation-comma" } ] }, - "object-member-body": { - "name": "meta.object.member.js", - "begin": ":", - "beginCaptures": { - "0": { - "name": "meta.object-literal.key.js punctuation.separator.key-value.js" - } - }, - "end": "(?=,|\\})", + "cast": { "patterns": [ { - "include": "#expression" + "include": "#jsx" } ] }, @@ -2916,64 +2274,473 @@ "name": "keyword.operator.expression.typeof.js", "match": "(?)", + "include": "#numeric-literal" + }, + { + "include": "#boolean-literal" + }, + { + "include": "#null-literal" + }, + { + "include": "#undefined-literal" + }, + { + "include": "#numericConstant-literal" + }, + { + "include": "#array-literal" + }, + { + "include": "#this-literal" + }, + { + "include": "#super-literal" + } + ] + }, + "array-literal": { + "name": "meta.array.literal.js", + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "meta.brace.square.js" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "meta.brace.square.js" + } + }, + "patterns": [ + { + "include": "#expression" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "numeric-literal": { + "patterns": [ + { + "name": "constant.numeric.hex.js", + "match": "\\b(? is on new line\n (\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n ) |\n (\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends \n ) |\n # arrow function possible to detect only with => on same line\n (\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*(.)*)? # return type\n \\s*=> # arrow operator\n )\n )\n)", + "match": "(?x)(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "support.constant.dom.js" + }, + "3": { + "name": "support.variable.property.dom.js" + } + } + }, + { + "name": "support.class.node.js", + "match": "(?x)(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "entity.name.function.js" + } + } + }, + { + "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "variable.other.constant.property.js" + } + } + }, + { + "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "variable.other.property.js" + } + } + }, + { + "name": "variable.other.constant.js", + "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" + }, + { + "name": "variable.other.readwrite.js", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "object-identifiers": { + "patterns": [ + { + "name": "support.class.js", + "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" + }, + { + "match": "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.js" + }, + "2": { + "name": "variable.other.constant.object.property.js" + }, + "3": { + "name": "variable.other.object.property.js" + } + } + }, + { + "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "variable.other.constant.object.js" + }, + "2": { + "name": "variable.other.object.js" + } + } + } + ] + }, + "type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.js", + "begin": "(:)(?=\\s*\\S)", "beginCaptures": { "1": { - "name": "storage.modifier.async.js" + "name": "keyword.operator.type.annotation.js" } }, - "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", "patterns": [ { - "include": "#comment" - }, - { - "include": "#type-parameters" - }, - { - "include": "#function-parameters" - }, - { - "include": "#arrow-return-type" + "include": "#type" } ] }, { - "name": "meta.arrow.js", - "begin": "=>", + "name": "meta.type.annotation.js", + "begin": "(:)", "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.js" + "1": { + "name": "keyword.operator.type.annotation.js" } }, - "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", "patterns": [ { - "include": "#decl-block" - }, - { - "include": "#expression" + "include": "#type" } ] } ] }, + "return-type": { + "patterns": [ + { + "name": "meta.return.type.js", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.js" + } + }, + "end": "(?)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.js" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.js", + "match": "(?)" + }, + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] }, - "punctuation-semicolon": { - "name": "punctuation.terminator.statement.js", - "match": ";" + "type": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#numeric-literal" + }, + { + "include": "#type-primitive" + }, + { + "include": "#type-builtin-literals" + }, + { + "include": "#type-parameters" + }, + { + "include": "#type-tuple" + }, + { + "include": "#type-object" + }, + { + "include": "#type-operators" + }, + { + "include": "#type-fn-type-parameters" + }, + { + "include": "#type-paren-or-function-parameters" + }, + { + "include": "#type-function-return-type" + }, + { + "include": "#type-name" + } + ] }, - "punctuation-accessor": { - "name": "punctuation.accessor.js", - "match": "\\." + "type-primitive": { + "name": "support.type.primitive.js", + "match": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.js", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.js" + } + }, + "end": "(?)(?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.js", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.js" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.js" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.js", + "match": "(?|/\\*|//)", - "captures": { - "1": { - "name": "entity.other.attribute-name.js" - } - } - }, - "jsx-tag-attribute-assignment": { - "name": "keyword.operator.assignment.js", - "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" - }, - "jsx-string-double-quoted": { - "name": "string.quoted.double.js", - "begin": "\"", - "end": "\"", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.js" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.js" - } - }, - "patterns": [ - { - "include": "#jsx-entities" - } - ] - }, - "jsx-string-single-quoted": { - "name": "string.quoted.single.js", - "begin": "'", - "end": "'", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.js" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.js" - } - }, - "patterns": [ - { - "include": "#jsx-entities" - } - ] - }, - "jsx-entities": { - "patterns": [ - { - "name": "constant.character.entity.js", - "match": "(&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)", - "captures": { - "1": { - "name": "punctuation.definition.entity.js" - }, - "3": { - "name": "punctuation.definition.entity.js" - } - } - }, - { - "name": "invalid.illegal.bad-ampersand.js", - "match": "&" - } - ] - }, - "jsx-evaluated-code": { - "name": "meta.embedded.expression.js", - "begin": "\\{", - "end": "\\}", - "beginCaptures": { - "0": { - "name": "punctuation.section.embedded.begin.js" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.section.embedded.end.js" - } - }, - "patterns": [ - { - "include": "#expression" - } - ] - }, - "jsx-tag-attributes-illegal": { - "name": "invalid.illegal.attribute.js", - "match": "\\S+" - }, "jsx-tag-without-attributes-in-expression": { "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", @@ -4314,18 +4156,120 @@ } ] }, - "jsx": { + "jsx-evaluated-code": { + "name": "meta.embedded.expression.js", + "begin": "\\{", + "end": "\\}", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.js" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.js" + } + }, "patterns": [ { - "include": "#jsx-tag-without-attributes-in-expression" - }, - { - "include": "#jsx-tag-in-expression" - }, - { - "include": "#jsx-tag-invalid" + "include": "#expression" } ] + }, + "jsx-entities": { + "patterns": [ + { + "name": "constant.character.entity.js", + "match": "(&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)", + "captures": { + "1": { + "name": "punctuation.definition.entity.js" + }, + "3": { + "name": "punctuation.definition.entity.js" + } + } + }, + { + "name": "invalid.illegal.bad-ampersand.js", + "match": "&" + } + ] + }, + "jsx-tag-attributes": { + "patterns": [ + { + "include": "#jsx-tag-attribute-name" + }, + { + "include": "#jsx-tag-attribute-assignment" + }, + { + "include": "#jsx-string-double-quoted" + }, + { + "include": "#jsx-string-single-quoted" + }, + { + "include": "#jsx-evaluated-code" + } + ] + }, + "jsx-tag-attribute-name": { + "match": "(?x)\n \\s*\n ([_$a-zA-Z][-$\\w]*)\n (?=\\s|=|/?>|/\\*|//)", + "captures": { + "1": { + "name": "entity.other.attribute-name.js" + } + } + }, + "jsx-tag-attribute-assignment": { + "name": "keyword.operator.assignment.js", + "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" + }, + "jsx-string-double-quoted": { + "name": "string.quoted.double.js", + "begin": "\"", + "end": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-string-single-quoted": { + "name": "string.quoted.single.js", + "begin": "'", + "end": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.js" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.js" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-tag-attributes-illegal": { + "name": "invalid.illegal.attribute.js", + "match": "\\S+" } } } \ No newline at end of file diff --git a/extensions/markdown/package.json b/extensions/markdown/package.json index d07b223fda5..769c6091855 100644 --- a/extensions/markdown/package.json +++ b/extensions/markdown/package.json @@ -299,9 +299,9 @@ "vscode-nls": "2.0.2" }, "devDependencies": { - "@types/highlight.js": "^9.1.9", + "@types/highlight.js": "9.1.10", "@types/markdown-it": "0.0.2", - "@types/node": "^7.0.4", + "@types/node": "8.0.33", "gulp-rename": "^1.2.2", "gulp-replace": "^0.5.4" } diff --git a/extensions/merge-conflict/package.json b/extensions/merge-conflict/package.json index 4ecece640ea..38a33087345 100644 --- a/extensions/merge-conflict/package.json +++ b/extensions/merge-conflict/package.json @@ -88,6 +88,6 @@ "vscode-nls": "^2.0.2" }, "devDependencies": { - "@types/node": "^7.0.4" + "@types/node": "8.0.33" } } \ No newline at end of file diff --git a/extensions/python/language-configuration.json b/extensions/python/language-configuration.json index 97feb4d8aca..51892242cc4 100644 --- a/extensions/python/language-configuration.json +++ b/extensions/python/language-configuration.json @@ -23,6 +23,10 @@ ["'", "'"] ], "folding": { - "offSide": true + "offSide": true, + "markers": { + "start": "^\\s*#region", + "end": "^\\s*#endregion" + } } -} \ No newline at end of file +} diff --git a/extensions/typescript/package.json b/extensions/typescript/package.json index a5093c1f0c3..11b93b77e10 100644 --- a/extensions/typescript/package.json +++ b/extensions/typescript/package.json @@ -17,8 +17,8 @@ "vscode-nls": "2.0.1" }, "devDependencies": { - "@types/node": "^7.0.4", - "@types/semver": "^5.3.30" + "@types/node": "8.0.33", + "@types/semver": "5.4.0" }, "scripts": { "vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:typescript ./tsconfig.json", diff --git a/extensions/typescript/syntaxes/TypeScript.tmLanguage.json b/extensions/typescript/syntaxes/TypeScript.tmLanguage.json index 510e532e022..28b955a0742 100644 --- a/extensions/typescript/syntaxes/TypeScript.tmLanguage.json +++ b/extensions/typescript/syntaxes/TypeScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/2dea76a2bd6c522cf824168c8a2d3cd05196069d", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/cd202a57fd738d6d2c712c2ed63f5f41a11eb558", "name": "TypeScript", "scopeName": "source.ts", "fileTypes": [ @@ -44,20 +44,14 @@ "include": "#declaration" }, { - "include": "#switch-statement" + "include": "#control-statement" }, { - "include": "#for-loop" - }, - { - "include": "#after-operator-block" + "include": "#after-operator-block-as-object-literal" }, { "include": "#decl-block" }, - { - "include": "#control-statement" - }, { "include": "#expression" }, @@ -66,6 +60,161 @@ } ] }, + "declaration": { + "patterns": [ + { + "include": "#decorator" + }, + { + "include": "#var-expr" + }, + { + "include": "#function-declaration" + }, + { + "include": "#class-declaration" + }, + { + "include": "#interface-declaration" + }, + { + "include": "#enum-declaration" + }, + { + "include": "#namespace-declaration" + }, + { + "include": "#type-alias-declaration" + }, + { + "include": "#import-equals-declaration" + }, + { + "include": "#import-declaration" + }, + { + "include": "#export-declaration" + } + ] + }, + "control-statement": { + "patterns": [ + { + "include": "#switch-statement" + }, + { + "include": "#for-loop" + }, + { + "name": "keyword.control.trycatch.ts", + "match": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.ts entity.name.function.ts" @@ -346,189 +495,342 @@ } ] }, - "ternary-expression": { - "begin": "(\\?)", - "beginCaptures": { - "0": { - "name": "keyword.operator.ternary.ts" - } - }, - "end": "(:)", - "endCaptures": { - "0": { - "name": "keyword.operator.ternary.ts" - } - }, + "parameter-name": { "patterns": [ { - "include": "#expression" + "match": "\\s*\\b(public|protected|private|readonly)(?=\\s+(public|protected|private|readonly)\\s+)", + "captures": { + "1": { + "name": "storage.modifier.ts" + } + } + }, + { + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.ts" + }, + "2": { + "name": "keyword.operator.rest.ts" + }, + "3": { + "name": "entity.name.function.ts variable.language.this.ts" + }, + "4": { + "name": "entity.name.function.ts" + }, + "5": { + "name": "keyword.operator.optional.ts" + } + } + }, + { + "match": "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + }, + { + "name": "meta.definition.property.ts variable.object.property.ts", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.ts", + "match": "\\?" + } + ] + } + ] + }, + "variable-initializer": { + "patterns": [ + { + "begin": "(?)", + "captures": { + "1": { + "name": "storage.modifier.async.ts" + }, + "2": { + "name": "variable.parameter.ts" + } + } + }, + { + "name": "meta.arrow.ts", + "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.ts" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.ts", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "patterns": [ + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.ts", + "begin": "(?:(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)" - }, - { - "name": "meta.definition.property.ts variable.object.property.ts", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - }, - { - "name": "keyword.operator.optional.ts", - "match": "\\?" - } - ] - } - ] - }, - "method-declaration": { - "patterns": [ - { - "name": "meta.method.declaration.ts", - "begin": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)", - "captures": { - "1": { - "name": "storage.modifier.ts" - }, - "2": { - "name": "keyword.operator.rest.ts" - }, - "3": { - "name": "entity.name.function.ts variable.language.this.ts" - }, - "4": { - "name": "entity.name.function.ts" - }, - "5": { - "name": "keyword.operator.optional.ts" - } - } - }, - { - "match": "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - }, - { - "name": "meta.type.annotation.ts", - "begin": "(:)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.ts" - } - }, - "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - } - ] - }, - "type": { - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#string" - }, - { - "include": "#numeric-literal" - }, - { - "include": "#type-primitive" - }, - { - "include": "#type-builtin-literals" - }, - { - "include": "#type-parameters" - }, - { - "include": "#type-tuple" - }, - { - "include": "#type-object" - }, - { - "include": "#type-operators" - }, - { - "include": "#type-fn-type-parameters" - }, - { - "include": "#type-paren-or-function-parameters" - }, - { - "include": "#type-function-return-type" - }, - { - "include": "#type-name" - } - ] - }, - "function-parameters": { - "name": "meta.parameters.ts", - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.definition.parameters.begin.ts" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.parameters.end.ts" - } - }, - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#decorator" - }, - { - "include": "#destructuring-parameter" - }, - { - "include": "#parameter-name" - }, - { - "include": "#type-annotation" - }, - { - "include": "#variable-initializer" - }, - { - "name": "punctuation.separator.parameter.ts", - "match": "," - } - ] - }, - "type-primitive": { - "name": "support.type.primitive.ts", - "match": "(?)\n ))\n )\n )\n)", - "end": "(?<=\\))", - "patterns": [ - { - "include": "#function-parameters" - } - ] - } - ] - }, - "type-operators": { - "patterns": [ - { - "include": "#typeof-operator" - }, - { - "begin": "([&|])(?=\\s*\\{)", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.ts" - } - }, - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "begin": "[&|]", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.ts" - } - }, - "end": "(?=\\S)" - }, - { - "name": "keyword.operator.expression.keyof.ts", - "match": "(?)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "storage.type.function.arrow.ts" - } - }, - "end": "(?)(?]|//|$)", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - }, - { - "name": "meta.type.function.return.ts", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.ts" - } - }, - "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - } - ] - }, - "type-function-return-type-core": { - "patterns": [ - { - "include": "#comment" - }, - { - "begin": "(?<==>)(?=\\s*\\{)", - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "include": "#type-predicate-operator" - }, - { - "include": "#type" - } - ] - }, - "type-tuple": { - "name": "meta.type.tuple.ts", - "begin": "\\[", - "beginCaptures": { - "0": { - "name": "meta.brace.square.ts" - } - }, - "end": "\\]", - "endCaptures": { - "0": { - "name": "meta.brace.square.ts" - } - }, - "patterns": [ - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "type-name": { - "patterns": [ - { - "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\.)", - "captures": { - "1": { - "name": "entity.name.type.module.ts" - }, - "2": { - "name": "punctuation.accessor.ts" - } - } - }, - { - "name": "entity.name.type.ts", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - } - ] - }, - "type-parameters": { - "name": "meta.type.parameters.ts", - "begin": "(<)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.begin.ts" - } - }, - "end": "(>)", - "endCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.end.ts" - } - }, - "patterns": [ - { - "include": "#comment" - }, - { - "name": "storage.modifier.ts", - "match": "(?)" - }, - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "variable-initializer": { - "patterns": [ - { - "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { + "0": { + "name": "meta.object-literal.key.ts" + }, "1": { - "name": "support.class.console.ts" - }, - "2": { - "name": "punctuation.accessor.ts" - }, - "3": { - "name": "support.function.console.ts" + "name": "entity.name.function.ts" } } }, { - "match": "(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "captures": { - "1": { - "name": "punctuation.accessor.ts" - }, - "2": { - "name": "support.constant.dom.ts" - }, - "3": { - "name": "support.variable.property.dom.ts" + "name": "meta.object.member.ts", + "begin": ":", + "beginCaptures": { + "0": { + "name": "meta.object-literal.key.ts punctuation.separator.key-value.ts" } - } - }, - { - "name": "support.class.node.ts", - "match": "(?x)(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n))", - "captures": { - "1": { - "name": "punctuation.accessor.ts" - }, - "2": { - "name": "entity.name.function.ts" - } - } + "include": "#class-declaration" }, { - "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", - "captures": { - "1": { - "name": "punctuation.accessor.ts" - }, - "2": { - "name": "variable.other.constant.property.ts" - } - } - }, - { - "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.ts" - }, - "2": { - "name": "variable.other.property.ts" - } - } - }, - { - "name": "variable.other.constant.ts", - "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" - }, - { - "name": "variable.other.readwrite.ts", - "match": "[_$[:alpha:]][_$[:alnum:]]*" + "include": "#type" } ] }, - "object-identifiers": { + "paren-expression": { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "meta.brace.round.ts" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "meta.brace.round.ts" + } + }, "patterns": [ { - "name": "support.class.ts", - "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" + "include": "#expression" }, { - "match": "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.ts" - }, - "2": { - "name": "variable.other.constant.object.property.ts" - }, - "3": { - "name": "variable.other.object.property.ts" - } - } - }, - { - "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "variable.other.constant.object.ts" - }, - "2": { - "name": "variable.other.object.ts" - } - } + "include": "#punctuation-comma" } ] }, @@ -2648,7 +2145,7 @@ "patterns": [ { "name": "cast.expr.ts", - "begin": "(?:(?<=return|throw|yield|await|default|[=(,:>+*?]))\\s*(<)(?!*?]|[^+]\\+))\\s*(<)(?!)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n)))", - "captures": { - "0": { - "name": "meta.object-literal.key.ts" - }, - "1": { - "name": "entity.name.function.ts" - } - } - }, - { - "name": "meta.object.member.ts", - "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", - "captures": { - "0": { - "name": "meta.object-literal.key.ts" - } - } - }, - { - "name": "meta.object.member.ts", - "begin": "\\.\\.\\.", - "beginCaptures": { - "0": { - "name": "keyword.operator.spread.ts" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "name": "meta.object.member.ts", - "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", - "captures": { - "1": { - "name": "variable.other.readwrite.ts" - } - } - }, - { - "name": "meta.object.member.ts", - "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", - "end": "(?=,|\\}|$)", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "include": "#object-member-body" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "object-member-body": { - "name": "meta.object.member.ts", - "begin": ":", - "beginCaptures": { - "0": { - "name": "meta.object-literal.key.ts punctuation.separator.key-value.ts" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, "expression-operators": { "patterns": [ { @@ -2947,64 +2305,473 @@ "name": "keyword.operator.expression.typeof.ts", "match": "(?)", + "include": "#numeric-literal" + }, + { + "include": "#boolean-literal" + }, + { + "include": "#null-literal" + }, + { + "include": "#undefined-literal" + }, + { + "include": "#numericConstant-literal" + }, + { + "include": "#array-literal" + }, + { + "include": "#this-literal" + }, + { + "include": "#super-literal" + } + ] + }, + "array-literal": { + "name": "meta.array.literal.ts", + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "meta.brace.square.ts" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "meta.brace.square.ts" + } + }, + "patterns": [ + { + "include": "#expression" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "numeric-literal": { + "patterns": [ + { + "name": "constant.numeric.hex.ts", + "match": "\\b(? is on new line\n (\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n ) |\n (\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends \n ) |\n # arrow function possible to detect only with => on same line\n (\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*(.)*)? # return type\n \\s*=> # arrow operator\n )\n )\n)", + "match": "(?x)(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "support.constant.dom.ts" + }, + "3": { + "name": "support.variable.property.dom.ts" + } + } + }, + { + "name": "support.class.node.ts", + "match": "(?x)(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "entity.name.function.ts" + } + } + }, + { + "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "variable.other.constant.property.ts" + } + } + }, + { + "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "variable.other.property.ts" + } + } + }, + { + "name": "variable.other.constant.ts", + "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" + }, + { + "name": "variable.other.readwrite.ts", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "object-identifiers": { + "patterns": [ + { + "name": "support.class.ts", + "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" + }, + { + "match": "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.ts" + }, + "2": { + "name": "variable.other.constant.object.property.ts" + }, + "3": { + "name": "variable.other.object.property.ts" + } + } + }, + { + "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "variable.other.constant.object.ts" + }, + "2": { + "name": "variable.other.object.ts" + } + } + } + ] + }, + "type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.ts", + "begin": "(:)(?=\\s*\\S)", "beginCaptures": { "1": { - "name": "storage.modifier.async.ts" + "name": "keyword.operator.type.annotation.ts" } }, - "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", "patterns": [ { - "include": "#comment" - }, - { - "include": "#type-parameters" - }, - { - "include": "#function-parameters" - }, - { - "include": "#arrow-return-type" + "include": "#type" } ] }, { - "name": "meta.arrow.ts", - "begin": "=>", + "name": "meta.type.annotation.ts", + "begin": "(:)", "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.ts" + "1": { + "name": "keyword.operator.type.annotation.ts" } }, - "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", "patterns": [ { - "include": "#decl-block" - }, - { - "include": "#expression" + "include": "#type" } ] } ] }, + "return-type": { + "patterns": [ + { + "name": "meta.return.type.ts", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.ts" + } + }, + "end": "(?)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.ts" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.ts", + "match": "(?)" + }, + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] }, - "punctuation-semicolon": { - "name": "punctuation.terminator.statement.ts", - "match": ";" + "type": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#numeric-literal" + }, + { + "include": "#type-primitive" + }, + { + "include": "#type-builtin-literals" + }, + { + "include": "#type-parameters" + }, + { + "include": "#type-tuple" + }, + { + "include": "#type-object" + }, + { + "include": "#type-operators" + }, + { + "include": "#type-fn-type-parameters" + }, + { + "include": "#type-paren-or-function-parameters" + }, + { + "include": "#type-function-return-type" + }, + { + "include": "#type-name" + } + ] }, - "punctuation-accessor": { - "name": "punctuation.accessor.ts", - "match": "\\." + "type-primitive": { + "name": "support.type.primitive.ts", + "match": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.ts", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "(?)(?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.ts", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.ts" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.ts" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.ts" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.ts", + "match": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.tsx entity.name.function.tsx" @@ -346,192 +498,342 @@ } ] }, - "ternary-expression": { - "begin": "(\\?)", - "beginCaptures": { - "0": { - "name": "keyword.operator.ternary.tsx" - } - }, - "end": "(:)", - "endCaptures": { - "0": { - "name": "keyword.operator.ternary.tsx" - } - }, + "parameter-name": { "patterns": [ { - "include": "#expression" + "match": "\\s*\\b(public|protected|private|readonly)(?=\\s+(public|protected|private|readonly)\\s+)", + "captures": { + "1": { + "name": "storage.modifier.tsx" + } + } + }, + { + "match": "(?x)(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))", + "captures": { + "1": { + "name": "storage.modifier.tsx" + }, + "2": { + "name": "keyword.operator.rest.tsx" + }, + "3": { + "name": "entity.name.function.tsx variable.language.this.tsx" + }, + "4": { + "name": "entity.name.function.tsx" + }, + "5": { + "name": "keyword.operator.optional.tsx" + } + } + }, + { + "match": "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)))" + }, + { + "name": "meta.definition.property.tsx variable.object.property.tsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + }, + { + "name": "keyword.operator.optional.tsx", + "match": "\\?" + } + ] + } + ] + }, + "variable-initializer": { + "patterns": [ + { + "begin": "(?)", + "captures": { + "1": { + "name": "storage.modifier.async.tsx" + }, + "2": { + "name": "variable.parameter.tsx" + } + } + }, + { + "name": "meta.arrow.tsx", + "begin": "(?x) (?:\n (? is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "beginCaptures": { + "1": { + "name": "storage.modifier.async.tsx" + } + }, + "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#type-parameters" + }, + { + "include": "#function-parameters" + }, + { + "include": "#arrow-return-type" + } + ] + }, + { + "name": "meta.arrow.tsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.tsx" + } + }, + "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "patterns": [ + { + "include": "#decl-block" + }, + { + "include": "#expression" + } + ] + } + ] + }, + "indexer-declaration": { + "name": "meta.indexer.declaration.tsx", + "begin": "(?:(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)" - }, - { - "name": "meta.definition.property.tsx variable.object.property.tsx", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - }, - { - "name": "keyword.operator.optional.tsx", - "match": "\\?" - } - ] - } - ] - }, - "method-declaration": { - "patterns": [ - { - "name": "meta.method.declaration.tsx", - "begin": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n )) |\n (:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n ))\n)", - "captures": { - "1": { - "name": "storage.modifier.tsx" - }, - "2": { - "name": "keyword.operator.rest.tsx" - }, - "3": { - "name": "entity.name.function.tsx variable.language.this.tsx" - }, - "4": { - "name": "entity.name.function.tsx" - }, - "5": { - "name": "keyword.operator.optional.tsx" - } - } - }, - { - "match": "(?:\\s*\\b(public|private|protected|readonly)\\s+)?(\\.\\.\\.)?\\s*(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - }, - { - "name": "meta.type.annotation.tsx", - "begin": "(:)", - "beginCaptures": { - "1": { - "name": "keyword.operator.type.annotation.tsx" - } - }, - "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", - "patterns": [ - { - "include": "#type" - } - ] - } - ] - }, - "type": { - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#string" - }, - { - "include": "#numeric-literal" - }, - { - "include": "#type-primitive" - }, - { - "include": "#type-builtin-literals" - }, - { - "include": "#type-parameters" - }, - { - "include": "#type-tuple" - }, - { - "include": "#type-object" - }, - { - "include": "#type-operators" - }, - { - "include": "#type-fn-type-parameters" - }, - { - "include": "#type-paren-or-function-parameters" - }, - { - "include": "#type-function-return-type" - }, - { - "include": "#type-name" - } - ] - }, - "function-parameters": { - "name": "meta.parameters.tsx", - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.definition.parameters.begin.tsx" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.definition.parameters.end.tsx" - } - }, - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#decorator" - }, - { - "include": "#destructuring-parameter" - }, - { - "include": "#parameter-name" - }, - { - "include": "#type-annotation" - }, - { - "include": "#variable-initializer" - }, - { - "name": "punctuation.separator.parameter.tsx", - "match": "," - } - ] - }, - "type-primitive": { - "name": "support.type.primitive.tsx", - "match": "(?)\n ))\n )\n )\n)", - "end": "(?<=\\))", - "patterns": [ - { - "include": "#function-parameters" - } - ] - } - ] - }, - "type-operators": { - "patterns": [ - { - "include": "#typeof-operator" - }, - { - "begin": "([&|])(?=\\s*\\{)", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.tsx" - } - }, - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "begin": "[&|]", - "beginCaptures": { - "0": { - "name": "keyword.operator.type.tsx" - } - }, - "end": "(?=\\S)" - }, - { - "name": "keyword.operator.expression.keyof.tsx", - "match": "(?)(?=\\s*\\S)", - "beginCaptures": { - "1": { - "name": "storage.type.function.arrow.tsx" - } - }, - "end": "(?)(?]|//|$)", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - }, - { - "name": "meta.type.function.return.tsx", - "begin": "=>", - "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.tsx" - } - }, - "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", - "patterns": [ - { - "include": "#type-function-return-type-core" - } - ] - } - ] - }, - "type-function-return-type-core": { - "patterns": [ - { - "include": "#comment" - }, - { - "begin": "(?<==>)(?=\\s*\\{)", - "end": "(?<=\\})", - "patterns": [ - { - "include": "#type-object" - } - ] - }, - { - "include": "#type-predicate-operator" - }, - { - "include": "#type" - } - ] - }, - "type-tuple": { - "name": "meta.type.tuple.tsx", - "begin": "\\[", - "beginCaptures": { - "0": { - "name": "meta.brace.square.tsx" - } - }, - "end": "\\]", - "endCaptures": { - "0": { - "name": "meta.brace.square.tsx" - } - }, - "patterns": [ - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "type-name": { - "patterns": [ - { - "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(\\.)", - "captures": { - "1": { - "name": "entity.name.type.module.tsx" - }, - "2": { - "name": "punctuation.accessor.tsx" - } - } - }, - { - "name": "entity.name.type.tsx", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - } - ] - }, - "type-parameters": { - "name": "meta.type.parameters.tsx", - "begin": "(<)", - "beginCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.begin.tsx" - } - }, - "end": "(>)", - "endCaptures": { - "1": { - "name": "punctuation.definition.typeparameters.end.tsx" - } - }, - "patterns": [ - { - "include": "#comment" - }, - { - "name": "storage.modifier.tsx", - "match": "(?)" - }, - { - "include": "#type" - }, - { - "include": "#punctuation-comma" - } - ] - }, - "variable-initializer": { - "patterns": [ - { - "begin": "(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { + "0": { + "name": "meta.object-literal.key.tsx" + }, "1": { - "name": "support.class.console.tsx" - }, - "2": { - "name": "punctuation.accessor.tsx" - }, - "3": { - "name": "support.function.console.tsx" + "name": "entity.name.function.tsx" } } }, { - "match": "(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", - "captures": { - "1": { - "name": "punctuation.accessor.tsx" - }, - "2": { - "name": "support.constant.dom.tsx" - }, - "3": { - "name": "support.variable.property.dom.tsx" + "name": "meta.object.member.tsx", + "begin": ":", + "beginCaptures": { + "0": { + "name": "meta.object-literal.key.tsx punctuation.separator.key-value.tsx" } - } - }, - { - "name": "support.class.node.tsx", - "match": "(?x)(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n))", - "captures": { - "1": { - "name": "punctuation.accessor.tsx" - }, - "2": { - "name": "entity.name.function.tsx" - } - } - }, - { - "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", - "captures": { - "1": { - "name": "punctuation.accessor.tsx" - }, - "2": { - "name": "variable.other.constant.property.tsx" - } - } - }, - { - "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.tsx" - }, - "2": { - "name": "variable.other.property.tsx" - } - } - }, - { - "name": "variable.other.constant.tsx", - "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" - }, - { - "name": "variable.other.readwrite.tsx", - "match": "[_$[:alpha:]][_$[:alnum:]]*" - } - ] - }, - "object-identifiers": { - "patterns": [ - { - "name": "support.class.tsx", - "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" - }, - { - "match": "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "punctuation.accessor.tsx" - }, - "2": { - "name": "variable.other.constant.object.property.tsx" - }, - "3": { - "name": "variable.other.object.property.tsx" - } - } - }, - { - "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", - "captures": { - "1": { - "name": "variable.other.constant.object.tsx" - }, - "2": { - "name": "variable.other.object.tsx" - } - } - } - ] - }, - "cast": { - "patterns": [ - { - "include": "#jsx" - } - ] - }, "new-expr": { "name": "new.expr.tsx", "begin": "(?)\n )) |\n ((async\\s*)?(\n ([(]\\s*(([)]\\s*:)|([_$[:alpha:]][_$[:alnum:]]*\\s*:)|(\\.\\.\\.) )) |\n ([<]\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s*[^=>])|(\\s*[,]))) |\n ((<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\)(\\s*:\\s*(.)*)?\\s*=>)\n ))\n)))", - "captures": { - "0": { - "name": "meta.object-literal.key.tsx" - }, - "1": { - "name": "entity.name.function.tsx" - } - } - }, - { - "name": "meta.object.member.tsx", - "match": "(?:[_$[:alpha:]][_$[:alnum:]]*)\\s*(?=:)", - "captures": { - "0": { - "name": "meta.object-literal.key.tsx" - } - } - }, - { - "name": "meta.object.member.tsx", - "begin": "\\.\\.\\.", - "beginCaptures": { - "0": { - "name": "keyword.operator.spread.tsx" - } - }, - "end": "(?=,|\\})", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "name": "meta.object.member.tsx", - "match": "([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=,|\\}|$)", - "captures": { - "1": { - "name": "variable.other.readwrite.tsx" - } - } - }, - { - "name": "meta.object.member.tsx", - "begin": "(?=[_$[:alpha:]][_$[:alnum:]]*\\s*=)", - "end": "(?=,|\\}|$)", - "patterns": [ - { - "include": "#expression" - } - ] - }, - { - "include": "#object-member-body" + "include": "#expression" }, { "include": "#punctuation-comma" } ] }, - "object-member-body": { - "name": "meta.object.member.tsx", - "begin": ":", - "beginCaptures": { - "0": { - "name": "meta.object-literal.key.tsx punctuation.separator.key-value.tsx" - } - }, - "end": "(?=,|\\})", + "cast": { "patterns": [ { - "include": "#expression" + "include": "#jsx" } ] }, @@ -2913,64 +2271,473 @@ "name": "keyword.operator.expression.typeof.tsx", "match": "(?)", + "include": "#numeric-literal" + }, + { + "include": "#boolean-literal" + }, + { + "include": "#null-literal" + }, + { + "include": "#undefined-literal" + }, + { + "include": "#numericConstant-literal" + }, + { + "include": "#array-literal" + }, + { + "include": "#this-literal" + }, + { + "include": "#super-literal" + } + ] + }, + "array-literal": { + "name": "meta.array.literal.tsx", + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "meta.brace.square.tsx" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "meta.brace.square.tsx" + } + }, + "patterns": [ + { + "include": "#expression" + }, + { + "include": "#punctuation-comma" + } + ] + }, + "numeric-literal": { + "patterns": [ + { + "name": "constant.numeric.hex.tsx", + "match": "\\b(? is on new line\n (\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n ) |\n (\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends \n ) |\n # arrow function possible to detect only with => on same line\n (\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*(.)*)? # return type\n \\s*=> # arrow operator\n )\n )\n)", + "match": "(?x)(?=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)?\\()", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "support.constant.dom.tsx" + }, + "3": { + "name": "support.variable.property.dom.tsx" + } + } + }, + { + "name": "support.class.node.tsx", + "match": "(?x)(?)\n )) |\n ((async\\s*)?(\n # sure shot arrow functions even if => is on new line\n(\n [(]\\s*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*[_$[:alpha:]\\{\\(]([^<>=]|=[^<]|\\<\\s*[_$[:alpha:]\\{\\(]([^=<>]|=[^<])+\\>)+>\\s*)? # typeparameters\n \\((\\s*[_$[:alpha:]\\{\\(]([^()]|\\((\\s*[_$[:alpha:]\\{\\(]\\{\\(][^()]*)?\\))*)?\\) # parameteres\n (\\s*:\\s*([^<>\\(\\)]|\\<[^<>]+\\>|\\([^\\(\\)]+\\))+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "entity.name.function.tsx" + } + } + }, + { + "match": "(\\.)\\s*([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "variable.other.constant.property.tsx" + } + } + }, + { + "match": "(\\.)\\s*([_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "variable.other.property.tsx" + } + } + }, + { + "name": "variable.other.constant.tsx", + "match": "([[:upper:]][_$[:digit:][:upper:]]*)(?![_$[:alnum:]])" + }, + { + "name": "variable.other.readwrite.tsx", + "match": "[_$[:alpha:]][_$[:alnum:]]*" + } + ] + }, + "object-identifiers": { + "patterns": [ + { + "name": "support.class.tsx", + "match": "([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\\.\\s*prototype\\b(?!\\$))" + }, + { + "match": "(?x)(\\.)\\s*(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "punctuation.accessor.tsx" + }, + "2": { + "name": "variable.other.constant.object.property.tsx" + }, + "3": { + "name": "variable.other.object.property.tsx" + } + } + }, + { + "match": "(?x)(?:\n ([[:upper:]][_$[:digit:][:upper:]]*) |\n ([_$[:alpha:]][_$[:alnum:]]*)\n)(?=\\s*\\.\\s*[_$[:alpha:]][_$[:alnum:]]*)", + "captures": { + "1": { + "name": "variable.other.constant.object.tsx" + }, + "2": { + "name": "variable.other.object.tsx" + } + } + } + ] + }, + "type-annotation": { + "patterns": [ + { + "name": "meta.type.annotation.tsx", + "begin": "(:)(?=\\s*\\S)", "beginCaptures": { "1": { - "name": "storage.modifier.async.tsx" + "name": "keyword.operator.type.annotation.tsx" } }, - "end": "(?==>|\\{|(^\\s*(export|function|class|interface|let|var|const|import|enum|namespace|module|type|abstract|declare)\\s+))", + "end": "(?])|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", "patterns": [ { - "include": "#comment" - }, - { - "include": "#type-parameters" - }, - { - "include": "#function-parameters" - }, - { - "include": "#arrow-return-type" + "include": "#type" } ] }, { - "name": "meta.arrow.tsx", - "begin": "=>", + "name": "meta.type.annotation.tsx", + "begin": "(:)", "beginCaptures": { - "0": { - "name": "storage.type.function.arrow.tsx" + "1": { + "name": "keyword.operator.type.annotation.tsx" } }, - "end": "(?<=\\}|\\S)(?)|((?!\\{)(?=\\S))", + "end": "(?])|(?=^\\s*$)|((?<=\\S)(?=\\s*$))|((?<=[\\}>\\]\\)]|[_$[:alpha:]])\\s*(?=\\{)))", "patterns": [ { - "include": "#decl-block" - }, - { - "include": "#expression" + "include": "#type" } ] } ] }, + "return-type": { + "patterns": [ + { + "name": "meta.return.type.tsx", + "begin": "(?<=\\))\\s*(:)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "keyword.operator.type.annotation.tsx" + } + }, + "end": "(?)", + "endCaptures": { + "1": { + "name": "punctuation.definition.typeparameters.end.tsx" + } + }, + "patterns": [ + { + "include": "#comment" + }, + { + "name": "storage.modifier.tsx", + "match": "(?)" + }, + { + "include": "#type" + }, + { + "include": "#punctuation-comma" + } + ] }, - "punctuation-semicolon": { - "name": "punctuation.terminator.statement.tsx", - "match": ";" + "type": { + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#string" + }, + { + "include": "#numeric-literal" + }, + { + "include": "#type-primitive" + }, + { + "include": "#type-builtin-literals" + }, + { + "include": "#type-parameters" + }, + { + "include": "#type-tuple" + }, + { + "include": "#type-object" + }, + { + "include": "#type-operators" + }, + { + "include": "#type-fn-type-parameters" + }, + { + "include": "#type-paren-or-function-parameters" + }, + { + "include": "#type-function-return-type" + }, + { + "include": "#type-name" + } + ] }, - "punctuation-accessor": { - "name": "punctuation.accessor.tsx", - "match": "\\." + "type-primitive": { + "name": "support.type.primitive.tsx", + "match": "(?)\n ))\n )\n )\n)", + "end": "(?<=\\))", + "patterns": [ + { + "include": "#function-parameters" + } + ] + } + ] + }, + "type-function-return-type": { + "patterns": [ + { + "name": "meta.type.function.return.tsx", + "begin": "(=>)(?=\\s*\\S)", + "beginCaptures": { + "1": { + "name": "storage.type.function.arrow.tsx" + } + }, + "end": "(?)(?]|//|$)", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + }, + { + "name": "meta.type.function.return.tsx", + "begin": "=>", + "beginCaptures": { + "0": { + "name": "storage.type.function.arrow.tsx" + } + }, + "end": "(?)(?]|//|^\\s*$)|((?<=\\S)(?=\\s*$)))", + "patterns": [ + { + "include": "#type-function-return-type-core" + } + ] + } + ] + }, + "type-function-return-type-core": { + "patterns": [ + { + "include": "#comment" + }, + { + "begin": "(?<==>)(?=\\s*\\{)", + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "include": "#type-predicate-operator" + }, + { + "include": "#type" + } + ] + }, + "type-operators": { + "patterns": [ + { + "include": "#typeof-operator" + }, + { + "begin": "([&|])(?=\\s*\\{)", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.tsx" + } + }, + "end": "(?<=\\})", + "patterns": [ + { + "include": "#type-object" + } + ] + }, + { + "begin": "[&|]", + "beginCaptures": { + "0": { + "name": "keyword.operator.type.tsx" + } + }, + "end": "(?=\\S)" + }, + { + "name": "keyword.operator.expression.keyof.tsx", + "match": "(?|/\\*|//)", - "captures": { - "1": { - "name": "entity.other.attribute-name.tsx" - } - } - }, - "jsx-tag-attribute-assignment": { - "name": "keyword.operator.assignment.tsx", - "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" - }, - "jsx-string-double-quoted": { - "name": "string.quoted.double.tsx", - "begin": "\"", - "end": "\"", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.tsx" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.tsx" - } - }, - "patterns": [ - { - "include": "#jsx-entities" - } - ] - }, - "jsx-string-single-quoted": { - "name": "string.quoted.single.tsx", - "begin": "'", - "end": "'", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.tsx" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.tsx" - } - }, - "patterns": [ - { - "include": "#jsx-entities" - } - ] - }, - "jsx-entities": { - "patterns": [ - { - "name": "constant.character.entity.tsx", - "match": "(&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)", - "captures": { - "1": { - "name": "punctuation.definition.entity.tsx" - }, - "3": { - "name": "punctuation.definition.entity.tsx" - } - } - }, - { - "name": "invalid.illegal.bad-ampersand.tsx", - "match": "&" - } - ] - }, - "jsx-evaluated-code": { - "name": "meta.embedded.expression.tsx", - "begin": "\\{", - "end": "\\}", - "beginCaptures": { - "0": { - "name": "punctuation.section.embedded.begin.tsx" - } - }, - "endCaptures": { - "0": { - "name": "punctuation.section.embedded.end.tsx" - } - }, - "patterns": [ - { - "include": "#expression" - } - ] - }, - "jsx-tag-attributes-illegal": { - "name": "invalid.illegal.attribute.tsx", - "match": "\\S+" - }, "jsx-tag-without-attributes-in-expression": { "begin": "(?x)\n (?<=[({\\[,?=>:*]|&&|\\|\\||\\?|\\Wreturn|^return|\\Wdefault|^)\\s*\n (?=(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", "end": "(?!\\s*(<)\\s*((?:[a-z][a-z0-9]*|([_$a-zA-Z][-$\\w.]*))(?))", @@ -4311,18 +4153,120 @@ } ] }, - "jsx": { + "jsx-evaluated-code": { + "name": "meta.embedded.expression.tsx", + "begin": "\\{", + "end": "\\}", + "beginCaptures": { + "0": { + "name": "punctuation.section.embedded.begin.tsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.section.embedded.end.tsx" + } + }, "patterns": [ { - "include": "#jsx-tag-without-attributes-in-expression" - }, - { - "include": "#jsx-tag-in-expression" - }, - { - "include": "#jsx-tag-invalid" + "include": "#expression" } ] + }, + "jsx-entities": { + "patterns": [ + { + "name": "constant.character.entity.tsx", + "match": "(&)([a-zA-Z0-9]+|#[0-9]+|#x[0-9a-fA-F]+)(;)", + "captures": { + "1": { + "name": "punctuation.definition.entity.tsx" + }, + "3": { + "name": "punctuation.definition.entity.tsx" + } + } + }, + { + "name": "invalid.illegal.bad-ampersand.tsx", + "match": "&" + } + ] + }, + "jsx-tag-attributes": { + "patterns": [ + { + "include": "#jsx-tag-attribute-name" + }, + { + "include": "#jsx-tag-attribute-assignment" + }, + { + "include": "#jsx-string-double-quoted" + }, + { + "include": "#jsx-string-single-quoted" + }, + { + "include": "#jsx-evaluated-code" + } + ] + }, + "jsx-tag-attribute-name": { + "match": "(?x)\n \\s*\n ([_$a-zA-Z][-$\\w]*)\n (?=\\s|=|/?>|/\\*|//)", + "captures": { + "1": { + "name": "entity.other.attribute-name.tsx" + } + } + }, + "jsx-tag-attribute-assignment": { + "name": "keyword.operator.assignment.tsx", + "match": "=(?=\\s*(?:'|\"|{|/\\*|//|\\n))" + }, + "jsx-string-double-quoted": { + "name": "string.quoted.double.tsx", + "begin": "\"", + "end": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.tsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.tsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-string-single-quoted": { + "name": "string.quoted.single.tsx", + "begin": "'", + "end": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.tsx" + } + }, + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.tsx" + } + }, + "patterns": [ + { + "include": "#jsx-entities" + } + ] + }, + "jsx-tag-attributes-illegal": { + "name": "invalid.illegal.attribute.tsx", + "match": "\\S+" } } } \ No newline at end of file diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index d6d05275089..17ee6622a1e 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -552,9 +552,9 @@ "resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.24.0.tgz" }, "vscode-ripgrep": { - "version": "0.0.27", - "from": "vscode-ripgrep@0.0.27", - "resolved": "https://registry.npmjs.org/vscode-ripgrep/-/vscode-ripgrep-0.0.27.tgz" + "version": "0.6.0-patch.0", + "from": "vscode-ripgrep@0.6.0-patch.0", + "resolved": "https://registry.npmjs.org/vscode-ripgrep/-/vscode-ripgrep-0.6.0-patch.0.tgz" }, "vscode-textmate": { "version": "3.1.5", @@ -574,7 +574,7 @@ "xterm": { "version": "2.9.1", "from": "Tyriar/xterm.js#vscode-release/1.18", - "resolved": "git+https://github.com/Tyriar/xterm.js.git#1f5d0a878dd1e187c992535302d9f272eb9c26f5" + "resolved": "git+https://github.com/Tyriar/xterm.js.git#b49fe4a329ca792e1eb59d647042e0460e860b4d" }, "yauzl": { "version": "2.8.0", diff --git a/package.json b/package.json index c59d4358d0a..2133570b711 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "semver": "4.3.6", "v8-profiler": "jrieken/v8-profiler#vscode", "vscode-debugprotocol": "1.24.0", - "vscode-ripgrep": "0.0.27", + "vscode-ripgrep": "0.6.0-patch.0", "vscode-textmate": "^3.1.5", "winreg": "1.2.0", "xterm": "Tyriar/xterm.js#vscode-release/1.18", @@ -50,12 +50,12 @@ }, "devDependencies": { "7zip": "0.0.6", - "@types/keytar": "^4.0.0", - "@types/minimist": "^1.2.0", - "@types/mocha": "^2.2.39", - "@types/semver": "^5.3.30", - "@types/sinon": "^1.16.34", - "@types/winreg": "^1.2.30", + "@types/keytar": "4.0.1", + "@types/minimist": "1.2.0", + "@types/mocha": "2.2.39", + "@types/semver": "5.3.30", + "@types/sinon": "1.16.34", + "@types/winreg": "1.2.30", "azure-storage": "^0.3.1", "clean-css": "3.4.6", "coveralls": "^2.11.11", diff --git a/resources/linux/debian/postrm.template b/resources/linux/debian/postrm.template index 1dfa892a0ea..c43a2b16ae3 100755 --- a/resources/linux/debian/postrm.template +++ b/resources/linux/debian/postrm.template @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash # # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. diff --git a/scripts/env.sh b/scripts/env.sh index f530bf28369..35d09f66bb2 100755 --- a/scripts/env.sh +++ b/scripts/env.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash export npm_config_disturl=https://atom.io/download/electron export npm_config_target=$(node -p "require('./package.json').electronVersion") export npm_config_runtime=electron diff --git a/scripts/npm.sh b/scripts/npm.sh index 02268eafd6e..69c6d0c48ae 100755 --- a/scripts/npm.sh +++ b/scripts/npm.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash if [[ "$OSTYPE" == "darwin"* ]]; then realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; } diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 454c212f358..0a9eea1b077 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash set -e if [[ "$OSTYPE" == "darwin"* ]]; then diff --git a/scripts/test-mocha.sh b/scripts/test-mocha.sh index 5d1d71a2da2..9aa16fa3241 100755 --- a/scripts/test-mocha.sh +++ b/scripts/test-mocha.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash if [[ "$OSTYPE" == "darwin"* ]]; then realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; } diff --git a/scripts/test.sh b/scripts/test.sh index 157c6da2cc7..ce1e5e11856 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash if [[ "$OSTYPE" == "darwin"* ]]; then diff --git a/src/vs/base/browser/htmlContentRenderer.ts b/src/vs/base/browser/htmlContentRenderer.ts index 7087efd5e66..bf8dfd41504 100644 --- a/src/vs/base/browser/htmlContentRenderer.ts +++ b/src/vs/base/browser/htmlContentRenderer.ts @@ -29,13 +29,13 @@ function createElement(options: RenderOptions): HTMLElement { return element; } -export function renderText(text: string, options: RenderOptions = {}): Node { +export function renderText(text: string, options: RenderOptions = {}): HTMLElement { const element = createElement(options); element.textContent = text; return element; } -export function renderFormattedText(formattedText: string, options: RenderOptions = {}): Node { +export function renderFormattedText(formattedText: string, options: RenderOptions = {}): HTMLElement { const element = createElement(options); _renderFormattedText(element, parseFormattedText(formattedText), options.actionCallback); return element; diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index 603024b7c73..378ec0c525d 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -391,9 +391,9 @@ export class InputBox extends Widget { className: 'monaco-inputbox-message' }; - let spanElement: HTMLElement = (this.message.formatContent + const spanElement = (this.message.formatContent ? renderFormattedText(this.message.content, renderOptions) - : renderText(this.message.content, renderOptions)) as any; + : renderText(this.message.content, renderOptions)); dom.addClass(spanElement, this.classForType(this.message.type)); const styles = this.stylesForType(this.message.type); diff --git a/src/vs/base/common/iterator.ts b/src/vs/base/common/iterator.ts index 0b19d5e56ae..f930237759c 100644 --- a/src/vs/base/common/iterator.ts +++ b/src/vs/base/common/iterator.ts @@ -5,11 +5,15 @@ 'use strict'; -export interface IIterator { +export interface IIterator { + next(): { done: boolean, value: E }; +} + +export interface INextIterator { next(): T; } -export class ArrayIterator implements IIterator { +export class ArrayIterator implements INextIterator { private items: T[]; protected start: number; @@ -73,16 +77,16 @@ export class ArrayNavigator extends ArrayIterator implements INavigator } -export class MappedIterator implements IIterator { +export class MappedIterator implements INextIterator { - constructor(protected iterator: IIterator, protected fn: (item: T) => R) { + constructor(protected iterator: INextIterator, protected fn: (item: T) => R) { // noop } next() { return this.fn(this.iterator.next()); } } -export interface INavigator extends IIterator { +export interface INavigator extends INextIterator { current(): T; previous(): T; parent(): T; diff --git a/src/vs/base/common/linkedList.ts b/src/vs/base/common/linkedList.ts index a75c81ac4a0..a6be2dc2ee1 100644 --- a/src/vs/base/common/linkedList.ts +++ b/src/vs/base/common/linkedList.ts @@ -5,6 +5,8 @@ 'use strict'; +import { IIterator } from 'vs/base/common/iterator'; + class Node { element: E; next: Node; @@ -87,7 +89,7 @@ export class LinkedList { }; } - iterator() { + iterator(): IIterator { let _done: boolean; let _value: E; let element = { diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index 2a03c10f6e5..72284c76d1a 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -418,35 +418,33 @@ export class TernarySearchTree { } else { return node.element || candidate; } - } - findSuperstr(key: string): E[] { + findSuperstr(key: string): TernarySearchTree { const segements = this._segments.reset(key); - const bucket: E[] = []; - this._findSuperstr(this._root, segements.next(), segements, bucket); - return bucket.length ? bucket : undefined; + return this._findSuperstr(this._root, segements.next(), segements); } - private _findSuperstr(node: TernarySearchTreeNode, key: string, segments: IKeySegements, bucket: E[]): void { + private _findSuperstr(node: TernarySearchTreeNode, key: string, segments: IKeySegements): TernarySearchTree { if (!node) { - return; + return undefined; } else if (node.str > key) { // left - this._findSuperstr(node.left, key, segments, bucket); + return this._findSuperstr(node.left, key, segments); } else if (node.str < key) { // right - this._findSuperstr(node.right, key, segments, bucket); + return this._findSuperstr(node.right, key, segments); } else if (segments.hasNext()) { // mid - this._findSuperstr(node.mid, segments.next(), segments, bucket); + return this._findSuperstr(node.mid, segments.next(), segments); } else { // collect - if (node.element) { - bucket.push(node.element); + if (!node.mid) { + return undefined; } - this._forEach(node.mid, [], (entry) => bucket.push(entry[1])); - + let ret = new TernarySearchTree(this._segments); + ret._root = node.mid; + return ret; } } diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 9f758d0e2f5..af01d2aed55 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -715,6 +715,10 @@ export function startsWithUTF8BOM(str: string): boolean { return (str && str.length > 0 && str.charCodeAt(0) === CharCode.UTF8_BOM); } +export function stripUTF8BOM(str: string): string { + return startsWithUTF8BOM(str) ? str.substr(1) : str; +} + /** * Appends two strings. If the appended result is longer than maxLength, * trims the start of the result and replaces it with '...'. diff --git a/src/vs/base/common/winjs.base.d.ts b/src/vs/base/common/winjs.base.d.ts index 54cfd1ada1c..a0ec0a59013 100644 --- a/src/vs/base/common/winjs.base.d.ts +++ b/src/vs/base/common/winjs.base.d.ts @@ -13,7 +13,7 @@ export declare class Promise { resolve: (value: T | PromiseLike) => void, reject: (reason: any) => void, progress: (progress: TProgress) => void) => void, - oncancel?: () => void); + oncancel?: () => void); public then( onfulfilled?: ((value: T) => TResult1 | PromiseLike) | null, @@ -29,7 +29,7 @@ export declare class Promise { public static as(value: null): Promise; public static as(value: undefined): Promise; - public static as>(value: TPromise): TPromise; + public static as>(value: SomePromise): SomePromise; public static as(value: T): Promise; public static is(value: any): value is PromiseLike; diff --git a/src/vs/base/node/terminateProcess.sh b/src/vs/base/node/terminateProcess.sh index dceeae9745f..acdcbf8ed42 100755 --- a/src/vs/base/node/terminateProcess.sh +++ b/src/vs/base/node/terminateProcess.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash terminateTree() { for cpid in $(/usr/bin/pgrep -P $1); do diff --git a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts index 2d8ea22ecc0..1dce6a05bad 100644 --- a/src/vs/base/parts/quickopen/common/quickOpenScorer.ts +++ b/src/vs/base/parts/quickopen/common/quickOpenScorer.ts @@ -253,13 +253,13 @@ export function scoreItem(item: T, query: string, fuzzy: boolean, accessor: I return cached; } - const itemScore = doScoreItem(label, description, accessor.getItemPath(item), query, fuzzy, accessor); + const itemScore = doScoreItem(label, description, accessor.getItemPath(item), query, fuzzy); cache[cacheHash] = itemScore; return itemScore; } -function doScoreItem(label: string, description: string, path: string, query: string, fuzzy: boolean, accessor: IItemAccessor): IItemScore { +function doScoreItem(label: string, description: string, path: string, query: string, fuzzy: boolean): IItemScore { // 1.) treat identity matches on full path highest if (path && isEqual(query, path, true)) { diff --git a/src/vs/base/parts/tree/browser/treeViewModel.ts b/src/vs/base/parts/tree/browser/treeViewModel.ts index f0434f5488a..fb4e6530932 100644 --- a/src/vs/base/parts/tree/browser/treeViewModel.ts +++ b/src/vs/base/parts/tree/browser/treeViewModel.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { EventEmitter } from 'vs/base/common/eventEmitter'; -import { IIterator, ArrayIterator } from 'vs/base/common/iterator'; +import { INextIterator, ArrayIterator } from 'vs/base/common/iterator'; import { Item } from './treeModel'; export interface IViewItem { @@ -30,7 +30,7 @@ export class HeightMap extends EventEmitter { return !last ? 0 : last.top + last.height; } - public onInsertItems(iterator: IIterator, afterItemId: string = null): number { + public onInsertItems(iterator: INextIterator, afterItemId: string = null): number { var item: Item; var viewItem: IViewItem; var i: number, j: number; @@ -90,7 +90,7 @@ export class HeightMap extends EventEmitter { } // Contiguous items - public onRemoveItems(iterator: IIterator): void { + public onRemoveItems(iterator: INextIterator): void { var itemId: string; var viewItem: IViewItem; var startIndex: number = null; @@ -139,7 +139,7 @@ export class HeightMap extends EventEmitter { } // Ordered, but not necessarily contiguous items - public onRefreshItems(iterator: IIterator): void { + public onRefreshItems(iterator: INextIterator): void { var item: Item; var viewItem: IViewItem; var newHeight: number; @@ -240,4 +240,4 @@ export class HeightMap extends EventEmitter { this.heightMap = null; this.indexes = null; } -} \ No newline at end of file +} diff --git a/src/vs/base/test/browser/htmlContent.test.ts b/src/vs/base/test/browser/htmlContent.test.ts index dcd1c4d5afb..b91068ae15e 100644 --- a/src/vs/base/test/browser/htmlContent.test.ts +++ b/src/vs/base/test/browser/htmlContent.test.ts @@ -10,7 +10,7 @@ import { renderMarkdown, renderText, renderFormattedText } from 'vs/base/browser suite('HtmlContent', () => { test('render simple element', () => { - var result: HTMLElement = renderText('testing'); + var result: HTMLElement = renderText('testing'); assert.strictEqual(result.nodeType, document.ELEMENT_NODE); assert.strictEqual(result.textContent, 'testing'); @@ -18,7 +18,7 @@ suite('HtmlContent', () => { }); test('render element with class', () => { - var result: HTMLElement = renderText('testing', { + var result: HTMLElement = renderText('testing', { className: 'testClass' }); assert.strictEqual(result.nodeType, document.ELEMENT_NODE); @@ -26,32 +26,32 @@ suite('HtmlContent', () => { }); test('simple formatting', () => { - var result: HTMLElement = renderFormattedText('**bold**'); + var result: HTMLElement = renderFormattedText('**bold**'); assert.strictEqual(result.children.length, 1); assert.strictEqual(result.firstChild.textContent, 'bold'); assert.strictEqual((result.firstChild).tagName, 'B'); assert.strictEqual(result.innerHTML, 'bold'); - result = renderFormattedText('__italics__'); + result = renderFormattedText('__italics__'); assert.strictEqual(result.innerHTML, 'italics'); - result = renderFormattedText('this string has **bold** and __italics__'); + result = renderFormattedText('this string has **bold** and __italics__'); assert.strictEqual(result.innerHTML, 'this string has bold and italics'); }); test('no formatting', () => { - var result: HTMLElement = renderFormattedText('this is just a string'); + var result: HTMLElement = renderFormattedText('this is just a string'); assert.strictEqual(result.innerHTML, 'this is just a string'); }); test('preserve newlines', () => { - var result: HTMLElement = renderFormattedText('line one\nline two'); + var result: HTMLElement = renderFormattedText('line one\nline two'); assert.strictEqual(result.innerHTML, 'line one
line two'); }); test('action', () => { var callbackCalled = false; - var result: HTMLElement = renderFormattedText('[[action]]', { + var result: HTMLElement = renderFormattedText('[[action]]', { actionCallback(content) { assert.strictEqual(content, '0'); callbackCalled = true; @@ -67,7 +67,7 @@ suite('HtmlContent', () => { test('fancy action', () => { var callbackCalled = false; - var result: HTMLElement = renderFormattedText('__**[[action]]**__', { + var result: HTMLElement = renderFormattedText('__**[[action]]**__', { actionCallback(content) { assert.strictEqual(content, '0'); callbackCalled = true; @@ -82,13 +82,13 @@ suite('HtmlContent', () => { }); test('escaped formatting', () => { - var result: HTMLElement = renderFormattedText('\\*\\*bold\\*\\*'); + var result: HTMLElement = renderFormattedText('\\*\\*bold\\*\\*'); assert.strictEqual(result.children.length, 0); assert.strictEqual(result.innerHTML, '**bold**'); }); test('image rendering conforms to default', () => { const markdown = { value: `![image](someimageurl 'caption')` }; - const result: HTMLElement = renderMarkdown(markdown); + const result: HTMLElement = renderMarkdown(markdown); const renderer = new marked.Renderer(); const imageFromMarked = marked(markdown.value, { sanitize: true, @@ -98,7 +98,7 @@ suite('HtmlContent', () => { }); test('image rendering conforms to default without title', () => { const markdown = { value: `![image](someimageurl)` }; - const result: HTMLElement = renderMarkdown(markdown); + const result: HTMLElement = renderMarkdown(markdown); const renderer = new marked.Renderer(); const imageFromMarked = marked(markdown.value, { sanitize: true, @@ -107,15 +107,15 @@ suite('HtmlContent', () => { assert.strictEqual(result.innerHTML, imageFromMarked); }); test('image width from title params', () => { - var result: HTMLElement = renderMarkdown({ value: `![image](someimageurl|width=100 'caption')` }); + var result: HTMLElement = renderMarkdown({ value: `![image](someimageurl|width=100 'caption')` }); assert.strictEqual(result.innerHTML, `

image

`); }); test('image height from title params', () => { - var result: HTMLElement = renderMarkdown({ value: `![image](someimageurl|height=100 'caption')` }); + var result: HTMLElement = renderMarkdown({ value: `![image](someimageurl|height=100 'caption')` }); assert.strictEqual(result.innerHTML, `

image

`); }); test('image width and height from title params', () => { - var result: HTMLElement = renderMarkdown({ value: `![image](someimageurl|height=200,width=100 'caption')` }); + var result: HTMLElement = renderMarkdown({ value: `![image](someimageurl|height=200,width=100 'caption')` }); assert.strictEqual(result.innerHTML, `

image

`); }); }); diff --git a/src/vs/base/test/common/map.test.ts b/src/vs/base/test/common/map.test.ts index b5549e82132..e53c60a028b 100644 --- a/src/vs/base/test/common/map.test.ts +++ b/src/vs/base/test/common/map.test.ts @@ -453,15 +453,16 @@ suite('Map', () => { map.set('/usr/foo', 4); const elements = map.findSuperstr('/user'); - const [first, second, third] = elements.sort(); - assert.equal(elements.length, 3); - assert.equal(first, 1); - assert.equal(second, 2); - assert.equal(third, 3); + assertTernarySearchTree(elements, ['foo/bar', 1], ['foo', 2], ['foo/flip/flop', 3]); + // assert.equal(elements.length, 3); + assert.equal(elements.get('foo/bar'), 1); + assert.equal(elements.get('foo'), 2); + assert.equal(elements.get('foo/flip/flop'), 3); - assert.deepEqual(map.findSuperstr('/usr'), [4]); - assert.deepEqual(map.findSuperstr('/usr/foo'), [4]); + assertTernarySearchTree(map.findSuperstr('/usr'), ['foo', 4]); + assert.equal(map.findSuperstr('/usr/foo'), undefined); + assert.equal(map.get('/usr/foo'), 4); assert.equal(map.findSuperstr('/not'), undefined); assert.equal(map.findSuperstr('/us'), undefined); diff --git a/src/vs/base/test/common/strings.test.ts b/src/vs/base/test/common/strings.test.ts index 2368d35add7..d9530ec5d48 100644 --- a/src/vs/base/test/common/strings.test.ts +++ b/src/vs/base/test/common/strings.test.ts @@ -334,4 +334,21 @@ suite('Strings', () => { assert.ok(!strings.fuzzyContains('hello world', 'wh')); assert.ok(!strings.fuzzyContains('d', 'dd')); }); + + test('startsWithUTF8BOM', () => { + assert(strings.startsWithUTF8BOM(strings.UTF8_BOM_CHARACTER)); + assert(strings.startsWithUTF8BOM(strings.UTF8_BOM_CHARACTER + 'a')); + assert(strings.startsWithUTF8BOM(strings.UTF8_BOM_CHARACTER + 'aaaaaaaaaa')); + assert(!strings.startsWithUTF8BOM(' ' + strings.UTF8_BOM_CHARACTER)); + assert(!strings.startsWithUTF8BOM('foo')); + assert(!strings.startsWithUTF8BOM('')); + }); + + test('stripUTF8BOM', () => { + assert.equal(strings.stripUTF8BOM(strings.UTF8_BOM_CHARACTER), ''); + assert.equal(strings.stripUTF8BOM(strings.UTF8_BOM_CHARACTER + 'foobar'), 'foobar'); + assert.equal(strings.stripUTF8BOM('foobar' + strings.UTF8_BOM_CHARACTER), 'foobar' + strings.UTF8_BOM_CHARACTER); + assert.equal(strings.stripUTF8BOM('abc'), 'abc'); + assert.equal(strings.stripUTF8BOM(''), ''); + }); }); diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index e78ec8c97b8..ea526f1c4c0 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -138,7 +138,7 @@ function setupIPC(accessor: ServicesAccessor): TPromise { // it happens on Linux and OS X that the pipe is left behind // let's delete it, since we can't connect to it - // and the retry the whole thing + // and then retry the whole thing try { fs.unlinkSync(environmentService.mainIPCHandle); } catch (e) { @@ -214,4 +214,4 @@ function main() { }).done(null, err => instantiationService.invokeFunction(quit, err)); } -main(); \ No newline at end of file +main(); diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 67dd97a9d4e..1262489e565 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -420,24 +420,42 @@ export class WindowsManager implements IWindowsMainService { // Open based on config const usedWindows = this.doOpen(openConfig, workspacesToOpen, workspacesToRestore, foldersToOpen, foldersToRestore, emptyToRestore, emptyToOpen, filesToOpen, filesToCreate, filesToDiff, filesToWait, foldersToAdd); - // Make sure to pass focus to one of the windows if we open multiple + // Make sure to pass focus to the most relevant of the windows if we open multiple if (usedWindows.length > 1) { - let focusLast = true; + let focusLastActive = this.windowsState.lastActiveWindow && !openConfig.forceEmpty && !openConfig.cli._.length && (!openConfig.pathsToOpen || !openConfig.pathsToOpen.length); + let focusLastOpened = true; + let focusLastWindow = true; - // Only focus the last active window if the user did not open a specific path via - // CLI or API. In those cases we do not want windows to get focus from previous - // session but actually one of the windows the user explicitly asked to open. - const focusLastActive = !openConfig.forceEmpty && !openConfig.cli._.length && (!openConfig.pathsToOpen || !openConfig.pathsToOpen.length); - if (focusLastActive && this.windowsState.lastActiveWindow) { + // 1.) focus last active window if we are not instructed to open any paths + if (focusLastActive) { const lastActiveWindw = usedWindows.filter(w => w.backupPath === this.windowsState.lastActiveWindow.backupPath); if (lastActiveWindw.length) { lastActiveWindw[0].focus(); - focusLast = false; + focusLastOpened = false; + focusLastWindow = false; } } - // Otherwise: focus last window we opened - if (focusLast) { + // 2.) if instructed to open paths, focus last window which is not restored + if (focusLastOpened) { + for (let i = usedWindows.length - 1; i >= 0; i--) { + const usedWindow = usedWindows[i]; + if ( + (usedWindow.openedWorkspace && workspacesToRestore.some(workspace => workspace.id === usedWindow.openedWorkspace.id)) || // skip over restored workspace + (usedWindow.openedFolderPath && foldersToRestore.some(folder => folder === usedWindow.openedFolderPath)) || // skip over restored folder + (usedWindow.backupPath && emptyToRestore.some(empty => empty === basename(usedWindow.backupPath))) // skip over restored empty window + ) { + continue; + } + + usedWindow.focus(); + focusLastWindow = false; + break; + } + } + + // 3.) finally, always ensure to have at least last used window focused + if (focusLastWindow) { usedWindows[usedWindows.length - 1].focus(); } } @@ -1306,8 +1324,8 @@ export class WindowsManager implements IWindowsMainService { return this.workspacesManager.saveAndEnterWorkspace(win, path).then(result => this.doEnterWorkspace(win, result)); } - public createAndEnterWorkspace(win: CodeWindow, folders?: string[], path?: string): TPromise { - return this.workspacesManager.createAndEnterWorkspace(win, folders, path).then(result => this.doEnterWorkspace(win, result)); + public createAndEnterWorkspace(win: CodeWindow, folderPaths?: string[], path?: string): TPromise { + return this.workspacesManager.createAndEnterWorkspace(win, folderPaths, path).then(result => this.doEnterWorkspace(win, result)); } private doEnterWorkspace(win: CodeWindow, result: IEnterWorkspaceResult): IEnterWorkspaceResult { @@ -1668,12 +1686,12 @@ class WorkspacesManager { return this.doSaveAndOpenWorkspace(window, window.openedWorkspace, path); } - public createAndEnterWorkspace(window: CodeWindow, folders?: string[], path?: string): TPromise { + public createAndEnterWorkspace(window: CodeWindow, folderPaths?: string[], path?: string): TPromise { if (!window || !window.win || window.readyState !== ReadyState.READY || !this.isValidTargetWorkspacePath(window, path)) { return TPromise.as(null); // return early if the window is not ready or disposed } - return this.workspacesService.createWorkspace(folders).then(workspace => { + return this.workspacesService.createWorkspace(folderPaths).then(workspace => { return this.doSaveAndOpenWorkspace(window, workspace, path); }); } diff --git a/src/vs/editor/contrib/comment/common/lineCommentCommand.ts b/src/vs/editor/contrib/comment/common/lineCommentCommand.ts index 1352bec2320..8f0abccfd32 100644 --- a/src/vs/editor/contrib/comment/common/lineCommentCommand.ts +++ b/src/vs/editor/contrib/comment/common/lineCommentCommand.ts @@ -200,8 +200,16 @@ export class LineCommentCommand implements editorCommon.ICommand { ops = LineCommentCommand._createAddLineCommentsOperations(data.lines, s.startLineNumber); } + const cursorPosition = new Position(s.positionLineNumber, s.positionColumn); + for (var i = 0, len = ops.length; i < len; i++) { builder.addEditOperation(ops[i].range, ops[i].text); + if (ops[i].range.isEmpty() && ops[i].range.getStartPosition().equals(cursorPosition)) { + const lineContent = model.getLineContent(cursorPosition.lineNumber); + if (lineContent.length + 1 === cursorPosition.column) { + this._deltaColumn = ops[i].text.length; + } + } } this._selectionId = builder.trackSelection(s); diff --git a/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts b/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts index 443415d8820..57c946f76f9 100644 --- a/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts +++ b/src/vs/editor/contrib/comment/test/common/lineCommentCommand.test.ts @@ -518,6 +518,50 @@ suite('Editor Contrib - Line Comment Command', () => { ); }); + test('issue #35673: Comment hotkeys throws the cursor before the comment', () => { + testLineCommentCommand( + [ + 'first', + '', + '\tsecond line', + 'third line', + 'fourth line', + 'fifth' + ], + new Selection(2, 1, 2, 1), + [ + 'first', + '!@# ', + '\tsecond line', + 'third line', + 'fourth line', + 'fifth' + ], + new Selection(2, 5, 2, 5) + ); + + testLineCommentCommand( + [ + 'first', + '\t', + '\tsecond line', + 'third line', + 'fourth line', + 'fifth' + ], + new Selection(2, 2, 2, 2), + [ + 'first', + '\t!@# ', + '\tsecond line', + 'third line', + 'fourth line', + 'fifth' + ], + new Selection(2, 6, 2, 6) + ); + }); + test('issue #2837 "Add Line Comment" fault when blank lines involved', function () { testAddLineCommentCommand( [ diff --git a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts index af7e4287af1..ebd0216c50a 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestWidget.ts @@ -253,7 +253,8 @@ class SuggestionDetails { this.docs.textContent = item.suggestion.documentation; } else { addClass(this.docs, 'markdown-docs'); - this.docs.innerHTML = this.markdownRenderer.render(item.suggestion.documentation).innerHTML; + this.docs.innerHTML = ''; + this.docs.appendChild(this.markdownRenderer.render(item.suggestion.documentation)); } if (item.suggestion.detail) { diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 41ddb0f59ee..98464fac20a 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -17,7 +17,7 @@ import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayo import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; import { IKeybindingEvent, KeybindingSource, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IConfirmation, IMessageService } from 'vs/platform/message/common/message'; +import { IConfirmation, IMessageService, IConfirmationResult } from 'vs/platform/message/common/message'; import { IWorkspaceContextService, IWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; @@ -236,6 +236,7 @@ export class SimpleProgressService implements IProgressService { } export class SimpleMessageService implements IMessageService { + public _serviceBrand: any; private static Empty = function () { /* nothing */ }; @@ -261,7 +262,7 @@ export class SimpleMessageService implements IMessageService { // No-op } - public confirm(confirmation: IConfirmation): boolean { + public confirmSync(confirmation: IConfirmation): boolean { let messageText = confirmation.message; if (confirmation.detail) { messageText = messageText + '\n\n' + confirmation.detail; @@ -269,6 +270,10 @@ export class SimpleMessageService implements IMessageService { return window.confirm(messageText); } + + public confirm(confirmation: IConfirmation): TPromise { + return TPromise.as({ confirmed: this.confirmSync(confirmation) } as IConfirmationResult); + } } export class StandaloneCommandService implements ICommandService { @@ -318,10 +323,11 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { constructor( contextKeyService: IContextKeyService, commandService: ICommandService, + telemetryService: ITelemetryService, messageService: IMessageService, domNode: HTMLElement ) { - super(contextKeyService, commandService, messageService); + super(contextKeyService, commandService, telemetryService, messageService); this._cachedResolver = null; this._dynamicKeybindings = []; diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index 17ed8f6e8f1..7fac82dc12b 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -176,7 +176,7 @@ export class DynamicStandaloneServices extends Disposable { let commandService = ensure(ICommandService, () => new StandaloneCommandService(this._instantiationService)); - ensure(IKeybindingService, () => this._register(new StandaloneKeybindingService(contextKeyService, commandService, messageService, domElement))); + ensure(IKeybindingService, () => this._register(new StandaloneKeybindingService(contextKeyService, commandService, telemetryService, messageService, domElement))); let contextViewService = ensure(IContextViewService, () => this._register(new ContextViewService(domElement, telemetryService, messageService))); diff --git a/src/vs/editor/standalone/test/browser/simpleServices.test.ts b/src/vs/editor/standalone/test/browser/simpleServices.test.ts index 12aaaad2825..e2a6120ec59 100644 --- a/src/vs/editor/standalone/test/browser/simpleServices.test.ts +++ b/src/vs/editor/standalone/test/browser/simpleServices.test.ts @@ -11,6 +11,7 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { KeyCode } from 'vs/base/common/keyCodes'; import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; +import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; suite('StandaloneKeybindingService', () => { @@ -35,7 +36,7 @@ suite('StandaloneKeybindingService', () => { let domElement = document.createElement('div'); - let keybindingService = new TestStandaloneKeybindingService(contextKeyService, commandService, messageService, domElement); + let keybindingService = new TestStandaloneKeybindingService(contextKeyService, commandService, NullTelemetryService, messageService, domElement); let commandInvoked = false; keybindingService.addDynamicKeybinding('testCommand', KeyCode.F9, () => { diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 15c5bef831a..c43c2f05b34 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -61,7 +61,7 @@ declare module monaco { public static as(value: null): Promise; public static as(value: undefined): Promise; - public static as>(value: TPromise): TPromise; + public static as>(value: SomePromise): SomePromise; public static as(value: T): Promise; public static is(value: any): value is PromiseLike; diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index 0b5586ace11..0ebbab71551 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -87,7 +87,7 @@ export interface IMenuRegistry { getMenuItems(loc: MenuId): IMenuItem[]; } -export const MenuRegistry: IMenuRegistry = new class { +export const MenuRegistry: IMenuRegistry = new class implements IMenuRegistry { private _commands: { [id: string]: ICommandAction } = Object.create(null); diff --git a/src/vs/platform/configuration/common/configurationRegistry.ts b/src/vs/platform/configuration/common/configurationRegistry.ts index 0d3276bf69d..52d651b43d7 100644 --- a/src/vs/platform/configuration/common/configurationRegistry.ts +++ b/src/vs/platform/configuration/common/configurationRegistry.ts @@ -29,6 +29,12 @@ export interface IConfigurationRegistry { */ registerConfigurations(configurations: IConfigurationNode[], validate?: boolean): void; + /** + * Signal that the schema of a configuration setting has changes. It is currently only supported to change enumeration values. + * Property or default value changes are not allowed. + */ + notifyConfigurationSchemaUpdated(configuration: IConfigurationNode): void; + registerDefaultConfigurations(defaultConfigurations: IDefaultConfigurationExtension[]): void; /** @@ -126,6 +132,10 @@ class ConfigurationRegistry implements IConfigurationRegistry { this._onDidRegisterConfiguration.fire(this); } + public notifyConfigurationSchemaUpdated(configuration: IConfigurationNode) { + contributionRegistry.registerSchema(editorConfigurationSchemaId, this.editorConfigurationSchema); + } + public registerOverrideIdentifiers(overrideIdentifiers: string[]): void { this.overrideIdentifiers.push(...overrideIdentifiers); this.updateOverridePropertyPatternKey(); diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index f5637497e53..607ec578b63 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -146,7 +146,7 @@ export class EnvironmentService implements IEnvironmentService { try { fs.writeFileSync(machineIdPath, this.machineUUID, 'utf8'); } catch (err) { - console.warn('Could not store machine ID'); + // noop } } diff --git a/src/vs/platform/keybinding/common/abstractKeybindingService.ts b/src/vs/platform/keybinding/common/abstractKeybindingService.ts index 176a15f5e27..85e8ad8165a 100644 --- a/src/vs/platform/keybinding/common/abstractKeybindingService.ts +++ b/src/vs/platform/keybinding/common/abstractKeybindingService.ts @@ -16,6 +16,7 @@ import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { IMessageService } from 'vs/platform/message/common/message'; import Event, { Emitter } from 'vs/base/common/event'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; interface CurrentChord { keypress: string; @@ -32,18 +33,21 @@ export abstract class AbstractKeybindingService implements IKeybindingService { protected _onDidUpdateKeybindings: Emitter; private _contextKeyService: IContextKeyService; - protected _commandService: ICommandService; private _statusService: IStatusbarService; private _messageService: IMessageService; + protected _commandService: ICommandService; + protected _telemetryService: ITelemetryService; constructor( contextKeyService: IContextKeyService, commandService: ICommandService, + telemetryService: ITelemetryService, messageService: IMessageService, statusService?: IStatusbarService ) { this._contextKeyService = contextKeyService; this._commandService = commandService; + this._telemetryService = telemetryService; this._statusService = statusService; this._messageService = messageService; @@ -161,6 +165,13 @@ export abstract class AbstractKeybindingService implements IKeybindingService { this._commandService.executeCommand(resolveResult.commandId, resolveResult.commandArgs || {}).done(undefined, err => { this._messageService.show(Severity.Warning, err); }); + /* __GDPR__ + "workbenchActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + this._telemetryService.publicLog('workbenchActionExecuted', { id: resolveResult.commandId, from: 'keybinding' }); } return shouldPreventDefault; diff --git a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts index f5cc9fb7984..e9468d0dd7b 100644 --- a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts +++ b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts @@ -19,6 +19,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { OS } from 'vs/base/common/platform'; import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; +import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; function createContext(ctx: any) { return { @@ -40,7 +41,7 @@ suite('AbstractKeybindingService', () => { messageService: IMessageService, statusService?: IStatusbarService ) { - super(contextKeyService, commandService, messageService, statusService); + super(contextKeyService, commandService, NullTelemetryService, messageService, statusService); this._resolver = resolver; } @@ -123,6 +124,7 @@ suite('AbstractKeybindingService', () => { let messageService: IMessageService = { _serviceBrand: undefined, hideAll: undefined, + confirmSync: undefined, confirm: undefined, show: (sev: Severity, message: any): () => void => { showMessageCalls.push({ diff --git a/src/vs/platform/message/common/message.ts b/src/vs/platform/message/common/message.ts index 627bbe0900b..cfe7e448854 100644 --- a/src/vs/platform/message/common/message.ts +++ b/src/vs/platform/message/common/message.ts @@ -23,6 +23,10 @@ export interface IConfirmation { detail?: string; primaryButton?: string; secondaryButton?: string; + checkbox?: { + label: string; + checked?: boolean; + }; } export const CloseAction = new Action('close.message', nls.localize('close', "Close"), null, true, () => TPromise.as(true)); @@ -31,6 +35,11 @@ export const CancelAction = new Action('cancel.message', nls.localize('cancel', export const IMessageService = createDecorator('messageService'); +export interface IConfirmationResult { + confirmed: boolean; + checkboxChecked?: boolean; +} + export interface IMessageService { _serviceBrand: any; @@ -53,7 +62,12 @@ export interface IMessageService { /** * Ask the user for confirmation. */ - confirm(confirmation: IConfirmation): boolean; + confirmSync(confirmation: IConfirmation): boolean; + + /** + * Ask the user for confirmation without blocking. + */ + confirm(confirmation: IConfirmation): TPromise; } export const IChoiceService = createDecorator('choiceService'); diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 0d21ee0e7a9..d33b183817f 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -89,7 +89,7 @@ class ColorRegistry implements IColorRegistry { public registerColor(id: string, defaults: ColorDefaults, description: string): ColorIdentifier { let colorContribution = { id, description, defaults }; this.colorsById[id] = colorContribution; - this.colorSchema.properties[id] = { type: 'string', description, format: 'color', pattern: colorPattern, patternErrorMessage: colorPatternErrorMessage }; + this.colorSchema.properties[id] = { type: 'string', description, format: 'color', default: '#ff0000', pattern: colorPattern, patternErrorMessage: colorPatternErrorMessage }; this.colorReferenceSchema.enum.push(id); this.colorReferenceSchema.enumDescriptions.push(description); return id; diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index 6be7162905c..5f6c19c1d55 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -48,7 +48,7 @@ export interface IWindowsService { toggleDevTools(windowId: number): TPromise; closeWorkspace(windowId: number): TPromise; openWorkspace(windowId: number): TPromise; - createAndEnterWorkspace(windowId: number, folders?: string[], path?: string): TPromise; + createAndEnterWorkspace(windowId: number, folderPaths?: string[], path?: string): TPromise; saveAndEnterWorkspace(windowId: number, path: string): TPromise; toggleFullScreen(windowId: number): TPromise; setRepresentedFilename(windowId: number, fileName: string): TPromise; @@ -100,6 +100,11 @@ export interface IWindowsService { export const IWindowService = createDecorator('windowService'); +export interface IMessageBoxResult { + button: number; + checkboxChecked?: boolean; +} + export interface IWindowService { _serviceBrand: any; @@ -116,7 +121,7 @@ export interface IWindowService { closeWorkspace(): TPromise; openWorkspace(): TPromise; updateTouchBar(items: ICommandAction[][]): TPromise; - createAndEnterWorkspace(folders?: string[], path?: string): TPromise; + createAndEnterWorkspace(folderPaths?: string[], path?: string): TPromise; saveAndEnterWorkspace(path: string): TPromise; toggleFullScreen(): TPromise; setRepresentedFilename(fileName: string): TPromise; @@ -130,7 +135,8 @@ export interface IWindowService { unmaximizeWindow(): TPromise; onWindowTitleDoubleClick(): TPromise; show(): TPromise; - showMessageBox(options: Electron.MessageBoxOptions): number; + showMessageBoxSync(options: Electron.MessageBoxOptions): number; + showMessageBox(options: Electron.MessageBoxOptions): TPromise; showSaveDialog(options: Electron.SaveDialogOptions, callback?: (fileName: string) => void): string; showOpenDialog(options: Electron.OpenDialogOptions, callback?: (fileNames: string[]) => void): string[]; } diff --git a/src/vs/platform/windows/common/windowsIpc.ts b/src/vs/platform/windows/common/windowsIpc.ts index a99c9fc5fe4..237fadf835f 100644 --- a/src/vs/platform/windows/common/windowsIpc.ts +++ b/src/vs/platform/windows/common/windowsIpc.ts @@ -174,8 +174,8 @@ export class WindowsChannelClient implements IWindowsService { return this.channel.call('openWorkspace', windowId); } - createAndEnterWorkspace(windowId: number, folders?: string[], path?: string): TPromise { - return this.channel.call('createAndEnterWorkspace', [windowId, folders, path]); + createAndEnterWorkspace(windowId: number, folderPaths?: string[], path?: string): TPromise { + return this.channel.call('createAndEnterWorkspace', [windowId, folderPaths, path]); } saveAndEnterWorkspace(windowId: number, path: string): TPromise { diff --git a/src/vs/platform/windows/electron-browser/windowService.ts b/src/vs/platform/windows/electron-browser/windowService.ts index adcffdff958..0cf353eb6f2 100644 --- a/src/vs/platform/windows/electron-browser/windowService.ts +++ b/src/vs/platform/windows/electron-browser/windowService.ts @@ -7,7 +7,7 @@ import Event, { filterEvent, mapEvent, any } from 'vs/base/common/event'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IWindowService, IWindowsService, INativeOpenDialogOptions, IEnterWorkspaceResult } from 'vs/platform/windows/common/windows'; +import { IWindowService, IWindowsService, INativeOpenDialogOptions, IEnterWorkspaceResult, IMessageBoxResult } from 'vs/platform/windows/common/windows'; import { remote } from 'electron'; import { IRecentlyOpened } from 'vs/platform/history/common/history'; import { ICommandAction } from 'vs/platform/actions/common/actions'; @@ -71,8 +71,8 @@ export class WindowService implements IWindowService { return this.windowsService.openWorkspace(this.windowId); } - createAndEnterWorkspace(folders?: string[], path?: string): TPromise { - return this.windowsService.createAndEnterWorkspace(this.windowId, folders, path); + createAndEnterWorkspace(folderPaths?: string[], path?: string): TPromise { + return this.windowsService.createAndEnterWorkspace(this.windowId, folderPaths, path); } saveAndEnterWorkspace(path: string): TPromise { @@ -127,10 +127,18 @@ export class WindowService implements IWindowService { return this.windowsService.showWindow(this.windowId); } - showMessageBox(options: Electron.MessageBoxOptions): number { + showMessageBoxSync(options: Electron.MessageBoxOptions): number { return remote.dialog.showMessageBox(remote.getCurrentWindow(), options); } + showMessageBox(options: Electron.MessageBoxOptions): TPromise { + return new TPromise((c, e) => { + return remote.dialog.showMessageBox(remote.getCurrentWindow(), options, (response: number, checkboxChecked: boolean) => { + c({ button: response, checkboxChecked }); + }); + }); + } + showSaveDialog(options: Electron.SaveDialogOptions, callback?: (fileName: string) => void): string { if (callback) { return remote.dialog.showSaveDialog(remote.getCurrentWindow(), options, callback); diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index b8396d068fb..ba04b4766e7 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -61,7 +61,7 @@ export interface IWindowsMainService { ready(initialUserEnv: IProcessEnvironment): void; reload(win: ICodeWindow, cli?: ParsedArgs): void; openWorkspace(win?: ICodeWindow): void; - createAndEnterWorkspace(win: ICodeWindow, folders?: string[], path?: string): TPromise; + createAndEnterWorkspace(win: ICodeWindow, folderPaths?: string[], path?: string): TPromise; saveAndEnterWorkspace(win: ICodeWindow, path: string): TPromise; closeWorkspace(win: ICodeWindow): void; open(openConfig: IOpenConfiguration): ICodeWindow[]; diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index ca30a357874..2c3ac1c8934 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -135,11 +135,11 @@ export class WindowsService implements IWindowsService, IDisposable { return TPromise.as(null); } - createAndEnterWorkspace(windowId: number, folders?: string[], path?: string): TPromise { + createAndEnterWorkspace(windowId: number, folderPaths?: string[], path?: string): TPromise { const codeWindow = this.windowsMainService.getWindowById(windowId); if (codeWindow) { - return this.windowsMainService.createAndEnterWorkspace(codeWindow, folders, path); + return this.windowsMainService.createAndEnterWorkspace(codeWindow, folderPaths, path); } return TPromise.as(null); diff --git a/src/vs/platform/workspaces/common/workspaces.ts b/src/vs/platform/workspaces/common/workspaces.ts index adaac16ff0b..f0e4c85463f 100644 --- a/src/vs/platform/workspaces/common/workspaces.ts +++ b/src/vs/platform/workspaces/common/workspaces.ts @@ -15,6 +15,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import Event from 'vs/base/common/event'; import { tildify, getPathLabel } from 'vs/base/common/labels'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import URI from 'vs/base/common/uri'; export const IWorkspacesMainService = createDecorator('workspacesMainService'); export const IWorkspacesService = createDecorator('workspacesService'); @@ -83,7 +84,9 @@ export interface IWorkspacesMainService extends IWorkspacesService { onUntitledWorkspaceDeleted: Event; saveWorkspace(workspace: IWorkspaceIdentifier, target: string): TPromise; - createWorkspaceSync(folders?: string[]): IWorkspaceIdentifier; + + createWorkspaceSync(folderPaths?: string[]): IWorkspaceIdentifier; + createWorkspaceSync(folderResources?: URI[]): IWorkspaceIdentifier; resolveWorkspace(path: string): TPromise; resolveWorkspaceSync(path: string): IResolvedWorkspace; @@ -100,7 +103,8 @@ export interface IWorkspacesMainService extends IWorkspacesService { export interface IWorkspacesService { _serviceBrand: any; - createWorkspace(folders?: string[]): TPromise; + createWorkspace(folderPaths?: string[]): TPromise; + createWorkspace(folderResources?: URI[]): TPromise; } export function getWorkspaceLabel(workspace: (IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier), environmentService: IEnvironmentService, options?: { verbose: boolean }): string { diff --git a/src/vs/platform/workspaces/common/workspacesIpc.ts b/src/vs/platform/workspaces/common/workspacesIpc.ts index 45c495b242f..31235b7a905 100644 --- a/src/vs/platform/workspaces/common/workspacesIpc.ts +++ b/src/vs/platform/workspaces/common/workspacesIpc.ts @@ -8,9 +8,10 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IWorkspacesService, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import URI from 'vs/base/common/uri'; export interface IWorkspacesChannel extends IChannel { - call(command: 'createWorkspace', arg: [string[]]): TPromise; + call(command: 'createWorkspace', arg: [(string | URI)[]]): TPromise; call(command: string, arg?: any): TPromise; } @@ -18,9 +19,22 @@ export class WorkspacesChannel implements IWorkspacesChannel { constructor(private service: IWorkspacesService) { } - call(command: string, arg?: any): TPromise { + public call(command: string, arg?: any): TPromise { switch (command) { - case 'createWorkspace': return this.service.createWorkspace(arg); + case 'createWorkspace': { + let folders: any[]; + if (Array.isArray(arg)) { + folders = arg.map(folder => { + if (typeof folder === 'string') { + return folder; + } + + return URI.revive(folder); + }); + } + + return this.service.createWorkspace(folders); + }; } return void 0; @@ -33,7 +47,9 @@ export class WorkspacesChannelClient implements IWorkspacesService { constructor(private channel: IWorkspacesChannel) { } - createWorkspace(folders?: string[]): TPromise { - return this.channel.call('createWorkspace', folders); + public createWorkspace(folderPaths?: string[]): TPromise; + public createWorkspace(folderResources?: URI[]): TPromise; + public createWorkspace(arg1?: any[]): TPromise { + return this.channel.call('createWorkspace', arg1); } } \ No newline at end of file diff --git a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts index 432850ff32d..c3b3bb22264 100644 --- a/src/vs/platform/workspaces/electron-main/workspacesMainService.ts +++ b/src/vs/platform/workspaces/electron-main/workspacesMainService.ts @@ -5,7 +5,7 @@ 'use strict'; -import { IWorkspacesMainService, IWorkspaceIdentifier, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isRawFileWorkspaceFolder, isStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesMainService, IWorkspaceIdentifier, WORKSPACE_EXTENSION, IWorkspaceSavedEvent, UNTITLED_WORKSPACE_NAME, IResolvedWorkspace, IStoredWorkspaceFolder, isRawFileWorkspaceFolder, isStoredWorkspaceFolder, IRawFileWorkspaceFolder, IRawUriWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { TPromise } from 'vs/base/common/winjs.base'; import { isParent } from 'vs/platform/files/common/files'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -120,16 +120,20 @@ export class WorkspacesMainService implements IWorkspacesMainService { return isParent(path, this.environmentService.workspacesHome, !isLinux /* ignore case */); } - public createWorkspace(folders: string[]): TPromise { - const { workspace, configParent, storedWorkspace } = this.createUntitledWorkspace(folders); + public createWorkspace(folders: string[]): TPromise; + public createWorkspace(resources: URI[]): TPromise; + public createWorkspace(arg1: string[] | URI[]): TPromise { + const { workspace, configParent, storedWorkspace } = this.createUntitledWorkspace(arg1); return mkdirp(configParent).then(() => { return writeFile(workspace.configPath, JSON.stringify(storedWorkspace, null, '\t')).then(() => workspace); }); } - public createWorkspaceSync(folders: string[]): IWorkspaceIdentifier { - const { workspace, configParent, storedWorkspace } = this.createUntitledWorkspace(folders); + public createWorkspaceSync(folders: string[]): IWorkspaceIdentifier; + public createWorkspaceSync(resources: URI[]): IWorkspaceIdentifier; + public createWorkspaceSync(arg1: string[] | URI[]): IWorkspaceIdentifier { + const { workspace, configParent, storedWorkspace } = this.createUntitledWorkspace(arg1); if (!existsSync(this.workspacesHome)) { mkdirSync(this.workspacesHome); @@ -142,15 +146,27 @@ export class WorkspacesMainService implements IWorkspacesMainService { return workspace; } - private createUntitledWorkspace(folders: string[]): { workspace: IWorkspaceIdentifier, configParent: string, storedWorkspace: IStoredWorkspace } { + private createUntitledWorkspace(folders: (string | URI)[]): { workspace: IWorkspaceIdentifier, configParent: string, storedWorkspace: IStoredWorkspace } { const randomId = (Date.now() + Math.round(Math.random() * 1000)).toString(); const untitledWorkspaceConfigFolder = join(this.workspacesHome, randomId); const untitledWorkspaceConfigPath = join(untitledWorkspaceConfigFolder, UNTITLED_WORKSPACE_NAME); const storedWorkspace: IStoredWorkspace = { - folders: folders.map(folder => ({ - path: folder - })) + folders: folders.map(folder => { + + // File path + if (typeof folder === 'string') { + return { path: massageFolderPathForWorkspace(folder, untitledWorkspaceConfigFolder, []) } as IRawFileWorkspaceFolder; + } + + // File URI + else if (folder.scheme === 'file') { + return { path: massageFolderPathForWorkspace(folder.fsPath, untitledWorkspaceConfigFolder, []) } as IRawFileWorkspaceFolder; + } + + // Any URI + return { uri: folder.toString(true) } as IRawUriWorkspaceFolder; + }) }; return { diff --git a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts index 918dd0ef819..3adce81a073 100644 --- a/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts +++ b/src/vs/platform/workspaces/test/electron-main/workspacesMainService.test.ts @@ -14,7 +14,7 @@ import pfs = require('vs/base/node/pfs'); import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { parseArgs } from 'vs/platform/environment/node/argv'; import { WorkspacesMainService, IStoredWorkspace } from 'vs/platform/workspaces/electron-main/workspacesMainService'; -import { WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier, IRawFileWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; +import { WORKSPACE_EXTENSION, IWorkspaceSavedEvent, IWorkspaceIdentifier, IRawFileWorkspaceFolder, IRawUriWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; import { LogMainService } from 'vs/platform/log/common/log'; import URI from 'vs/base/common/uri'; @@ -73,18 +73,42 @@ suite('WorkspacesMainService', () => { }); }); - test('createWorkspaceSync (folders)', () => { + test('createWorkspaceSync (folders as paths)', () => { const workspace = service.createWorkspaceSync([process.cwd(), os.tmpdir()]); assert.ok(workspace); assert.ok(fs.existsSync(workspace.configPath)); assert.ok(service.isUntitledWorkspace(workspace)); const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; - assert.equal(ws.folders.length, 2); // + assert.equal(ws.folders.length, 2); assert.equal((ws.folders[0]).path, process.cwd()); assert.equal((ws.folders[1]).path, os.tmpdir()); }); + test('createWorkspaceSync (folders as file URIs)', () => { + const workspace = service.createWorkspaceSync([URI.file(process.cwd()), URI.file(os.tmpdir())]); + assert.ok(workspace); + assert.ok(fs.existsSync(workspace.configPath)); + assert.ok(service.isUntitledWorkspace(workspace)); + + const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; + assert.equal(ws.folders.length, 2); + assert.equal((ws.folders[0]).path, process.cwd()); + assert.equal((ws.folders[1]).path, os.tmpdir()); + }); + + test('createWorkspaceSync (folders as other resource URIs)', () => { + const workspace = service.createWorkspaceSync([URI.from({ scheme: 'myScheme', path: process.cwd() }), URI.from({ scheme: 'myScheme', path: os.tmpdir() })]); + assert.ok(workspace); + assert.ok(fs.existsSync(workspace.configPath)); + assert.ok(service.isUntitledWorkspace(workspace)); + + const ws = JSON.parse(fs.readFileSync(workspace.configPath).toString()) as IStoredWorkspace; + assert.equal(ws.folders.length, 2); + assert.equal((ws.folders[0]).uri, URI.from({ scheme: 'myScheme', path: process.cwd() }).toString(true)); + assert.equal((ws.folders[1]).uri, URI.from({ scheme: 'myScheme', path: os.tmpdir() }).toString(true)); + }); + test('resolveWorkspaceSync', done => { return service.createWorkspace([process.cwd(), os.tmpdir()]).then(workspace => { assert.ok(service.resolveWorkspaceSync(workspace.configPath)); diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 2d29266d818..1a63221b1f9 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1970,6 +1970,13 @@ declare module 'vscode' { * @param value Markdown string. */ appendMarkdown(value: string): MarkdownString; + + /** + * Appends the given string as codeblock using the provided language. + * @param value A code snippet. + * @param language An optional [language identifier](#languages.getLanguages). + */ + appendCodeblock(value: string, language?: string): MarkdownString; } /** diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index db429979dd7..c0044aa87a9 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -843,6 +843,15 @@ export class MarkdownString { this.value += value; return this; } + + appendCodeblock(code: string, language: string = ''): MarkdownString { + this.value += '\n```'; + this.value += language; + this.value += '\n'; + this.value += code; + this.value += '\n```\n'; + return this; + } } export class ParameterInformation { @@ -1465,4 +1474,4 @@ export class RelativePattern implements IRelativePattern { this.base = typeof base === 'string' ? base : base.uri.fsPath; this.pattern = pattern; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index b154a0b6f21..ea253e70218 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -9,14 +9,14 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { Action } from 'vs/base/common/actions'; import nls = require('vs/nls'); import { distinct } from 'vs/base/common/arrays'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import URI from 'vs/base/common/uri'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { WORKSPACE_FILTER } from 'vs/platform/workspaces/common/workspaces'; +import { WORKSPACE_FILTER, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { isLinux } from 'vs/base/common/platform'; import { dirname } from 'vs/base/common/paths'; @@ -226,6 +226,27 @@ export class RemoveRootFolderAction extends Action { } } +export class OpenFolderSettingsAction extends Action { + + static ID = 'workbench.action.openFolderSettings'; + static LABEL = nls.localize('openFolderSettings', "Open Folder Settings"); + + constructor( + private rootUri: URI, + id: string, + label: string, + @IWorkspaceContextService private contextService: IWorkspaceContextService, + @ICommandService private commandService: ICommandService + ) { + super(id, label); + } + + public run(): TPromise { + const workspaceFolder = this.contextService.getWorkspaceFolder(this.rootUri); + return this.commandService.executeCommand('_workbench.action.openFolderSettings', workspaceFolder); + } +} + export class SaveWorkspaceAsAction extends BaseWorkspacesAction { static ID = 'workbench.action.saveWorkspaceAs'; @@ -320,6 +341,49 @@ export class OpenWorkspaceConfigFileAction extends Action { } } +export class OpenFolderAsWorkspaceInNewWindowAction extends Action { + + public static ID = 'workbench.action.openFolderAsWorkspaceInNewWindow'; + public static LABEL = nls.localize('openFolderAsWorkspaceInNewWindow', "Open Folder as Workspace in New Window"); + + constructor( + id: string, + label: string, + @IWorkspaceContextService private workspaceContextService: IWorkspaceContextService, + @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, + @IWindowsService private windowsService: IWindowsService, + @ICommandService private commandService: ICommandService, + @IWorkspacesService private workspacesService: IWorkspacesService + ) { + super(id, label); + } + + public run(): TPromise { + const folders = this.workspaceContextService.getWorkspace().folders; + + let folderPromise: TPromise; + if (folders.length === 0) { + folderPromise = TPromise.as(null); + } else if (folders.length === 1) { + folderPromise = TPromise.as(folders[0]); + } else { + folderPromise = this.commandService.executeCommand(PICK_WORKSPACE_FOLDER_COMMAND); + } + + return folderPromise.then(folder => { + if (!folder) { + return void 0; // need at least one folder + } + + return this.workspacesService.createWorkspace([folder.uri]).then(newWorkspace => { + return this.workspaceEditingService.copyWorkspaceSettings(newWorkspace).then(() => { + return this.windowsService.openWindow([newWorkspace.configPath], { forceNewWindow: true }); + }); + }); + }); + } +} + export const PICK_WORKSPACE_FOLDER_COMMAND = '_workbench.pickWorkspaceFolder'; CommandsRegistry.registerCommand(PICK_WORKSPACE_FOLDER_COMMAND, function (accessor: ServicesAccessor, args?: [IPickOptions, CancellationToken]) { diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index afcd51a8b91..93a7498c27b 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -270,6 +270,7 @@ export function getIconClasses(modelService: IModelService, modeService: IModeSe for (let i = 1; i < dotSegments.length; i++) { classes.push(`${dotSegments.slice(i).join('.')}-ext-file-icon`); // add each combination of all found extensions if more than one } + classes.push(`ext-file-icon`); // extra segment to increase file-ext score // Configured Language let configuredLangId = getConfiguredLangId(modelService, resource); diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index e4a27f10a31..238b3b33b11 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -16,7 +16,7 @@ import { IPanelService, IPanelIdentifier } from 'vs/workbench/services/panel/com import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -export class PanelAction extends Action { +export class OpenPanelAction extends Action { constructor( private panel: IPanelIdentifier, diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index 9e761d9263e..1608bfe44d2 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -23,7 +23,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; -import { ClosePanelAction, PanelAction, ToggleMaximizedPanelAction } from 'vs/workbench/browser/parts/panel/panelActions'; +import { ClosePanelAction, OpenPanelAction, ToggleMaximizedPanelAction } from 'vs/workbench/browser/parts/panel/panelActions'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER } from 'vs/workbench/common/theme'; import { activeContrastBorder, focusBorder, contrastBorder, editorBackground } from 'vs/platform/theme/common/colorRegistry'; @@ -37,7 +37,7 @@ export class PanelPart extends CompositePart implements IPanelService { private blockOpeningPanel: boolean; private panelSwitcherBar: ActionBar; - private panelIdToActions: { [panelId: string]: PanelAction; }; + private panelIdToActions: { [panelId: string]: OpenPanelAction; }; constructor( id: string, @@ -183,7 +183,7 @@ export class PanelPart extends CompositePart implements IPanelService { const panels = this.getPanels(); this.panelSwitcherBar.push(panels.map(panel => { - const action = this.instantiationService.createInstance(PanelAction, panel); + const action = this.instantiationService.createInstance(OpenPanelAction, panel); this.panelIdToActions[panel.id] = action; this.toUnbind.push(action); diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index 72bfb28604c..011fb2a1548 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -17,7 +17,6 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { Part } from 'vs/workbench/browser/part'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { StatusbarAlignment, IStatusbarRegistry, Extensions, IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -287,29 +286,6 @@ class StatusBarEntryItem implements IStatusbarItem { private executeCommand(id: string, args?: any[]) { args = args || []; - // Lookup built in commands - const builtInActionDescriptor = Registry.as(ActionExtensions.WorkbenchActions).getWorkbenchAction(id); - if (builtInActionDescriptor) { - const action = this.instantiationService.createInstance(builtInActionDescriptor.syncDescriptor); - - if (action.enabled) { - /* __GDPR__ - "workbenchActionExecuted" : { - "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('workbenchActionExecuted', { id: action.id, from: 'status bar' }); - (action.run() || TPromise.as(null)).done(() => { - action.dispose(); - }, (err) => this.messageService.show(Severity.Error, toErrorMessage(err))); - } else { - this.messageService.show(Severity.Warning, nls.localize('canNotRun', "Command '{0}' is currently not enabled and can not be run.", action.label || id)); - } - - return; - } - // Maintain old behaviour of always focusing the editor here const activeEditor = this.editorService.getActiveEditor(); const codeEditor = getCodeEditor(activeEditor); @@ -317,7 +293,13 @@ class StatusBarEntryItem implements IStatusbarItem { codeEditor.focus(); } - // Fallback to the command service for any other case + /* __GDPR__ + "workbenchActionExecuted" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('workbenchActionExecuted', { id, from: 'status bar' }); this.commandService.executeCommand(id, ...args).done(undefined, err => this.messageService.show(Severity.Error, toErrorMessage(err))); } } @@ -355,4 +337,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { if (statusBarProminentItemHoverBackground) { collector.addRule(`.monaco-workbench > .part.statusbar > .statusbar-item a.status-bar-info:hover:not([disabled]):not(.disabled) { background-color: ${statusBarProminentItemHoverBackground}; }`); } -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index e849116bb98..29e5639eacd 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -211,9 +211,8 @@ export class ViewsViewlet extends PanelViewlet { private viewHeaderContextMenuListeners: IDisposable[] = []; private viewletSettings: object; private readonly viewsContextKeys: Set = new Set(); - private viewsViewletPanels: ViewsViewletPanel[] = []; - + private didLayout = false; protected viewsStates: Map = new Map(); private areExtensionsReady: boolean = false; @@ -272,6 +271,11 @@ export class ViewsViewlet extends PanelViewlet { layout(dimension: Dimension): void { super.layout(dimension); + if (!this.didLayout) { + this.didLayout = true; + this._resizePanels(); + } + for (const view of this.viewsViewletPanels) { let viewState = this.updateViewStateSize(view); this.viewsStates.set(view.id, viewState); @@ -416,6 +420,10 @@ export class ViewsViewlet extends PanelViewlet { } private _resizePanels(): void { + if (!this.didLayout) { + return; + } + for (const panel of this.viewsViewletPanels) { const viewState = this.viewsStates.get(panel.id); const size = (viewState && viewState.size) || 200; diff --git a/src/vs/workbench/common/actions.ts b/src/vs/workbench/common/actions.ts index 1bd3ba72aa6..d1b8e840b46 100644 --- a/src/vs/workbench/common/actions.ts +++ b/src/vs/workbench/common/actions.ts @@ -5,17 +5,16 @@ 'use strict'; import { TPromise } from 'vs/base/common/winjs.base'; -import collections = require('vs/base/common/collections'); import { Registry } from 'vs/platform/registry/common/platform'; import { IAction } from 'vs/base/common/actions'; -import { KeybindingsRegistry, ICommandAndKeybindingRule } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IPartService } from 'vs/workbench/services/part/common/partService'; -import { ICommandHandler } from 'vs/platform/commands/common/commands'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { IMessageService } from 'vs/platform/message/common/message'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import Severity from 'vs/base/common/severity'; +import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; export const Extensions = { WorkbenchActions: 'workbench.contributions.actions' @@ -31,166 +30,97 @@ export interface IWorkbenchActionRegistry { * Registers a workbench action to the platform. Workbench actions are not * visible by default and can only be invoked through a keybinding if provided. */ - registerWorkbenchAction(descriptor: SyncActionDescriptor, alias: string, category?: string): void; - - /** - * Unregisters a workbench action from the platform. - */ - unregisterWorkbenchAction(id: string): boolean; - - /** - * Returns the workbench action descriptor for the given id or null if none. - */ - getWorkbenchAction(id: string): SyncActionDescriptor; - - /** - * Returns an array of registered workbench actions known to the platform. - */ - getWorkbenchActions(): SyncActionDescriptor[]; - - /** - * Returns the alias associated with the given action or null if none. - */ - getAlias(actionId: string): string; - - /** - * Returns the category for the given action or null if none. - */ - getCategory(actionId: string): string; + registerWorkbenchAction(descriptor: SyncActionDescriptor, alias: string, category?: string): IDisposable; } -interface IActionMeta { - alias: string; - category?: string; -} +Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionRegistry { -class WorkbenchActionRegistry implements IWorkbenchActionRegistry { - private workbenchActions: collections.IStringDictionary; - private mapActionIdToMeta: { [id: string]: IActionMeta; }; - - constructor() { - this.workbenchActions = Object.create(null); - this.mapActionIdToMeta = Object.create(null); + registerWorkbenchAction(descriptor: SyncActionDescriptor, alias: string, category?: string): IDisposable { + return this._registerWorkbenchCommandFromAction(descriptor, alias, category); } - public registerWorkbenchAction(descriptor: SyncActionDescriptor, alias: string, category?: string): void { - if (!this.workbenchActions[descriptor.id]) { - this.workbenchActions[descriptor.id] = descriptor; - registerWorkbenchCommandFromAction(descriptor); + private _registerWorkbenchCommandFromAction(descriptor: SyncActionDescriptor, alias: string, category?: string): IDisposable { + let registrations: IDisposable[] = []; - const meta: IActionMeta = { alias }; - if (typeof category === 'string') { - meta.category = category; - } + // command + registrations.push(CommandsRegistry.registerCommand(descriptor.id, this._createCommandHandler(descriptor))); - this.mapActionIdToMeta[descriptor.id] = meta; - } - } - - public unregisterWorkbenchAction(id: string): boolean { - if (!this.workbenchActions[id]) { - return false; - } - - delete this.workbenchActions[id]; - delete this.mapActionIdToMeta[id]; - - return true; - } - - public getWorkbenchAction(id: string): SyncActionDescriptor { - return this.workbenchActions[id] || null; - } - - public getCategory(id: string): string { - return (this.mapActionIdToMeta[id] && this.mapActionIdToMeta[id].category) || null; - } - - public getAlias(id: string): string { - return (this.mapActionIdToMeta[id] && this.mapActionIdToMeta[id].alias) || null; - } - - public getWorkbenchActions(): SyncActionDescriptor[] { - return collections.values(this.workbenchActions); - } - - public setWorkbenchActions(actions: SyncActionDescriptor[]): void { - this.workbenchActions = Object.create(null); - this.mapActionIdToMeta = Object.create(null); - - actions.forEach(action => this.registerWorkbenchAction(action, ''), this); - } -} - -Registry.add(Extensions.WorkbenchActions, new WorkbenchActionRegistry()); - -function registerWorkbenchCommandFromAction(descriptor: SyncActionDescriptor): void { - const when = descriptor.keybindingContext; - const weight = (typeof descriptor.keybindingWeight === 'undefined' ? KeybindingsRegistry.WEIGHT.workbenchContrib() : descriptor.keybindingWeight); - const keybindings = descriptor.keybindings; - - const desc: ICommandAndKeybindingRule = { - id: descriptor.id, - handler: createCommandHandler(descriptor), - weight: weight, - when: when, - primary: keybindings && keybindings.primary, - secondary: keybindings && keybindings.secondary, - win: keybindings && keybindings.win, - mac: keybindings && keybindings.mac, - linux: keybindings && keybindings.linux - }; - - KeybindingsRegistry.registerCommandAndKeybindingRule(desc); -} - -function createCommandHandler(descriptor: SyncActionDescriptor): ICommandHandler { - return (accessor, args) => { - const messageService = accessor.get(IMessageService); - const instantiationService = accessor.get(IInstantiationService); - const telemetryService = accessor.get(ITelemetryService); - const partService = accessor.get(IPartService); - - TPromise.as(triggerAndDisposeAction(instantiationService, telemetryService, partService, descriptor, args)).done(null, (err) => { - messageService.show(Severity.Error, err); + // keybinding + const when = descriptor.keybindingContext; + const weight = (typeof descriptor.keybindingWeight === 'undefined' ? KeybindingsRegistry.WEIGHT.workbenchContrib() : descriptor.keybindingWeight); + const keybindings = descriptor.keybindings; + KeybindingsRegistry.registerKeybindingRule({ + id: descriptor.id, + weight: weight, + when: when, + primary: keybindings && keybindings.primary, + secondary: keybindings && keybindings.secondary, + win: keybindings && keybindings.win, + mac: keybindings && keybindings.mac, + linux: keybindings && keybindings.linux }); - }; -} -function triggerAndDisposeAction(instantitationService: IInstantiationService, telemetryService: ITelemetryService, partService: IPartService, descriptor: SyncActionDescriptor, args: any): TPromise { - const actionInstance = instantitationService.createInstance(descriptor.syncDescriptor); - actionInstance.label = descriptor.label || actionInstance.label; + // menu item + // TODO@Ben slightly weird if-check required because of + // https://github.com/Microsoft/vscode/blob/d28ace31aa147596e35adf101a27768a048c79ec/src/vs/workbench/parts/files/browser/fileActions.contribution.ts#L194 + if (descriptor.label) { - // don't run the action when not enabled - if (!actionInstance.enabled) { - actionInstance.dispose(); + const command = { + id: descriptor.id, + title: { value: descriptor.label, original: alias }, + category + }; - return void 0; + MenuRegistry.addCommand(command); + + registrations.push(MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command })); + } + + // TODO@alex,joh + // support removal of keybinding rule + // support removal of command-ui + return combinedDisposable(registrations); } - const from = args && args.from || 'keybinding'; - if (telemetryService) { - /* __GDPR__ - "workbenchActionExecuted" : { - "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - telemetryService.publicLog('workbenchActionExecuted', { id: actionInstance.id, from }); + private _createCommandHandler(descriptor: SyncActionDescriptor): ICommandHandler { + return (accessor, args) => { + const messageService = accessor.get(IMessageService); + const instantiationService = accessor.get(IInstantiationService); + const partService = accessor.get(IPartService); + + TPromise.as(this._triggerAndDisposeAction(instantiationService, partService, descriptor, args)).done(null, (err) => { + messageService.show(Severity.Error, err); + }); + }; } - // run action when workbench is created - return partService.joinCreation().then(() => { - try { - return TPromise.as(actionInstance.run(undefined, { from })).then(() => { - actionInstance.dispose(); - }, (err) => { + private _triggerAndDisposeAction(instantitationService: IInstantiationService, partService: IPartService, descriptor: SyncActionDescriptor, args: any): TPromise { + const actionInstance = instantitationService.createInstance(descriptor.syncDescriptor); + actionInstance.label = descriptor.label || actionInstance.label; + + // don't run the action when not enabled + if (!actionInstance.enabled) { + actionInstance.dispose(); + + return void 0; + } + + const from = args && args.from || 'keybinding'; + + // run action when workbench is created + return partService.joinCreation().then(() => { + try { + return TPromise.as(actionInstance.run(undefined, { from })).then(() => { + actionInstance.dispose(); + }, (err) => { + actionInstance.dispose(); + return TPromise.wrapError(err); + }); + } catch (err) { actionInstance.dispose(); return TPromise.wrapError(err); - }); - } catch (err) { - actionInstance.dispose(); - return TPromise.wrapError(err); - } - }); -} \ No newline at end of file + } + }); + } +}); + diff --git a/src/vs/workbench/electron-browser/main.contribution.ts b/src/vs/workbench/electron-browser/main.contribution.ts index 93bac904d3c..dc469437580 100644 --- a/src/vs/workbench/electron-browser/main.contribution.ts +++ b/src/vs/workbench/electron-browser/main.contribution.ts @@ -18,7 +18,7 @@ import { CloseEditorAction, KeybindingsReferenceAction, OpenDocumentationUrlActi import { MessagesVisibleContext } from 'vs/workbench/electron-browser/workbench'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { registerCommands } from 'vs/workbench/electron-browser/commands'; -import { AddRootFolderAction, GlobalRemoveRootFolderAction, OpenWorkspaceAction, SaveWorkspaceAsAction, OpenWorkspaceConfigFileAction } from 'vs/workbench/browser/actions/workspaceActions'; +import { AddRootFolderAction, GlobalRemoveRootFolderAction, OpenWorkspaceAction, SaveWorkspaceAsAction, OpenWorkspaceConfigFileAction, OpenFolderAsWorkspaceInNewWindowAction } from 'vs/workbench/browser/actions/workspaceActions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { inQuickOpenContext, getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -92,6 +92,7 @@ if (product.quality !== 'stable') { workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace As...', workspacesCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceConfigFileAction, OpenWorkspaceConfigFileAction.ID, OpenWorkspaceConfigFileAction.LABEL), 'Workspaces: Open Workspace Configuration File', workspacesCategory); + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAsWorkspaceInNewWindowAction, OpenFolderAsWorkspaceInNewWindowAction.ID, OpenFolderAsWorkspaceInNewWindowAction.LABEL), 'Workspaces: Open Folder as Workspace in New Window', workspacesCategory); } // Developer related actions diff --git a/src/vs/workbench/parts/debug/browser/debugActions.ts b/src/vs/workbench/parts/debug/browser/debugActions.ts index 205804ac872..dbe837021a9 100644 --- a/src/vs/workbench/parts/debug/browser/debugActions.ts +++ b/src/vs/workbench/parts/debug/browser/debugActions.ts @@ -217,7 +217,7 @@ export class RestartAction extends AbstractDebugAction { } protected isEnabled(state: State): boolean { - return super.isEnabled(state) && state !== State.Inactive; + return super.isEnabled(state) && (state === State.Running || state === State.Stopped); } } @@ -301,7 +301,7 @@ export class StopAction extends AbstractDebugAction { } protected isEnabled(state: State): boolean { - return super.isEnabled(state) && state !== State.Inactive; + return super.isEnabled(state) && (state === State.Running || state === State.Stopped); } } @@ -319,7 +319,7 @@ export class DisconnectAction extends AbstractDebugAction { } protected isEnabled(state: State): boolean { - return super.isEnabled(state) && state !== State.Inactive; + return super.isEnabled(state) && (state === State.Running || state === State.Stopped); } } @@ -518,7 +518,7 @@ export class ReapplyBreakpointsAction extends AbstractDebugAction { protected isEnabled(state: State): boolean { const model = this.debugService.getModel(); - return super.isEnabled(state) && state !== State.Inactive && + return super.isEnabled(state) && (state === State.Running || state === State.Stopped) && (model.getFunctionBreakpoints().length + model.getBreakpoints().length + model.getExceptionBreakpoints().length > 0); } } diff --git a/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts b/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts index fed2b8590fc..5818d30bd3b 100644 --- a/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts +++ b/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts @@ -196,7 +196,7 @@ export class DebugActionsWidget extends Themable implements IWorkbenchContributi } private update(state: State): void { - if (state === State.Inactive || this.configurationService.getConfiguration('debug').hideActionBar) { + if (state === State.Inactive || state === State.Initializing || this.configurationService.getConfiguration('debug').hideActionBar) { return this.hide(); } diff --git a/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts b/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts index e229724a162..6fd5d7c1c20 100644 --- a/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts +++ b/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts @@ -274,7 +274,7 @@ export class DebugEditorModelManager implements IWorkbenchContribution { private getBreakpointDecorationOptions(breakpoint: IBreakpoint): IModelDecorationOptions { const activated = this.debugService.getModel().areBreakpointsActivated(); const state = this.debugService.state; - const debugActive = state === State.Running || state === State.Stopped || state === State.Initializing; + const debugActive = state === State.Running || state === State.Stopped; const modelData = this.modelDataMap.get(breakpoint.uri.toString()); let result = (!breakpoint.enabled || !activated) ? DebugEditorModelManager.BREAKPOINT_DISABLED_DECORATION : diff --git a/src/vs/workbench/parts/debug/browser/debugStatus.ts b/src/vs/workbench/parts/debug/browser/debugStatus.ts new file mode 100644 index 00000000000..9e575478b01 --- /dev/null +++ b/src/vs/workbench/parts/debug/browser/debugStatus.ts @@ -0,0 +1,80 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import * as dom from 'vs/base/browser/dom'; +import * as errors from 'vs/base/common/errors'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; +import { IDebugService } from 'vs/workbench/parts/debug/common/debug'; +import { Themable, STATUS_BAR_FOREGROUND } from 'vs/workbench/common/theme'; + +const $ = dom.$; +const MAX_LABEL_LENGTH = 17; + +export class DebugStatus extends Themable implements IStatusbarItem { + private toDispose: IDisposable[]; + private container: HTMLElement; + private label: HTMLElement; + private icon: HTMLElement; + private hidden = true; + + constructor( + @IQuickOpenService private quickOpenService: IQuickOpenService, + @IDebugService private debugService: IDebugService, + @IThemeService themeService: IThemeService + ) { + super(themeService); + this.toDispose = []; + this.toDispose.push(this.debugService.getConfigurationManager().onDidSelectConfiguration(e => { + this.setLabel(); + })); + this.toDispose.push(this.debugService.onDidNewProcess(() => { + if (this.hidden) { + this.hidden = false; + this.render(this.container); + } + })); + } + + protected updateStyles(): void { + super.updateStyles(); + this.icon.style.backgroundColor = this.getColor(STATUS_BAR_FOREGROUND); + } + + public render(container: HTMLElement): IDisposable { + this.container = container; + if (!this.hidden) { + const statusBarItem = dom.append(container, $('.debug-statusbar-item')); + this.toDispose.push(dom.addDisposableListener(statusBarItem, 'click', () => { + this.quickOpenService.show('debug ').done(undefined, errors.onUnexpectedError); + })); + statusBarItem.title = nls.localize('debug', "Debug"); + this.icon = dom.append(statusBarItem, $('.icon')); + this.label = dom.append(statusBarItem, $('span.label')); + this.setLabel(); + this.updateStyles(); + } + + return this; + } + + private setLabel(): void { + if (this.label && !this.hidden) { + let name = this.debugService.getConfigurationManager().selectedName || ''; + if (name.length > MAX_LABEL_LENGTH) { + name = name.substring(0, MAX_LABEL_LENGTH) + '...'; + } + this.label.textContent = name; + } + } + + public dispose(): void { + super.dispose(); + this.toDispose = dispose(this.toDispose); + } +} diff --git a/src/vs/workbench/parts/debug/browser/media/debug.contribution.css b/src/vs/workbench/parts/debug/browser/media/debug.contribution.css index 87918a9013a..69bf974a45f 100644 --- a/src/vs/workbench/parts/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/parts/debug/browser/media/debug.contribution.css @@ -102,6 +102,20 @@ box-sizing: border-box; } +/* Debug status */ +.monaco-workbench .part.statusbar .debug-statusbar-item { + cursor: pointer; + display: flex; +} + +.monaco-workbench .part.statusbar .debug-statusbar-item .icon { + -webkit-mask: url('debug-dark.svg') no-repeat 50% 50%; + -webkit-mask-size: 18px; + display: inline-block; + padding-right: 2px; + width: 16px; +} + /* Expressions */ .monaco-workbench .monaco-tree-row .expression { diff --git a/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts b/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts index 2ee47d4318a..a88503d3faf 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debug.contribution.ts @@ -15,6 +15,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v import { IWorkbenchActionRegistry, Extensions as WorkbenchActionRegistryExtensions } from 'vs/workbench/common/actions'; import { ToggleViewletAction, Extensions as ViewletExtensions, ViewletRegistry, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { TogglePanelAction, Extensions as PanelExtensions, PanelRegistry, PanelDescriptor } from 'vs/workbench/browser/panel'; +import { StatusbarItemDescriptor, StatusbarAlignment, IStatusbarRegistry, Extensions as StatusExtensions } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { VariablesView, WatchExpressionsView, CallStackView, BreakpointsView } from 'vs/workbench/parts/debug/electron-browser/debugViews'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { @@ -44,6 +45,7 @@ import URI from 'vs/base/common/uri'; import { DebugViewlet, FocusVariablesViewAction, FocusBreakpointsViewAction, FocusCallStackViewAction, FocusWatchViewAction } from 'vs/workbench/parts/debug/browser/debugViewlet'; import { Repl } from 'vs/workbench/parts/debug/electron-browser/repl'; import { DebugQuickOpenHandler } from 'vs/workbench/parts/debug/browser/debugQuickOpen'; +import { DebugStatus } from 'vs/workbench/parts/debug/browser/debugStatus'; class OpenDebugViewletAction extends ToggleViewletAction { public static ID = VIEWLET_ID; @@ -196,6 +198,10 @@ configurationRegistry.registerConfiguration({ debugCommands.registerCommands(); +// Register Debug Status +const statusBar = Registry.as(StatusExtensions.Statusbar); +statusBar.registerStatusbarItem(new StatusbarItemDescriptor(DebugStatus, StatusbarAlignment.LEFT, 30 /* Low Priority */)); + // Touch Bar if (isMacintosh) { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index 3ea09044e57..a47e5a09be6 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -518,6 +518,7 @@ export class DebugService implements debug.IDebugService { } private updateStateAndEmit(sessionId?: string, newState?: debug.State): void { + const previousState = this.state; if (sessionId) { if (newState === debug.State.Inactive) { this.sessionStates.delete(sessionId); @@ -527,11 +528,13 @@ export class DebugService implements debug.IDebugService { } const state = this.state; - const stateLabel = debug.State[state]; - if (stateLabel) { - this.debugState.set(stateLabel.toLowerCase()); + if (previousState !== state) { + const stateLabel = debug.State[state]; + if (stateLabel) { + this.debugState.set(stateLabel.toLowerCase()); + } + this._onDidChangeState.fire(state); } - this._onDidChangeState.fire(state); } public focusStackFrameAndEvaluate(stackFrame: debug.IStackFrame, process?: debug.IProcess, explicit?: boolean): TPromise { @@ -741,12 +744,15 @@ export class DebugService implements debug.IDebugService { return TPromise.wrapError(errors.create(message, { actions: [this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL), CloseAction] })); } + const sessionId = generateUuid(); + this.updateStateAndEmit(sessionId, debug.State.Initializing); + return this.runPreLaunchTask(root, resolvedConfig.preLaunchTask).then((taskSummary: ITaskSummary) => { const errorCount = resolvedConfig.preLaunchTask ? this.markerService.getStatistics().errors : 0; const successExitCode = taskSummary && taskSummary.exitCode === 0; const failureExitCode = taskSummary && taskSummary.exitCode !== undefined && taskSummary.exitCode !== 0; if (successExitCode || (errorCount === 0 && !failureExitCode)) { - return this.doCreateProcess(root, resolvedConfig); + return this.doCreateProcess(root, resolvedConfig, sessionId); } this.messageService.show(severity.Error, { @@ -756,7 +762,7 @@ export class DebugService implements debug.IDebugService { actions: [ new Action('debug.continue', nls.localize('debugAnyway', "Debug Anyway"), null, true, () => { this.messageService.hideAll(); - return this.doCreateProcess(root, resolvedConfig); + return this.doCreateProcess(root, resolvedConfig, sessionId); }), this.instantiationService.createInstance(ToggleMarkersPanelAction, ToggleMarkersPanelAction.ID, ToggleMarkersPanelAction.LABEL), CloseAction @@ -764,6 +770,7 @@ export class DebugService implements debug.IDebugService { }); return undefined; }, (err: TaskError) => { + this.updateStateAndEmit(sessionId, debug.State.Inactive); this.messageService.show(err.severity, { message: err.message, actions: [ @@ -789,9 +796,8 @@ export class DebugService implements debug.IDebugService { ); } - private doCreateProcess(root: IWorkspaceFolder, configuration: debug.IConfig, sessionId = generateUuid()): TPromise { + private doCreateProcess(root: IWorkspaceFolder, configuration: debug.IConfig, sessionId: string): TPromise { configuration.__sessionId = sessionId; - this.updateStateAndEmit(sessionId, debug.State.Initializing); this.inDebugMode.set(true); return this.telemetryService.getTelemetryInfo().then(info => { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts index e5be9a9f8c0..d8104fbc3a2 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts @@ -70,8 +70,10 @@ export function renderExpressionValue(expressionOrValue: debug.IExpression | str } } - if (options.colorize) { - if (!isNaN(+value)) { + if (options.colorize && typeof expressionOrValue !== 'string') { + if (expressionOrValue.type === 'number' || expressionOrValue.type === 'boolean' || expressionOrValue.type === 'string') { + dom.addClass(container, expressionOrValue.type); + } else if (!isNaN(+value)) { dom.addClass(container, 'number'); } else if (booleanRegex.test(value)) { dom.addClass(container, 'boolean'); @@ -1237,7 +1239,7 @@ export class BreakpointsRenderer implements IRenderer { data.filePath.textContent = getPathLabel(resources.dirname(breakpoint.uri), this.contextService, this.environmentService); data.checkbox.checked = breakpoint.enabled; - const debugActive = this.debugService.state === debug.State.Running || this.debugService.state === debug.State.Stopped || this.debugService.state === debug.State.Initializing; + const debugActive = this.debugService.state === debug.State.Running || this.debugService.state === debug.State.Stopped; if (debugActive && !breakpoint.verified) { tree.addTraits('disabled', [breakpoint]); if (breakpoint.message) { diff --git a/src/vs/workbench/parts/debug/electron-browser/replViewer.ts b/src/vs/workbench/parts/debug/electron-browser/replViewer.ts index 96975857047..848ec016c5f 100644 --- a/src/vs/workbench/parts/debug/electron-browser/replViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/replViewer.ts @@ -232,7 +232,8 @@ export class ReplExpressionsRenderer implements IRenderer { templateData.input.textContent = expression.name; renderExpressionValue(expression, templateData.value, { preserveWhitespace: !expression.hasChildren, - showHover: false + showHover: false, + colorize: true }); if (expression.hasChildren) { templateData.annotation.className = 'annotation octicon octicon-info'; diff --git a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts index 4d01be27283..1217632d2ab 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts @@ -878,7 +878,7 @@ export class ReloadAction extends Action { } run(): TPromise { - if (this.messageService.confirm({ message: this.reloadMessaage, type: 'question', primaryButton: localize('reload', "&&Reload Window") })) { + if (this.messageService.confirmSync({ message: this.reloadMessaage, type: 'question', primaryButton: localize('reload', "&&Reload Window") })) { return this.windowService.reloadWindow(); } return TPromise.wrap(null); diff --git a/src/vs/workbench/parts/feedback/electron-browser/feedbackStatusbarItem.ts b/src/vs/workbench/parts/feedback/electron-browser/feedbackStatusbarItem.ts index 0dd4994a388..6af8ce910c7 100644 --- a/src/vs/workbench/parts/feedback/electron-browser/feedbackStatusbarItem.ts +++ b/src/vs/workbench/parts/feedback/electron-browser/feedbackStatusbarItem.ts @@ -26,7 +26,7 @@ class TwitterFeedbackService implements IFeedbackService { } public submitFeedback(feedback: IFeedback): void { - const queryString = `?${feedback.sentiment === 1 ? `hashtags=${this.combineHashTagsAsString()}&` : null}ref_src=twsrc%5Etfw&related=twitterapi%2Ctwitter&text=${feedback.feedback}&tw_p=tweetbutton&via=${TwitterFeedbackService.VIA_NAME}`; + const queryString = `?${feedback.sentiment === 1 ? `hashtags=${this.combineHashTagsAsString()}&` : null}ref_src=twsrc%5Etfw&related=twitterapi%2Ctwitter&text=${encodeURIComponent(feedback.feedback)}&tw_p=tweetbutton&via=${TwitterFeedbackService.VIA_NAME}`; const url = TwitterFeedbackService.TWITTER_URL + queryString; window.open(url); diff --git a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts index c64ab4ad996..aa587300cc4 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.contribution.ts @@ -19,7 +19,7 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { FileStat, Model } from 'vs/workbench/parts/files/common/explorerModel'; import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; -import { OpenFolderAction, OpenFileFolderAction, AddRootFolderAction, RemoveRootFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; +import { OpenFolderAction, OpenFileFolderAction, AddRootFolderAction, RemoveRootFolderAction, OpenFolderSettingsAction } from 'vs/workbench/browser/actions/workspaceActions'; import { copyFocusedFilesExplorerViewItem, revealInOSFocusedFilesExplorerItem, openFocusedExplorerItemSideBySideCommand, copyPathOfFocusedExplorerItem, copyPathCommand, revealInExplorerCommand, revealInOSCommand, openFolderPickerCommand, openWindowCommand, openFileInNewWindowCommand, deleteFocusedFilesExplorerViewItemCommand, moveFocusedFilesExplorerViewItemToTrashCommand, renameFocusedFilesExplorerViewItemCommand } from 'vs/workbench/parts/files/browser/fileCommands'; import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -96,10 +96,14 @@ class FilesViewerActionContributor extends ActionBarContributor { addRootFolderAction.order = 52; actions.push(addRootFolderAction); + const openFolderSettingsActions = this.instantiationService.createInstance(OpenFolderSettingsAction, stat.resource, OpenFolderSettingsAction.ID, OpenFolderSettingsAction.LABEL); + openFolderSettingsActions.order = 53; + actions.push(openFolderSettingsActions); const removeRootFolderAction = this.instantiationService.createInstance(RemoveRootFolderAction, stat.resource, RemoveRootFolderAction.ID, RemoveRootFolderAction.LABEL); - removeRootFolderAction.order = 53; + removeRootFolderAction.order = 54; actions.push(removeRootFolderAction); - actions.push(new Separator(null, 54)); + + actions.push(new Separator(null, 55)); } // Copy File/Folder @@ -191,7 +195,7 @@ const registry = Registry.as(ActionExtensions.Workbenc registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalCopyPathAction, GlobalCopyPathAction.ID, GlobalCopyPathAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_P) }), 'Files: Copy Path of Active File', category); registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFileAction, SaveFileAction.ID, SaveFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_S }), 'Files: Save', category); registry.registerWorkbenchAction(new SyncActionDescriptor(SaveAllAction, SaveAllAction.ID, SaveAllAction.LABEL, { primary: void 0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_S }, win: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_S) } }), 'Files: Save All', category); -registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFilesAction, SaveFilesAction.ID, null /* only for programmatic trigger */), null); +registry.registerWorkbenchAction(new SyncActionDescriptor(SaveFilesAction, SaveFilesAction.ID, SaveFilesAction.LABEL), 'Files: Save All Files', category); registry.registerWorkbenchAction(new SyncActionDescriptor(RevertFileAction, RevertFileAction.ID, RevertFileAction.LABEL), 'Files: Revert File', category); registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewFileAction, GlobalNewFileAction.ID, GlobalNewFileAction.LABEL), 'Files: New File', category); registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalNewFolderAction, GlobalNewFolderAction.ID, GlobalNewFolderAction.LABEL), 'Files: New Folder', category); diff --git a/src/vs/workbench/parts/files/browser/fileActions.ts b/src/vs/workbench/parts/files/browser/fileActions.ts index 03004325482..8f9afccbafe 100644 --- a/src/vs/workbench/parts/files/browser/fileActions.ts +++ b/src/vs/workbench/parts/files/browser/fileActions.ts @@ -40,7 +40,7 @@ import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { Position, IResourceInput, IEditorInput, IUntitledResourceInput } from 'vs/platform/editor/common/editor'; import { IInstantiationService, IConstructorSignature2, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IMessageService, IMessageWithAction, IConfirmation, Severity, CancelAction } from 'vs/platform/message/common/message'; +import { IMessageService, IMessageWithAction, IConfirmation, Severity, CancelAction, IConfirmationResult } from 'vs/platform/message/common/message'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { getCodeEditor } from 'vs/editor/common/services/codeEditorService'; import { IEditorViewState } from 'vs/editor/common/editorCommon'; @@ -50,6 +50,8 @@ import { withFocusedFilesExplorer, revealInOSCommand, revealInExplorerCommand, c import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; export interface IEditableData { action: IAction; @@ -623,6 +625,9 @@ export class CreateFolderAction extends BaseCreateAction { } export class BaseDeleteFileAction extends BaseFileAction { + + private static CONFIRM_DELETE_SETTING_KEY = 'explorer.confirmDelete'; + private tree: ITree; private useTrash: boolean; private skipConfirm: boolean; @@ -635,7 +640,9 @@ export class BaseDeleteFileAction extends BaseFileAction { useTrash: boolean, @IFileService fileService: IFileService, @IMessageService messageService: IMessageService, - @ITextFileService textFileService: ITextFileService + @ITextFileService textFileService: ITextFileService, + @IConfigurationService private configurationService: IConfigurationService, + @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService ) { super(id, label, fileService, messageService, textFileService); @@ -687,7 +694,7 @@ export class BaseDeleteFileAction extends BaseFileAction { message = nls.localize('dirtyMessageFileDelete', "You are deleting a file with unsaved changes. Do you want to continue?"); } - const res = this.messageService.confirm({ + const res = this.messageService.confirmSync({ message, type: 'warning', detail: nls.localize('dirtyWarning', "Your changes will be lost if you don't save them."), @@ -704,51 +711,73 @@ export class BaseDeleteFileAction extends BaseFileAction { // Check if file is dirty in editor and save it to avoid data loss return revertPromise.then(() => { + let confirmPromise: TPromise; - // Ask for Confirm - if (!this.skipConfirm) { - let confirm: IConfirmation; - if (this.useTrash) { - confirm = { - message: this.element.isDirectory ? nls.localize('confirmMoveTrashMessageFolder', "Are you sure you want to delete '{0}' and its contents?", this.element.name) : nls.localize('confirmMoveTrashMessageFile', "Are you sure you want to delete '{0}'?", this.element.name), - detail: isWindows ? nls.localize('undoBin', "You can restore from the recycle bin.") : nls.localize('undoTrash', "You can restore from the trash."), - primaryButton, - type: 'question' - }; - } else { - confirm = { - message: this.element.isDirectory ? nls.localize('confirmDeleteMessageFolder', "Are you sure you want to permanently delete '{0}' and its contents?", this.element.name) : nls.localize('confirmDeleteMessageFile', "Are you sure you want to permanently delete '{0}'?", this.element.name), - detail: nls.localize('irreversible', "This action is irreversible!"), - primaryButton, - type: 'warning' - }; - } - - if (!this.messageService.confirm(confirm)) { - return TPromise.as(null); - } + // Check if we need to ask for confirmation at all + if (this.skipConfirm || (this.useTrash && this.configurationService.lookup(BaseDeleteFileAction.CONFIRM_DELETE_SETTING_KEY).value === false)) { + confirmPromise = TPromise.as({ confirmed: true } as IConfirmationResult); } - // Call function - const servicePromise = this.fileService.del(this.element.resource, this.useTrash).then(() => { - if (this.element.parent) { - this.tree.setFocus(this.element.parent); // move focus to parent - } - }, (error: any) => { + // Confirm for moving to trash + else if (this.useTrash) { + confirmPromise = this.messageService.confirm({ + message: this.element.isDirectory ? nls.localize('confirmMoveTrashMessageFolder', "Are you sure you want to delete '{0}' and its contents?", this.element.name) : nls.localize('confirmMoveTrashMessageFile', "Are you sure you want to delete '{0}'?", this.element.name), + detail: isWindows ? nls.localize('undoBin', "You can restore from the recycle bin.") : nls.localize('undoTrash', "You can restore from the trash."), + primaryButton, + checkbox: { + label: nls.localize('doNotAskAgain', "Do not ask me again") + }, + type: 'question' + }); + } - // Allow to retry - let extraAction: Action; - if (this.useTrash) { - extraAction = new Action('permanentDelete', nls.localize('permDelete', "Delete Permanently"), null, true, () => { this.useTrash = false; this.skipConfirm = true; return this.run(); }); + // Confirm for deleting permanently + else { + confirmPromise = this.messageService.confirm({ + message: this.element.isDirectory ? nls.localize('confirmDeleteMessageFolder', "Are you sure you want to permanently delete '{0}' and its contents?", this.element.name) : nls.localize('confirmDeleteMessageFile', "Are you sure you want to permanently delete '{0}'?", this.element.name), + detail: nls.localize('irreversible', "This action is irreversible!"), + primaryButton, + type: 'warning' + }); + } + + return confirmPromise.then(confirmation => { + + // Check for confirmation checkbox + let updateConfirmSettingsPromise: TPromise = TPromise.as(void 0); + if (confirmation.checkboxChecked === true) { + updateConfirmSettingsPromise = this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: BaseDeleteFileAction.CONFIRM_DELETE_SETTING_KEY, value: false }); } - this.onErrorWithRetry(error, () => this.run(), extraAction); + return updateConfirmSettingsPromise.then(() => { - // Focus back to tree - this.tree.DOMFocus(); + // Check for confirmation + if (!confirmation.confirmed) { + return TPromise.as(null); + } + + // Call function + const servicePromise = this.fileService.del(this.element.resource, this.useTrash).then(() => { + if (this.element.parent) { + this.tree.setFocus(this.element.parent); // move focus to parent + } + }, (error: any) => { + + // Allow to retry + let extraAction: Action; + if (this.useTrash) { + extraAction = new Action('permanentDelete', nls.localize('permDelete', "Delete Permanently"), null, true, () => { this.useTrash = false; this.skipConfirm = true; return this.run(); }); + } + + this.onErrorWithRetry(error, () => this.run(), extraAction); + + // Focus back to tree + this.tree.DOMFocus(); + }); + + return servicePromise; + }); }); - - return servicePromise; }); } } @@ -762,9 +791,11 @@ export class MoveFileToTrashAction extends BaseDeleteFileAction { element: FileStat, @IFileService fileService: IFileService, @IMessageService messageService: IMessageService, - @ITextFileService textFileService: ITextFileService + @ITextFileService textFileService: ITextFileService, + @IConfigurationService configurationService: IConfigurationService, + @IConfigurationEditingService configurationEditingService: IConfigurationEditingService ) { - super(MoveFileToTrashAction.ID, nls.localize('delete', "Delete"), tree, element, true, fileService, messageService, textFileService); + super(MoveFileToTrashAction.ID, nls.localize('delete', "Delete"), tree, element, true, fileService, messageService, textFileService, configurationService, configurationEditingService); } } @@ -836,7 +867,7 @@ export class ImportFileAction extends BaseFileAction { type: 'warning' }; - overwrite = this.messageService.confirm(confirm); + overwrite = this.messageService.confirmSync(confirm); } if (!overwrite) { @@ -1047,14 +1078,14 @@ export class DuplicateFileAction extends BaseFileAction { private findTarget(): URI { let name = this.element.name; - let candidate = this.target.resource.with({ path: paths.join(this.target.resource.fsPath, name) }); + let candidate = this.target.resource.with({ path: paths.join(this.target.resource.path, name) }); while (true) { if (!this.element.root.find(candidate)) { break; } name = this.toCopyName(name, this.element.isDirectory); - candidate = this.target.resource.with({ path: paths.join(this.target.resource.fsPath, name) }); + candidate = this.target.resource.with({ path: paths.join(this.target.resource.path, name) }); } return candidate; @@ -1652,7 +1683,7 @@ export class SaveAllInGroupAction extends BaseSaveAllAction { export class SaveFilesAction extends BaseSaveAllAction { public static ID = 'workbench.action.files.saveFiles'; - public static LABEL = nls.localize('saveFiles', "Save Dirty Files"); + public static LABEL = nls.localize('saveFiles', "Save All Files"); protected getSaveAllArguments(): boolean { return this.includeUntitled(); diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index 9f5b2e412eb..173b92b32bd 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -328,6 +328,16 @@ configurationRegistry.registerConfiguration({ 'description': nls.localize('enableDragAndDrop', "Controls if the explorer should allow to move files and folders via drag and drop."), 'default': true }, + 'explorer.confirmDragAndDrop': { + 'type': 'boolean', + 'description': nls.localize('confirmDragAndDrop', "Controls if the explorer should ask for confirmation when moving files or folders around via drag and drop."), + 'default': true + }, + 'explorer.confirmDelete': { + 'type': 'boolean', + 'description': nls.localize('confirmDelete', "Controls if the explorer should ask for confirmation when deleting a file via the trash."), + 'default': true + }, 'explorer.sortOrder': { 'type': 'string', 'enum': [SortOrderConfiguration.DEFAULT, SortOrderConfiguration.MIXED, SortOrderConfiguration.FILES_FIRST, SortOrderConfiguration.TYPE, SortOrderConfiguration.MODIFIED], diff --git a/src/vs/workbench/parts/files/browser/views/explorerView.ts b/src/vs/workbench/parts/files/browser/views/explorerView.ts index d5b7388c0e0..eb9f3dbdc9b 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerView.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerView.ts @@ -734,11 +734,7 @@ export class ExplorerView extends ViewsViewletPanel { } private doRefresh(targetsToExpand: URI[] = []): TPromise { - const targetsToResolve: { root: FileStat, resource: URI, options: { resolveTo: URI[] } }[] = []; - this.model.roots.forEach(root => { - const rootAndTargets = { root, resource: root.resource, options: { resolveTo: [] } }; - targetsToResolve.push(rootAndTargets); - }); + const targetsToResolve = this.model.roots.map(root => ({ root, resource: root.resource, options: { resolveTo: [] } })); // First time refresh: Receive target through active editor input or selection and also include settings from previous session if (!this.isCreated) { @@ -768,24 +764,11 @@ export class ExplorerView extends ViewsViewletPanel { } // Load Root Stat with given target path configured - const promise = this.fileService.resolveFiles(targetsToResolve).then(results => { + const promise = TPromise.join(targetsToResolve.map((target, index) => this.fileService.resolveFile(target.resource, target.options).then(result => { // Convert to model - const modelStats = results.map((result, index) => { - if (result.success) { - return FileStat.create(result.stat, targetsToResolve[index].root, targetsToResolve[index].options.resolveTo); - } - - return FileStat.create({ - resource: targetsToResolve[index].resource, - name: resources.basenameOrAuthority(targetsToResolve[index].resource), - mtime: 0, - etag: undefined, - isDirectory: true, - hasChildren: false - }, targetsToResolve[index].root); - }); + const modelStat = FileStat.create(result, target.root, target.options.resolveTo); // Subsequent refresh: Merge stat into our local model and refresh tree - modelStats.forEach((modelStat, index) => FileStat.mergeLocalWithDisk(modelStat, this.model.roots[index])); + FileStat.mergeLocalWithDisk(modelStat, this.model.roots[index]); const input = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? this.model.roots[0] : this.model; let statsToExpand: FileStat[] = this.explorerViewer.getExpandedElements().concat(targetsToExpand.map(target => this.model.findClosest(target))); @@ -793,7 +776,6 @@ export class ExplorerView extends ViewsViewletPanel { return this.explorerViewer.refresh().then(() => sequence(statsToExpand.map(e => () => this.explorerViewer.expand(e)))); } - // Display roots only when multi folder workspace // Make sure to expand all folders that where expanded in the previous session if (input === this.model) { @@ -801,7 +783,14 @@ export class ExplorerView extends ViewsViewletPanel { statsToExpand = this.model.roots.concat(statsToExpand); } return this.explorerViewer.setInput(input).then(() => sequence(statsToExpand.map(e => () => this.explorerViewer.expand(e)))); - }, e => TPromise.wrapError(e)); + }, e => FileStat.create({ + resource: target.resource, + name: resources.basenameOrAuthority(target.resource), + mtime: 0, + etag: undefined, + isDirectory: true, + hasChildren: false + }, target.root)))); this.progressService.showWhile(promise, this.partService.isCreated() ? 800 : 3200 /* less ugly initial startup */); diff --git a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts index c088be1988d..d60aa33d4d8 100644 --- a/src/vs/workbench/parts/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/parts/files/browser/views/explorerViewer.ts @@ -41,7 +41,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IMessageService, IConfirmation, Severity } from 'vs/platform/message/common/message'; +import { IMessageService, IConfirmation, Severity, IConfirmationResult } from 'vs/platform/message/common/message'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { KeyCode } from 'vs/base/common/keyCodes'; @@ -57,6 +57,7 @@ import { distinct } from 'vs/base/common/arrays'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { getPathLabel } from 'vs/base/common/labels'; import { extractResources } from 'vs/base/browser/dnd'; +import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; export class FileDataSource implements IDataSource { constructor( @@ -728,13 +729,15 @@ export class FileFilter implements IFilter { // Explorer Drag And Drop Controller export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { + + private static CONFIRM_DND_SETTING_KEY = 'explorer.confirmDragAndDrop'; + private toDispose: IDisposable[]; private dropEnabled: boolean; constructor( @IMessageService private messageService: IMessageService, @IWorkspaceContextService private contextService: IWorkspaceContextService, - @IProgressService private progressService: IProgressService, @IFileService private fileService: IFileService, @IConfigurationService private configurationService: IConfigurationService, @IInstantiationService private instantiationService: IInstantiationService, @@ -742,7 +745,8 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { @IBackupFileService private backupFileService: IBackupFileService, @IWindowService private windowService: IWindowService, @IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService, - @IEnvironmentService private environmentService: IEnvironmentService + @IEnvironmentService private environmentService: IEnvironmentService, + @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService ) { super(stat => this.statToResource(stat)); @@ -891,8 +895,6 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { } } - this.progressService.showWhile(promise, 800); - promise.done(null, errors.onUnexpectedError); } @@ -917,7 +919,7 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { } // If we are in single-folder context, ask for confirmation to create a workspace - const result = this.messageService.confirm({ + const result = this.messageService.confirmSync({ message: folders.length > 1 ? nls.localize('dropFolders', "Do you want to add the folders to the workspace?") : nls.localize('dropFolder', "Do you want to add the folder to the workspace?"), type: 'question', primaryButton: folders.length > 1 ? nls.localize('addFolders', "&&Add Folders") : nls.localize('addFolder', "&&Add Folder") @@ -947,6 +949,41 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { const source: FileStat = data.getData()[0]; const isCopy = (originalEvent.ctrlKey && !isMacintosh) || (originalEvent.altKey && isMacintosh); + let confirmPromise: TPromise; + + // Handle confirm setting + const confirmDragAndDrop = !isCopy && this.configurationService.lookup(FileDragAndDrop.CONFIRM_DND_SETTING_KEY).value; + if (confirmDragAndDrop) { + confirmPromise = this.messageService.confirm({ + message: nls.localize('confirmMove', "Are you sure you want to move '{0}'?", source.name), + checkbox: { + label: nls.localize('doNotAskAgain', "Do not ask me again") + }, + type: 'question' + }); + } else { + confirmPromise = TPromise.as({ confirmed: true } as IConfirmationResult); + } + + return confirmPromise.then(confirmation => { + + // Check for confirmation checkbox + let updateConfirmSettingsPromise: TPromise = TPromise.as(void 0); + if (confirmation.checkboxChecked === true) { + updateConfirmSettingsPromise = this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: FileDragAndDrop.CONFIRM_DND_SETTING_KEY, value: false }); + } + + return updateConfirmSettingsPromise.then(() => { + if (confirmation.confirmed) { + return this.doHandleExplorerDrop(tree, data, source, target, isCopy); + } + + return TPromise.as(void 0); + }); + }); + } + + private doHandleExplorerDrop(tree: ITree, data: IDragAndDropData, source: FileStat, target: FileStat, isCopy: boolean): TPromise { return tree.expand(target).then(() => { // Reuse duplicate action if user copies @@ -1011,7 +1048,7 @@ export class FileDragAndDrop extends SimpleFileResourceDragAndDrop { }; // Move with overwrite if the user confirms - if (this.messageService.confirm(confirm)) { + if (this.messageService.confirmSync(confirm)) { const targetDirty = this.textFileService.getDirty().filter(d => resources.isEqualOrParent(d, targetResource, !isLinux /* ignorecase */)); // Make sure to revert all dirty in target first to be able to overwrite properly diff --git a/src/vs/workbench/parts/files/common/files.ts b/src/vs/workbench/parts/files/common/files.ts index ec7e56f865b..f2a423c3ce9 100644 --- a/src/vs/workbench/parts/files/common/files.ts +++ b/src/vs/workbench/parts/files/common/files.ts @@ -69,6 +69,7 @@ export interface IFilesConfiguration extends IFilesConfiguration, IWorkbenchEdit }; autoReveal: boolean; enableDragAndDrop: boolean; + confirmDelete: boolean; sortOrder: SortOrder; }; editor: IEditorOptions; diff --git a/src/vs/workbench/parts/performance/electron-browser/performance.contribution.ts b/src/vs/workbench/parts/performance/electron-browser/performance.contribution.ts index fb56e3ed9b7..fffca3a3e5e 100644 --- a/src/vs/workbench/parts/performance/electron-browser/performance.contribution.ts +++ b/src/vs/workbench/parts/performance/electron-browser/performance.contribution.ts @@ -57,7 +57,7 @@ class StartupProfiler implements IWorkbenchContribution { }).then(files => { const profileFiles = files.reduce((prev, cur) => `${prev}${join(profileStartup.dir, cur)}\n`, '\n'); - const primaryButton = this._messageService.confirm({ + const primaryButton = this._messageService.confirmSync({ type: 'info', message: localize('prof.message', "Successfully created profiles."), detail: localize('prof.detail', "Please create an issue and manually attach the following files:\n{0}", profileFiles), @@ -72,7 +72,7 @@ class StartupProfiler implements IWorkbenchContribution { action.run(`:warning: Make sure to **attach** these files from your *home*-directory: :warning:\n${files.map(file => `-\`${file}\``).join('\n')}`) ]).then(() => { // keep window stable until restart is selected - this._messageService.confirm({ + this._messageService.confirmSync({ type: 'info', message: localize('prof.thanks', "Thanks for helping us."), detail: localize('prof.detail.restart', "A final restart is required to continue to use '{0}'. Again, thank you for your contribution.", this._environmentService.appNameLong), diff --git a/src/vs/workbench/parts/preferences/common/keybindingsEditorModel.ts b/src/vs/workbench/parts/preferences/common/keybindingsEditorModel.ts index 9fcc3bdf489..8549fbdd25a 100644 --- a/src/vs/workbench/parts/preferences/common/keybindingsEditorModel.ts +++ b/src/vs/workbench/parts/preferences/common/keybindingsEditorModel.ts @@ -13,7 +13,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { ResolvedKeybinding, ResolvedKeybindingPart } from 'vs/base/common/keyCodes'; import { AriaLabelProvider, UserSettingsLabelProvider, UILabelProvider, ModifierLabels as ModLabels } from 'vs/base/common/keybindingLabels'; import { CommonEditorRegistry, EditorAction } from 'vs/editor/common/editorCommonExtensions'; -import { MenuRegistry, ILocalizedString, SyncActionDescriptor, ICommandAction } from 'vs/platform/actions/common/actions'; +import { MenuRegistry, ILocalizedString, ICommandAction } from 'vs/platform/actions/common/actions'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { EditorModel } from 'vs/workbench/common/editor'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; @@ -200,26 +200,21 @@ export class KeybindingsEditorModel extends EditorModel { } private static toKeybindingEntry(command: string, keybindingItem: ResolvedKeybindingItem, workbenchActionsRegistry: IWorkbenchActionRegistry, editorActions: {}): IKeybindingItem { - const workbenchAction = workbenchActionsRegistry.getWorkbenchAction(command); const menuCommand = MenuRegistry.getCommand(command); const editorAction: EditorAction = editorActions[command]; return { keybinding: keybindingItem.resolvedKeybinding, keybindingItem, command, - commandLabel: KeybindingsEditorModel.getCommandLabel(workbenchAction, menuCommand, editorAction), - commandDefaultLabel: KeybindingsEditorModel.getCommandDefaultLabel(workbenchAction, menuCommand, workbenchActionsRegistry), + commandLabel: KeybindingsEditorModel.getCommandLabel(menuCommand, editorAction), + commandDefaultLabel: KeybindingsEditorModel.getCommandDefaultLabel(menuCommand, workbenchActionsRegistry), when: keybindingItem.when ? keybindingItem.when.serialize() : '', source: keybindingItem.isDefault ? localize('default', "Default") : localize('user', "User") }; } - private static getCommandDefaultLabel(workbenchAction: SyncActionDescriptor, menuCommand: ICommandAction, workbenchActionsRegistry: IWorkbenchActionRegistry): string { + private static getCommandDefaultLabel(menuCommand: ICommandAction, workbenchActionsRegistry: IWorkbenchActionRegistry): string { if (language !== LANGUAGE_DEFAULT) { - if (workbenchAction) { - return workbenchActionsRegistry.getAlias(workbenchAction.id); - } - if (menuCommand && menuCommand.title && (menuCommand.title).original) { return (menuCommand.title).original; } @@ -227,11 +222,7 @@ export class KeybindingsEditorModel extends EditorModel { return null; } - private static getCommandLabel(workbenchAction: SyncActionDescriptor, menuCommand: ICommandAction, editorAction: EditorAction): string { - if (workbenchAction) { - return workbenchAction.label; - } - + private static getCommandLabel(menuCommand: ICommandAction, editorAction: EditorAction): string { if (menuCommand) { return typeof menuCommand.title === 'string' ? menuCommand.title : menuCommand.title.value; } @@ -560,4 +551,4 @@ class KeybindingItemMatches { } return false; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts b/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts index d366f705447..f5e99434096 100644 --- a/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts +++ b/src/vs/workbench/parts/quickopen/browser/commandsHandler.ts @@ -16,8 +16,6 @@ import { Mode, IEntryRunContext, IAutoFocus, IModel, IQuickNavigateConfiguration import { QuickOpenEntryGroup, IHighlight, QuickOpenModel, QuickOpenEntry } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { SyncActionDescriptor, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; -import { Registry } from 'vs/platform/registry/common/platform'; import { QuickOpenHandler, IWorkbenchQuickOpenConfiguration } from 'vs/workbench/browser/quickopen'; import { IEditorAction, IEditor, ICommonCodeEditor } from 'vs/editor/common/editorCommon'; import { matchesWords, matchesPrefix, matchesContiguousSubString, or } from 'vs/base/common/filters'; @@ -418,11 +416,6 @@ export class CommandsHandler extends QuickOpenHandler { searchValue = searchValue.trim(); this.lastSearchValue = searchValue; - // Workbench Actions - let workbenchEntries: CommandEntry[] = []; - const workbenchActions = Registry.as(ActionExtensions.WorkbenchActions).getWorkbenchActions(); - workbenchEntries = this.actionDescriptorsToEntries(workbenchActions, searchValue); - // Editor Actions const activeEditor = this.editorService.getActiveEditor(); const activeEditorControl = activeEditor ? activeEditor.getControl() : null; @@ -443,7 +436,7 @@ export class CommandsHandler extends QuickOpenHandler { const commandEntries = this.menuItemActionsToEntries(menuActions, searchValue); // Concat - let entries = [...workbenchEntries, ...editorEntries, ...commandEntries]; + let entries = [...editorEntries, ...commandEntries]; // Remove duplicates entries = arrays.distinct(entries, entry => `${entry.getLabel()}${entry.getGroupLabel()}${entry.getCommandId()}`); @@ -498,35 +491,6 @@ export class CommandsHandler extends QuickOpenHandler { return TPromise.as(new QuickOpenModel(entries)); } - private actionDescriptorsToEntries(actionDescriptors: SyncActionDescriptor[], searchValue: string): CommandEntry[] { - const entries: CommandEntry[] = []; - const registry = Registry.as(ActionExtensions.WorkbenchActions); - - for (let i = 0; i < actionDescriptors.length; i++) { - const actionDescriptor = actionDescriptors[i]; - if (actionDescriptor.label) { - - // Label (with optional category) - let label = actionDescriptor.label; - const category = registry.getCategory(actionDescriptor.id); - if (category) { - label = nls.localize('commandLabel', "{0}: {1}", category, label); - } - - // Alias for non default languages - const alias = (language !== LANGUAGE_DEFAULT) ? registry.getAlias(actionDescriptor.id) : null; - const labelHighlights = wordFilter(searchValue, label); - const aliasHighlights = alias ? wordFilter(searchValue, alias) : null; - - if (labelHighlights || aliasHighlights) { - entries.push(this.instantiationService.createInstance(CommandEntry, actionDescriptor.id, this.keybindingService.lookupKeybinding(actionDescriptor.id), label, alias, { label: labelHighlights, alias: aliasHighlights }, actionDescriptor, (id: string) => this.onBeforeRunCommand(id))); - } - } - } - - return entries; - } - private editorActionsToEntries(actions: IEditorAction[], searchValue: string): EditorActionCommandEntry[] { const entries: EditorActionCommandEntry[] = []; @@ -621,4 +585,4 @@ export class CommandsHandler extends QuickOpenHandler { lastCommandPaletteInput = void 0; // clear last input when user canceled quick open } } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.ts b/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.ts index e64e76450d8..854fbca08ae 100644 --- a/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.ts +++ b/src/vs/workbench/parts/relauncher/electron-browser/relauncher.contribution.ts @@ -130,7 +130,7 @@ export class SettingsChangeRelauncher implements IWorkbenchContribution { private doConfirm(message: string, detail: string, primaryButton: string, confirmed: () => void): void { this.windowService.isFocused().then(focused => { if (focused) { - const confirm = this.messageService.confirm({ + const confirm = this.messageService.confirmSync({ type: 'info', message, detail, diff --git a/src/vs/workbench/parts/search/browser/searchViewlet.ts b/src/vs/workbench/parts/search/browser/searchViewlet.ts index e047c75a4e7..c509fe0a1a5 100644 --- a/src/vs/workbench/parts/search/browser/searchViewlet.ts +++ b/src/vs/workbench/parts/search/browser/searchViewlet.ts @@ -388,7 +388,7 @@ export class SearchViewlet extends Viewlet { type: 'question' }; - if (this.messageService.confirm(confirmation)) { + if (this.messageService.confirmSync(confirmation)) { this.searchWidget.setReplaceAllActionState(false); this.viewModel.searchResult.replaceAll(progressRunner).then(() => { progressRunner.done(); diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index 66fe980eaf3..1737491b685 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -797,6 +797,10 @@ class TaskService extends EventEmitter implements ITaskService { } public getTask(folder: IWorkspaceFolder | string, alias: string): TPromise { + let name = Types.isString(folder) ? folder : folder.name; + if (this.ignoredWorkspaceFolders.some(ignored => ignored.name === name)) { + return TPromise.wrapError(new Error(nls.localize('TaskServer.folderIgnored', 'The folder {0} is ignored since it uses task version 0.1.0', name))); + } return this.getGroupedTasks().then((map) => { let values = map.get(folder); if (!values) { @@ -1745,7 +1749,7 @@ class TaskService extends EventEmitter implements ITaskService { if (this._taskSystem instanceof TerminalTaskSystem) { return false; } - if (this._taskSystem.canAutoTerminate() || this.messageService.confirm({ + if (this._taskSystem.canAutoTerminate() || this.messageService.confirmSync({ message: nls.localize('TaskSystem.runningTask', 'There is a task running. Do you want to terminate it?'), primaryButton: nls.localize({ key: 'TaskSystem.terminateTask', comment: ['&& denotes a mnemonic'] }, "&&Terminate Task"), type: 'question' @@ -1767,7 +1771,7 @@ class TaskService extends EventEmitter implements ITaskService { this.disposeTaskSystemListeners(); return false; // no veto } else if (code && code === TerminateResponseCode.ProcessNotFound) { - return !this.messageService.confirm({ + return !this.messageService.confirmSync({ message: nls.localize('TaskSystem.noProcess', 'The launched task doesn\'t exist anymore. If the task spawned background processes exiting VS Code might result in orphaned processes. To avoid this start the last background process with a wait flag.'), primaryButton: nls.localize({ key: 'TaskSystem.exitAnyways', comment: ['&& denotes a mnemonic'] }, "&&Exit Anyways"), type: 'info' diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminal.ts b/src/vs/workbench/parts/terminal/electron-browser/terminal.ts index 4601182e9a7..e91d9b86fda 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminal.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminal.ts @@ -8,6 +8,7 @@ import * as cp from 'child_process'; import * as os from 'os'; import * as platform from 'vs/base/common/platform'; import * as processes from 'vs/base/node/processes'; +import { readFile, fileExists } from 'vs/base/node/pfs'; export const TERMINAL_DEFAULT_SHELL_LINUX = !platform.isWindows ? (process.env.SHELL || 'sh') : 'sh'; export const TERMINAL_DEFAULT_SHELL_OSX = !platform.isWindows ? (process.env.SHELL || 'sh') : 'sh'; @@ -21,3 +22,20 @@ export const TERMINAL_DEFAULT_SHELL_WINDOWS = isAtLeastWindows10 ? powerShellPat export interface ITerminalProcessFactory { create(env: { [key: string]: string }): cp.ChildProcess; } + +if (platform.isLinux) { + const file = '/etc/os-release'; + fileExists(file).then(exists => { + if (!exists) { + return; + } + readFile(file).then(b => { + const contents = b.toString(); + if (contents.indexOf('NAME=Fedora') >= 0) { + isFedora = true; + } + }); + }); +} + +export let isFedora = false; \ No newline at end of file diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts index 6507587aa97..b1793339026 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalConfigHelper.ts @@ -14,6 +14,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { ITerminalConfiguration, ITerminalConfigHelper, ITerminalFont, IShellLaunchConfig, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY } from 'vs/workbench/parts/terminal/common/terminal'; import { TPromise } from 'vs/base/common/winjs.base'; import Severity from 'vs/base/common/severity'; +import { isFedora } from 'vs/workbench/parts/terminal/electron-browser/terminal'; interface IEditorConfiguration { editor: IEditorOptions; @@ -89,7 +90,15 @@ export class TerminalConfigHelper implements ITerminalConfigHelper { const editorConfig = (config).editor; const terminalConfig = this.config; - const fontFamily = terminalConfig.fontFamily || editorConfig.fontFamily; + let fontFamily = terminalConfig.fontFamily || editorConfig.fontFamily; + + // Work around bad font on Fedora + if (!terminalConfig.fontFamily) { + if (isFedora) { + fontFamily = '\'DejaVu Sans Mono\''; + } + } + let fontSize = this._toInteger(terminalConfig.fontSize, 0); if (fontSize <= 0) { fontSize = EDITOR_FONT_DEFAULTS.fontSize; diff --git a/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts b/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts index baa9d6819ad..512c65ed2d4 100644 --- a/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/parts/terminal/electron-browser/terminalService.ts @@ -6,7 +6,6 @@ import * as nls from 'vs/nls'; import * as pfs from 'vs/base/node/pfs'; import * as platform from 'vs/base/common/platform'; -import product from 'vs/platform/node/product'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; @@ -20,7 +19,7 @@ import { TerminalService as AbstractTerminalService } from 'vs/workbench/parts/t import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper'; import { TerminalInstance } from 'vs/workbench/parts/terminal/electron-browser/terminalInstance'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IChoiceService } from 'vs/platform/message/common/message'; +import { IChoiceService, IMessageService } from 'vs/platform/message/common/message'; import Severity from 'vs/base/common/severity'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { TERMINAL_DEFAULT_SHELL_WINDOWS } from 'vs/workbench/parts/terminal/electron-browser/terminal'; @@ -42,7 +41,8 @@ export class TerminalService extends AbstractTerminalService implements ITermina @IQuickOpenService private _quickOpenService: IQuickOpenService, @IConfigurationEditingService private _configurationEditingService: IConfigurationEditingService, @IChoiceService private _choiceService: IChoiceService, - @IStorageService private _storageService: IStorageService + @IStorageService private _storageService: IStorageService, + @IMessageService private _messageService: IMessageService ) { super(_contextKeyService, _configurationService, _panelService, _partService, _lifecycleService); @@ -218,22 +218,17 @@ export class TerminalService extends AbstractTerminalService implements ITermina } protected _showTerminalCloseConfirmation(): boolean { - const cancelId = 1; let message; if (this.terminalInstances.length === 1) { message = nls.localize('terminalService.terminalCloseConfirmationSingular', "There is an active terminal session, do you want to kill it?"); } else { message = nls.localize('terminalService.terminalCloseConfirmationPlural', "There are {0} active terminal sessions, do you want to kill them?", this.terminalInstances.length); } - const opts: Electron.MessageBoxOptions = { - title: product.nameLong, + + return !this._messageService.confirmSync({ message, type: 'warning', - buttons: [nls.localize('yes', "Yes"), nls.localize('cancel', "Cancel")], - noLink: true, - cancelId - }; - return this._windowService.showMessageBox(opts) === cancelId; + }); } public setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void { diff --git a/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts b/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts index e95533d078f..3eecd534b8c 100644 --- a/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts +++ b/src/vs/workbench/parts/terminal/test/electron-browser/terminalConfigHelper.test.ts @@ -11,7 +11,7 @@ import { Platform } from 'vs/base/common/platform'; import { TPromise } from 'vs/base/common/winjs.base'; import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper'; import { EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; - +import { isFedora } from 'vs/workbench/parts/terminal/electron-browser/terminal'; class MockConfigurationService implements IConfigurationService { public _serviceBrand: any; @@ -63,7 +63,11 @@ suite('Workbench - TerminalConfigHelper', () => { }); configHelper = new TerminalConfigHelper(Platform.Linux, configurationService, null, null, null); configHelper.panelContainer = fixture; - assert.equal(configHelper.getFont().fontFamily, 'foo', 'editor.fontFamily should be the fallback when terminal.integrated.fontFamily not set'); + if (isFedora) { + assert.equal(configHelper.getFont().fontFamily, '\'DejaVu Sans Mono\'', 'Fedora should have its font overridden when terminal.integrated.fontFamily not set'); + } else { + assert.equal(configHelper.getFont().fontFamily, 'foo', 'editor.fontFamily should be the fallback when terminal.integrated.fontFamily not set'); + } }); test('TerminalConfigHelper - getFont fontSize', function () { diff --git a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.css b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.css index 305fece6c6b..225f1c5415f 100644 --- a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.css +++ b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.css @@ -114,7 +114,7 @@ white-space: pre; } -.file-icons-enabled .show-file-icons .vs_code_editor_walkthrough\.md-name-file-icon.md-ext-file-icon.markdown-lang-file-icon.file-icon::before { +.file-icons-enabled .show-file-icons .vs_code_editor_walkthrough\.md-name-file-icon.md-ext-file-icon.ext-file-icon.markdown-lang-file-icon.file-icon::before { content: ' '; background-image: url('../../code-icon.svg'); } diff --git a/src/vs/workbench/services/configuration/test/node/configuration.test.ts b/src/vs/workbench/services/configuration/test/node/configuration.test.ts index 8073bb82a98..ea5d59653ca 100644 --- a/src/vs/workbench/services/configuration/test/node/configuration.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configuration.test.ts @@ -150,6 +150,17 @@ suite('WorkspaceConfigurationService - Node', () => { } }); + configurationRegistry.registerConfiguration({ + 'id': '_test', + 'type': 'object', + 'properties': { + 'workspaceLookup.service.testSetting': { + 'type': 'string', + 'default': 'isSet' + } + } + }); + createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { return createService(workspaceDir, globalSettingsFile).then(service => { const config = service.getConfiguration(); @@ -213,18 +224,6 @@ suite('WorkspaceConfigurationService - Node', () => { }; } - const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); - configurationRegistry.registerConfiguration({ - 'id': '_test_workspace', - 'type': 'object', - 'properties': { - 'workspace.service.testSetting': { - 'type': 'string', - 'default': 'isSet' - } - } - }); - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { return createService(workspaceDir, globalSettingsFile).then(service => { fs.writeFileSync(globalSettingsFile, '{ "workspace.service.testSetting": "isChanged" }'); @@ -357,18 +356,6 @@ suite('WorkspaceConfigurationService - Node', () => { test('lookup', (done: () => void) => { - const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); - configurationRegistry.registerConfiguration({ - 'id': '_test', - 'type': 'object', - 'properties': { - 'workspaceLookup.service.testSetting': { - 'type': 'string', - 'default': 'isSet' - } - } - }); - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { return createService(workspaceDir, globalSettingsFile).then(service => { let res = service.lookup('something.missing'); @@ -414,17 +401,6 @@ suite('WorkspaceConfigurationService - Node', () => { }); test('keys', (done: () => void) => { - const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); - configurationRegistry.registerConfiguration({ - 'id': '_test', - 'type': 'object', - 'properties': { - 'workspaceLookup.service.testSetting': { - 'type': 'string', - 'default': 'isSet' - } - } - }); function contains(array: string[], key: string): boolean { return array.indexOf(key) >= 0; @@ -482,18 +458,6 @@ suite('WorkspaceConfigurationService - Node', () => { }); test('values', (done: () => void) => { - const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); - configurationRegistry.registerConfiguration({ - 'id': '_test', - 'type': 'object', - 'properties': { - 'workspaceLookup.service.testSetting': { - 'type': 'string', - 'default': 'isSet' - } - } - }); - createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { return createService(workspaceDir, globalSettingsFile).then(service => { let values = service.values(); diff --git a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts index c86a09cbae7..1b4f1bcd61d 100644 --- a/src/vs/workbench/services/files/electron-browser/remoteFileService.ts +++ b/src/vs/workbench/services/files/electron-browser/remoteFileService.ts @@ -72,8 +72,7 @@ export function toDeepIFileStat(provider: IFileSystemProvider, tuple: [URI, ISta } return toIFileStat(provider, tuple, candidate => { - const sub = trie.findSuperstr(candidate[0].toString()); - return !!sub; + return Boolean(trie.findSuperstr(candidate[0].toString()) || trie.get(candidate[0].toString())); }); } diff --git a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts index b4c10edb678..9634a27da63 100644 --- a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts @@ -259,13 +259,13 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { windowElement: Window, @IContextKeyService contextKeyService: IContextKeyService, @ICommandService commandService: ICommandService, - @ITelemetryService private telemetryService: ITelemetryService, + @ITelemetryService telemetryService: ITelemetryService, @IMessageService messageService: IMessageService, @IEnvironmentService environmentService: IEnvironmentService, @IStatusbarService statusBarService: IStatusbarService, @IConfigurationService configurationService: IConfigurationService ) { - super(contextKeyService, commandService, messageService, statusBarService); + super(contextKeyService, commandService, telemetryService, messageService, statusBarService); let dispatchConfig = getDispatchConfig(configurationService); configurationService.onDidUpdateConfiguration((e) => { @@ -415,7 +415,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { "keyCount" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ - this.telemetryService.publicLog('customKeybindingsChanged', { + this._telemetryService.publicLog('customKeybindingsChanged', { keyCount: cnt }); } diff --git a/src/vs/workbench/services/message/browser/messageList.ts b/src/vs/workbench/services/message/browser/messageList.ts index e1b5be6d5a6..a882703c7ae 100644 --- a/src/vs/workbench/services/message/browser/messageList.ts +++ b/src/vs/workbench/services/message/browser/messageList.ts @@ -353,7 +353,7 @@ export class MessageList { sevLabel.title(title); - $(messageContentElement as HTMLElement).title(title).appendTo(div); + $(messageContentElement).title(title).appendTo(div); }); }); } diff --git a/src/vs/workbench/services/message/browser/messageService.ts b/src/vs/workbench/services/message/browser/messageService.ts index f0f6af73d98..9fe4dd36645 100644 --- a/src/vs/workbench/services/message/browser/messageService.ts +++ b/src/vs/workbench/services/message/browser/messageService.ts @@ -9,9 +9,10 @@ import { toErrorMessage } from 'vs/base/common/errorMessage'; import types = require('vs/base/common/types'); import { MessageList, Severity as BaseSeverity } from 'vs/workbench/services/message/browser/messageList'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IMessageService, IMessageWithAction, IConfirmation, Severity } from 'vs/platform/message/common/message'; +import { IMessageService, IMessageWithAction, IConfirmation, Severity, IConfirmationResult } from 'vs/platform/message/common/message'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import Event from 'vs/base/common/event'; +import { TPromise } from 'vs/base/common/winjs.base'; interface IBufferedMessage { severity: Severity; @@ -135,7 +136,7 @@ export class WorkbenchMessageService implements IMessageService { } } - public confirm(confirmation: IConfirmation): boolean { + public confirmSync(confirmation: IConfirmation): boolean { let messageText = confirmation.message; if (confirmation.detail) { messageText = messageText + '\n\n' + confirmation.detail; @@ -144,6 +145,10 @@ export class WorkbenchMessageService implements IMessageService { return window.confirm(messageText); } + public confirm(confirmation: IConfirmation): TPromise { + return TPromise.as({ confirmed: this.confirmSync(confirmation) } as IConfirmationResult); + } + public dispose(): void { this.toDispose = dispose(this.toDispose); } diff --git a/src/vs/workbench/services/message/electron-browser/messageService.ts b/src/vs/workbench/services/message/electron-browser/messageService.ts index dc057c38560..f676f67dc54 100644 --- a/src/vs/workbench/services/message/electron-browser/messageService.ts +++ b/src/vs/workbench/services/message/electron-browser/messageService.ts @@ -9,11 +9,11 @@ import nls = require('vs/nls'); import product from 'vs/platform/node/product'; import { TPromise } from 'vs/base/common/winjs.base'; import { WorkbenchMessageService } from 'vs/workbench/services/message/browser/messageService'; -import { IConfirmation, Severity, IChoiceService } from 'vs/platform/message/common/message'; +import { IConfirmation, Severity, IChoiceService, IConfirmationResult } from 'vs/platform/message/common/message'; import { isLinux } from 'vs/base/common/platform'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Action } from 'vs/base/common/actions'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IWindowService, IMessageBoxResult } from 'vs/platform/windows/common/windows'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; export class MessageService extends WorkbenchMessageService implements IChoiceService { @@ -26,8 +26,26 @@ export class MessageService extends WorkbenchMessageService implements IChoiceSe super(container, telemetryService); } - public confirm(confirmation: IConfirmation): boolean { + public confirm(confirmation: IConfirmation): TPromise { + const opts = this.getConfirmOptions(confirmation); + return this.showMessageBox(opts).then(result => { + return { + confirmed: result.button === 0 ? true : false, + checkboxChecked: result.checkboxChecked + } as IConfirmationResult; + }); + } + + public confirmSync(confirmation: IConfirmation): boolean { + const opts = this.getConfirmOptions(confirmation); + + const result = this.showMessageBoxSync(opts); + + return result === 0 ? true : false; + } + + private getConfirmOptions(confirmation: IConfirmation): Electron.MessageBoxOptions { const buttons: string[] = []; if (confirmation.primaryButton) { buttons.push(confirmation.primaryButton); @@ -57,15 +75,18 @@ export class MessageService extends WorkbenchMessageService implements IChoiceSe opts.type = confirmation.type; } - let result = this.showMessageBox(opts); + if (confirmation.checkbox) { + opts.checkboxLabel = confirmation.checkbox.label; + opts.checkboxChecked = confirmation.checkbox.checked; + } - return result === 0 ? true : false; + return opts; } public choose(severity: Severity, message: string, options: string[], cancelId: number, modal: boolean = false): TPromise { if (modal) { const type: 'none' | 'info' | 'error' | 'question' | 'warning' = severity === Severity.Info ? 'question' : severity === Severity.Error ? 'error' : severity === Severity.Warning ? 'warning' : 'none'; - return TPromise.wrap(this.showMessageBox({ message, buttons: options, type, cancelId })); + return TPromise.wrap(this.showMessageBoxSync({ message, buttons: options, type, cancelId })); } let onCancel: () => void = null; @@ -84,7 +105,25 @@ export class MessageService extends WorkbenchMessageService implements IChoiceSe return promise; } - private showMessageBox(opts: Electron.MessageBoxOptions): number { + private showMessageBox(opts: Electron.MessageBoxOptions): TPromise { + opts = this.massageMessageBoxOptions(opts); + + return this.windowService.showMessageBox(opts).then(result => { + return { + button: isLinux ? opts.buttons.length - result.button - 1 : result.button, + checkboxChecked: result.checkboxChecked + } as IMessageBoxResult; + }); + } + + private showMessageBoxSync(opts: Electron.MessageBoxOptions): number { + opts = this.massageMessageBoxOptions(opts); + + const result = this.windowService.showMessageBoxSync(opts); + return isLinux ? opts.buttons.length - result - 1 : result; + } + + private massageMessageBoxOptions(opts: Electron.MessageBoxOptions): Electron.MessageBoxOptions { opts.buttons = opts.buttons.map(button => mnemonicButtonLabel(button)); opts.buttons = isLinux ? opts.buttons.reverse() : opts.buttons; @@ -99,7 +138,6 @@ export class MessageService extends WorkbenchMessageService implements IChoiceSe opts.noLink = true; opts.title = opts.title || product.nameLong; - const result = this.windowService.showMessageBox(opts); - return isLinux ? opts.buttons.length - result - 1 : result; + return opts; } } diff --git a/src/vs/workbench/services/search/node/ripgrepTextSearch.ts b/src/vs/workbench/services/search/node/ripgrepTextSearch.ts index 0feb4151cb9..da61448ee47 100644 --- a/src/vs/workbench/services/search/node/ripgrepTextSearch.ts +++ b/src/vs/workbench/services/search/node/ripgrepTextSearch.ts @@ -237,6 +237,10 @@ export class RipgrepParser extends EventEmitter { } private handleMatchLine(outputLine: string, lineNum: number, text: string): void { + if (lineNum === 0) { + text = strings.stripUTF8BOM(text); + } + const lineMatch = new LineMatch(text, lineNum); this.fileMatch.addMatch(lineMatch); diff --git a/src/vs/workbench/services/textfile/electron-browser/textFileService.ts b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts index d0d82ebc959..efff4d1b7f1 100644 --- a/src/vs/workbench/services/textfile/electron-browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts @@ -132,7 +132,7 @@ export class TextFileService extends AbstractTextFileService { opts.defaultId = 2; } - const choice = this.windowService.showMessageBox(opts); + const choice = this.windowService.showMessageBoxSync(opts); return buttons[choice].result; } diff --git a/src/vs/workbench/services/themes/common/workbenchThemeService.ts b/src/vs/workbench/services/themes/common/workbenchThemeService.ts index f943d4229c4..dfacea5a13c 100644 --- a/src/vs/workbench/services/themes/common/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/common/workbenchThemeService.ts @@ -20,7 +20,6 @@ export const VS_HC_THEME = 'hc-black'; export const COLOR_THEME_SETTING = 'workbench.colorTheme'; export const ICON_THEME_SETTING = 'workbench.iconTheme'; export const CUSTOM_WORKBENCH_COLORS_SETTING = 'workbench.colorCustomizations'; -export const DEPRECATED_CUSTOM_COLORS_SETTING = 'workbench.experimental.colorCustomizations'; export const CUSTOM_EDITOR_COLORS_SETTING = 'editor.tokenColorCustomizations'; export const CUSTOM_EDITOR_SCOPE_COLORS_SETTING = 'textMateRules'; diff --git a/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts b/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts index ebdb67e5e07..528d7fa234c 100644 --- a/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts +++ b/src/vs/workbench/services/themes/electron-browser/colorThemeData.ts @@ -2,6 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +'use strict'; import Paths = require('vs/base/common/paths'); import Json = require('vs/base/common/json'); @@ -36,25 +37,27 @@ const tokenGroupToScopesMap = { export class ColorThemeData implements IColorTheme { - constructor() { + private constructor() { } id: string; label: string; settingsId: string; description?: string; + isLoaded: boolean; + path?: string; + extensionData: ExtensionData; + get tokenColors(): ITokenColorizationRule[] { // Add the custom colors after the theme colors // so that they will override them return this.themeTokenColors.concat(this.customTokenColors); } - themeTokenColors: ITokenColorizationRule[] = []; - customTokenColors: ITokenColorizationRule[] = []; - isLoaded: boolean; - path?: string; - extensionData: ExtensionData; - colorMap: IColorMap = {}; - customColorMap: IColorMap = {}; + + private themeTokenColors: ITokenColorizationRule[] = []; + private customTokenColors: ITokenColorizationRule[] = []; + private colorMap: IColorMap = {}; + private customColorMap: IColorMap = {}; public getColor(colorId: ColorIdentifier, useDefault?: boolean): Color { let color = this.customColorMap[colorId]; @@ -119,18 +122,36 @@ export class ColorThemeData implements IColorTheme { public ensureLoaded(themeService: WorkbenchThemeService): TPromise { if (!this.isLoaded) { - this.themeTokenColors = []; - this.colorMap = {}; if (this.path) { return _loadColorThemeFromFile(this.path, this.themeTokenColors, this.colorMap).then(_ => { this.isLoaded = true; - _sanitizeTokenColors(this); + this.sanitizeTokenColors(); }); } } return TPromise.as(null); } + /** + * Place the default settings first and add add the token-info rules + */ + private sanitizeTokenColors() { + let hasDefaultTokens = false; + let updatedTokenColors: ITokenColorizationRule[] = [updateDefaultRuleSettings({ settings: {} }, this)]; + this.tokenColors.forEach(rule => { + if (rule.scope) { + if (rule.scope === 'token.info-token') { + hasDefaultTokens = true; + } + updatedTokenColors.push(rule); + } + }); + if (!hasDefaultTokens) { + updatedTokenColors.push(...defaultThemeColors[this.type]); + } + this.themeTokenColors = updatedTokenColors; + } + toThemeFile() { if (!this.isLoaded) { return ''; @@ -171,56 +192,60 @@ export class ColorThemeData implements IColorTheme { default: return 'dark'; } } -} -export function createUnloadedTheme(id: string): ColorThemeData { - let themeData = new ColorThemeData(); - themeData.id = id; - themeData.label = ''; - themeData.settingsId = null; - themeData.isLoaded = false; - themeData.themeTokenColors = [{ settings: {} }]; - return themeData; -} + // constructors -export function fromStorageData(input: string): ColorThemeData { - try { - let data = JSON.parse(input); - let theme = new ColorThemeData(); - for (let key in data) { - switch (key) { - case 'colorMap': - let colorMapData = data[key]; - for (let id in colorMapData) { - theme.colorMap[id] = Color.fromHex(colorMapData[id]); - } - break; - case 'themeTokenColors': - case 'id': case 'label': case 'settingsId': case 'extensionData': - theme[key] = data[key]; - break; + static createUnloadedTheme(id: string): ColorThemeData { + let themeData = new ColorThemeData(); + themeData.id = id; + themeData.label = ''; + themeData.settingsId = null; + themeData.isLoaded = false; + themeData.themeTokenColors = [{ settings: {} }]; + return themeData; + } + + static fromStorageData(input: string): ColorThemeData { + try { + let data = JSON.parse(input); + let theme = new ColorThemeData(); + for (let key in data) { + switch (key) { + case 'colorMap': + let colorMapData = data[key]; + for (let id in colorMapData) { + theme.colorMap[id] = Color.fromHex(colorMapData[id]); + } + break; + case 'themeTokenColors': + case 'id': case 'label': case 'settingsId': case 'extensionData': + theme[key] = data[key]; + break; + } } + return theme; + } catch (e) { + return null; } - return theme; - } catch (e) { - return null; + } + + static fromExtensionTheme(theme: IThemeExtensionPoint, normalizedAbsolutePath: string, extensionData: ExtensionData): ColorThemeData { + let baseTheme: string = theme['uiTheme'] || 'vs-dark'; + + let themeSelector = toCSSSelector(extensionData.extensionId + '-' + Paths.normalize(theme.path)); + let themeData = new ColorThemeData(); + themeData.id = `${baseTheme} ${themeSelector}`; + themeData.label = theme.label || Paths.basename(theme.path); + themeData.settingsId = theme.id || themeData.label; + themeData.description = theme.description; + themeData.path = normalizedAbsolutePath; + themeData.extensionData = extensionData; + themeData.isLoaded = false; + return themeData; } } -export function fromExtensionTheme(theme: IThemeExtensionPoint, normalizedAbsolutePath: string, extensionData: ExtensionData): ColorThemeData { - let baseTheme: string = theme['uiTheme'] || 'vs-dark'; - let themeSelector = toCSSSelector(extensionData.extensionId + '-' + Paths.normalize(theme.path)); - let themeData = new ColorThemeData(); - themeData.id = `${baseTheme} ${themeSelector}`; - themeData.label = theme.label || Paths.basename(theme.path); - themeData.settingsId = theme.id || themeData.label; - themeData.description = theme.description; - themeData.path = normalizedAbsolutePath; - themeData.extensionData = extensionData; - themeData.isLoaded = false; - return themeData; -} function toCSSSelector(str: string) { str = str.replace(/[^_\-a-zA-Z0-9]/g, '-'); @@ -296,25 +321,7 @@ function _loadSyntaxTokensFromFile(themePath: string, resultRules: ITokenColoriz return TPromise.wrapError(new Error(nls.localize('error.cannotload', "Problems loading tmTheme file {0}: {1}", themePath, error.message))); }); } -/** - * Place the default settings first and add add the token-info rules - */ -function _sanitizeTokenColors(theme: ColorThemeData) { - let hasDefaultTokens = false; - let updatedTokenColors: ITokenColorizationRule[] = [updateDefaultRuleSettings({ settings: {} }, theme)]; - theme.tokenColors.forEach(rule => { - if (rule.scope) { - if (rule.scope === 'token.info-token') { - hasDefaultTokens = true; - } - updatedTokenColors.push(rule); - } - }); - if (!hasDefaultTokens) { - updatedTokenColors.push(...defaultThemeColors[theme.type]); - } - theme.themeTokenColors = updatedTokenColors; -} + function updateDefaultRuleSettings(defaultRule: ITokenColorizationRule, theme: ColorThemeData): ITokenColorizationRule { let foreground = theme.getColor(editorForeground) || theme.getDefault(editorForeground); @@ -324,7 +331,6 @@ function updateDefaultRuleSettings(defaultRule: ITokenColorizationRule, theme: C return defaultRule; } - let defaultThemeColors: { [baseTheme: string]: ITokenColorizationRule[] } = { 'light': [ { scope: 'token.info-token', settings: { foreground: '#316bcd' } }, diff --git a/src/vs/workbench/services/themes/electron-browser/colorThemeStore.ts b/src/vs/workbench/services/themes/electron-browser/colorThemeStore.ts new file mode 100644 index 00000000000..34751542947 --- /dev/null +++ b/src/vs/workbench/services/themes/electron-browser/colorThemeStore.ts @@ -0,0 +1,141 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import nls = require('vs/nls'); + +import * as types from 'vs/base/common/types'; +import * as Paths from 'path'; +import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry'; +import { IColorTheme, ExtensionData, IThemeExtensionPoint, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { ColorThemeData } from 'vs/workbench/services/themes/electron-browser/colorThemeData'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { TPromise } from 'vs/base/common/winjs.base'; +import Event, { Emitter } from 'vs/base/common/event'; + + +let themesExtPoint = ExtensionsRegistry.registerExtensionPoint('themes', [], { + description: nls.localize('vscode.extension.contributes.themes', 'Contributes textmate color themes.'), + type: 'array', + items: { + type: 'object', + defaultSnippets: [{ body: { label: '${1:label}', id: '${2:id}', uiTheme: VS_DARK_THEME, path: './themes/${3:id}.tmTheme.' } }], + properties: { + id: { + description: nls.localize('vscode.extension.contributes.themes.id', 'Id of the icon theme as used in the user settings.'), + type: 'string' + }, + label: { + description: nls.localize('vscode.extension.contributes.themes.label', 'Label of the color theme as shown in the UI.'), + type: 'string' + }, + uiTheme: { + description: nls.localize('vscode.extension.contributes.themes.uiTheme', 'Base theme defining the colors around the editor: \'vs\' is the light color theme, \'vs-dark\' is the dark color theme. \'hc-black\' is the dark high contrast theme.'), + enum: [VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME] + }, + path: { + description: nls.localize('vscode.extension.contributes.themes.path', 'Path of the tmTheme file. The path is relative to the extension folder and is typically \'./themes/themeFile.tmTheme\'.'), + type: 'string' + } + }, + required: ['path', 'uiTheme'] + } +}); + +export class ColorThemeStore { + + private extensionsColorThemes: ColorThemeData[]; + private onDidChangeEmitter: Emitter; + + public get onDidChange(): Event { return this.onDidChangeEmitter.event; } + + constructor( @IExtensionService private extensionService: IExtensionService) { + this.extensionsColorThemes = []; + this.onDidChangeEmitter = new Emitter(); + this.initialize(); + } + + + private initialize() { + themesExtPoint.setHandler((extensions) => { + for (let ext of extensions) { + let extensionData = { + extensionId: ext.description.id, + extensionPublisher: ext.description.publisher, + extensionName: ext.description.name, + extensionIsBuiltin: ext.description.isBuiltin + }; + this.onThemes(ext.description.extensionFolderPath, extensionData, ext.value, ext.collector); + } + this.onDidChangeEmitter.fire(this.extensionsColorThemes); + }); + } + + private onThemes(extensionFolderPath: string, extensionData: ExtensionData, themes: IThemeExtensionPoint[], collector: ExtensionMessageCollector): void { + if (!Array.isArray(themes)) { + collector.error(nls.localize( + 'reqarray', + "Extension point `{0}` must be an array.", + themesExtPoint.name + )); + return; + } + themes.forEach(theme => { + if (!theme.path || !types.isString(theme.path)) { + collector.error(nls.localize( + 'reqpath', + "Expected string in `contributes.{0}.path`. Provided value: {1}", + themesExtPoint.name, + String(theme.path) + )); + return; + } + let normalizedAbsolutePath = Paths.normalize(Paths.join(extensionFolderPath, theme.path)); + + if (normalizedAbsolutePath.indexOf(Paths.normalize(extensionFolderPath)) !== 0) { + collector.warn(nls.localize('invalid.path.1', "Expected `contributes.{0}.path` ({1}) to be included inside extension's folder ({2}). This might make the extension non-portable.", themesExtPoint.name, normalizedAbsolutePath, extensionFolderPath)); + } + let themeData = ColorThemeData.fromExtensionTheme(theme, normalizedAbsolutePath, extensionData); + this.extensionsColorThemes.push(themeData); + }); + } + + public findThemeData(themeId: string, defaultId?: string): TPromise { + return this.getColorThemes().then(allThemes => { + let defaultTheme: ColorThemeData = void 0; + for (let t of allThemes) { + if (t.id === themeId) { + return t; + } + if (t.id === defaultId) { + defaultTheme = t; + } + } + return defaultTheme; + }); + } + + public findThemeDataBySettingsId(settingsId: string, defaultId: string): TPromise { + return this.getColorThemes().then(allThemes => { + let defaultTheme: ColorThemeData = void 0; + for (let t of allThemes) { + if (t.settingsId === settingsId) { + return t; + } + if (t.id === defaultId) { + defaultTheme = t; + } + } + return defaultTheme; + }); + } + + public getColorThemes(): TPromise { + return this.extensionService.onReady().then(isReady => { + return this.extensionsColorThemes; + }); + } + +} diff --git a/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts b/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts new file mode 100644 index 00000000000..fcdd7f82d21 --- /dev/null +++ b/src/vs/workbench/services/themes/electron-browser/fileIconThemeData.ts @@ -0,0 +1,291 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import URI from 'vs/base/common/uri'; +import nls = require('vs/nls'); +import * as Paths from 'path'; +import Json = require('vs/base/common/json'); +import { ExtensionData, IThemeExtensionPoint, IFileIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { TPromise } from 'vs/base/common/winjs.base'; +import pfs = require('vs/base/node/pfs'); +import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService'; +import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; + +export class FileIconThemeData implements IFileIconTheme { + id: string; + label: string; + settingsId: string; + description?: string; + hasFileIcons?: boolean; + hasFolderIcons?: boolean; + isLoaded: boolean; + path?: string; + extensionData: ExtensionData; + + private styleSheetContent?: string; + + private constructor() { + } + + public ensureLoaded(themeService: WorkbenchThemeService): TPromise { + if (!this.isLoaded) { + if (this.path) { + return _loadIconThemeDocument(this.path).then(iconThemeDocument => { + let result = _processIconThemeDocument(this.id, this.path, iconThemeDocument); + this.styleSheetContent = result.content; + this.hasFileIcons = result.hasFileIcons; + this.hasFolderIcons = result.hasFolderIcons; + this.isLoaded = true; + return this.styleSheetContent; + }); + } + } + return TPromise.as(this.styleSheetContent); + } + + static fromExtensionTheme(iconTheme: IThemeExtensionPoint, normalizedAbsolutePath: string, extensionData: ExtensionData): FileIconThemeData { + let themeData = new FileIconThemeData(); + themeData.id = extensionData.extensionId + '-' + iconTheme.id; + themeData.label = iconTheme.label || Paths.basename(iconTheme.path); + themeData.settingsId = iconTheme.id; + themeData.description = iconTheme.description; + themeData.path = normalizedAbsolutePath; + themeData.extensionData = extensionData; + themeData.isLoaded = false; + return themeData; + } + + private static _noIconTheme: FileIconThemeData = null; + + static noIconTheme(): FileIconThemeData { + let themeData = FileIconThemeData._noIconTheme; + if (!themeData) { + themeData = FileIconThemeData._noIconTheme = new FileIconThemeData(); + themeData.id = ''; + themeData.label = ''; + themeData.settingsId = null; + themeData.hasFileIcons = false; + themeData.hasFolderIcons = false; + themeData.isLoaded = true; + themeData.extensionData = null; + } + return themeData; + } +} + +interface IconDefinition { + iconPath: string; + fontColor: string; + fontCharacter: string; + fontSize: string; + fontId: string; +} + +interface FontDefinition { + id: string; + weight: string; + style: string; + size: string; + src: { path: string; format: string; }[]; +} + +interface IconsAssociation { + folder?: string; + file?: string; + folderExpanded?: string; + rootFolder?: string; + rootFolderExpanded?: string; + folderNames?: { [folderName: string]: string; }; + folderNamesExpanded?: { [folderName: string]: string; }; + fileExtensions?: { [extension: string]: string; }; + fileNames?: { [fileName: string]: string; }; + languageIds?: { [languageId: string]: string; }; +} + +interface IconThemeDocument extends IconsAssociation { + iconDefinitions: { [key: string]: IconDefinition }; + fonts: FontDefinition[]; + light?: IconsAssociation; + highContrast?: IconsAssociation; +} + +function _loadIconThemeDocument(fileSetPath: string): TPromise { + return pfs.readFile(fileSetPath).then(content => { + let errors: Json.ParseError[] = []; + let contentValue = Json.parse(content.toString(), errors); + if (errors.length > 0) { + return TPromise.wrapError(new Error(nls.localize('error.cannotparseicontheme', "Problems parsing file icons file: {0}", errors.map(e => getParseErrorMessage(e.error)).join(', ')))); + } + return TPromise.as(contentValue); + }); +} + +function _processIconThemeDocument(id: string, iconThemeDocumentPath: string, iconThemeDocument: IconThemeDocument): { content: string; hasFileIcons: boolean; hasFolderIcons: boolean; } { + + let result = { content: '', hasFileIcons: false, hasFolderIcons: false }; + + if (!iconThemeDocument.iconDefinitions) { + return result; + } + let selectorByDefinitionId: { [def: string]: string[] } = {}; + + function resolvePath(path: string) { + const uri = URI.file(Paths.join(Paths.dirname(iconThemeDocumentPath), path)); + return uri.toString(); + } + + function collectSelectors(associations: IconsAssociation, baseThemeClassName?: string) { + function addSelector(selector: string, defId: string) { + if (defId) { + let list = selectorByDefinitionId[defId]; + if (!list) { + list = selectorByDefinitionId[defId] = []; + } + list.push(selector); + } + } + if (associations) { + let qualifier = '.show-file-icons'; + if (baseThemeClassName) { + qualifier = baseThemeClassName + ' ' + qualifier; + } + + let expanded = '.monaco-tree-row.expanded'; // workaround for #11453 + + if (associations.folder) { + addSelector(`${qualifier} .folder-icon::before`, associations.folder); + result.hasFolderIcons = true; + } + + if (associations.folderExpanded) { + addSelector(`${qualifier} ${expanded} .folder-icon::before`, associations.folderExpanded); + result.hasFolderIcons = true; + } + + let rootFolder = associations.rootFolder || associations.folder; + let rootFolderExpanded = associations.rootFolderExpanded || associations.folderExpanded; + + if (rootFolder) { + addSelector(`${qualifier} .rootfolder-icon::before`, rootFolder); + result.hasFolderIcons = true; + } + + if (rootFolderExpanded) { + addSelector(`${qualifier} ${expanded} .rootfolder-icon::before`, rootFolderExpanded); + result.hasFolderIcons = true; + } + + if (associations.file) { + addSelector(`${qualifier} .file-icon::before`, associations.file); + result.hasFileIcons = true; + } + + let folderNames = associations.folderNames; + if (folderNames) { + for (let folderName in folderNames) { + addSelector(`${qualifier} .${escapeCSS(folderName.toLowerCase())}-name-folder-icon.folder-icon::before`, folderNames[folderName]); + result.hasFolderIcons = true; + } + } + let folderNamesExpanded = associations.folderNamesExpanded; + if (folderNamesExpanded) { + for (let folderName in folderNamesExpanded) { + addSelector(`${qualifier} ${expanded} .${escapeCSS(folderName.toLowerCase())}-name-folder-icon.folder-icon::before`, folderNamesExpanded[folderName]); + result.hasFolderIcons = true; + } + } + + let languageIds = associations.languageIds; + if (languageIds) { + for (let languageId in languageIds) { + addSelector(`${qualifier} .${escapeCSS(languageId)}-lang-file-icon.file-icon::before`, languageIds[languageId]); + result.hasFileIcons = true; + } + } + let fileExtensions = associations.fileExtensions; + if (fileExtensions) { + for (let fileExtension in fileExtensions) { + let selectors: string[] = []; + let segments = fileExtension.toLowerCase().split('.'); + if (segments.length) { + for (let i = 0; i < segments.length; i++) { + selectors.push(`.${escapeCSS(segments.slice(i).join('.'))}-ext-file-icon`); + } + selectors.push('.ext-file-icon'); // extra segment to increase file-ext score + } + addSelector(`${qualifier} ${selectors.join('')}.file-icon::before`, fileExtensions[fileExtension]); + result.hasFileIcons = true; + } + } + let fileNames = associations.fileNames; + if (fileNames) { + for (let fileName in fileNames) { + let selectors: string[] = []; + fileName = fileName.toLowerCase(); + selectors.push(`.${escapeCSS(fileName)}-name-file-icon`); + let segments = fileName.split('.'); + if (segments.length) { + for (let i = 1; i < segments.length; i++) { + selectors.push(`.${escapeCSS(segments.slice(i).join('.'))}-ext-file-icon`); + } + selectors.push('.ext-file-icon'); // extra segment to increase file-ext score + } + addSelector(`${qualifier} ${selectors.join('')}.file-icon::before`, fileNames[fileName]); + result.hasFileIcons = true; + } + } + } + } + collectSelectors(iconThemeDocument); + collectSelectors(iconThemeDocument.light, '.vs'); + collectSelectors(iconThemeDocument.highContrast, '.hc-black'); + + if (!result.hasFileIcons && !result.hasFolderIcons) { + return result; + } + + let cssRules: string[] = []; + + let fonts = iconThemeDocument.fonts; + if (Array.isArray(fonts)) { + fonts.forEach(font => { + let src = font.src.map(l => `url('${resolvePath(l.path)}') format('${l.format}')`).join(', '); + cssRules.push(`@font-face { src: ${src}; font-family: '${font.id}'; font-weigth: ${font.weight}; font-style: ${font.style}; }`); + }); + cssRules.push(`.show-file-icons .file-icon::before, .show-file-icons .folder-icon::before, .show-file-icons .rootfolder-icon::before { font-family: '${fonts[0].id}'; font-size: ${fonts[0].size || '150%'}}`); + } + + for (let defId in selectorByDefinitionId) { + let selectors = selectorByDefinitionId[defId]; + let definition = iconThemeDocument.iconDefinitions[defId]; + if (definition) { + if (definition.iconPath) { + cssRules.push(`${selectors.join(', ')} { content: ' '; background-image: url("${resolvePath(definition.iconPath)}"); }`); + } + if (definition.fontCharacter || definition.fontColor) { + let body = ''; + if (definition.fontColor) { + body += ` color: ${definition.fontColor};`; + } + if (definition.fontCharacter) { + body += ` content: '${definition.fontCharacter}';`; + } + if (definition.fontSize) { + body += ` font-size: ${definition.fontSize};`; + } + if (definition.fontId) { + body += ` font-family: ${definition.fontId};`; + } + cssRules.push(`${selectors.join(', ')} { ${body} }`); + } + } + } + result.content = cssRules.join('\n'); + return result; +} +function escapeCSS(str: string) { + return window['CSS'].escape(str); +} \ No newline at end of file diff --git a/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.ts b/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.ts new file mode 100644 index 00000000000..a4d110811b9 --- /dev/null +++ b/src/vs/workbench/services/themes/electron-browser/fileIconThemeStore.ts @@ -0,0 +1,137 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import nls = require('vs/nls'); + +import * as types from 'vs/base/common/types'; +import * as Paths from 'path'; +import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry'; +import { ExtensionData, IThemeExtensionPoint } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; +import { TPromise } from 'vs/base/common/winjs.base'; +import Event, { Emitter } from 'vs/base/common/event'; +import { FileIconThemeData } from 'vs/workbench/services/themes/electron-browser/fileIconThemeData'; + +let iconThemeExtPoint = ExtensionsRegistry.registerExtensionPoint('iconThemes', [], { + description: nls.localize('vscode.extension.contributes.iconThemes', 'Contributes file icon themes.'), + type: 'array', + items: { + type: 'object', + defaultSnippets: [{ body: { id: '${1:id}', label: '${2:label}', path: './fileicons/${3:id}-icon-theme.json' } }], + properties: { + id: { + description: nls.localize('vscode.extension.contributes.iconThemes.id', 'Id of the icon theme as used in the user settings.'), + type: 'string' + }, + label: { + description: nls.localize('vscode.extension.contributes.iconThemes.label', 'Label of the icon theme as shown in the UI.'), + type: 'string' + }, + path: { + description: nls.localize('vscode.extension.contributes.iconThemes.path', 'Path of the icon theme definition file. The path is relative to the extension folder and is typically \'./icons/awesome-icon-theme.json\'.'), + type: 'string' + } + }, + required: ['path', 'id'] + } +}); +export class FileIconThemeStore { + + private knownIconThemes: FileIconThemeData[]; + private onDidChangeEmitter: Emitter; + + public get onDidChange(): Event { return this.onDidChangeEmitter.event; } + + constructor( @IExtensionService private extensionService: IExtensionService) { + this.knownIconThemes = []; + this.onDidChangeEmitter = new Emitter(); + this.initialize(); + } + + private initialize() { + iconThemeExtPoint.setHandler((extensions) => { + for (let ext of extensions) { + let extensionData = { + extensionId: ext.description.id, + extensionPublisher: ext.description.publisher, + extensionName: ext.description.name, + extensionIsBuiltin: ext.description.isBuiltin + }; + this.onIconThemes(ext.description.extensionFolderPath, extensionData, ext.value, ext.collector); + } + this.onDidChangeEmitter.fire(this.knownIconThemes); + }); + } + + private onIconThemes(extensionFolderPath: string, extensionData: ExtensionData, iconThemes: IThemeExtensionPoint[], collector: ExtensionMessageCollector): void { + if (!Array.isArray(iconThemes)) { + collector.error(nls.localize( + 'reqarray', + "Extension point `{0}` must be an array.", + iconThemeExtPoint.name + )); + return; + } + iconThemes.forEach(iconTheme => { + if (!iconTheme.path || !types.isString(iconTheme.path)) { + collector.error(nls.localize( + 'reqpath', + "Expected string in `contributes.{0}.path`. Provided value: {1}", + iconThemeExtPoint.name, + String(iconTheme.path) + )); + return; + } + if (!iconTheme.id || !types.isString(iconTheme.id)) { + collector.error(nls.localize( + 'reqid', + "Expected string in `contributes.{0}.id`. Provided value: {1}", + iconThemeExtPoint.name, + String(iconTheme.path) + )); + return; + } + let normalizedAbsolutePath = Paths.normalize(Paths.join(extensionFolderPath, iconTheme.path)); + + if (normalizedAbsolutePath.indexOf(Paths.normalize(extensionFolderPath)) !== 0) { + collector.warn(nls.localize('invalid.path.1', "Expected `contributes.{0}.path` ({1}) to be included inside extension's folder ({2}). This might make the extension non-portable.", iconThemeExtPoint.name, normalizedAbsolutePath, extensionFolderPath)); + } + + let themeData = FileIconThemeData.fromExtensionTheme(iconTheme, normalizedAbsolutePath, extensionData); + this.knownIconThemes.push(themeData); + }); + + } + + public findThemeData(iconTheme: string): TPromise { + return this.getFileIconThemes().then(allIconSets => { + for (let iconSet of allIconSets) { + if (iconSet.id === iconTheme) { + return iconSet; + } + } + return null; + }); + } + + public findThemeBySettingsId(settingsId: string): TPromise { + return this.getFileIconThemes().then(allIconSets => { + for (let iconSet of allIconSets) { + if (iconSet.settingsId === settingsId) { + return iconSet; + } + } + return null; + }); + } + + public getFileIconThemes(): TPromise { + return this.extensionService.onReady().then(isReady => { + return this.knownIconThemes; + }); + } + +} diff --git a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts index 7fb9b9a90c8..6766e10bc34 100644 --- a/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/electron-browser/workbenchThemeService.ts @@ -5,15 +5,11 @@ 'use strict'; import { TPromise, Promise } from 'vs/base/common/winjs.base'; -import URI from 'vs/base/common/uri'; import nls = require('vs/nls'); -import * as Paths from 'path'; -import Json = require('vs/base/common/json'); import * as types from 'vs/base/common/types'; import * as objects from 'vs/base/common/objects'; import { IExtensionService } from 'vs/platform/extensions/common/extensions'; -import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/platform/extensions/common/extensionsRegistry'; -import { IWorkbenchThemeService, IColorTheme, ITokenColorCustomizations, IFileIconTheme, ExtensionData, IThemeExtensionPoint, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME, COLOR_THEME_SETTING, ICON_THEME_SETTING, CUSTOM_WORKBENCH_COLORS_SETTING, DEPRECATED_CUSTOM_COLORS_SETTING, CUSTOM_EDITOR_COLORS_SETTING, CUSTOM_EDITOR_SCOPE_COLORS_SETTING } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IWorkbenchThemeService, IColorTheme, ITokenColorCustomizations, IFileIconTheme, ExtensionData, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME, COLOR_THEME_SETTING, ICON_THEME_SETTING, CUSTOM_WORKBENCH_COLORS_SETTING, CUSTOM_EDITOR_COLORS_SETTING, CUSTOM_EDITOR_SCOPE_COLORS_SETTING } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -26,7 +22,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { IMessageService } from 'vs/platform/message/common/message'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import Severity from 'vs/base/common/severity'; -import { ColorThemeData, fromStorageData, fromExtensionTheme, createUnloadedTheme } from './colorThemeData'; +import { ColorThemeData } from './colorThemeData'; import { ITheme, Extensions as ThemingExtensions, IThemingRegistry } from 'vs/platform/theme/common/themeService'; import { editorBackground } from 'vs/platform/theme/common/colorRegistry'; import { Color } from 'vs/base/common/color'; @@ -39,8 +35,10 @@ import pfs = require('vs/base/node/pfs'); import colorThemeSchema = require('vs/workbench/services/themes/common/colorThemeSchema'); import fileIconThemeSchema = require('vs/workbench/services/themes/common/fileIconThemeSchema'); import { IDisposable } from 'vs/base/common/lifecycle'; -import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; import { IBroadcastService } from 'vs/platform/broadcast/electron-browser/broadcastService'; +import { ColorThemeStore } from 'vs/workbench/services/themes/electron-browser/colorThemeStore'; +import { FileIconThemeStore } from 'vs/workbench/services/themes/electron-browser/fileIconThemeStore'; +import { FileIconThemeData } from 'vs/workbench/services/themes/electron-browser/fileIconThemeData'; // implementation @@ -55,6 +53,9 @@ const oldDefaultThemeExtensionId = 'vscode-theme-colorful-defaults'; const DEFAULT_ICON_THEME_SETTING_VALUE = 'vs-seti'; const fileIconsEnabledClass = 'file-icons-enabled'; +const colorThemeRulesClassName = 'contributedColorTheme'; +const iconThemeRulesClassName = 'contributedIconTheme'; + const themingRegistry = Registry.as(ThemingExtensions.ThemingContribution); function validateThemeId(theme: string): string { @@ -69,125 +70,14 @@ function validateThemeId(theme: string): string { return theme; } -let themesExtPoint = ExtensionsRegistry.registerExtensionPoint('themes', [], { - description: nls.localize('vscode.extension.contributes.themes', 'Contributes textmate color themes.'), - type: 'array', - items: { - type: 'object', - defaultSnippets: [{ body: { label: '${1:label}', id: '${2:id}', uiTheme: VS_DARK_THEME, path: './themes/${3:id}.tmTheme.' } }], - properties: { - id: { - description: nls.localize('vscode.extension.contributes.themes.id', 'Id of the icon theme as used in the user settings.'), - type: 'string' - }, - label: { - description: nls.localize('vscode.extension.contributes.themes.label', 'Label of the color theme as shown in the UI.'), - type: 'string' - }, - uiTheme: { - description: nls.localize('vscode.extension.contributes.themes.uiTheme', 'Base theme defining the colors around the editor: \'vs\' is the light color theme, \'vs-dark\' is the dark color theme. \'hc-black\' is the dark high contrast theme.'), - enum: [VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME] - }, - path: { - description: nls.localize('vscode.extension.contributes.themes.path', 'Path of the tmTheme file. The path is relative to the extension folder and is typically \'./themes/themeFile.tmTheme\'.'), - type: 'string' - } - }, - required: ['path', 'uiTheme'] - } -}); - -let iconThemeExtPoint = ExtensionsRegistry.registerExtensionPoint('iconThemes', [], { - description: nls.localize('vscode.extension.contributes.iconThemes', 'Contributes file icon themes.'), - type: 'array', - items: { - type: 'object', - defaultSnippets: [{ body: { id: '${1:id}', label: '${2:label}', path: './fileicons/${3:id}-icon-theme.json' } }], - properties: { - id: { - description: nls.localize('vscode.extension.contributes.iconThemes.id', 'Id of the icon theme as used in the user settings.'), - type: 'string' - }, - label: { - description: nls.localize('vscode.extension.contributes.iconThemes.label', 'Label of the icon theme as shown in the UI.'), - type: 'string' - }, - path: { - description: nls.localize('vscode.extension.contributes.iconThemes.path', 'Path of the icon theme definition file. The path is relative to the extension folder and is typically \'./icons/awesome-icon-theme.json\'.'), - type: 'string' - } - }, - required: ['path', 'id'] - } -}); - -interface IInternalIconThemeData extends IFileIconTheme { - id: string; - label: string; - settingsId: string; - description?: string; - hasFileIcons?: boolean; - hasFolderIcons?: boolean; - isLoaded: boolean; - path?: string; - styleSheetContent?: string; - extensionData: ExtensionData; -} - -interface IconDefinition { - iconPath: string; - fontColor: string; - fontCharacter: string; - fontSize: string; - fontId: string; -} - -interface FontDefinition { - id: string; - weight: string; - style: string; - size: string; - src: { path: string; format: string; }[]; -} - -interface IconsAssociation { - folder?: string; - file?: string; - folderExpanded?: string; - rootFolder?: string; - rootFolderExpanded?: string; - folderNames?: { [folderName: string]: string; }; - folderNamesExpanded?: { [folderName: string]: string; }; - fileExtensions?: { [extension: string]: string; }; - fileNames?: { [fileName: string]: string; }; - languageIds?: { [languageId: string]: string; }; -} - -interface IconThemeDocument extends IconsAssociation { - iconDefinitions: { [key: string]: IconDefinition }; - fonts: FontDefinition[]; - light?: IconsAssociation; - highContrast?: IconsAssociation; -} - export interface IColorCustomizations { [colorId: string]: string; } -const noFileIconTheme: IFileIconTheme = { - id: '', - label: '', - settingsId: null, - hasFileIcons: false, - hasFolderIcons: false, - isLoaded: true, - extensionData: null -}; - export class WorkbenchThemeService implements IWorkbenchThemeService { _serviceBrand: any; - private extensionsColorThemes: ColorThemeData[]; + private colorThemeStore: ColorThemeStore; private colorCustomizations: IColorCustomizations; private tokenColorCustomizations: ITokenColorCustomizations; private numberOfColorCustomizations: number; @@ -195,7 +85,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { private container: HTMLElement; private onColorThemeChange: Emitter; - private knownIconThemes: IInternalIconThemeData[]; + private iconThemeStore: FileIconThemeStore; private currentIconTheme: IFileIconTheme; private onFileIconThemeChange: Emitter; @@ -214,11 +104,11 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { @IInstantiationService private instantiationService: IInstantiationService) { this.container = container; - this.extensionsColorThemes = []; + this.colorThemeStore = new ColorThemeStore(extensionService); this.colorCustomizations = {}; this.tokenColorCustomizations = {}; this.onFileIconThemeChange = new Emitter(); - this.knownIconThemes = []; + this.iconThemeStore = new FileIconThemeStore(extensionService); this.onColorThemeChange = new Emitter(); this.currentIconTheme = { @@ -239,46 +129,34 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { let themeData = null; let persistedThemeData = this.storageService.get(PERSISTED_THEME_STORAGE_KEY); if (persistedThemeData) { - themeData = fromStorageData(persistedThemeData); + themeData = ColorThemeData.fromStorageData(persistedThemeData); } if (!themeData) { let isLightTheme = (Array.prototype.indexOf.call(document.body.classList, 'vs') >= 0); - themeData = createUnloadedTheme(isLightTheme ? VS_LIGHT_THEME : VS_DARK_THEME); + themeData = ColorThemeData.createUnloadedTheme(isLightTheme ? VS_LIGHT_THEME : VS_DARK_THEME); } themeData.setCustomColors(this.colorCustomizations); themeData.setCustomTokenColors(this.tokenColorCustomizations); this.updateDynamicCSSRules(themeData); this.applyTheme(themeData, null, true); - themesExtPoint.setHandler((extensions) => { - for (let ext of extensions) { - let extensionData = { - extensionId: ext.description.id, - extensionPublisher: ext.description.publisher, - extensionName: ext.description.name, - extensionIsBuiltin: ext.description.isBuiltin - }; - this.onThemes(ext.description.extensionFolderPath, extensionData, ext.value, ext.collector); - } - }); - - iconThemeExtPoint.setHandler((extensions) => { - for (let ext of extensions) { - let extensionData = { - extensionId: ext.description.id, - extensionPublisher: ext.description.publisher, - extensionName: ext.description.name, - extensionIsBuiltin: ext.description.isBuiltin - }; - this.onIconThemes(ext.description.extensionFolderPath, extensionData, ext.value, ext.collector); - } - }); - this.migrate().then(_ => { this.initialize().then(null, errors.onUnexpectedError).then(_ => { this.installConfigurationListener(); }); }); + + // update settings schema setting + this.colorThemeStore.onDidChange(themes => { + colorThemeSettingSchema.enum = themes.map(t => t.settingsId); + colorThemeSettingSchema.enumDescriptions = themes.map(t => themeData.description || ''); + configurationRegistry.notifyConfigurationSchemaUpdated(colorThemeSettingSchema); + }); + this.iconThemeStore.onDidChange(themes => { + iconThemeSettingSchema.enum = themes.map(t => t.settingsId); + iconThemeSettingSchema.enumDescriptions = themes.map(t => themeData.description || ''); + configurationRegistry.notifyConfigurationSchemaUpdated(iconThemeSettingSchema); + }); } public get onDidColorThemeChange(): Event { @@ -316,7 +194,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { let promise = TPromise.as(null); if (!types.isUndefined(legacyColorThemeId)) { this.storageService.remove('workbench.theme', StorageScope.GLOBAL); - promise = this.findThemeData(legacyColorThemeId, DEFAULT_THEME_ID).then(theme => { + promise = this.colorThemeStore.findThemeData(legacyColorThemeId, DEFAULT_THEME_ID).then(theme => { let value = theme ? theme.settingsId : DEFAULT_THEME_SETTING_VALUE; return this.configurationWriter.writeConfiguration(COLOR_THEME_SETTING, value, ConfigurationTarget.USER).then(null, error => null); }); @@ -324,7 +202,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { if (!types.isUndefined(legacyIconThemeId)) { this.storageService.remove('workbench.iconTheme', StorageScope.GLOBAL); promise = promise.then(_ => { - return this._findIconThemeData(legacyIconThemeId).then(theme => { + return this.iconThemeStore.findThemeData(legacyIconThemeId).then(theme => { let value = theme ? theme.settingsId : null; return this.configurationWriter.writeConfiguration(ICON_THEME_SETTING, value, ConfigurationTarget.USER).then(null, error => null); }); @@ -348,10 +226,10 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { let iconThemeSetting = this.configurationService.lookup(ICON_THEME_SETTING).value || ''; return Promise.join([ - this.findThemeDataBySettingsId(colorThemeSetting, DEFAULT_THEME_ID).then(theme => { + this.colorThemeStore.findThemeDataBySettingsId(colorThemeSetting, DEFAULT_THEME_ID).then(theme => { return this.setColorTheme(theme && theme.id, null); }), - this.findIconThemeBySettingsId(iconThemeSetting).then(theme => { + this.iconThemeStore.findThemeBySettingsId(iconThemeSetting).then(theme => { return this.setFileIconTheme(theme && theme.id, null); }), ]); @@ -361,7 +239,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { this.configurationService.onDidUpdateConfiguration(e => { let colorThemeSetting = this.configurationService.lookup(COLOR_THEME_SETTING).value; if (colorThemeSetting !== this.currentColorTheme.settingsId) { - this.findThemeDataBySettingsId(colorThemeSetting, null).then(theme => { + this.colorThemeStore.findThemeDataBySettingsId(colorThemeSetting, null).then(theme => { if (theme) { this.setColorTheme(theme.id, null); } @@ -370,7 +248,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { let iconThemeSetting = this.configurationService.lookup(ICON_THEME_SETTING).value || ''; if (iconThemeSetting !== this.currentIconTheme.settingsId) { - this.findIconThemeBySettingsId(iconThemeSetting).then(theme => { + this.iconThemeStore.findThemeBySettingsId(iconThemeSetting).then(theme => { this.setFileIconTheme(theme && theme.id, null); }); } @@ -379,6 +257,14 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { }); } + public getColorTheme(): IColorTheme { + return this.currentColorTheme; + } + + public getColorThemes(): TPromise { + return this.colorThemeStore.getColorThemes(); + } + public getTheme(): ITheme { return this.getColorTheme(); } @@ -393,8 +279,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { themeId = validateThemeId(themeId); // migrate theme ids - - return this.findThemeData(themeId, DEFAULT_THEME_ID).then(themeData => { + return this.colorThemeStore.findThemeData(themeId, DEFAULT_THEME_ID).then(themeData => { if (themeData) { return themeData.ensureLoaded(this).then(_ => { if (themeId === this.currentColorTheme.id && !this.currentColorTheme.isLoaded && this.currentColorTheme.hasEqualData(themeData)) { @@ -471,46 +356,6 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { return TPromise.as(this.currentColorTheme); } - public getColorTheme(): IColorTheme { - return this.currentColorTheme; - } - - private findThemeData(themeId: string, defaultId?: string): TPromise { - return this.getColorThemes().then(allThemes => { - let defaultTheme: ColorThemeData = void 0; - for (let t of allThemes) { - if (t.id === themeId) { - return t; - } - if (t.id === defaultId) { - defaultTheme = t; - } - } - return defaultTheme; - }); - } - - public findThemeDataBySettingsId(settingsId: string, defaultId: string): TPromise { - return this.getColorThemes().then(allThemes => { - let defaultTheme: ColorThemeData = void 0; - for (let t of allThemes) { - if (t.settingsId === settingsId) { - return t; - } - if (t.id === defaultId) { - defaultTheme = t; - } - } - return defaultTheme; - }); - } - - public getColorThemes(): TPromise { - return this.extensionService.onReady().then(isReady => { - return this.extensionsColorThemes; - }); - } - private hasCustomizationChanged(newColorCustomizations: IColorCustomizations, newColorIds: string[], newTokenColorCustomizations: ITokenColorCustomizations): boolean { if (newColorIds.length !== this.numberOfColorCustomizations) { return true; @@ -532,10 +377,6 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { private updateColorCustomizations(notify = true): void { let newColorCustomizations = this.configurationService.lookup(CUSTOM_WORKBENCH_COLORS_SETTING).value || {}; let newColorIds = Object.keys(newColorCustomizations); - if (newColorIds.length === 0) { - newColorCustomizations = this.configurationService.lookup(DEPRECATED_CUSTOM_COLORS_SETTING).value || {}; - newColorIds = Object.keys(newColorCustomizations); - } let newTokenColorCustomizations = this.configurationService.lookup(CUSTOM_EDITOR_COLORS_SETTING).value || {}; @@ -555,88 +396,6 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } } - private onThemes(extensionFolderPath: string, extensionData: ExtensionData, themes: IThemeExtensionPoint[], collector: ExtensionMessageCollector): void { - if (!Array.isArray(themes)) { - collector.error(nls.localize( - 'reqarray', - "Extension point `{0}` must be an array.", - themesExtPoint.name - )); - return; - } - themes.forEach(theme => { - if (!theme.path || !types.isString(theme.path)) { - collector.error(nls.localize( - 'reqpath', - "Expected string in `contributes.{0}.path`. Provided value: {1}", - themesExtPoint.name, - String(theme.path) - )); - return; - } - let normalizedAbsolutePath = Paths.normalize(Paths.join(extensionFolderPath, theme.path)); - - if (normalizedAbsolutePath.indexOf(Paths.normalize(extensionFolderPath)) !== 0) { - collector.warn(nls.localize('invalid.path.1', "Expected `contributes.{0}.path` ({1}) to be included inside extension's folder ({2}). This might make the extension non-portable.", themesExtPoint.name, normalizedAbsolutePath, extensionFolderPath)); - } - let themeData = fromExtensionTheme(theme, normalizedAbsolutePath, extensionData); - this.extensionsColorThemes.push(themeData); - - colorThemeSettingSchema.enum.push(themeData.settingsId); - colorThemeSettingSchema.enumDescriptions.push(themeData.description || ''); - }); - } - - private onIconThemes(extensionFolderPath: string, extensionData: ExtensionData, iconThemes: IThemeExtensionPoint[], collector: ExtensionMessageCollector): void { - if (!Array.isArray(iconThemes)) { - collector.error(nls.localize( - 'reqarray', - "Extension point `{0}` must be an array.", - themesExtPoint.name - )); - return; - } - iconThemes.forEach(iconTheme => { - if (!iconTheme.path || !types.isString(iconTheme.path)) { - collector.error(nls.localize( - 'reqpath', - "Expected string in `contributes.{0}.path`. Provided value: {1}", - themesExtPoint.name, - String(iconTheme.path) - )); - return; - } - if (!iconTheme.id || !types.isString(iconTheme.id)) { - collector.error(nls.localize( - 'reqid', - "Expected string in `contributes.{0}.id`. Provided value: {1}", - themesExtPoint.name, - String(iconTheme.path) - )); - return; - } - let normalizedAbsolutePath = Paths.normalize(Paths.join(extensionFolderPath, iconTheme.path)); - - if (normalizedAbsolutePath.indexOf(Paths.normalize(extensionFolderPath)) !== 0) { - collector.warn(nls.localize('invalid.path.1', "Expected `contributes.{0}.path` ({1}) to be included inside extension's folder ({2}). This might make the extension non-portable.", themesExtPoint.name, normalizedAbsolutePath, extensionFolderPath)); - } - - let themeData = { - id: extensionData.extensionId + '-' + iconTheme.id, - label: iconTheme.label || Paths.basename(iconTheme.path), - settingsId: iconTheme.id, - description: iconTheme.description, - path: normalizedAbsolutePath, - extensionData: extensionData, - isLoaded: false - }; - this.knownIconThemes.push(themeData); - - iconThemeSettingSchema.enum.push(themeData.settingsId); - iconThemeSettingSchema.enumDescriptions.push(themeData.description || ''); - }); - } - private themeExtensionsActivated = new Map(); private sendTelemetry(themeId: string, themeData: ExtensionData, themeType: string) { if (themeData) { @@ -664,9 +423,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } public getFileIconThemes(): TPromise { - return this.extensionService.onReady().then(isReady => { - return this.knownIconThemes; - }); + return this.iconThemeStore.getFileIconThemes(); } public getFileIconTheme() { @@ -678,11 +435,11 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { if (iconTheme === this.currentIconTheme.id && this.currentIconTheme.isLoaded) { return this.writeFileIconConfiguration(settingsTarget); } - let onApply = (newIconTheme: IInternalIconThemeData) => { + let onApply = (newIconTheme: FileIconThemeData) => { if (newIconTheme) { this.currentIconTheme = newIconTheme; } else { - this.currentIconTheme = noFileIconTheme; + this.currentIconTheme = FileIconThemeData.noIconTheme(); } if (this.container) { @@ -699,7 +456,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { return this.writeFileIconConfiguration(settingsTarget); }; - return this._findIconThemeData(iconTheme).then(iconThemeData => { + return this.iconThemeStore.findThemeData(iconTheme).then(iconThemeData => { return _applyIconTheme(iconThemeData, onApply); }); } @@ -718,229 +475,21 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } return this._configurationWriter; } - - private _findIconThemeData(iconTheme: string): TPromise { - return this.getFileIconThemes().then(allIconSets => { - for (let iconSet of allIconSets) { - if (iconSet.id === iconTheme) { - return iconSet; - } - } - return null; - }); - } - - private findIconThemeBySettingsId(settingsId: string): TPromise { - return this.getFileIconThemes().then(allIconSets => { - for (let iconSet of allIconSets) { - if (iconSet.settingsId === settingsId) { - return iconSet; - } - } - return null; - }); - } } -function _applyIconTheme(data: IInternalIconThemeData, onApply: (theme: IInternalIconThemeData) => TPromise): TPromise { +function _applyIconTheme(data: FileIconThemeData, onApply: (theme: FileIconThemeData) => TPromise): TPromise { if (!data) { _applyRules('', iconThemeRulesClassName); return TPromise.as(onApply(data)); } - - if (data.styleSheetContent) { - _applyRules(data.styleSheetContent, iconThemeRulesClassName); - return TPromise.as(onApply(data)); - } - return _loadIconThemeDocument(data.path).then(iconThemeDocument => { - let result = _processIconThemeDocument(data.id, data.path, iconThemeDocument); - data.styleSheetContent = result.content; - data.hasFileIcons = result.hasFileIcons; - data.hasFolderIcons = result.hasFolderIcons; - data.isLoaded = true; - _applyRules(data.styleSheetContent, iconThemeRulesClassName); + return data.ensureLoaded(this).then(styleSheetContent => { + _applyRules(styleSheetContent, iconThemeRulesClassName); return onApply(data); }, error => { return TPromise.wrapError(new Error(nls.localize('error.cannotloadicontheme', "Unable to load {0}", data.path))); }); } -function _loadIconThemeDocument(fileSetPath: string): TPromise { - return pfs.readFile(fileSetPath).then(content => { - let errors: Json.ParseError[] = []; - let contentValue = Json.parse(content.toString(), errors); - if (errors.length > 0) { - return TPromise.wrapError(new Error(nls.localize('error.cannotparseicontheme', "Problems parsing file icons file: {0}", errors.map(e => getParseErrorMessage(e.error)).join(', ')))); - } - return TPromise.as(contentValue); - }); -} - -function _processIconThemeDocument(id: string, iconThemeDocumentPath: string, iconThemeDocument: IconThemeDocument): { content: string; hasFileIcons: boolean; hasFolderIcons: boolean; } { - - let result = { content: '', hasFileIcons: false, hasFolderIcons: false }; - - if (!iconThemeDocument.iconDefinitions) { - return result; - } - let selectorByDefinitionId: { [def: string]: string[] } = {}; - - function resolvePath(path: string) { - const uri = URI.file(Paths.join(Paths.dirname(iconThemeDocumentPath), path)); - return uri.toString(); - } - - function collectSelectors(associations: IconsAssociation, baseThemeClassName?: string) { - function addSelector(selector: string, defId: string) { - if (defId) { - let list = selectorByDefinitionId[defId]; - if (!list) { - list = selectorByDefinitionId[defId] = []; - } - list.push(selector); - } - } - if (associations) { - let qualifier = '.show-file-icons'; - if (baseThemeClassName) { - qualifier = baseThemeClassName + ' ' + qualifier; - } - - let expanded = '.monaco-tree-row.expanded'; // workaround for #11453 - - if (associations.folder) { - addSelector(`${qualifier} .folder-icon::before`, associations.folder); - result.hasFolderIcons = true; - } - - if (associations.folderExpanded) { - addSelector(`${qualifier} ${expanded} .folder-icon::before`, associations.folderExpanded); - result.hasFolderIcons = true; - } - - let rootFolder = associations.rootFolder || associations.folder; - let rootFolderExpanded = associations.rootFolderExpanded || associations.folderExpanded; - - if (rootFolder) { - addSelector(`${qualifier} .rootfolder-icon::before`, rootFolder); - result.hasFolderIcons = true; - } - - if (rootFolderExpanded) { - addSelector(`${qualifier} ${expanded} .rootfolder-icon::before`, rootFolderExpanded); - result.hasFolderIcons = true; - } - - if (associations.file) { - addSelector(`${qualifier} .file-icon::before`, associations.file); - result.hasFileIcons = true; - } - - let folderNames = associations.folderNames; - if (folderNames) { - for (let folderName in folderNames) { - addSelector(`${qualifier} .${escapeCSS(folderName.toLowerCase())}-name-folder-icon.folder-icon::before`, folderNames[folderName]); - result.hasFolderIcons = true; - } - } - let folderNamesExpanded = associations.folderNamesExpanded; - if (folderNamesExpanded) { - for (let folderName in folderNamesExpanded) { - addSelector(`${qualifier} ${expanded} .${escapeCSS(folderName.toLowerCase())}-name-folder-icon.folder-icon::before`, folderNamesExpanded[folderName]); - result.hasFolderIcons = true; - } - } - - let languageIds = associations.languageIds; - if (languageIds) { - for (let languageId in languageIds) { - addSelector(`${qualifier} .${escapeCSS(languageId)}-lang-file-icon.file-icon::before`, languageIds[languageId]); - result.hasFileIcons = true; - } - } - let fileExtensions = associations.fileExtensions; - if (fileExtensions) { - for (let fileExtension in fileExtensions) { - let selectors: string[] = []; - let segments = fileExtension.toLowerCase().split('.'); - for (let i = 0; i < segments.length; i++) { - selectors.push(`.${escapeCSS(segments.slice(i).join('.'))}-ext-file-icon`); - } - addSelector(`${qualifier} ${selectors.join('')}.file-icon::before`, fileExtensions[fileExtension]); - result.hasFileIcons = true; - } - } - let fileNames = associations.fileNames; - if (fileNames) { - for (let fileName in fileNames) { - let selectors: string[] = []; - fileName = fileName.toLowerCase(); - selectors.push(`.${escapeCSS(fileName)}-name-file-icon`); - let segments = fileName.split('.'); - for (let i = 1; i < segments.length; i++) { - selectors.push(`.${escapeCSS(segments.slice(i).join('.'))}-ext-file-icon`); - } - addSelector(`${qualifier} ${selectors.join('')}.file-icon::before`, fileNames[fileName]); - result.hasFileIcons = true; - } - } - } - } - collectSelectors(iconThemeDocument); - collectSelectors(iconThemeDocument.light, '.vs'); - collectSelectors(iconThemeDocument.highContrast, '.hc-black'); - - if (!result.hasFileIcons && !result.hasFolderIcons) { - return result; - } - - let cssRules: string[] = []; - - let fonts = iconThemeDocument.fonts; - if (Array.isArray(fonts)) { - fonts.forEach(font => { - let src = font.src.map(l => `url('${resolvePath(l.path)}') format('${l.format}')`).join(', '); - cssRules.push(`@font-face { src: ${src}; font-family: '${font.id}'; font-weigth: ${font.weight}; font-style: ${font.style}; }`); - }); - cssRules.push(`.show-file-icons .file-icon::before, .show-file-icons .folder-icon::before, .show-file-icons .rootfolder-icon::before { font-family: '${fonts[0].id}'; font-size: ${fonts[0].size || '150%'}}`); - } - - for (let defId in selectorByDefinitionId) { - let selectors = selectorByDefinitionId[defId]; - let definition = iconThemeDocument.iconDefinitions[defId]; - if (definition) { - if (definition.iconPath) { - cssRules.push(`${selectors.join(', ')} { content: ' '; background-image: url("${resolvePath(definition.iconPath)}"); }`); - } - if (definition.fontCharacter || definition.fontColor) { - let body = ''; - if (definition.fontColor) { - body += ` color: ${definition.fontColor};`; - } - if (definition.fontCharacter) { - body += ` content: '${definition.fontCharacter}';`; - } - if (definition.fontSize) { - body += ` font-size: ${definition.fontSize};`; - } - if (definition.fontId) { - body += ` font-family: ${definition.fontId};`; - } - cssRules.push(`${selectors.join(', ')} { ${body} }`); - } - } - } - result.content = cssRules.join('\n'); - return result; -} - -function escapeCSS(str: string) { - return window['CSS'].escape(str); -} - -let colorThemeRulesClassName = 'contributedColorTheme'; -let iconThemeRulesClassName = 'contributedIconTheme'; - function _applyRules(styleSheetContent: string, rulesClassName: string) { let themeStyles = document.head.getElementsByClassName(rulesClassName); if (themeStyles.length === 0) { @@ -992,6 +541,7 @@ const colorThemeSettingSchema: IJSONSchema = { enumDescriptions: [], errorMessage: nls.localize('colorThemeError', "Theme is unknown or not installed."), }; + const iconThemeSettingSchema: IJSONSchema = { type: ['string', 'null'], default: DEFAULT_ICON_THEME_SETTING_VALUE, @@ -1004,6 +554,7 @@ const colorCustomizationsSchema: IJSONSchema = { type: ['object'], description: nls.localize('workbenchColors', "Overrides colors from the currently selected color theme."), properties: colorThemeSchema.colorsSchema.properties, + additionalProperties: false, default: {}, defaultSnippets: [{ body: { @@ -1014,11 +565,6 @@ const colorCustomizationsSchema: IJSONSchema = { }] }; -const deprecatedColorCustomizationsSchema: IJSONSchema = objects.mixin({ - deprecationMessage: nls.localize('workbenchColors.deprecated', "The setting is no longer experimental and has been renamed to 'workbench.colorCustomizations'"), - description: nls.localize('workbenchColors.deprecatedDescription', "Use 'workbench.colorCustomizations' instead") -}, colorCustomizationsSchema, false); - configurationRegistry.registerConfiguration({ id: 'workbench', order: 7.1, @@ -1026,8 +572,7 @@ configurationRegistry.registerConfiguration({ properties: { [COLOR_THEME_SETTING]: colorThemeSettingSchema, [ICON_THEME_SETTING]: iconThemeSettingSchema, - [CUSTOM_WORKBENCH_COLORS_SETTING]: colorCustomizationsSchema, - [DEPRECATED_CUSTOM_COLORS_SETTING]: deprecatedColorCustomizationsSchema + [CUSTOM_WORKBENCH_COLORS_SETTING]: colorCustomizationsSchema } }); @@ -1054,6 +599,7 @@ configurationRegistry.registerConfiguration({ [CUSTOM_EDITOR_COLORS_SETTING]: { description: nls.localize('editorColors', "Overrides editor colors and font style from the currently selected color theme."), default: {}, + additionalProperties: false, properties: { comments: tokenGroupSettings(nls.localize('editorColors.comments', "Sets the colors and styles for comments")), strings: tokenGroupSettings(nls.localize('editorColors.strings', "Sets the colors and styles for strings literals.")), diff --git a/src/vs/workbench/services/workspace/common/workspaceEditing.ts b/src/vs/workbench/services/workspace/common/workspaceEditing.ts index 7a9a1783ee2..56f6b473db2 100644 --- a/src/vs/workbench/services/workspace/common/workspaceEditing.ts +++ b/src/vs/workbench/services/workspace/common/workspaceEditing.ts @@ -29,12 +29,17 @@ export interface IWorkspaceEditingService { * creates a new workspace with the provided folders and opens it. if path is provided * the workspace will be saved into that location. */ - createAndEnterWorkspace(folders?: string[], path?: string): TPromise; + createAndEnterWorkspace(folderPaths?: string[], path?: string): TPromise; /** * saves the workspace to the provided path and opens it. requires a workspace to be opened. */ saveAndEnterWorkspace(path: string): TPromise; + + /** + * copies current workspace settings to the target workspace. + */ + copyWorkspaceSettings(toWorkspace: IWorkspaceIdentifier): TPromise; } export const IWorkspaceMigrationService = createDecorator('workspaceMigrationService'); diff --git a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts index aa99ca9f75a..934b4c70a19 100644 --- a/src/vs/workbench/services/workspace/node/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/node/workspaceEditingService.ts @@ -64,11 +64,15 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { return; // already existing } + // File resource: use "path" property if (folderToAdd.scheme === Schemas.file) { storedFoldersToAdd.push({ path: massageFolderPathForWorkspace(folderToAdd.fsPath, workspaceConfigFolder, currentStoredFolders) }); - } else { + } + + // Any other resource: use "uri" property + else { storedFoldersToAdd.push({ uri: folderToAdd.toString(true) }); @@ -129,8 +133,8 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { }); } - public createAndEnterWorkspace(folders?: string[], path?: string): TPromise { - return this.doEnterWorkspace(() => this.windowService.createAndEnterWorkspace(folders, path)); + public createAndEnterWorkspace(folderPaths?: string[], path?: string): TPromise { + return this.doEnterWorkspace(() => this.windowService.createAndEnterWorkspace(folderPaths, path)); } public saveAndEnterWorkspace(path: string): TPromise { @@ -165,9 +169,16 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { } private migrate(toWorkspace: IWorkspaceIdentifier): TPromise { + + // Storage (UI State) migration this.migrateStorage(toWorkspace); - return this.migrateConfiguration(toWorkspace); + // Settings migration (only if we come from a folder workspace) + if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) { + return this.copyWorkspaceSettings(toWorkspace); + } + + return TPromise.as(void 0); } private migrateStorage(toWorkspace: IWorkspaceIdentifier): void { @@ -178,11 +189,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { storageImpl.setWorkspaceId(newWorkspaceId); } - private migrateConfiguration(toWorkspace: IWorkspaceIdentifier): TPromise { - if (this.contextService.getWorkbenchState() !== WorkbenchState.FOLDER) { - return TPromise.as(void 0); // return early if not a folder workspace is opened - } - + public copyWorkspaceSettings(toWorkspace: IWorkspaceIdentifier): TPromise { const configurationProperties = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); const targetWorkspaceConfiguration = {}; for (const key of this.workspaceConfigurationService.keys().workspace) { diff --git a/src/vs/workbench/test/browser/actionRegistry.test.ts b/src/vs/workbench/test/browser/actionRegistry.test.ts index b990f175019..97a62c5cc7f 100644 --- a/src/vs/workbench/test/browser/actionRegistry.test.ts +++ b/src/vs/workbench/test/browser/actionRegistry.test.ts @@ -6,10 +6,7 @@ 'use strict'; import * as assert from 'assert'; -import * as Platform from 'vs/platform/registry/common/platform'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; -import { Extensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { prepareActions } from 'vs/workbench/browser/actions'; import { Action } from 'vs/base/common/actions'; @@ -22,26 +19,6 @@ class MyClass extends Action { suite('Workbench Action Registry', () => { - test('Workbench Action Registration', function () { - let Registry = Platform.Registry.as(Extensions.WorkbenchActions); - - let d = new SyncActionDescriptor(MyClass, 'id', 'name'); - - let oldActions = Registry.getWorkbenchActions().slice(0); - let oldCount = Registry.getWorkbenchActions().length; - - Registry.registerWorkbenchAction(d, 'My Alias', 'category'); - Registry.registerWorkbenchAction(d, null); - - assert.equal(Registry.getWorkbenchActions().length, 1 + oldCount); - assert.strictEqual(d, Registry.getWorkbenchAction('id')); - - assert.deepEqual(Registry.getAlias(d.id), 'My Alias'); - assert.equal(Registry.getCategory(d.id), 'category'); - - (Registry).setWorkbenchActions(oldActions); - }); - test('Workbench Action Bar prepareActions()', function () { let a1 = new Separator(); let a2 = new Separator(); @@ -57,4 +34,4 @@ suite('Workbench Action Registry', () => { assert(actions[1] === a5); assert(actions[2] === a6); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index ada172ca08d..e09df0d1813 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -26,7 +26,7 @@ import { TextModelResolverService } from 'vs/workbench/services/textmodelResolve import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { IEditorInput, IEditorOptions, Position, Direction, IEditor, IResourceInput, ITextEditorSelection } from 'vs/platform/editor/common/editor'; import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { IMessageService, IConfirmation } from 'vs/platform/message/common/message'; +import { IMessageService, IConfirmation, IConfirmationResult } from 'vs/platform/message/common/message'; import { IWorkspaceContextService, IWorkspace as IWorkbenchWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; import { ILifecycleService, ShutdownEvent, ShutdownReason, StartupKind, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { EditorStacksModel } from 'vs/workbench/common/editor/editorStacksModel'; @@ -46,7 +46,7 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; -import { IWindowsService, IWindowService, INativeOpenDialogOptions, IEnterWorkspaceResult } from 'vs/platform/windows/common/windows'; +import { IWindowsService, IWindowService, INativeOpenDialogOptions, IEnterWorkspaceResult, IMessageBoxResult } from 'vs/platform/windows/common/windows'; import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; import { RawTextSource, IRawTextSource } from 'vs/editor/common/model/textSource'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -299,6 +299,7 @@ export class TestHistoryService implements IHistoryService { } export class TestMessageService implements IMessageService { + public _serviceBrand: any; private counter: number; @@ -321,9 +322,13 @@ export class TestMessageService implements IMessageService { // No-op } - public confirm(confirmation: IConfirmation): boolean { + public confirmSync(confirmation: IConfirmation): boolean { return false; } + + public confirm(confirmation: IConfirmation): Promise { + return TPromise.as({ confirmed: false }); + } } export class TestPartService implements IPartService { @@ -903,7 +908,7 @@ export class TestWindowService implements IWindowService { return TPromise.as(void 0); } - createAndEnterWorkspace(folders?: string[], path?: string): TPromise { + createAndEnterWorkspace(folderPaths?: string[], path?: string): TPromise { return TPromise.as(void 0); } @@ -955,10 +960,14 @@ export class TestWindowService implements IWindowService { return TPromise.as(void 0); } - showMessageBox(options: Electron.MessageBoxOptions): number { + showMessageBoxSync(options: Electron.MessageBoxOptions): number { return 0; } + showMessageBox(options: Electron.MessageBoxOptions): Promise { + return TPromise.as(void 0); + } + showSaveDialog(options: Electron.SaveDialogOptions, callback?: (fileName: string) => void): string { return void 0; } @@ -1051,7 +1060,7 @@ export class TestWindowsService implements IWindowsService { return TPromise.as(void 0); } - createAndEnterWorkspace(windowId: number, folders?: string[], path?: string): TPromise { + createAndEnterWorkspace(windowId: number, folderPaths?: string[], path?: string): TPromise { return TPromise.as(void 0); } diff --git a/test/smoke/package.json b/test/smoke/package.json index 95d42199ece..8e1a6e4793e 100644 --- a/test/smoke/package.json +++ b/test/smoke/package.json @@ -9,13 +9,13 @@ }, "devDependencies": { "@types/electron": "~1.4.37", - "@types/htmlparser2": "^3.7.29", - "@types/mkdirp": "^0.5.1", - "@types/mocha": "^2.2.41", - "@types/ncp": "^2.0.1", - "@types/node": "^8.0.26", - "@types/rimraf": "^2.0.2", - "@types/webdriverio": "^4.6.1", + "@types/htmlparser2": "3.7.29", + "@types/mkdirp": "0.5.1", + "@types/mocha": "2.2.41", + "@types/ncp": "2.0.1", + "@types/node": "8.0.33", + "@types/rimraf": "2.0.2", + "@types/webdriverio": "4.6.1", "htmlparser2": "^3.9.2", "mkdirp": "^0.5.1", "mocha": "^3.2.0", diff --git a/test/smoke/src/areas/explorer/explorer.ts b/test/smoke/src/areas/explorer/explorer.ts index 3fdf04dd594..e799bc0f225 100644 --- a/test/smoke/src/areas/explorer/explorer.ts +++ b/test/smoke/src/areas/explorer/explorer.ts @@ -32,11 +32,11 @@ export class Explorer extends Viewlet { public getExtensionSelector(fileName: string): string { const extension = fileName.split('.')[1]; if (extension === 'js') { - return 'js-ext-file-icon javascript-lang-file-icon'; + return 'js-ext-file-icon ext-file-icon javascript-lang-file-icon'; } else if (extension === 'json') { - return 'json-ext-file-icon json-lang-file-icon'; + return 'json-ext-file-icon ext-file-icon json-lang-file-icon'; } else if (extension === 'md') { - return 'md-ext-file-icon markdown-lang-file-icon'; + return 'md-ext-file-icon ext-file-icon markdown-lang-file-icon'; } throw new Error('No class defined for this file extension'); }