diff --git a/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json index 601bc9c8a78..a5bdbba8c86 100644 --- a/extensions/configuration-editing/package.json +++ b/extensions/configuration-editing/package.json @@ -37,7 +37,8 @@ "launch.json", "tasks.json", "keybindings.json", - "extensions.json" + "extensions.json", + "argv.json" ] } ], diff --git a/extensions/csharp/language-configuration.json b/extensions/csharp/language-configuration.json index 88107685266..d8698b46c09 100644 --- a/extensions/csharp/language-configuration.json +++ b/extensions/csharp/language-configuration.json @@ -13,8 +13,7 @@ ["[", "]"], ["(", ")"], { "open": "'", "close": "'", "notIn": ["string", "comment"] }, - { "open": "\"", "close": "\"", "notIn": ["string", "comment"] }, - { "open": "/*", "close": " */", "notIn": ["string"] } + { "open": "\"", "close": "\"", "notIn": ["string", "comment"] } ], "surroundingPairs": [ ["{", "}"], @@ -30,4 +29,4 @@ "end": "^\\s*#endregion\\b" } } -} \ No newline at end of file +} diff --git a/extensions/git/package.json b/extensions/git/package.json index b64dfb4707e..eafc4916439 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -362,6 +362,11 @@ "title": "%command.ignore%", "category": "Git" }, + { + "command": "git.revealInExplorer", + "title": "%command.revealInExplorer%", + "category": "Git" + }, { "command": "git.stashIncludeUntracked", "title": "%command.stashIncludeUntracked%", @@ -507,6 +512,10 @@ "command": "git.restoreCommitTemplate", "when": "false" }, + { + "command": "git.revealInExplorer", + "when": "false" + }, { "command": "git.undoCommit", "when": "config.git.enabled && gitOpenRepositoryCount != 0" @@ -913,6 +922,11 @@ "when": "scmProvider == git && scmResourceGroup == merge", "group": "inline" }, + { + "command": "git.revealInExplorer", + "when": "scmProvider == git && scmResourceGroup == merge", + "group": "2_view" + }, { "command": "git.openFile2", "when": "scmProvider == git && scmResourceGroup == merge && config.git.showInlineOpenFileAction && config.git.openDiffOnClick", @@ -948,6 +962,11 @@ "when": "scmProvider == git && scmResourceGroup == index", "group": "inline" }, + { + "command": "git.revealInExplorer", + "when": "scmProvider == git && scmResourceGroup == index", + "group": "2_view" + }, { "command": "git.openFile2", "when": "scmProvider == git && scmResourceGroup == index && config.git.showInlineOpenFileAction && config.git.openDiffOnClick", @@ -1007,6 +1026,11 @@ "command": "git.ignore", "when": "scmProvider == git && scmResourceGroup == workingTree", "group": "1_modification@3" + }, + { + "command": "git.revealInExplorer", + "when": "scmProvider == git && scmResourceGroup == workingTree", + "group": "2_view" } ], "editor/title": [ diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 6587b65421d..c6a474439f5 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -56,6 +56,7 @@ "command.publish": "Publish Branch", "command.showOutput": "Show Git Output", "command.ignore": "Add to .gitignore", + "command.revealInExplorer": "Reveal in Explorer", "command.stashIncludeUntracked": "Stash (Include Untracked)", "command.stash": "Stash", "command.stashPop": "Pop Stash...", diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index d17c27e7c28..349435d7aeb 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1249,11 +1249,13 @@ export class CommandCenter { promptToSaveFilesBeforeCommit = 'never'; } + const enableSmartCommit = config.get('enableSmartCommit') === true; + if (promptToSaveFilesBeforeCommit !== 'never') { let documents = workspace.textDocuments .filter(d => !d.isUntitled && d.isDirty && isDescendant(repository.root, d.uri.fsPath)); - if (promptToSaveFilesBeforeCommit === 'staged') { + if (promptToSaveFilesBeforeCommit === 'staged' || repository.indexGroup.resourceStates.length > 0) { documents = documents .filter(d => repository.indexGroup.resourceStates.some(s => s.resourceUri.path === d.uri.fsPath)); } @@ -1275,7 +1277,6 @@ export class CommandCenter { } } - const enableSmartCommit = config.get('enableSmartCommit') === true; const enableCommitSigning = config.get('enableCommitSigning') === true; const noStagedChanges = repository.indexGroup.resourceStates.length === 0; const noUnstagedChanges = repository.workingTreeGroup.resourceStates.length === 0; @@ -1370,9 +1371,18 @@ export class CommandCenter { value = (await repository.getCommit(repository.HEAD.commit)).message; } + const branchName = repository.headShortName; + let placeHolder: string; + + if (branchName) { + placeHolder = localize('commitMessageWithHeadLabel2', "Message (commit on '{0}')", branchName); + } else { + placeHolder = localize('commit message', "Commit message"); + } + return await window.showInputBox({ value, - placeHolder: localize('commit message', "Commit message"), + placeHolder, prompt: localize('provide commit message', "Please provide a commit message"), ignoreFocusOut: true }); @@ -2069,6 +2079,19 @@ export class CommandCenter { await this.runByRepository(resources, async (repository, resources) => repository.ignore(resources)); } + @command('git.revealInExplorer') + async revealInExplorer(resourceState: SourceControlResourceState): Promise { + if (!resourceState) { + return; + } + + if (!(resourceState.resourceUri instanceof Uri)) { + return; + } + + await commands.executeCommand('revealInExplorer', resourceState.resourceUri); + } + private async _stash(repository: Repository, includeUntracked = false): Promise { const noUnstagedChanges = repository.workingTreeGroup.resourceStates.length === 0; const noStagedChanges = repository.indexGroup.resourceStates.length === 0; diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index fadd1ac6e74..416e98ce79a 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -579,6 +579,23 @@ export class Repository implements Disposable { return this._refs; } + get headShortName(): string | undefined { + if (!this.HEAD) { + return; + } + + const HEAD = this.HEAD; + const tag = this.refs.filter(iref => iref.type === RefType.Tag && iref.commit === HEAD.commit)[0]; + const tagName = tag && tag.name; + const branchName = HEAD.name || tagName || HEAD.commit; + + if (branchName === undefined) { + return; + } + + return branchName.substr(0, 8); + } + private _remotes: Remote[] = []; get remotes(): Remote[] { return this._remotes; @@ -1643,15 +1660,11 @@ export class Repository implements Disposable { } private updateInputBoxPlaceholder(): void { - const HEAD = this.HEAD; - - if (HEAD) { - const tag = this.refs.filter(iref => iref.type === RefType.Tag && iref.commit === HEAD.commit)[0]; - const tagName = tag && tag.name; - const head = HEAD.name || tagName || (HEAD.commit || '').substr(0, 8); + const branchName = this.headShortName; + if (branchName) { // '{0}' will be replaced by the corresponding key-command later in the process, which is why it needs to stay. - this._sourceControl.inputBox.placeholder = localize('commitMessageWithHeadLabel', "Message ({0} to commit on '{1}')", "{0}", head); + this._sourceControl.inputBox.placeholder = localize('commitMessageWithHeadLabel', "Message ({0} to commit on '{1}')", "{0}", branchName); } else { this._sourceControl.inputBox.placeholder = localize('commitMessage', "Message ({0} to commit)"); } diff --git a/extensions/html-language-features/server/src/modes/embeddedSupport.ts b/extensions/html-language-features/server/src/modes/embeddedSupport.ts index de80fa5c8e3..df47be3ed97 100644 --- a/extensions/html-language-features/server/src/modes/embeddedSupport.ts +++ b/extensions/html-language-features/server/src/modes/embeddedSupport.ts @@ -56,7 +56,7 @@ export function getDocumentRegions(languageService: LanguageService, document: T } importedScripts.push(value); } else if (lastAttributeName === 'type' && lastTagName.toLowerCase() === 'script') { - if (/["'](module|(text|application)\/(java|ecma)script)["']/.test(scanner.getTokenText())) { + if (/["'](module|(text|application)\/(java|ecma)script|text\/babel)["']/.test(scanner.getTokenText())) { languageIdFromType = 'javascript'; } else { languageIdFromType = undefined; @@ -228,4 +228,4 @@ function getAttributeLanguage(attributeName: string): string | null { return null; } return match[1] ? 'css' : 'javascript'; -} \ No newline at end of file +} diff --git a/extensions/json/language-configuration.json b/extensions/json/language-configuration.json index 9a73ac64aae..7faa70cef7a 100644 --- a/extensions/json/language-configuration.json +++ b/extensions/json/language-configuration.json @@ -12,8 +12,7 @@ { "open": "[", "close": "]", "notIn": ["string"] }, { "open": "(", "close": ")", "notIn": ["string"] }, { "open": "'", "close": "'", "notIn": ["string"] }, - { "open": "/*", "close": "*/", "notIn": ["string"] }, { "open": "\"", "close": "\"", "notIn": ["string", "comment"] }, { "open": "`", "close": "`", "notIn": ["string", "comment"] } ] -} \ No newline at end of file +} diff --git a/extensions/markdown-language-features/src/features/preview.ts b/extensions/markdown-language-features/src/features/preview.ts index 13f6d792a2d..16636dd1585 100644 --- a/extensions/markdown-language-features/src/features/preview.ts +++ b/extensions/markdown-language-features/src/features/preview.ts @@ -536,7 +536,7 @@ export class MarkdownPreview extends Disposable { } private async onDidClickPreviewLink(href: string) { - let [hrefPath, fragment] = href.split('#'); + let [hrefPath, fragment] = decodeURIComponent(href).split('#'); // We perviously already resolve absolute paths. // Now make sure we handle relative file paths diff --git a/extensions/npm/README.md b/extensions/npm/README.md index a24a7d69d6e..941da175102 100644 --- a/extensions/npm/README.md +++ b/extensions/npm/README.md @@ -24,7 +24,7 @@ the hover shown on a script or using the command `Run Selected Npm Script`. ### Others -The extension fetches data from https://registry.npmjs/org and https://registry.bower.io to provide auto-completion and information on hover features on npm dependencies. +The extension fetches data from https://registry.npmjs.org and https://registry.bower.io to provide auto-completion and information on hover features on npm dependencies. ## Settings diff --git a/extensions/npm/package.nls.json b/extensions/npm/package.nls.json index 40121b8fa8d..b5e00dd614b 100644 --- a/extensions/npm/package.nls.json +++ b/extensions/npm/package.nls.json @@ -7,7 +7,7 @@ "config.npm.exclude": "Configure glob patterns for folders that should be excluded from automatic script detection.", "config.npm.enableScriptExplorer": "Enable an explorer view for npm scripts when there is no top-level 'package.json' file.", "config.npm.scriptExplorerAction": "The default click action used in the scripts explorer: `open` or `run`, the default is `open`.", - "config.npm.fetchOnlinePackageInfo": "Fetch data from https://registry.npmjs/org and https://registry.bower.io to provide auto-completion and information on hover features on npm dependencies.", + "config.npm.fetchOnlinePackageInfo": "Fetch data from https://registry.npmjs.org and https://registry.bower.io to provide auto-completion and information on hover features on npm dependencies.", "npm.parseError": "Npm task detection: failed to parse the file {0}", "taskdef.script": "The npm script to customize.", "taskdef.path": "The path to the folder of the package.json file that provides the script. Can be omitted.", diff --git a/extensions/rust/language-configuration.json b/extensions/rust/language-configuration.json index 6f198f44f4e..bd4cbb8d8f0 100644 --- a/extensions/rust/language-configuration.json +++ b/extensions/rust/language-configuration.json @@ -21,6 +21,10 @@ ["\"", "\""], ["'", "'"] ], + "indentationRules": { + "increaseIndentPattern": "^.*\\{[^}\"']*$|^.*\\([^\\)\"']*$", + "decreaseIndentPattern": "^\\s*(\\s*\\/[*].*[*]\\/\\s*)*[})]" + }, "folding": { "markers": { "start": "^\\s*//\\s*#?region\\b", diff --git a/extensions/shellscript/package.json b/extensions/shellscript/package.json index a55af2b08ff..211401a070c 100644 --- a/extensions/shellscript/package.json +++ b/extensions/shellscript/package.json @@ -23,6 +23,12 @@ "language": "shellscript", "scopeName": "source.shell", "path": "./syntaxes/shell-unix-bash.tmLanguage.json" - }] + }], + "configurationDefaults": { + "[shellscript]": { + "files.eol": "\n" + } + } + } } diff --git a/package.json b/package.json index 73de0699d82..7f469d57bb0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.40.0", - "distro": "7d62db65536347b7a7c21ae355071b55920c4d84", + "distro": "9627858bf882fef220a55f51257dca1491763dc1", "author": { "name": "Microsoft Corporation" }, @@ -51,8 +51,8 @@ "vscode-ripgrep": "^1.5.7", "vscode-sqlite3": "4.0.8", "vscode-textmate": "^4.2.2", - "xterm": "4.1.0-beta8", - "xterm-addon-search": "0.2.0", + "xterm": "4.2.0-beta4", + "xterm-addon-search": "0.3.0-beta5", "xterm-addon-web-links": "0.2.0", "yauzl": "^2.9.2", "yazl": "^2.4.3" @@ -100,6 +100,7 @@ "gulp-tslint": "^8.1.3", "gulp-untar": "^0.0.7", "gulp-vinyl-zip": "^2.1.2", + "husky": "^0.13.1", "innosetup": "5.6.1", "is": "^3.1.0", "istanbul-lib-coverage": "^2.0.5", diff --git a/remote/package.json b/remote/package.json index d65eddd673d..15aaa8f30b1 100644 --- a/remote/package.json +++ b/remote/package.json @@ -20,8 +20,8 @@ "vscode-proxy-agent": "0.4.0", "vscode-ripgrep": "^1.5.7", "vscode-textmate": "^4.2.2", - "xterm": "4.1.0-beta8", - "xterm-addon-search": "0.2.0", + "xterm": "4.2.0-beta4", + "xterm-addon-search": "0.3.0-beta5", "xterm-addon-web-links": "0.2.0", "yauzl": "^2.9.2", "yazl": "^2.4.3" diff --git a/remote/web/package.json b/remote/web/package.json index 01e11a75fb2..db6e5d18e12 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -5,8 +5,8 @@ "onigasm-umd": "^2.2.2", "semver-umd": "^5.5.3", "vscode-textmate": "^4.2.2", - "xterm": "4.1.0-beta8", - "xterm-addon-search": "0.2.0", + "xterm": "4.2.0-beta4", + "xterm-addon-search": "0.3.0-beta5", "xterm-addon-web-links": "0.2.0" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 696c1956a47..759deded50b 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -31,17 +31,17 @@ vscode-textmate@^4.2.2: dependencies: oniguruma "^7.2.0" -xterm-addon-search@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0.tgz#46659c7c33f9fc268ad3e7e6c5824bb2fdb65852" - integrity sha512-C/v2VvFn3hb1qUgjJPo7LxzxNCLBgNJv8n6v/bH2NqPz32/PNUF+IHu0SFf1TaIH+pydUpKXCtob5a/UyZg/+Q== +xterm-addon-search@0.3.0-beta5: + version "0.3.0-beta5" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.3.0-beta5.tgz#fd53d33a77a0235018479c712be8c12f7c0d083a" + integrity sha512-3GkGc4hST35/4hzgnQPLLvQ29WH7MkZ0mUrBE/Vm1IQum7TnMvWPTkGemwM+wAl4tdBmynNccHJlFeQzaQtVUg== xterm-addon-web-links@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.0.tgz#b408a0be46211d8d4a0bb5e701d8f3c2bd07d473" integrity sha512-dq81c4Pzli2PgKVBgY2REte9sCVibR3df8AP3SEvCTM9uYFnUFxtxzMTplPnc7+rXabVhFdbU6x+rstIk8HNQg== -xterm@4.1.0-beta8: - version "4.1.0-beta8" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.1.0-beta8.tgz#c1ef323ba336d92f5b52302b66f672dfff75b3ef" - integrity sha512-6lf+XVv0qT285w49P92tSYoUB406jdbgdhnPKNzxCIGtGX8kcwK+pHZ8HncDwcEhmTmI4LZ/WXPGtOQJg+onwg== +xterm@4.2.0-beta4: + version "4.2.0-beta4" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.2.0-beta4.tgz#596577f94a1da372119d192363ea2b19d1f8b50c" + integrity sha512-BmkpxCpqdOJoNdIcddkRT8S65sGjgBbWI0uIJNSnzZvj81OKcraMSTmF/ODw0TF/MDLc33Fx9cpDx/D6lQgl8Q== diff --git a/remote/yarn.lock b/remote/yarn.lock index a081e69b960..b018aafbaab 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -416,20 +416,20 @@ vscode-windows-registry@1.0.2: resolved "https://registry.yarnpkg.com/vscode-windows-registry/-/vscode-windows-registry-1.0.2.tgz#b863e704a6a69c50b3098a55fbddbe595b0c124a" integrity sha512-/CLLvuOSM2Vme2z6aNyB+4Omd7hDxpf4Thrt8ImxnXeQtxzel2bClJpFQvQqK/s4oaXlkBKS7LqVLeZM+uSVIA== -xterm-addon-search@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0.tgz#46659c7c33f9fc268ad3e7e6c5824bb2fdb65852" - integrity sha512-C/v2VvFn3hb1qUgjJPo7LxzxNCLBgNJv8n6v/bH2NqPz32/PNUF+IHu0SFf1TaIH+pydUpKXCtob5a/UyZg/+Q== +xterm-addon-search@0.3.0-beta5: + version "0.3.0-beta5" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.3.0-beta5.tgz#fd53d33a77a0235018479c712be8c12f7c0d083a" + integrity sha512-3GkGc4hST35/4hzgnQPLLvQ29WH7MkZ0mUrBE/Vm1IQum7TnMvWPTkGemwM+wAl4tdBmynNccHJlFeQzaQtVUg== xterm-addon-web-links@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.0.tgz#b408a0be46211d8d4a0bb5e701d8f3c2bd07d473" integrity sha512-dq81c4Pzli2PgKVBgY2REte9sCVibR3df8AP3SEvCTM9uYFnUFxtxzMTplPnc7+rXabVhFdbU6x+rstIk8HNQg== -xterm@4.1.0-beta8: - version "4.1.0-beta8" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.1.0-beta8.tgz#c1ef323ba336d92f5b52302b66f672dfff75b3ef" - integrity sha512-6lf+XVv0qT285w49P92tSYoUB406jdbgdhnPKNzxCIGtGX8kcwK+pHZ8HncDwcEhmTmI4LZ/WXPGtOQJg+onwg== +xterm@4.2.0-beta4: + version "4.2.0-beta4" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.2.0-beta4.tgz#596577f94a1da372119d192363ea2b19d1f8b50c" + integrity sha512-BmkpxCpqdOJoNdIcddkRT8S65sGjgBbWI0uIJNSnzZvj81OKcraMSTmF/ODw0TF/MDLc33Fx9cpDx/D6lQgl8Q== yauzl@^2.9.2: version "2.10.0" diff --git a/resources/linux/bin/code.sh b/resources/linux/bin/code.sh index 564f13ef95c..516c05e4ee0 100755 --- a/resources/linux/bin/code.sh +++ b/resources/linux/bin/code.sh @@ -30,7 +30,7 @@ if [ ! -L $0 ]; then # if path is not a symlink, find relatively VSCODE_PATH="$(dirname $0)/.." else - if which readlink >/dev/null; then + if command -v readlink >/dev/null; then # if readlink exists, follow the symlink and find relatively VSCODE_PATH="$(dirname $(readlink -f $0))/.." else diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index 3f3815b4feb..0d7b9ee4b37 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -29,16 +29,18 @@ call .\scripts\test.bat --runGlob **\*.integrationTest.js %* if %errorlevel% neq 0 exit /b %errorlevel% :: Tests in the extension host -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% + +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% if %errorlevel% neq 0 exit /b %errorlevel% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% + if %errorlevel% neq 0 exit /b %errorlevel% -call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% +call "%INTEGRATION_TEST_ELECTRON_PATH%" %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% if %errorlevel% neq 0 exit /b %errorlevel% -call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% . +call "%INTEGRATION_TEST_ELECTRON_PATH%" $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% . if %errorlevel% neq 0 exit /b %errorlevel% :: Tests in commonJS (HTML, CSS, JSON language server tests...) diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index b63daeb74a7..a3891cf96fc 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -37,13 +37,14 @@ fi ./scripts/test.sh --runGlob **/*.integrationTest.js "$@" # Tests in the extension host -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testWorkspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --enable-proposed-api=vscode.vscode-api-tests --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/vscode-colorize-tests/test --extensionDevelopmentPath=$ROOT/extensions/vscode-colorize-tests --extensionTestsPath=$ROOT/extensions/vscode-colorize-tests/out --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR + mkdir -p $ROOT/extensions/emmet/test-fixtures -"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR +"$INTEGRATION_TEST_ELECTRON_PATH" $LINUX_NO_SANDBOX $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-telemetry --disable-crash-reporter --disable-updates --disable-extensions --skip-getting-started --user-data-dir=$VSCODEUSERDATADIR rm -rf $ROOT/extensions/emmet/test-fixtures # Remote Integration Tests diff --git a/src/bootstrap-window.js b/src/bootstrap-window.js index 72403b1e413..3999314e9fe 100644 --- a/src/bootstrap-window.js +++ b/src/bootstrap-window.js @@ -21,7 +21,7 @@ exports.assign = function assign(destination, source) { * * @param {string[]} modulePaths * @param {(result, configuration: object) => any} resultCallback - * @param {{ forceEnableDeveloperKeybindings?: boolean, removeDeveloperKeybindingsAfterLoad?: boolean, canModifyDOM?: (config: object) => void, beforeLoaderConfig?: (config: object, loaderConfig: object) => void, beforeRequire?: () => void }=} options + * @param {{ forceEnableDeveloperKeybindings?: boolean, disallowReloadKeybinding?: boolean, removeDeveloperKeybindingsAfterLoad?: boolean, canModifyDOM?: (config: object) => void, beforeLoaderConfig?: (config: object, loaderConfig: object) => void, beforeRequire?: () => void }=} options */ exports.load = function (modulePaths, resultCallback, options) { @@ -58,7 +58,7 @@ exports.load = function (modulePaths, resultCallback, options) { const enableDeveloperTools = (process.env['VSCODE_DEV'] || !!configuration.extensionDevelopmentPath) && !configuration.extensionTestsPath; let developerToolsUnbind; if (enableDeveloperTools || (options && options.forceEnableDeveloperKeybindings)) { - developerToolsUnbind = registerDeveloperKeybindings(); + developerToolsUnbind = registerDeveloperKeybindings(options && options.disallowReloadKeybinding); } // Correctly inherit the parent's environment @@ -159,9 +159,10 @@ function parseURLQueryArgs() { } /** + * @param {boolean} disallowReloadKeybinding * @returns {() => void} */ -function registerDeveloperKeybindings() { +function registerDeveloperKeybindings(disallowReloadKeybinding) { // @ts-ignore const ipc = require('electron').ipcRenderer; @@ -185,7 +186,7 @@ function registerDeveloperKeybindings() { const key = extractKey(e); if (key === TOGGLE_DEV_TOOLS_KB || key === TOGGLE_DEV_TOOLS_KB_ALT) { ipc.send('vscode:toggleDevTools'); - } else if (key === RELOAD_KB) { + } else if (key === RELOAD_KB && !disallowReloadKeybinding) { ipc.send('vscode:reloadWindow'); } }; diff --git a/src/main.js b/src/main.js index 4b0be14bf99..bac4f4ead6d 100644 --- a/src/main.js +++ b/src/main.js @@ -12,6 +12,8 @@ const lp = require('./vs/base/node/languagePacks'); perf.mark('main:started'); const path = require('path'); +const fs = require('fs'); +const os = require('os'); const bootstrap = require('./bootstrap'); const paths = require('./paths'); // @ts-ignore @@ -25,7 +27,7 @@ const portable = bootstrap.configurePortable(); // Enable ASAR support bootstrap.enableASARSupport(); -// Set userData path before app 'ready' event and call to process.chdir +// Set userData path before app 'ready' event const args = parseCLIArgs(); const userDataPath = getUserDataPath(args); app.setPath('userData', userDataPath); @@ -37,17 +39,18 @@ setCurrentWorkingDirectory(); registerListeners(); /** - * Support user defined locale + * Support user defined locale: load it early before app('ready') + * to have more things running in parallel. * - * @type {Promise} + * @type {Promise} nlsConfig | undefined */ -let nlsConfiguration = undefined; +let nlsConfigurationPromise = undefined; const userDefinedLocale = getUserDefinedLocale(); const metaDataFile = path.join(__dirname, 'nls.metadata.json'); userDefinedLocale.then(locale => { - if (locale && !nlsConfiguration) { - nlsConfiguration = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale); + if (locale && !nlsConfigurationPromise) { + nlsConfigurationPromise = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale); } }); @@ -74,62 +77,35 @@ app.once('ready', function () { } }); -function onReady() { +/** + * Main startup routine + * + * @param {string | undefined} cachedDataDir + * @param {import('./vs/base/node/languagePacks').NLSConfiguration} nlsConfig + */ +function startup(cachedDataDir, nlsConfig) { + nlsConfig._languagePackSupport = true; + + process.env['VSCODE_NLS_CONFIG'] = JSON.stringify(nlsConfig); + process.env['VSCODE_NODE_CACHED_DATA_DIR'] = cachedDataDir || ''; + + // Load main in AMD + perf.mark('willLoadMainBundle'); + require('./bootstrap-amd').load('vs/code/electron-main/main', () => { + perf.mark('didLoadMainBundle'); + }); +} + +async function onReady() { perf.mark('main:appReady'); - Promise.all([nodeCachedDataDir.ensureExists(), userDefinedLocale]).then(([cachedDataDir, locale]) => { - if (locale && !nlsConfiguration) { - nlsConfiguration = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale); - } + try { + const [cachedDataDir, locale] = await Promise.all([nodeCachedDataDir.ensureExists(), userDefinedLocale]); - if (!nlsConfiguration) { - nlsConfiguration = Promise.resolve(undefined); - } - - // First, we need to test a user defined locale. If it fails we try the app locale. - // If that fails we fall back to English. - nlsConfiguration.then(nlsConfig => { - - const startup = nlsConfig => { - nlsConfig._languagePackSupport = true; - process.env['VSCODE_NLS_CONFIG'] = JSON.stringify(nlsConfig); - process.env['VSCODE_NODE_CACHED_DATA_DIR'] = cachedDataDir || ''; - - // Load main in AMD - perf.mark('willLoadMainBundle'); - require('./bootstrap-amd').load('vs/code/electron-main/main', () => { - perf.mark('didLoadMainBundle'); - }); - }; - - // We received a valid nlsConfig from a user defined locale - if (nlsConfig) { - startup(nlsConfig); - } - - // Try to use the app locale. Please note that the app locale is only - // valid after we have received the app ready event. This is why the - // code is here. - else { - let appLocale = app.getLocale(); - if (!appLocale) { - startup({ locale: 'en', availableLanguages: {} }); - } else { - - // See above the comment about the loader and case sensitiviness - appLocale = appLocale.toLowerCase(); - - lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, appLocale).then(nlsConfig => { - if (!nlsConfig) { - nlsConfig = { locale: appLocale, availableLanguages: {} }; - } - - startup(nlsConfig); - }); - } - } - }); - }, console.error); + startup(cachedDataDir, await resolveNlsConfiguration(locale)); + } catch (error) { + console.error(error); + } } /** @@ -139,16 +115,97 @@ function onReady() { */ function configureCommandlineSwitches(cliArgs) { - // Force pre-Chrome-60 color profile handling (for https://github.com/Microsoft/vscode/issues/51791) - app.commandLine.appendSwitch('disable-color-correct-rendering'); + // Read argv config + const argvConfig = readArgvConfig(); + + // Append each flag to Electron + Object.keys(argvConfig).forEach(flag => { + const value = argvConfig[flag]; + if (value === true || value === 'true') { + if (flag === 'disable-gpu') { + app.disableHardwareAcceleration(); // needs to be called explicitly + } + + app.commandLine.appendArgument(flag); + } else { + app.commandLine.appendSwitch(flag, value); + } + }); // Support JS Flags const jsFlags = getJSFlags(cliArgs); if (jsFlags) { - app.commandLine.appendSwitch('--js-flags', jsFlags); + app.commandLine.appendSwitch('js-flags', jsFlags); } } +function readArgvConfig() { + + // Read or create the argv.json config file sync before app('ready') + const argvConfigPath = getArgvConfigPath(); + let argvConfig; + try { + argvConfig = JSON.parse(stripComments(fs.readFileSync(argvConfigPath).toString())); + } catch (error) { + if (error && error.code === 'ENOENT') { + try { + const argvConfigPathDirname = path.dirname(argvConfigPath); + if (!fs.existsSync(argvConfigPathDirname)) { + fs.mkdirSync(argvConfigPathDirname); + } + + // Create initial argv.json if not existing + fs.writeFileSync(argvConfigPath, `// This configuration file allows to pass permanent command line arguments to VSCode. +// +// PLEASE DO NOT CHANGE WITHOUT UNDERSTANDING THE IMPACT +// +// If the command line argument does not have any values, simply assign +// it in the JSON below with a value of 'true'. Otherwise, put the value +// directly. +// +// If you see rendering issues in VSCode and have a better experience +// with software rendering, you can configure this by adding: +// +// 'disable-gpu': true +// +// NOTE: Changing this file requires a restart of VSCode. +{ + // Enabled by default by VSCode to resolve color issues in the renderer + // See https://github.com/Microsoft/vscode/issues/51791 for details + "disable-color-correct-rendering": true +}`); + } catch (error) { + console.error(`Unable to create argv.json configuration file in ${argvConfigPath}, falling back to defaults (${error})`); + } + } else { + console.warn(`Unable to read argv.json configuration file in ${argvConfigPath}, falling back to defaults (${error})`); + } + } + + // Fallback to default + if (!argvConfig) { + argvConfig = { + 'disable-color-correct-rendering': true // Force pre-Chrome-60 color profile handling (for https://github.com/Microsoft/vscode/issues/51791) + }; + } + + return argvConfig; +} + +function getArgvConfigPath() { + const vscodePortable = process.env['VSCODE_PORTABLE']; + if (vscodePortable) { + return path.join(vscodePortable, 'argv.json'); + } + + let dataFolderName = product.dataFolderName; + if (process.env['VSCODE_DEV']) { + dataFolderName = `${dataFolderName}-dev`; + } + + return path.join(os.homedir(), dataFolderName, 'argv.json'); +} + /** * @param {ParsedArgs} cliArgs * @returns {string} @@ -249,7 +306,7 @@ function registerListeners() { } /** - * @returns {{ ensureExists: () => Promise }} + * @returns {{ ensureExists: () => Promise }} */ function getNodeCachedDir() { return new class { @@ -258,8 +315,14 @@ function getNodeCachedDir() { this.value = this._compute(); } - ensureExists() { - return bootstrap.mkdirp(this.value).then(() => this.value, () => { /*ignore*/ }); + async ensureExists() { + try { + await bootstrap.mkdirp(this.value); + + return this.value; + } catch (error) { + // ignore + } } _compute() { @@ -284,6 +347,50 @@ function getNodeCachedDir() { } //#region NLS Support +/** + * Resolve the NLS configuration + * + * @param {string | undefined} locale + * @return {Promise} + */ +async function resolveNlsConfiguration(locale) { + + // First, we need to test a user defined locale. If it fails we try the app locale. + // If that fails we fall back to English. + if (locale && !nlsConfigurationPromise) { + nlsConfigurationPromise = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale); + } else if (!nlsConfigurationPromise) { + nlsConfigurationPromise = Promise.resolve(undefined); + } + + // First, we need to test a user defined locale. If it fails we try the app locale. + // If that fails we fall back to English. + let nlsConfiguration = await nlsConfigurationPromise; + if (!nlsConfiguration) { + + // Try to use the app locale. Please note that the app locale is only + // valid after we have received the app ready event. This is why the + // code is here. + let appLocale = app.getLocale(); + if (!appLocale) { + nlsConfiguration = { locale: 'en', availableLanguages: {} }; + } else { + + // See above the comment about the loader and case sensitiviness + appLocale = appLocale.toLowerCase(); + + nlsConfiguration = await lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, appLocale); + if (!nlsConfiguration) { + nlsConfiguration = { locale: appLocale, availableLanguages: {} }; + } + } + } else { + // We received a valid nlsConfig from a user defined locale + } + + return nlsConfiguration; +} + /** * @param {string} content * @returns {string} @@ -312,30 +419,29 @@ function stripComments(content) { }); } -// Language tags are case insensitive however an amd loader is case sensitive -// To make this work on case preserving & insensitive FS we do the following: -// the language bundles have lower case language tags and we always lower case -// the locale we receive from the user or OS. /** + * Language tags are case insensitive however an amd loader is case sensitive + * To make this work on case preserving & insensitive FS we do the following: + * the language bundles have lower case language tags and we always lower case + * the locale we receive from the user or OS. + * * @returns {Promise} */ -function getUserDefinedLocale() { +async function getUserDefinedLocale() { const locale = args['locale']; if (locale) { - return Promise.resolve(locale.toLowerCase()); + return locale.toLowerCase(); } const localeConfig = path.join(userDataPath, 'User', 'locale.json'); - return bootstrap.readFile(localeConfig).then(content => { - content = stripComments(content); - try { - const value = JSON.parse(content).locale; - return value && typeof value === 'string' ? value.toLowerCase() : undefined; - } catch (e) { - return undefined; - } - }, () => { - return undefined; - }); + + try { + const content = stripComments(await bootstrap.readFile(localeConfig)); + + const value = JSON.parse(content).locale; + return value && typeof value === 'string' ? value.toLowerCase() : undefined; + } catch (error) { + // ignore + } } //#endregion diff --git a/src/vs/base/browser/fastDomNode.ts b/src/vs/base/browser/fastDomNode.ts index cb121546529..6dfec19f492 100644 --- a/src/vs/base/browser/fastDomNode.ts +++ b/src/vs/base/browser/fastDomNode.ts @@ -18,6 +18,7 @@ export class FastDomNode { private _fontFamily: string; private _fontWeight: string; private _fontSize: number; + private _fontFeatureSettings: string; private _lineHeight: number; private _letterSpacing: number; private _className: string; @@ -38,6 +39,7 @@ export class FastDomNode { this._fontFamily = ''; this._fontWeight = ''; this._fontSize = -1; + this._fontFeatureSettings = ''; this._lineHeight = -1; this._letterSpacing = -100; this._className = ''; @@ -135,6 +137,14 @@ export class FastDomNode { this.domNode.style.fontSize = this._fontSize + 'px'; } + public setFontFeatureSettings(fontFeatureSettings: string): void { + if (this._fontFeatureSettings === fontFeatureSettings) { + return; + } + this._fontFeatureSettings = fontFeatureSettings; + this.domNode.style.fontFeatureSettings = this._fontFeatureSettings; + } + public setLineHeight(lineHeight: number): void { if (this._lineHeight === lineHeight) { return; diff --git a/src/vs/base/browser/ui/codiconLabel/codiconLabel.ts b/src/vs/base/browser/ui/codiconLabel/codiconLabel.ts index 42d38948e88..e496fd3a164 100644 --- a/src/vs/base/browser/ui/codiconLabel/codiconLabel.ts +++ b/src/vs/base/browser/ui/codiconLabel/codiconLabel.ts @@ -8,7 +8,7 @@ import 'vs/css!./codicon/codicon-animations'; import { escape } from 'vs/base/common/strings'; function expand(text: string): string { - return text.replace(/\$\(((.+?)(~(.*?))?)\)/g, (_match, _g1, name, _g3, animation) => { + return text.replace(/\$\((([a-z0-9\-]+?)(~([a-z0-9\-]*?))?)\)/gi, (_match, _g1, name, _g3, animation) => { return ``; }); } diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index 6f0ea59ff10..352dd6b8e34 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -155,6 +155,14 @@ export class PagedList implements IDisposable { this.list.scrollTop = scrollTop; } + get scrollLeft(): number { + return this.list.scrollLeft; + } + + set scrollLeft(scrollLeft: number) { + this.list.scrollLeft = scrollLeft; + } + open(indexes: number[], browserEvent?: UIEvent): void { this.list.open(indexes, browserEvent); } diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 937fc0c870d..97ec6f37206 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -686,7 +686,7 @@ export class ListView implements ISpliceable, IDisposable { return scrollPosition.scrollLeft; } - setScrollLeftt(scrollLeft: number): void { + setScrollLeft(scrollLeft: number): void { if (this.scrollableElementUpdateDisposable) { this.scrollableElementUpdateDisposable.dispose(); this.scrollableElementUpdateDisposable = null; diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index a8a2a63da47..a70969206fb 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -1316,7 +1316,7 @@ export class List implements ISpliceable, IDisposable { } set scrollLeft(scrollLeft: number) { - this.view.setScrollLeftt(scrollLeft); + this.view.setScrollLeft(scrollLeft); } get scrollHeight(): number { diff --git a/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts b/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts index c5d77ed9724..209ba4133f5 100644 --- a/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts +++ b/src/vs/base/browser/ui/octiconLabel/octiconLabel.ts @@ -8,7 +8,7 @@ import 'vs/css!./octicons/octicons-animations'; import { escape } from 'vs/base/common/strings'; function expand(text: string): string { - return text.replace(/\$\(((.+?)(~(.*?))?)\)/g, (_match, _g1, name, _g3, animation) => { + return text.replace(/\$\((([a-z0-9\-]+?)(~([a-z0-9\-]*?))?)\)/gi, (_match, _g1, name, _g3, animation) => { return ``; }); } diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 925a9128552..e0376d8a519 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -1368,7 +1368,7 @@ export abstract class AbstractTree implements IDisposable } get scrollLeft(): number { - return this.view.scrollTop; + return this.view.scrollLeft; } set scrollLeft(scrollLeft: number) { diff --git a/src/vs/base/common/cancellation.ts b/src/vs/base/common/cancellation.ts index fb274fb941f..f741f6b7af1 100644 --- a/src/vs/base/common/cancellation.ts +++ b/src/vs/base/common/cancellation.ts @@ -116,7 +116,10 @@ export class CancellationTokenSource { } } - dispose(): void { + dispose(cancel: boolean = false): void { + if (cancel) { + this.cancel(); + } if (this._parentListener) { this._parentListener.dispose(); } diff --git a/src/vs/base/common/htmlContent.ts b/src/vs/base/common/htmlContent.ts index fee84c57bf6..c9bfed7ea8f 100644 --- a/src/vs/base/common/htmlContent.ts +++ b/src/vs/base/common/htmlContent.ts @@ -7,23 +7,27 @@ import { equals } from 'vs/base/common/arrays'; import { UriComponents } from 'vs/base/common/uri'; export interface IMarkdownString { - value: string; - isTrusted?: boolean; + readonly value: string; + readonly isTrusted?: boolean; uris?: { [href: string]: UriComponents }; } export class MarkdownString implements IMarkdownString { - value: string; - isTrusted?: boolean; + private _value: string; + private _isTrusted: boolean; - constructor(value: string = '') { - this.value = value; + constructor(value: string = '', isTrusted = false) { + this._value = value; + this._isTrusted = isTrusted; } + get value() { return this._value; } + get isTrusted() { return this._isTrusted; } + appendText(value: string): MarkdownString { // escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash - this.value += value + this._value += value .replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&') .replace('\n', '\n\n'); @@ -31,16 +35,16 @@ export class MarkdownString implements IMarkdownString { } appendMarkdown(value: string): MarkdownString { - this.value += value; + this._value += value; return this; } appendCodeblock(langId: string, code: string): MarkdownString { - this.value += '\n```'; - this.value += langId; - this.value += '\n'; - this.value += code; - this.value += '\n```\n'; + this._value += '\n```'; + this._value += langId; + this._value += '\n'; + this._value += code; + this._value += '\n```\n'; return this; } } diff --git a/src/vs/base/common/octicon.ts b/src/vs/base/common/octicon.ts index 48da86f6cc1..80b5653f32e 100644 --- a/src/vs/base/common/octicon.ts +++ b/src/vs/base/common/octicon.ts @@ -9,8 +9,8 @@ import { ltrim } from 'vs/base/common/strings'; const octiconStartMarker = '$('; export interface IParsedOcticons { - text: string; - octiconOffsets?: number[]; + readonly text: string; + readonly octiconOffsets?: readonly number[]; } export function parseOcticons(text: string): IParsedOcticons { @@ -78,7 +78,16 @@ function doParseOcticons(text: string, firstOcticonIndex: number): IParsedOctico // within octicon else if (currentOcticonStart !== -1) { - currentOcticonValue += char; + // Make sure this is a real octicon name + if (/^[a-z0-9\-]$/i.test(char)) { + currentOcticonValue += char; + } else { + // This is not a real octicon, treat it as text + appendChars(currentOcticonValue); + + currentOcticonStart = -1; + currentOcticonValue = ''; + } } // any value outside of octicons @@ -123,4 +132,4 @@ export function matchesFuzzyOcticonAware(query: string, target: IParsedOcticons, } return matches; -} \ No newline at end of file +} diff --git a/src/vs/base/common/resourceTree.ts b/src/vs/base/common/resourceTree.ts index f11e02c42b5..1272d4a6ad0 100644 --- a/src/vs/base/common/resourceTree.ts +++ b/src/vs/base/common/resourceTree.ts @@ -159,12 +159,12 @@ export class ResourceTree, C> { delete(uri: URI): T | undefined { const key = relativePath(this.root.uri, uri) || uri.fsPath; - const parts = key.split(/[\\\/]/).filter(p => !!p); - return this._delete(this.root, parts, 0); + const iterator = new PathIterator(false).reset(key); + return this._delete(this.root, iterator); } - private _delete(node: BranchNode, parts: string[], index: number): T | undefined { - const name = parts[index]; + private _delete(node: BranchNode, iterator: PathIterator): T | undefined { + const name = iterator.value(); const child = node.get(name); if (!child) { @@ -172,9 +172,9 @@ export class ResourceTree, C> { } // not at end - if (index < parts.length - 1) { + if (iterator.hasNext()) { if (child instanceof BranchNode) { - const result = this._delete(child, parts, index + 1); + const result = this._delete(child, iterator.next()); if (typeof result !== 'undefined' && child.size === 0) { node.delete(name); diff --git a/src/vs/base/node/languagePacks.d.ts b/src/vs/base/node/languagePacks.d.ts index 241392e5eca..5c69043ef23 100644 --- a/src/vs/base/node/languagePacks.d.ts +++ b/src/vs/base/node/languagePacks.d.ts @@ -9,6 +9,7 @@ export interface NLSConfiguration { [key: string]: string; }; pseudo?: boolean; + _languagePackSupport?: boolean; } export interface InternalNLSConfiguration extends NLSConfiguration { @@ -20,4 +21,4 @@ export interface InternalNLSConfiguration extends NLSConfiguration { _languagePackSupport?: boolean; } -export function getNLSConfiguration(commit: string, userDataPath: string, metaDataFile: string, locale: string): Promise; \ No newline at end of file +export function getNLSConfiguration(commit: string, userDataPath: string, metaDataFile: string, locale: string): Promise; diff --git a/src/vs/base/test/common/cancellation.test.ts b/src/vs/base/test/common/cancellation.test.ts index 536b2e21139..88d7d26e6fb 100644 --- a/src/vs/base/test/common/cancellation.test.ts +++ b/src/vs/base/test/common/cancellation.test.ts @@ -95,6 +95,20 @@ suite('CancellationToken', function () { assert.equal(count, 0); }); + test('dispose calls no listeners (unless told to cancel)', function () { + + let count = 0; + + let source = new CancellationTokenSource(); + source.token.onCancellationRequested(function () { + count += 1; + }); + + source.dispose(true); + // source.cancel(); + assert.equal(count, 1); + }); + test('parent cancels child', function () { let parent = new CancellationTokenSource(); diff --git a/src/vs/base/test/common/octicon.test.ts b/src/vs/base/test/common/octicon.test.ts index c91055525d2..8ba48579337 100644 --- a/src/vs/base/test/common/octicon.test.ts +++ b/src/vs/base/test/common/octicon.test.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { IMatch } from 'vs/base/common/filters'; -import { matchesFuzzyOcticonAware, parseOcticons } from 'vs/base/common/octicon'; +import { matchesFuzzyOcticonAware, parseOcticons, IParsedOcticons } from 'vs/base/common/octicon'; export interface IOcticonFilter { // Returns null if word doesn't match. - (query: string, target: { text: string, octiconOffsets?: number[] }): IMatch[] | null; + (query: string, target: IParsedOcticons): IMatch[] | null; } -function filterOk(filter: IOcticonFilter, word: string, target: { text: string, octiconOffsets?: number[] }, highlights?: { start: number; end: number; }[]) { +function filterOk(filter: IOcticonFilter, word: string, target: IParsedOcticons, highlights?: { start: number; end: number; }[]) { let r = filter(word, target); assert(r); if (highlights) { diff --git a/src/vs/code/electron-browser/issue/issueReporter.js b/src/vs/code/electron-browser/issue/issueReporter.js index 71c2b34a4e5..5d11dd15ae4 100644 --- a/src/vs/code/electron-browser/issue/issueReporter.js +++ b/src/vs/code/electron-browser/issue/issueReporter.js @@ -10,4 +10,4 @@ const bootstrapWindow = require('../../../../bootstrap-window'); bootstrapWindow.load(['vs/code/electron-browser/issue/issueReporterMain'], function (issueReporter, configuration) { issueReporter.startup(configuration); -}, { forceEnableDeveloperKeybindings: true }); \ No newline at end of file +}, { forceEnableDeveloperKeybindings: true, disallowReloadKeybinding: true }); diff --git a/src/vs/editor/browser/config/charWidthReader.ts b/src/vs/editor/browser/config/charWidthReader.ts index 601a8ae8ad7..21a54663412 100644 --- a/src/vs/editor/browser/config/charWidthReader.ts +++ b/src/vs/editor/browser/config/charWidthReader.ts @@ -71,6 +71,7 @@ class DomCharWidthReader { regularDomNode.style.fontFamily = this._bareFontInfo.getMassagedFontFamily(); regularDomNode.style.fontWeight = this._bareFontInfo.fontWeight; regularDomNode.style.fontSize = this._bareFontInfo.fontSize + 'px'; + regularDomNode.style.fontFeatureSettings = this._bareFontInfo.fontFeatureSettings; regularDomNode.style.lineHeight = this._bareFontInfo.lineHeight + 'px'; regularDomNode.style.letterSpacing = this._bareFontInfo.letterSpacing + 'px'; container.appendChild(regularDomNode); @@ -79,6 +80,7 @@ class DomCharWidthReader { boldDomNode.style.fontFamily = this._bareFontInfo.getMassagedFontFamily(); boldDomNode.style.fontWeight = 'bold'; boldDomNode.style.fontSize = this._bareFontInfo.fontSize + 'px'; + boldDomNode.style.fontFeatureSettings = this._bareFontInfo.fontFeatureSettings; boldDomNode.style.lineHeight = this._bareFontInfo.lineHeight + 'px'; boldDomNode.style.letterSpacing = this._bareFontInfo.letterSpacing + 'px'; container.appendChild(boldDomNode); @@ -87,6 +89,7 @@ class DomCharWidthReader { italicDomNode.style.fontFamily = this._bareFontInfo.getMassagedFontFamily(); italicDomNode.style.fontWeight = this._bareFontInfo.fontWeight; italicDomNode.style.fontSize = this._bareFontInfo.fontSize + 'px'; + italicDomNode.style.fontFeatureSettings = this._bareFontInfo.fontFeatureSettings; italicDomNode.style.lineHeight = this._bareFontInfo.lineHeight + 'px'; italicDomNode.style.letterSpacing = this._bareFontInfo.letterSpacing + 'px'; italicDomNode.style.fontStyle = 'italic'; diff --git a/src/vs/editor/browser/config/configuration.ts b/src/vs/editor/browser/config/configuration.ts index 6f28ca355ff..471c97e1162 100644 --- a/src/vs/editor/browser/config/configuration.ts +++ b/src/vs/editor/browser/config/configuration.ts @@ -11,7 +11,7 @@ import * as platform from 'vs/base/common/platform'; import { CharWidthRequest, CharWidthRequestType, readCharWidths } from 'vs/editor/browser/config/charWidthReader'; import { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver'; import { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig'; -import { EditorOption, IEditorConstructionOptions } from 'vs/editor/common/config/editorOptions'; +import { EditorOption, IEditorConstructionOptions, EditorFontLigatures } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo'; import { IDimension } from 'vs/editor/common/editorCommon'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; @@ -79,6 +79,7 @@ export interface ISerializedFontInfo { readonly fontFamily: string; readonly fontWeight: string; readonly fontSize: number; + fontFeatureSettings: string; readonly lineHeight: number; readonly letterSpacing: number; readonly isMonospace: boolean; @@ -151,11 +152,14 @@ class CSSBasedConfiguration extends Disposable { return this._cache.getValues().filter(item => item.isTrusted); } - public restoreFontInfo(savedFontInfo: ISerializedFontInfo[]): void { + public restoreFontInfo(savedFontInfos: ISerializedFontInfo[]): void { // Take all the saved font info and insert them in the cache without the trusted flag. // The reason for this is that a font might have been installed on the OS in the meantime. - for (let i = 0, len = savedFontInfo.length; i < len; i++) { - const fontInfo = new FontInfo(savedFontInfo[i], false); + for (let i = 0, len = savedFontInfos.length; i < len; i++) { + const savedFontInfo = savedFontInfos[i]; + // compatibility with older versions of VS Code which did not store this... + savedFontInfo.fontFeatureSettings = savedFontInfo.fontFeatureSettings || EditorFontLigatures.OFF; + const fontInfo = new FontInfo(savedFontInfo, false); this._writeToCache(fontInfo, fontInfo); } } @@ -171,6 +175,7 @@ class CSSBasedConfiguration extends Disposable { fontFamily: readConfig.fontFamily, fontWeight: readConfig.fontWeight, fontSize: readConfig.fontSize, + fontFeatureSettings: readConfig.fontFeatureSettings, lineHeight: readConfig.lineHeight, letterSpacing: readConfig.letterSpacing, isMonospace: readConfig.isMonospace, @@ -249,9 +254,9 @@ class CSSBasedConfiguration extends Disposable { const maxDigitWidth = Math.max(digit0.width, digit1.width, digit2.width, digit3.width, digit4.width, digit5.width, digit6.width, digit7.width, digit8.width, digit9.width); - let isMonospace = true; + let isMonospace = (bareFontInfo.fontFeatureSettings === EditorFontLigatures.OFF); const referenceWidth = monospace[0].width; - for (let i = 1, len = monospace.length; i < len; i++) { + for (let i = 1, len = monospace.length; isMonospace && i < len; i++) { const diff = referenceWidth - monospace[i].width; if (diff < -0.001 || diff > 0.001) { isMonospace = false; @@ -276,6 +281,7 @@ class CSSBasedConfiguration extends Disposable { fontFamily: bareFontInfo.fontFamily, fontWeight: bareFontInfo.fontWeight, fontSize: bareFontInfo.fontSize, + fontFeatureSettings: bareFontInfo.fontFeatureSettings, lineHeight: bareFontInfo.lineHeight, letterSpacing: bareFontInfo.letterSpacing, isMonospace: isMonospace, @@ -294,6 +300,7 @@ export class Configuration extends CommonEditorConfiguration { domNode.style.fontFamily = fontInfo.getMassagedFontFamily(); domNode.style.fontWeight = fontInfo.fontWeight; domNode.style.fontSize = fontInfo.fontSize + 'px'; + domNode.style.fontFeatureSettings = fontInfo.fontFeatureSettings; domNode.style.lineHeight = fontInfo.lineHeight + 'px'; domNode.style.letterSpacing = fontInfo.letterSpacing + 'px'; } @@ -302,6 +309,7 @@ export class Configuration extends CommonEditorConfiguration { domNode.setFontFamily(fontInfo.getMassagedFontFamily()); domNode.setFontWeight(fontInfo.fontWeight); domNode.setFontSize(fontInfo.fontSize); + domNode.setFontFeatureSettings(fontInfo.fontFeatureSettings); domNode.setLineHeight(fontInfo.lineHeight); domNode.setLetterSpacing(fontInfo.letterSpacing); } diff --git a/src/vs/editor/browser/viewParts/lines/viewLine.ts b/src/vs/editor/browser/viewParts/lines/viewLine.ts index 4e0016d5fac..b3b0ac98942 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLine.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLine.ts @@ -16,7 +16,7 @@ import { CharacterMapping, ForeignElementType, RenderLineInput, renderViewLine, import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel'; import { HIGH_CONTRAST, ThemeType } from 'vs/platform/theme/common/themeService'; -import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { EditorOption, EditorFontLigatures } from 'vs/editor/common/config/editorOptions'; const canUseFastRenderedViewLine = (function () { if (platform.isNative) { @@ -77,7 +77,7 @@ export class ViewLineOptions { public readonly canUseHalfwidthRightwardsArrow: boolean; public readonly lineHeight: number; public readonly stopRenderingLineAfter: number; - public readonly fontLigatures: boolean; + public readonly fontLigatures: string; constructor(config: IConfiguration, themeType: ThemeType) { this.themeType = themeType; @@ -89,7 +89,6 @@ export class ViewLineOptions { this.useMonospaceOptimizations = ( fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations) - && !options.get(EditorOption.fontLigatures) ); this.canUseHalfwidthRightwardsArrow = fontInfo.canUseHalfwidthRightwardsArrow; this.lineHeight = options.get(EditorOption.lineHeight); @@ -218,7 +217,7 @@ export class ViewLine implements IVisibleLine { options.stopRenderingLineAfter, options.renderWhitespace, options.renderControlCharacters, - options.fontLigatures, + options.fontLigatures !== EditorFontLigatures.OFF, selectionsOnLine ); diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index f6b8b30bb9c..d1bc2ad7820 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -20,7 +20,7 @@ import * as editorBrowser from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { DiffReview } from 'vs/editor/browser/widget/diffReview'; -import { IDiffEditorOptions, IEditorOptions, EditorLayoutInfo, IComputedEditorOptions, EditorOption, EditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IDiffEditorOptions, IEditorOptions, EditorLayoutInfo, IComputedEditorOptions, EditorOption, EditorOptions, EditorFontLigatures } from 'vs/editor/common/config/editorOptions'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import { ISelection, Selection } from 'vs/editor/common/core/selection'; @@ -2060,7 +2060,7 @@ class InlineViewZonesComputer extends ViewZonesComputer { const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, originalModel.mightContainNonBasicASCII()); const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, originalModel.mightContainRTL()); const output = renderViewLine(new RenderLineInput( - (fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations) && !options.get(EditorOption.fontLigatures)), + (fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations)), fontInfo.canUseHalfwidthRightwardsArrow, lineContent, false, @@ -2074,7 +2074,7 @@ class InlineViewZonesComputer extends ViewZonesComputer { options.get(EditorOption.stopRenderingLineAfter), options.get(EditorOption.renderWhitespace), options.get(EditorOption.renderControlCharacters), - options.get(EditorOption.fontLigatures), + options.get(EditorOption.fontLigatures) !== EditorFontLigatures.OFF, null // Send no selections, original line cannot be selected ), sb); diff --git a/src/vs/editor/browser/widget/diffReview.ts b/src/vs/editor/browser/widget/diffReview.ts index 0f71723805c..8a915a659ff 100644 --- a/src/vs/editor/browser/widget/diffReview.ts +++ b/src/vs/editor/browser/widget/diffReview.ts @@ -17,7 +17,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget'; -import { IComputedEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions'; +import { IComputedEditorOptions, EditorOption, EditorFontLigatures } from 'vs/editor/common/config/editorOptions'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; import { Position } from 'vs/editor/common/core/position'; import { ILineChange, ScrollType } from 'vs/editor/common/editorCommon'; @@ -770,7 +770,7 @@ export class DiffReview extends Disposable { const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, model.mightContainNonBasicASCII()); const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, model.mightContainRTL()); const r = renderViewLine(new RenderLineInput( - (fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations) && !options.get(EditorOption.fontLigatures)), + (fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations)), fontInfo.canUseHalfwidthRightwardsArrow, lineContent, false, @@ -784,7 +784,7 @@ export class DiffReview extends Disposable { options.get(EditorOption.stopRenderingLineAfter), options.get(EditorOption.renderWhitespace), options.get(EditorOption.renderControlCharacters), - options.get(EditorOption.fontLigatures), + options.get(EditorOption.fontLigatures) !== EditorFontLigatures.OFF, null )); diff --git a/src/vs/editor/browser/widget/media/editor.css b/src/vs/editor/browser/widget/media/editor.css index fb9e5f5e8b8..7936ff11ad8 100644 --- a/src/vs/editor/browser/widget/media/editor.css +++ b/src/vs/editor/browser/widget/media/editor.css @@ -21,12 +21,6 @@ position: relative; overflow: visible; -webkit-text-size-adjust: 100%; - -webkit-font-feature-settings: "liga" off, "calt" off; - font-feature-settings: "liga" off, "calt" off; -} -.monaco-editor.enable-ligatures { - -webkit-font-feature-settings: "liga" on, "calt" on; - font-feature-settings: "liga" on, "calt" on; } /* -------------------- Misc -------------------- */ diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index dde4e5888c9..65134543ae7 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -178,7 +178,7 @@ export interface IEditorOptions { * Enable font ligatures. * Defaults to false. */ - fontLigatures?: boolean; + fontLigatures?: boolean | string; /** * Disable the use of `will-change` for the editor margin and lines layers. * The usage of `will-change` acts as a hint for browsers to create an extra layer. @@ -641,6 +641,9 @@ export interface IEditorOption { type PossibleKeyName0 = { [K in keyof IEditorOptions]: IEditorOptions[K] extends V | undefined ? K : never }[keyof IEditorOptions]; type PossibleKeyName = NonNullable>; +/** + * @internal + */ abstract class BaseEditorOption implements IEditorOption { public readonly id: K1; @@ -1044,7 +1047,7 @@ function _cursorStyleFromString(cursorStyle: 'line' | 'block' | 'underline' | 'l class EditorClassName extends ComputedEditorOption { constructor() { - super(EditorOption.editorClassName, [EditorOption.mouseStyle, EditorOption.fontLigatures, EditorOption.extraEditorClassName]); + super(EditorOption.editorClassName, [EditorOption.mouseStyle, EditorOption.extraEditorClassName]); } public compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: string): string { @@ -1055,9 +1058,6 @@ class EditorClassName extends ComputedEditorOption //#endregion +//#region fontLigatures + +/** + * @internal + */ +export class EditorFontLigatures extends BaseEditorOption { + + public static OFF = '"liga" off, "calt" off'; + public static ON = '"liga" on, "calt" on'; + + constructor() { + super( + EditorOption.fontLigatures, 'fontLigatures', EditorFontLigatures.OFF, + { + anyOf: [ + { + type: 'boolean', + description: nls.localize('fontLigatures', "Enables/Disables font ligatures."), + }, + { + type: 'string', + description: nls.localize('fontFeatureSettings', "Explicit font-feature-settings.") + } + ], + default: false + } + ); + } + + public validate(input: any): string { + if (typeof input === 'undefined') { + return this.defaultValue; + } + if (typeof input === 'string') { + if (input === 'false') { + return EditorFontLigatures.OFF; + } + if (input === 'true') { + return EditorFontLigatures.ON; + } + return input; + } + if (Boolean(input)) { + return EditorFontLigatures.ON; + } + return EditorFontLigatures.OFF; + } +} + +//#endregion + //#region fontInfo class EditorFontInfo extends ComputedEditorOption { @@ -2910,10 +2961,7 @@ export const EditorOptions = { { description: nls.localize('fontFamily', "Controls the font family.") } )), fontInfo: register(new EditorFontInfo()), - fontLigatures: register(new EditorBooleanOption( - EditorOption.fontLigatures, 'fontLigatures', false, - { description: nls.localize('fontLigatures', "Enables/Disables font ligatures.") } - )), + fontLigatures2: register(new EditorFontLigatures()), fontSize: register(new EditorFontSize()), fontWeight: register(new EditorStringOption( EditorOption.fontWeight, 'fontWeight', EDITOR_FONT_DEFAULTS.fontWeight, diff --git a/src/vs/editor/common/config/fontInfo.ts b/src/vs/editor/common/config/fontInfo.ts index 6aa495b1d82..16719602fa1 100644 --- a/src/vs/editor/common/config/fontInfo.ts +++ b/src/vs/editor/common/config/fontInfo.ts @@ -28,27 +28,29 @@ export class BareFontInfo { const fontFamily = options.get(EditorOption.fontFamily); const fontWeight = options.get(EditorOption.fontWeight); const fontSize = options.get(EditorOption.fontSize); + const fontFeatureSettings = options.get(EditorOption.fontLigatures); const lineHeight = options.get(EditorOption.lineHeight); const letterSpacing = options.get(EditorOption.letterSpacing); - return BareFontInfo._create(fontFamily, fontWeight, fontSize, lineHeight, letterSpacing, zoomLevel, ignoreEditorZoom); + return BareFontInfo._create(fontFamily, fontWeight, fontSize, fontFeatureSettings, lineHeight, letterSpacing, zoomLevel, ignoreEditorZoom); } /** * @internal */ - public static createFromRawSettings(opts: { fontFamily?: string; fontWeight?: string; fontSize?: number; lineHeight?: number; letterSpacing?: number; }, zoomLevel: number, ignoreEditorZoom: boolean = false): BareFontInfo { + public static createFromRawSettings(opts: { fontFamily?: string; fontWeight?: string; fontSize?: number; fontLigatures?: boolean | string; lineHeight?: number; letterSpacing?: number; }, zoomLevel: number, ignoreEditorZoom: boolean = false): BareFontInfo { const fontFamily = EditorOptions.fontFamily.validate(opts.fontFamily); const fontWeight = EditorOptions.fontWeight.validate(opts.fontWeight); const fontSize = EditorOptions.fontSize.validate(opts.fontSize); + const fontFeatureSettings = EditorOptions.fontLigatures2.validate(opts.fontLigatures); const lineHeight = EditorOptions.lineHeight.validate(opts.lineHeight); const letterSpacing = EditorOptions.letterSpacing.validate(opts.letterSpacing); - return BareFontInfo._create(fontFamily, fontWeight, fontSize, lineHeight, letterSpacing, zoomLevel, ignoreEditorZoom); + return BareFontInfo._create(fontFamily, fontWeight, fontSize, fontFeatureSettings, lineHeight, letterSpacing, zoomLevel, ignoreEditorZoom); } /** * @internal */ - private static _create(fontFamily: string, fontWeight: string, fontSize: number, lineHeight: number, letterSpacing: number, zoomLevel: number, ignoreEditorZoom: boolean): BareFontInfo { + private static _create(fontFamily: string, fontWeight: string, fontSize: number, fontFeatureSettings: string, lineHeight: number, letterSpacing: number, zoomLevel: number, ignoreEditorZoom: boolean): BareFontInfo { if (lineHeight === 0) { lineHeight = Math.round(GOLDEN_LINE_HEIGHT_RATIO * fontSize); } else if (lineHeight < MINIMUM_LINE_HEIGHT) { @@ -64,6 +66,7 @@ export class BareFontInfo { fontFamily: fontFamily, fontWeight: fontWeight, fontSize: fontSize, + fontFeatureSettings: fontFeatureSettings, lineHeight: lineHeight, letterSpacing: letterSpacing }); @@ -73,6 +76,7 @@ export class BareFontInfo { readonly fontFamily: string; readonly fontWeight: string; readonly fontSize: number; + readonly fontFeatureSettings: string; readonly lineHeight: number; readonly letterSpacing: number; @@ -84,6 +88,7 @@ export class BareFontInfo { fontFamily: string; fontWeight: string; fontSize: number; + fontFeatureSettings: string; lineHeight: number; letterSpacing: number; }) { @@ -91,6 +96,7 @@ export class BareFontInfo { this.fontFamily = String(opts.fontFamily); this.fontWeight = String(opts.fontWeight); this.fontSize = opts.fontSize; + this.fontFeatureSettings = opts.fontFeatureSettings; this.lineHeight = opts.lineHeight | 0; this.letterSpacing = opts.letterSpacing; } @@ -99,7 +105,7 @@ export class BareFontInfo { * @internal */ public getId(): string { - return this.zoomLevel + '-' + this.fontFamily + '-' + this.fontWeight + '-' + this.fontSize + '-' + this.lineHeight + '-' + this.letterSpacing; + return this.zoomLevel + '-' + this.fontFamily + '-' + this.fontWeight + '-' + this.fontSize + '-' + this.fontFeatureSettings + '-' + this.lineHeight + '-' + this.letterSpacing; } /** @@ -138,6 +144,7 @@ export class FontInfo extends BareFontInfo { fontFamily: string; fontWeight: string; fontSize: number; + fontFeatureSettings: string; lineHeight: number; letterSpacing: number; isMonospace: boolean; @@ -165,6 +172,7 @@ export class FontInfo extends BareFontInfo { this.fontFamily === other.fontFamily && this.fontWeight === other.fontWeight && this.fontSize === other.fontSize + && this.fontFeatureSettings === other.fontFeatureSettings && this.lineHeight === other.lineHeight && this.letterSpacing === other.letterSpacing && this.typicalHalfwidthCharacterWidth === other.typicalHalfwidthCharacterWidth diff --git a/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts index 9fc69bc842e..0df564775fd 100644 --- a/src/vs/editor/common/controller/cursorTypeOperations.ts +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -81,15 +81,12 @@ export class TypeOperations { const selection = selections[i]; let position = selection.getPosition(); + if (pasteOnNewLine && !selection.isEmpty()) { + pasteOnNewLine = false; + } if (pasteOnNewLine && text.indexOf('\n') !== text.length - 1) { pasteOnNewLine = false; } - if (pasteOnNewLine && selection.startLineNumber !== selection.endLineNumber) { - pasteOnNewLine = false; - } - if (pasteOnNewLine && selection.startColumn === model.getLineMinColumn(selection.startLineNumber) && selection.endColumn === model.getLineMaxColumn(selection.startLineNumber)) { - pasteOnNewLine = false; - } if (pasteOnNewLine) { // Paste entire line at the beginning of line diff --git a/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts index 1c9d7a274a9..5b5070184ea 100644 --- a/src/vs/editor/common/services/modelServiceImpl.ts +++ b/src/vs/editor/common/services/modelServiceImpl.ts @@ -218,6 +218,10 @@ export class ModelServiceImpl extends Disposable implements IModelService { } private static _setModelOptionsForModel(model: ITextModel, newOptions: ITextModelCreationOptions, currentOptions: ITextModelCreationOptions): void { + if (currentOptions && currentOptions.defaultEOL !== newOptions.defaultEOL && model.getLineCount() === 1) { + model.setEOL(newOptions.defaultEOL === DefaultEndOfLine.LF ? EndOfLineSequence.LF : EndOfLineSequence.CRLF); + } + if (currentOptions && (currentOptions.detectIndentation === newOptions.detectIndentation) && (currentOptions.insertSpaces === newOptions.insertSpaces) diff --git a/src/vs/editor/contrib/hover/hover.ts b/src/vs/editor/contrib/hover/hover.ts index 215ddd5844c..ac7d39b6d94 100644 --- a/src/vs/editor/contrib/hover/hover.ts +++ b/src/vs/editor/contrib/hover/hover.ts @@ -7,7 +7,7 @@ import 'vs/css!./hover'; import * as nls from 'vs/nls'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { IEmptyContentData } from 'vs/editor/browser/controller/mouseTarget'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; @@ -34,21 +34,21 @@ export class ModesHoverController implements IEditorContribution { private readonly _toUnhook = new DisposableStore(); private readonly _didChangeConfigurationHandler: IDisposable; - private _contentWidget: ModesContentHoverWidget | null; - private _glyphWidget: ModesGlyphHoverWidget | null; + private readonly _contentWidget = new MutableDisposable(); + private readonly _glyphWidget = new MutableDisposable(); get contentWidget(): ModesContentHoverWidget { - if (!this._contentWidget) { + if (!this._contentWidget.value) { this._createHoverWidgets(); } - return this._contentWidget!; + return this._contentWidget.value!; } get glyphWidget(): ModesGlyphHoverWidget { - if (!this._glyphWidget) { + if (!this._glyphWidget.value) { this._createHoverWidgets(); } - return this._glyphWidget!; + return this._glyphWidget.value!; } private _isMouseDown: boolean; @@ -69,8 +69,6 @@ export class ModesHoverController implements IEditorContribution { ) { this._isMouseDown = false; this._hoverClicked = false; - this._contentWidget = null; - this._glyphWidget = null; this._hookEvents(); @@ -197,17 +195,17 @@ export class ModesHoverController implements IEditorContribution { } private _hideWidgets(): void { - if (!this._glyphWidget || !this._contentWidget || (this._isMouseDown && this._hoverClicked && this._contentWidget.isColorPickerVisible())) { + if (!this._glyphWidget.value || !this._contentWidget.value || (this._isMouseDown && this._hoverClicked && this._contentWidget.value.isColorPickerVisible())) { return; } - this._glyphWidget!.hide(); - this._contentWidget.hide(); + this._glyphWidget.value.hide(); + this._contentWidget.value.hide(); } private _createHoverWidgets() { - this._contentWidget = new ModesContentHoverWidget(this._editor, this._markerDecorationsService, this._themeService, this._keybindingService, this._modeService, this._openerService); - this._glyphWidget = new ModesGlyphHoverWidget(this._editor, this._modeService, this._openerService); + this._contentWidget.value = new ModesContentHoverWidget(this._editor, this._markerDecorationsService, this._themeService, this._keybindingService, this._modeService, this._openerService); + this._glyphWidget.value = new ModesGlyphHoverWidget(this._editor, this._modeService, this._openerService); } public showContentHover(range: Range, mode: HoverStartMode, focus: boolean): void { @@ -222,13 +220,8 @@ export class ModesHoverController implements IEditorContribution { this._unhookEvents(); this._toUnhook.dispose(); this._didChangeConfigurationHandler.dispose(); - - if (this._glyphWidget) { - this._glyphWidget.dispose(); - } - if (this._contentWidget) { - this._contentWidget.dispose(); - } + this._glyphWidget.dispose(); + this._contentWidget.dispose(); } } diff --git a/src/vs/editor/contrib/links/links.ts b/src/vs/editor/contrib/links/links.ts index a387d6cd9db..184fa18ecf0 100644 --- a/src/vs/editor/contrib/links/links.ts +++ b/src/vs/editor/contrib/links/links.ts @@ -44,8 +44,7 @@ function getHoverMessage(link: Link, useMetaKey: boolean): MarkdownString { : nls.localize('links.navigate.kb.alt', "alt + click"); if (link.url) { - const hoverMessage = new MarkdownString().appendMarkdown(`[${label}](${link.url.toString()}) (${kb})`); - hoverMessage.isTrusted = true; + const hoverMessage = new MarkdownString('', true).appendMarkdown(`[${label}](${link.url.toString()}) (${kb})`); return hoverMessage; } else { return new MarkdownString().appendText(`${label} (${kb})`); diff --git a/src/vs/editor/contrib/rename/rename.ts b/src/vs/editor/contrib/rename/rename.ts index 8c0858b6984..796a028890b 100644 --- a/src/vs/editor/contrib/rename/rename.ts +++ b/src/vs/editor/contrib/rename/rename.ts @@ -20,15 +20,15 @@ import { Position, IPosition } from 'vs/editor/common/core/position'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { Range } from 'vs/editor/common/core/range'; import { MessageController } from 'vs/editor/contrib/message/messageController'; -import { EditorState, CodeEditorStateFlag } from 'vs/editor/browser/core/editorState'; +import { CodeEditorStateFlag, EditorStateCancellationTokenSource } from 'vs/editor/browser/core/editorState'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; import { URI } from 'vs/base/common/uri'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; +import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { IdleValue, raceCancellation } from 'vs/base/common/async'; import { withNullAsUndefined } from 'vs/base/common/types'; class RenameSkeleton { @@ -95,21 +95,17 @@ export async function rename(model: ITextModel, position: Position, newName: str // --- register actions and commands -class RenameController extends Disposable implements IEditorContribution { +class RenameController implements IEditorContribution { private static readonly ID = 'editor.contrib.renameController'; - public static get(editor: ICodeEditor): RenameController { + static get(editor: ICodeEditor): RenameController { return editor.getContribution(RenameController.ID); } - private _renameInputField?: RenameInputField; - private _renameOperationIdPool = 1; - - private _activeRename?: { - readonly id: number; - readonly operation: CancelablePromise; - }; + private readonly _renameInputField: IdleValue; + private readonly _dispoableStore = new DisposableStore(); + private _cts: CancellationTokenSource = new CancellationTokenSource(); constructor( private readonly editor: ICodeEditor, @@ -119,37 +115,22 @@ class RenameController extends Disposable implements IEditorContribution { @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IThemeService private readonly _themeService: IThemeService, ) { - super(); - this._register(this.editor.onDidChangeModel(() => this.onModelChanged())); - this._register(this.editor.onDidChangeModelLanguage(() => this.onModelChanged())); - this._register(this.editor.onDidChangeCursorSelection(() => this.onModelChanged())); - } - - private get renameInputField(): RenameInputField { - if (!this._renameInputField) { - this._renameInputField = this._register(new RenameInputField(this.editor, this._themeService, this._contextKeyService)); - } - return this._renameInputField; + this._renameInputField = new IdleValue(() => this._dispoableStore.add(new RenameInputField(this.editor, this._themeService, this._contextKeyService))); } getId(): string { return RenameController.ID; } - async run(): Promise { - if (this._activeRename) { - this._activeRename.operation.cancel(); - } - - const id = this._renameOperationIdPool++; - this._activeRename = { - id, - operation: createCancelablePromise(token => this.doRename(token, id)) - }; - return this._activeRename.operation; + dispose(): void { + this._dispoableStore.dispose(); + this._cts.dispose(true); } - private async doRename(token: CancellationToken, id: number): Promise { + async run(): Promise { + + this._cts.dispose(true); + if (!this.editor.hasModel()) { return undefined; } @@ -161,9 +142,12 @@ class RenameController extends Disposable implements IEditorContribution { return undefined; } + this._cts = new EditorStateCancellationTokenSource(this.editor, CodeEditorStateFlag.Position | CodeEditorStateFlag.Value); + + // resolve rename location let loc: RenameLocation & Rejection | undefined; try { - const resolveLocationOperation = skeleton.resolveRenameLocation(token); + const resolveLocationOperation = skeleton.resolveRenameLocation(this._cts.token); this._progressService.showWhile(resolveLocationOperation, 250); loc = await resolveLocationOperation; } catch (e) { @@ -180,10 +164,11 @@ class RenameController extends Disposable implements IEditorContribution { return undefined; } - if (!this._activeRename || this._activeRename.id !== id) { + if (this._cts.token.isCancellationRequested) { return undefined; } + // do rename at location let selection = this.editor.getSelection(); let selectionStart = 0; let selectionEnd = loc.text.length; @@ -193,71 +178,52 @@ class RenameController extends Disposable implements IEditorContribution { selectionEnd = Math.min(loc.range.endColumn, selection.endColumn) - loc.range.startColumn; } - return this.renameInputField.getInput(loc.range, loc.text, selectionStart, selectionEnd).then(newNameOrFocusFlag => { + const newNameOrFocusFlag = await this._renameInputField.getValue().getInput(loc.range, loc.text, selectionStart, selectionEnd); - if (typeof newNameOrFocusFlag === 'boolean') { - if (newNameOrFocusFlag) { - this.editor.focus(); - } - return undefined; + + if (typeof newNameOrFocusFlag === 'boolean') { + if (newNameOrFocusFlag) { + this.editor.focus(); + } + return undefined; + } + + this.editor.focus(); + + const renameOperation = raceCancellation(skeleton.provideRenameEdits(newNameOrFocusFlag, 0, [], this._cts.token), this._cts.token).then(async renameResult => { + + if (!renameResult || !this.editor.hasModel()) { + return; } - this.editor.focus(); + if (renameResult.rejectReason) { + this._notificationService.info(renameResult.rejectReason); + return; + } - const state = new EditorState(this.editor, CodeEditorStateFlag.Position | CodeEditorStateFlag.Value | CodeEditorStateFlag.Selection | CodeEditorStateFlag.Scroll); + const editResult = await this._bulkEditService.apply(renameResult, { editor: this.editor }); - const renameOperation = Promise.resolve(skeleton.provideRenameEdits(newNameOrFocusFlag, 0, [], token).then(result => { - - if (!this.editor.hasModel()) { - return undefined; - } - - if (result.rejectReason) { - if (state.validate(this.editor)) { - MessageController.get(this.editor).showMessage(result.rejectReason, this.editor.getPosition()); - } else { - this._notificationService.info(result.rejectReason); - } - return undefined; - } - - return this._bulkEditService.apply(result, { editor: this.editor }).then(result => { - // alert - if (result.ariaSummary) { - alert(nls.localize('aria', "Successfully renamed '{0}' to '{1}'. Summary: {2}", loc!.text, newNameOrFocusFlag, result.ariaSummary)); - } - }); - - }, err => { - this._notificationService.error(nls.localize('rename.failed', "Rename failed to execute.")); - return Promise.reject(err); - })); - - this._progressService.showWhile(renameOperation, 250); - return renameOperation; + // alert + if (editResult.ariaSummary) { + alert(nls.localize('aria', "Successfully renamed '{0}' to '{1}'. Summary: {2}", loc!.text, newNameOrFocusFlag, editResult.ariaSummary)); + } + }, err => { + this._notificationService.error(nls.localize('rename.failed', "Rename failed to execute.")); + return Promise.reject(err); }); + + this._progressService.showWhile(renameOperation, 250); + return renameOperation; + } - public acceptRenameInput(): void { - if (this._renameInputField) { - this._renameInputField.acceptInput(); - } + acceptRenameInput(): void { + this._renameInputField.getValue().acceptInput(); } - public cancelRenameInput(): void { - if (this._renameInputField) { - this._renameInputField.cancelInput(true); - } - } - - private onModelChanged(): void { - if (this._activeRename) { - this._activeRename.operation.cancel(); - this._activeRename = undefined; - - this.cancelRenameInput(); - } + cancelRenameInput(): void { + this._renameInputField.getValue().cancelInput(true); } } diff --git a/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts b/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts index b918921b059..f0eedb8324d 100644 --- a/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts +++ b/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts @@ -12,33 +12,11 @@ import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageCo import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; import { javascriptOnEnterRules } from 'vs/editor/test/common/modes/supports/javascriptOnEnterRules'; -import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { isLinux, isMacintosh } from 'vs/base/common/platform'; import { BracketSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/bracketSelections'; import { provideSelectionRanges } from 'vs/editor/contrib/smartSelect/smartSelect'; import { CancellationToken } from 'vs/base/common/cancellation'; import { WordSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/wordSelections'; - -class TestTextResourcePropertiesService implements ITextResourcePropertiesService { - - _serviceBrand: undefined; - - constructor( - @IConfigurationService private readonly configurationService: IConfigurationService, - ) { - } - - getEOL(resource: URI | undefined): string { - const filesConfiguration = this.configurationService.getValue<{ eol: string }>('files'); - if (filesConfiguration && filesConfiguration.eol) { - if (filesConfiguration.eol !== 'auto') { - return filesConfiguration.eol; - } - } - return (isLinux || isMacintosh) ? '\n' : '\r\n'; - } -} +import { TestTextResourcePropertiesService } from 'vs/editor/test/common/services/modelService.test'; class MockJSMode extends MockMode { diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 495b81c11dd..121167d45ef 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -515,12 +515,10 @@ export class SimpleResourcePropertiesService implements ITextResourcePropertiesS ) { } - getEOL(resource: URI): string { - const filesConfiguration = this.configurationService.getValue<{ eol: string }>('files'); - if (filesConfiguration && filesConfiguration.eol) { - if (filesConfiguration.eol !== 'auto') { - return filesConfiguration.eol; - } + getEOL(resource: URI, language?: string): string { + const eol = this.configurationService.getValue('files.eol', { overrideIdentifier: language, resource }); + if (eol && eol !== 'auto') { + return eol; } return (isLinux || isMacintosh) ? '\n' : '\r\n'; } diff --git a/src/vs/editor/test/browser/controller/cursor.test.ts b/src/vs/editor/test/browser/controller/cursor.test.ts index 984a1e23856..0a8680d8557 100644 --- a/src/vs/editor/test/browser/controller/cursor.test.ts +++ b/src/vs/editor/test/browser/controller/cursor.test.ts @@ -1494,6 +1494,25 @@ suite('Editor Controller - Regression tests', () => { }); }); + test('issue #74722: Pasting whole line does not replace selection', () => { + usingCursor({ + text: [ + 'line1', + 'line sel 2', + 'line3' + ], + }, (model, cursor) => { + cursor.setSelections('test', [new Selection(2, 6, 2, 9)]); + + cursorCommand(cursor, H.Paste, { text: 'line1\n', pasteOnNewLine: true }); + + assert.equal(model.getLineContent(1), 'line1'); + assert.equal(model.getLineContent(2), 'line line1'); + assert.equal(model.getLineContent(3), ' 2'); + assert.equal(model.getLineContent(4), 'line3'); + }); + }); + test('issue #4996: Multiple cursor paste pastes contents of all cursors', () => { usingCursor({ text: [ diff --git a/src/vs/editor/test/common/mocks/testConfiguration.ts b/src/vs/editor/test/common/mocks/testConfiguration.ts index 5da181c240d..b54f06ffc90 100644 --- a/src/vs/editor/test/common/mocks/testConfiguration.ts +++ b/src/vs/editor/test/common/mocks/testConfiguration.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/config/commonEditorConfig'; -import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IEditorOptions, EditorFontLigatures } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; @@ -33,6 +33,7 @@ export class TestConfiguration extends CommonEditorConfiguration { fontFamily: 'mockFont', fontWeight: 'normal', fontSize: 14, + fontFeatureSettings: EditorFontLigatures.OFF, lineHeight: 19, letterSpacing: 1.5, isMonospace: true, diff --git a/src/vs/editor/test/common/services/modelService.test.ts b/src/vs/editor/test/common/services/modelService.test.ts index 20d3b7d3312..0a28a285b38 100644 --- a/src/vs/editor/test/common/services/modelService.test.ts +++ b/src/vs/editor/test/common/services/modelService.test.ts @@ -365,7 +365,7 @@ assertComputeEdits(file1, file2); } } -class TestTextResourcePropertiesService implements ITextResourcePropertiesService { +export class TestTextResourcePropertiesService implements ITextResourcePropertiesService { _serviceBrand: undefined; @@ -375,11 +375,9 @@ class TestTextResourcePropertiesService implements ITextResourcePropertiesServic } getEOL(resource: URI, language?: string): string { - const filesConfiguration = this.configurationService.getValue<{ eol: string }>('files', { overrideIdentifier: language, resource }); - if (filesConfiguration && filesConfiguration.eol) { - if (filesConfiguration.eol !== 'auto') { - return filesConfiguration.eol; - } + const eol = this.configurationService.getValue('files.eol', { overrideIdentifier: language, resource }); + if (eol && eol !== 'auto') { + return eol; } return (platform.isLinux || platform.isMacintosh) ? '\n' : '\r\n'; } diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index cfb897053b2..70aed6e2f7d 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -44,7 +44,7 @@ declare namespace monaco { constructor(parent?: CancellationToken); readonly token: CancellationToken; cancel(): void; - dispose(): void; + dispose(cancel?: boolean): void; } export interface CancellationToken { @@ -379,8 +379,8 @@ declare namespace monaco { } export interface IMarkdownString { - value: string; - isTrusted?: boolean; + readonly value: string; + readonly isTrusted?: boolean; uris?: { [href: string]: UriComponents; }; @@ -2581,7 +2581,7 @@ declare namespace monaco.editor { * Enable font ligatures. * Defaults to false. */ - fontLigatures?: boolean; + fontLigatures?: boolean | string; /** * Disable the use of `will-change` for the editor margin and lines layers. * The usage of `will-change` acts as a hint for browsers to create an extra layer. @@ -4124,6 +4124,7 @@ declare namespace monaco.editor { readonly fontFamily: string; readonly fontWeight: string; readonly fontSize: number; + readonly fontFeatureSettings: string; readonly lineHeight: number; readonly letterSpacing: number; } diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 789bb4c805f..1d3a1760946 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -71,7 +71,6 @@ export interface ParsedArgs { 'driver-verbose'?: boolean; remote?: string; 'disable-user-env-probe'?: boolean; - 'disable-inspect'?: boolean; 'force'?: boolean; 'force-user-env'?: boolean; @@ -117,6 +116,7 @@ export interface IEnvironmentService { keybindingsResource: URI; keyboardLayoutResource: URI; localeResource: URI; + argvResource: URI; // sync resources userDataSyncLogResource: URI; diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index e61113171d0..c15320d20b1 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -109,7 +109,6 @@ export const OPTIONS: OptionDescriptions> = { 'trace': { type: 'boolean' }, 'trace-category-filter': { type: 'string' }, 'trace-options': { type: 'string' }, - 'disable-inspect': { type: 'boolean' }, 'force-user-env': { type: 'boolean' }, 'js-flags': { type: 'string' }, // chrome js flags diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index f7d207009de..27408546a34 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -95,7 +95,6 @@ export class EnvironmentService implements IEnvironmentService { @memoize get userDataPath(): string { const vscodePortable = process.env['VSCODE_PORTABLE']; - if (vscodePortable) { return path.join(vscodePortable, 'user-data'); } @@ -143,6 +142,16 @@ export class EnvironmentService implements IEnvironmentService { @memoize get localeResource(): URI { return resources.joinPath(this.userRoamingDataHome, 'locale.json'); } + @memoize + get argvResource(): URI { + const vscodePortable = process.env['VSCODE_PORTABLE']; + if (vscodePortable) { + return URI.file(path.join(vscodePortable, 'argv.json')); + } + + return URI.file(path.join(this.userHome, product.dataFolderName, 'argv.json')); + } + @memoize get isExtensionDevelopment(): boolean { return !!this._args.extensionDevelopmentPath; } @@ -182,7 +191,6 @@ export class EnvironmentService implements IEnvironmentService { } const vscodePortable = process.env['VSCODE_PORTABLE']; - if (vscodePortable) { return path.join(vscodePortable, 'extensions'); } diff --git a/src/vs/workbench/api/browser/media/test.svg b/src/vs/workbench/api/browser/media/test.svg index 57cd408942d..569947a033e 100644 --- a/src/vs/workbench/api/browser/media/test.svg +++ b/src/vs/workbench/api/browser/media/test.svg @@ -1,10 +1,3 @@ - - - - - - - - + + - diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 0c9236b67af..608b6d90707 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -303,9 +303,7 @@ export namespace MarkdownString { } export function to(value: htmlContent.IMarkdownString): vscode.MarkdownString { - const ret = new htmlContent.MarkdownString(value.value); - ret.isTrusted = value.isTrusted; - return ret; + return new htmlContent.MarkdownString(value.value, value.isTrusted); } export function fromStrict(value: string | types.MarkdownString): undefined | string | htmlContent.IMarkdownString { diff --git a/src/vs/workbench/browser/actions/listCommands.ts b/src/vs/workbench/browser/actions/listCommands.ts index d33cb450d5d..81fb3c49efe 100644 --- a/src/vs/workbench/browser/actions/listCommands.ts +++ b/src/vs/workbench/browser/actions/listCommands.ts @@ -17,6 +17,11 @@ import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; import { DataTree } from 'vs/base/browser/ui/tree/dataTree'; import { ITreeNode } from 'vs/base/browser/ui/tree/tree'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; + +function isLegacyTree(widget: ListWidget): widget is ITree { + return widget instanceof Tree; +} function ensureDOMFocus(widget: ListWidget | undefined): void { // it can happen that one of the commands is executed while @@ -833,3 +838,67 @@ CommandsRegistry.registerCommand({ } } }); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'list.scrollUp', + weight: KeybindingWeight.WorkbenchContrib, + when: WorkbenchListFocusContextKey, + primary: KeyMod.CtrlCmd | KeyCode.UpArrow, + handler: accessor => { + const focused = accessor.get(IListService).lastFocusedList; + + if (!focused || isLegacyTree(focused)) { + return; + } + + focused.scrollTop -= 10; + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'list.scrollDown', + weight: KeybindingWeight.WorkbenchContrib, + when: WorkbenchListFocusContextKey, + primary: KeyMod.CtrlCmd | KeyCode.DownArrow, + handler: accessor => { + const focused = accessor.get(IListService).lastFocusedList; + + if (!focused || isLegacyTree(focused)) { + return; + } + + focused.scrollTop += 10; + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'list.scrollLeft', + weight: KeybindingWeight.WorkbenchContrib, + when: WorkbenchListFocusContextKey, + primary: KeyMod.CtrlCmd | KeyCode.LeftArrow, + handler: accessor => { + const focused = accessor.get(IListService).lastFocusedList; + + if (!focused || isLegacyTree(focused)) { + return; + } + + focused.scrollLeft -= 10; + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'list.scrollRight', + weight: KeybindingWeight.WorkbenchContrib, + when: WorkbenchListFocusContextKey, + primary: KeyMod.CtrlCmd | KeyCode.RightArrow, + handler: accessor => { + const focused = accessor.get(IListService).lastFocusedList; + + if (!focused || isLegacyTree(focused)) { + return; + } + + focused.scrollLeft += 10; + } +}); diff --git a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts index 20d1c228439..924ad443981 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts @@ -290,6 +290,7 @@ function getSuggestEnabledInputOptions(ariaLabel?: string): IEditorOptions { ariaLabel: ariaLabel || '', snippetSuggestions: 'none', - suggest: { filterGraceful: false, showIcons: false } + suggest: { filterGraceful: false, showIcons: false }, + autoClosingBrackets: 'never' }; } diff --git a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts index bd3ea6d7f9d..87f2dd31cc5 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts @@ -76,10 +76,7 @@ class CommentingRangeDecoration { options: commentingOptions }]; - let model = this._editor.getModel(); - if (model) { - this._decorationId = model.deltaDecorations([this._decorationId], commentingRangeDecorations)[0]; - } + this._decorationId = this._editor.deltaDecorations([], commentingRangeDecorations)[0]; } public getCommentAction(): { ownerId: string, extensionId: string | undefined, label: string | undefined, commentingRangesInfo: modes.CommentingRanges } { diff --git a/src/vs/workbench/contrib/comments/browser/commentsPanel.ts b/src/vs/workbench/contrib/comments/browser/commentsPanel.ts index 5f0e33758a4..eeafa5eb74a 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsPanel.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsPanel.ts @@ -27,13 +27,13 @@ import { CommentsList, COMMENTS_PANEL_ID, COMMENTS_PANEL_TITLE } from 'vs/workbe export class CommentsPanel extends Panel { - private treeLabels: ResourceLabels; - private tree: CommentsList; - private treeContainer: HTMLElement; - private messageBoxContainer: HTMLElement; - private messageBox: HTMLElement; - private commentsModel: CommentsModel; - private collapseAllAction: IAction; + private treeLabels!: ResourceLabels; + private tree!: CommentsList; + private treeContainer!: HTMLElement; + private messageBoxContainer!: HTMLElement; + private messageBox!: HTMLElement; + private commentsModel!: CommentsModel; + private collapseAllAction?: IAction; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -195,7 +195,9 @@ export class CommentsPanel extends Panel { private refresh(): void { if (this.isVisible()) { - this.collapseAllAction.enabled = this.commentsModel.hasCommentThreads(); + if (this.collapseAllAction) { + this.collapseAllAction.enabled = this.commentsModel.hasCommentThreads(); + } dom.toggleClass(this.treeContainer, 'hidden', !this.commentsModel.hasCommentThreads()); this.tree.updateChildren().then(() => { diff --git a/src/vs/workbench/contrib/customEditor/browser/commands.ts b/src/vs/workbench/contrib/customEditor/browser/commands.ts index 44ff3ec8490..996aa3ceb7e 100644 --- a/src/vs/workbench/contrib/customEditor/browser/commands.ts +++ b/src/vs/workbench/contrib/customEditor/browser/commands.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -// import { Schemas } from 'vs/base/common/network'; import { firstOrDefault } from 'vs/base/common/arrays'; import { URI } from 'vs/base/common/uri'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; @@ -13,8 +12,7 @@ import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IListService } from 'vs/platform/list/browser/listService'; import { IEditorCommandsContext } from 'vs/workbench/common/editor'; -// import { ResourceContextKey } from 'vs/workbench/common/resources'; -import { ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; +import { ICustomEditorService, CONTEXT_HAS_CUSTOM_EDITORS } from 'vs/workbench/contrib/customEditor/common/customEditor'; import { getMultiSelectedResources } from 'vs/workbench/contrib/files/browser/files'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -95,7 +93,8 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, { id: REOPEN_WITH_COMMAND_ID, title: REOPEN_WITH_TITLE, category: viewCategory, - } + }, + when: CONTEXT_HAS_CUSTOM_EDITORS, }); // #endregion diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts index 0edbf4912e0..19677c10188 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts @@ -5,7 +5,7 @@ import { coalesce, distinct } from 'vs/base/common/arrays'; import * as glob from 'vs/base/common/glob'; -import { UnownedDisposable } from 'vs/base/common/lifecycle'; +import { UnownedDisposable, Disposable } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { basename, DataUri, isEqual } from 'vs/base/common/resources'; import { withNullAsUndefined } from 'vs/base/common/types'; @@ -22,12 +22,13 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { EditorInput, EditorOptions, IEditor, IEditorInput } from 'vs/workbench/common/editor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { webviewEditorsExtensionPoint } from 'vs/workbench/contrib/customEditor/browser/extensionPoint'; -import { CustomEditorPriority, CustomEditorInfo, CustomEditorSelector, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; +import { CustomEditorPriority, CustomEditorInfo, CustomEditorSelector, ICustomEditorService, CONTEXT_HAS_CUSTOM_EDITORS } from 'vs/workbench/contrib/customEditor/common/customEditor'; import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/editor/common/editorService'; import { CustomFileEditorInput } from './customEditorInput'; +import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; const defaultEditorId = 'default'; @@ -67,18 +68,22 @@ export class CustomEditorStore { } } -export class CustomEditorService implements ICustomEditorService { +export class CustomEditorService extends Disposable implements ICustomEditorService { _serviceBrand: any; private readonly editors = new CustomEditorStore(); + private readonly _hasCustomEditor: IContextKey; constructor( + @IContextKeyService contextKeyService: IContextKeyService, @IConfigurationService private readonly configurationService: IConfigurationService, @IEditorService private readonly editorService: IEditorService, @IInstantiationService private readonly instantiationService: IInstantiationService, @IQuickInputService private readonly quickInputService: IQuickInputService, @IWebviewService private readonly webviewService: IWebviewService, ) { + super(); + webviewEditorsExtensionPoint.setHandler(extensions => { this.editors.clear(); @@ -92,7 +97,13 @@ export class CustomEditorService implements ICustomEditorService { }); } } + this.updateContext(); }); + + this._hasCustomEditor = CONTEXT_HAS_CUSTOM_EDITORS.bindTo(contextKeyService); + + this._register(this.editorService.onDidActiveEditorChange(() => this.updateContext())); + this.updateContext(); } public getContributedCustomEditors(resource: URI): readonly CustomEditorInfo[] { @@ -154,7 +165,7 @@ export class CustomEditorService implements ICustomEditorService { resource: URI, viewType: string, group: IEditorGroup | undefined, - options?: { readonly customClasses: string }, + options?: { readonly customClasses: string; }, ): CustomFileEditorInput { const id = generateUuid(); const webview = this.webviewService.createWebviewEditorOverlay(id, { customClasses: options ? options.customClasses : undefined }, {}); @@ -190,11 +201,29 @@ export class CustomEditorService implements ICustomEditorService { } return this.editorService.openEditor(input, options, group); } + + private updateContext() { + const activeControl = this.editorService.activeControl; + if (!activeControl) { + this._hasCustomEditor.reset(); + return; + } + const resource = activeControl.input.getResource(); + if (!resource) { + this._hasCustomEditor.reset(); + return; + } + const possibleEditors = [ + ...this.getContributedCustomEditors(resource), + ...this.getUserConfiguredCustomEditors(resource), + ]; + this._hasCustomEditor.set(possibleEditors.length > 0); + } } export const customEditorsAssociationsKey = 'workbench.experimental.editorAssociations'; -export type CustomEditorsAssociations = readonly (CustomEditorSelector & { readonly viewType: string })[]; +export type CustomEditorsAssociations = readonly (CustomEditorSelector & { readonly viewType: string; })[]; export class CustomEditorContribution implements IWorkbenchContribution { constructor( diff --git a/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts b/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts index c5c85509532..0ab4cbd7514 100644 --- a/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts +++ b/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts @@ -41,7 +41,7 @@ const webviewEditorsContribution: IJSONSchema = { }, [WebviewEditorContribution.displayName]: { type: 'string', - description: nls.localize('contributes.displayName', 'Name of the custom editor displayed to users.'), + description: nls.localize('contributes.displayName', 'Human readable name of the custom editor. This is displayed to users when selecting which editor to use.'), }, [WebviewEditorContribution.selector]: { type: 'array', diff --git a/src/vs/workbench/contrib/customEditor/common/customEditor.ts b/src/vs/workbench/contrib/customEditor/common/customEditor.ts index 699441fc7da..f635727192f 100644 --- a/src/vs/workbench/contrib/customEditor/common/customEditor.ts +++ b/src/vs/workbench/contrib/customEditor/common/customEditor.ts @@ -8,9 +8,12 @@ import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { EditorInput, IEditor } from 'vs/workbench/common/editor'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export const ICustomEditorService = createDecorator('customEditorService'); +export const CONTEXT_HAS_CUSTOM_EDITORS = new RawContextKey('hasCustomEditors', false); + export interface ICustomEditorService { _serviceBrand: any; diff --git a/src/vs/workbench/contrib/debug/node/debugAdapter.ts b/src/vs/workbench/contrib/debug/node/debugAdapter.ts index 84ec75a9c84..617c0fa74d3 100644 --- a/src/vs/workbench/contrib/debug/node/debugAdapter.ts +++ b/src/vs/workbench/contrib/debug/node/debugAdapter.ts @@ -178,7 +178,6 @@ export class ExecutableDebugAdapter extends StreamDebugAdapter { if (options.env) { env = objects.mixin(env, options.env); } - delete env.VSCODE_PREVENT_FOREIGN_INSPECT; if (command === 'node') { if (Array.isArray(args) && args.length > 0) { diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts index 79f86a33774..29ae1fd3043 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts @@ -107,12 +107,12 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio } } - public startProfiling(): Promise | null { + public async startProfiling(): Promise { if (this._state !== ProfileSessionState.None) { return null; } - const inspectPort = this._extensionService.getInspectPort(); + const inspectPort = await this._extensionService.getInspectPort(false); if (!inspectPort) { return this._dialogService.confirm({ type: 'info', diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts index 56fe69484cd..c5b6f8b87a1 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsAutoProfiler.ts @@ -43,7 +43,7 @@ export class ExtensionsAutoProfiler extends Disposable implements IWorkbenchCont private async _onDidChangeResponsiveChange(event: IResponsiveStateChangeEvent): Promise { - const port = this._extensionService.getInspectPort(); + const port = await this._extensionService.getInspectPort(true); if (!port) { return; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts index f3da8de29a1..003ab9fe360 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts @@ -547,7 +547,7 @@ export class DebugExtensionHostAction extends Action { async run(): Promise { - const inspectPort = this._extensionService.getInspectPort(); + const inspectPort = await this._extensionService.getInspectPort(false); if (!inspectPort) { const res = await this._dialogService.confirm({ type: 'info', diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index 1f4cd95f65d..8afe9ace396 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -253,6 +253,7 @@ configurationRegistry.registerConfiguration({ }, 'files.eol': { 'type': 'string', + 'overridable': true, 'enum': [ '\n', '\r\n', diff --git a/src/vs/workbench/contrib/scm/browser/repositoryPanel.ts b/src/vs/workbench/contrib/scm/browser/repositoryPanel.ts index d3e83e0d735..130e661fff5 100644 --- a/src/vs/workbench/contrib/scm/browser/repositoryPanel.ts +++ b/src/vs/workbench/contrib/scm/browser/repositoryPanel.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/scmViewlet'; import { Event, Emitter } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; -import { basename } from 'vs/base/common/resources'; +import { basename, isEqual } from 'vs/base/common/resources'; import { IDisposable, Disposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle'; import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; import { append, $, addClass, toggleClass, trackFocus, removeClass } from 'vs/base/browser/dom'; @@ -32,7 +32,7 @@ import { InputBox, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; import { format } from 'vs/base/common/strings'; import { WorkbenchCompressibleObjectTree } from 'vs/platform/list/browser/listService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ThrottledDelayer } from 'vs/base/common/async'; +import { ThrottledDelayer, disposableTimeout } from 'vs/base/common/async'; import { INotificationService } from 'vs/platform/notification/common/notification'; import * as platform from 'vs/base/common/platform'; import { ITreeNode, ITreeFilter, ITreeSorter, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree'; @@ -51,6 +51,7 @@ import { flatten } from 'vs/base/common/arrays'; import { memoize } from 'vs/base/common/decorators'; import { IWorkbenchThemeService, IFileIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { toResource, SideBySideEditor } from 'vs/workbench/common/editor'; type TreeElement = ISCMResourceGroup | IBranchNode | ISCMResource; @@ -409,12 +410,15 @@ class ViewModel { private items: IGroupItem[] = []; private visibilityDisposables = new DisposableStore(); private scrollTop: number | undefined; + private firstVisible = true; private disposables = new DisposableStore(); constructor( private groups: ISequence, private tree: ObjectTree, - private _mode: ViewModelMode + private _mode: ViewModelMode, + @IEditorService protected editorService: IEditorService, + @IConfigurationService protected configurationService: IConfigurationService, ) { } private onDidSpliceGroups({ start, deleteCount, toInsert }: ISplice): void { @@ -470,6 +474,9 @@ class ViewModel { this.tree.scrollTop = this.scrollTop; this.scrollTop = undefined; } + + this.editorService.onDidActiveEditorChange(this.onDidActiveEditorChange, this, this.visibilityDisposables); + this.onDidActiveEditorChange(); } else { this.visibilityDisposables.dispose(); this.onDidSpliceGroups({ start: 0, deleteCount: this.items.length, toInsert: [] }); @@ -485,6 +492,45 @@ class ViewModel { } } + private onDidActiveEditorChange(): void { + if (!this.configurationService.getValue('scm.autoReveal')) { + return; + } + + if (this.firstVisible) { + this.firstVisible = false; + this.visibilityDisposables.add(disposableTimeout(() => this.onDidActiveEditorChange(), 250)); + return; + } + + const editor = this.editorService.activeEditor; + + if (!editor) { + return; + } + + const uri = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }); + + if (!uri) { + return; + } + + // go backwards from last group + for (let i = this.groups.elements.length - 1; i >= 0; i--) { + const group = this.groups.elements[i]; + + for (const resource of group.elements) { + if (isEqual(uri, resource.sourceUri)) { + this.tree.reveal(resource); + this.tree.setSelection([resource]); + this.tree.setFocus([resource]); + + return; + } + } + } + } + dispose(): void { this.visibilityDisposables.dispose(); this.disposables.dispose(); @@ -708,7 +754,7 @@ export class RepositoryPanel extends ViewletPanel { } } - this.viewModel = new ViewModel(this.repository.provider.groups, this.tree, mode); + this.viewModel = this.instantiationService.createInstance(ViewModel, this.repository.provider.groups, this.tree, mode); this._register(this.viewModel); addClass(this.listContainer, 'file-icon-themable-tree'); diff --git a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts index a8888407cb8..64a34245284 100644 --- a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -114,8 +114,13 @@ Registry.as(ConfigurationExtensions.Configuration).regis localize('scm.defaultViewMode.list', "Show the repository changes as a list.") ], description: localize('scm.defaultViewMode', "Controls the default Source Control repository view mode."), - default: 'tree' - } + default: 'list' + }, + 'scm.autoReveal': { + type: 'boolean', + description: localize('autoReveal', "Controls whether the SCM view should automatically reveal and select files when opening them."), + default: true + }, } }); diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index eae307ef62c..841a2b59bfe 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -251,6 +251,11 @@ configurationRegistry.registerConfiguration({ }, default: [] }, + 'terminal.integrated.allowChords': { + markdownDescription: nls.localize('terminal.integrated.allowChords', "Whether or not to allow chord keybindings in the terminal. Note that when this is true and the keystroke results in a chord it will bypass `terminal.integrated.commandsToSkipShell`, setting this to false is particularly useful when you want ctrl+k to go to your shell (not VS Code)."), + type: 'boolean', + default: true + }, 'terminal.integrated.inheritEnv': { markdownDescription: nls.localize('terminal.integrated.inheritEnv', "Whether new shells should inherit their environment from VS Code. This is not supported on Windows."), type: 'boolean', diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 25baad14130..1997bdac7ad 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -10,7 +10,6 @@ import { IWindowsShellHelper, ITerminalConfigHelper, ITerminalChildProcess, IShe import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IProcessEnvironment, Platform } from 'vs/base/common/platform'; import { Event } from 'vs/base/common/event'; -import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IDisposable } from 'vs/base/common/lifecycle'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; import { URI } from 'vs/base/common/uri'; @@ -65,7 +64,7 @@ export interface ITerminalTab { setVisible(visible: boolean): void; layout(width: number, height: number): void; addDisposable(disposable: IDisposable): void; - split(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance | undefined; + split(shellLaunchConfig: IShellLaunchConfig): ITerminalInstance; } export interface ITerminalService { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index ef6bdddec6f..b9eed7e31ec 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -561,7 +561,10 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // Attach the xterm object to the DOM, exposing it to the smoke tests this._wrapperElement.xterm = this._xterm; + this._wrapperElement.appendChild(this._xtermElement); + this._container.appendChild(this._wrapperElement); xterm.open(this._xtermElement); + xterm.textarea.addEventListener('focus', () => this._onFocus.fire(this)); xterm.attachCustomKeyEventHandler((event: KeyboardEvent): boolean => { // Disable all input if the terminal is exiting @@ -573,7 +576,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { // within commandsToSkipShell const standardKeyboardEvent = new StandardKeyboardEvent(event); const resolveResult = this._keybindingService.softDispatch(standardKeyboardEvent, standardKeyboardEvent.target); - if (resolveResult && this._skipTerminalCommands.some(k => k === resolveResult.commandId)) { + const allowChords = resolveResult && resolveResult.enterChord && this._configHelper.config.allowChords; + if (allowChords || resolveResult && this._skipTerminalCommands.some(k => k === resolveResult.commandId)) { event.preventDefault(); return false; } @@ -638,9 +642,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance { this._refreshSelectionContextKey(); })); - this._wrapperElement.appendChild(this._xtermElement); - this._container.appendChild(this._wrapperElement); - const widgetManager = new TerminalWidgetManager(this._wrapperElement); this._widgetManager = widgetManager; this._processManager.onProcessReady(() => { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 6bb7530ed79..173957233b9 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -11,7 +11,6 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { INotificationService } from 'vs/platform/notification/common/notification'; import { TerminalTab } from 'vs/workbench/contrib/terminal/browser/terminalTab'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -92,7 +91,6 @@ export class TerminalService implements ITerminalService { @IPanelService private _panelService: IPanelService, @IWorkbenchLayoutService private _layoutService: IWorkbenchLayoutService, @ILifecycleService lifecycleService: ILifecycleService, - @INotificationService private _notificationService: INotificationService, @IDialogService private _dialogService: IDialogService, @IInstantiationService private _instantiationService: IInstantiationService, @IExtensionService private _extensionService: IExtensionService, @@ -393,12 +391,7 @@ export class TerminalService implements ITerminalService { return null; } - const instance = tab.split(this._terminalFocusContextKey, this.configHelper, shellLaunchConfig); - if (!instance) { - this._showNotEnoughSpaceToast(); - return null; - } - + const instance = tab.split(shellLaunchConfig); this._initInstanceListeners(instance); this._onInstancesChanged.fire(); @@ -495,10 +488,6 @@ export class TerminalService implements ITerminalService { return !res.confirmed; } - protected _showNotEnoughSpaceToast(): void { - this._notificationService.info(nls.localize('terminal.minWidth', "Not enough space to split terminal.")); - } - protected _validateShellPaths(label: string, potentialPaths: string[]): Promise<[string, string] | null> { if (potentialPaths.length === 0) { return Promise.resolve(null); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTab.ts b/src/vs/workbench/contrib/terminal/browser/terminalTab.ts index 3d4d50cdc9f..68ff40e9135 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTab.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTab.ts @@ -14,7 +14,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ITerminalInstance, Direction, ITerminalTab, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal'; const SPLIT_PANE_MIN_SIZE = 120; -const TERMINAL_MIN_USEFUL_SIZE = 250; class SplitPaneContainer extends Disposable { private _height: number; @@ -370,18 +369,11 @@ export class TerminalTab extends Disposable implements ITerminalTab { this.terminalInstances.forEach(i => i.setVisible(visible)); } - public split( - terminalFocusContextKey: IContextKey, - configHelper: ITerminalConfigHelper, - shellLaunchConfig: IShellLaunchConfig - ): ITerminalInstance | undefined { + public split(shellLaunchConfig: IShellLaunchConfig): ITerminalInstance { if (!this._container) { throw new Error('Cannot split terminal that has not been attached'); } - const newTerminalSize = ((this._panelPosition === Position.BOTTOM ? this._container.clientWidth : this._container.clientHeight) / (this._terminalInstances.length + 1)); - if (newTerminalSize < TERMINAL_MIN_USEFUL_SIZE) { - return undefined; - } + const instance = this._terminalService.createInstance(undefined, shellLaunchConfig); this._terminalInstances.splice(this._activeInstanceIndex + 1, 0, instance); this._initInstanceListeners(instance); diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 444ac1b408f..f587dbc700f 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -101,6 +101,7 @@ export interface ITerminalConfiguration { detectLocale: 'auto' | 'off' | 'on'; scrollback: number; commandsToSkipShell: string[]; + allowChords: boolean; cwd: string; confirmOnExit: boolean; enableBell: boolean; diff --git a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts index fefece531e3..bdaf6d62248 100644 --- a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts @@ -84,7 +84,9 @@ suite('Workbench - TerminalCommandTracker', () => { (window).matchMedia = () => { return { addListener: () => { } }; }; - xterm.open(document.createElement('div')); + const e = document.createElement('div'); + document.body.appendChild(e); + xterm.open(e); await writePromise(xterm, '\r0'); await writePromise(xterm, '\n\r1'); @@ -109,12 +111,16 @@ suite('Workbench - TerminalCommandTracker', () => { assert.equal(xterm.getSelection(), '2'); commandTracker.selectToNextCommand(); assert.equal(xterm.getSelection(), isWindows ? '\r\n' : '\n'); + + document.body.removeChild(e); }); test('should select to the next and previous lines & commands', async () => { (window).matchMedia = () => { return { addListener: () => { } }; }; - xterm.open(document.createElement('div')); + const e = document.createElement('div'); + document.body.appendChild(e); + xterm.open(e); await writePromise(xterm, '\r0'); await writePromise(xterm, '\n\r1'); @@ -144,6 +150,8 @@ suite('Workbench - TerminalCommandTracker', () => { assert.equal(xterm.getSelection(), isWindows ? '1\r\n2' : '1\n2'); commandTracker.selectToPreviousLine(); assert.equal(xterm.getSelection(), isWindows ? '0\r\n1\r\n2' : '0\n1\n2'); + + document.body.removeChild(e); }); }); }); diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts index f4a36a39767..b293a6d68b8 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts @@ -146,7 +146,6 @@ interface ExtensionSuggestion { const extensionPacks: ExtensionSuggestion[] = [ { name: localize('welcomePage.javaScript', "JavaScript"), id: 'dbaeumer.vscode-eslint' }, - { name: localize('welcomePage.typeScript', "TypeScript"), id: 'ms-vscode.vscode-typescript-tslint-plugin' }, { name: localize('welcomePage.python', "Python"), id: 'ms-python.python' }, // { name: localize('welcomePage.go', "Go"), id: 'lukehoban.go' }, { name: localize('welcomePage.php', "PHP"), id: 'felixfbecker.php-pack' }, diff --git a/src/vs/workbench/electron-browser/actions/developerActions.ts b/src/vs/workbench/electron-browser/actions/developerActions.ts index a33bd626c5a..e4c1160ca47 100644 --- a/src/vs/workbench/electron-browser/actions/developerActions.ts +++ b/src/vs/workbench/electron-browser/actions/developerActions.ts @@ -7,13 +7,19 @@ import { Action } from 'vs/base/common/actions'; import * as nls from 'vs/nls'; import { IElectronService } from 'vs/platform/electron/node/electron'; import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; export class ToggleDevToolsAction extends Action { static readonly ID = 'workbench.action.toggleDevTools'; static readonly LABEL = nls.localize('toggleDevTools', "Toggle Developer Tools"); - constructor(id: string, label: string, @IElectronService private readonly electronService: IElectronService) { + constructor( + id: string, + label: string, + @IElectronService private readonly electronService: IElectronService + ) { super(id, label); } @@ -27,7 +33,11 @@ export class ToggleSharedProcessAction extends Action { static readonly ID = 'workbench.action.toggleSharedProcess'; static readonly LABEL = nls.localize('toggleSharedProcess', "Toggle Shared Process"); - constructor(id: string, label: string, @ISharedProcessService private readonly sharedProcessService: ISharedProcessService) { + constructor( + id: string, + label: string, + @ISharedProcessService private readonly sharedProcessService: ISharedProcessService + ) { super(id, label); } @@ -35,3 +45,22 @@ export class ToggleSharedProcessAction extends Action { return this.sharedProcessService.toggleSharedProcessWindow(); } } + +export class ConfigureRuntimeArgumentsAction extends Action { + + static readonly ID = 'workbench.action.configureRuntimeArguments'; + static readonly LABEL = nls.localize('configureRuntimeArguments', "Configure Runtime Arguments"); + + constructor( + id: string, + label: string, + @IEnvironmentService private readonly environmentService: IEnvironmentService, + @IEditorService private readonly editorService: IEditorService + ) { + super(id, label); + } + + async run(): Promise { + await this.editorService.openEditor({ resource: this.environmentService.argvResource }); + } +} diff --git a/src/vs/workbench/electron-browser/desktop.contribution.ts b/src/vs/workbench/electron-browser/desktop.contribution.ts index b50b169627c..44481c27a31 100644 --- a/src/vs/workbench/electron-browser/desktop.contribution.ts +++ b/src/vs/workbench/electron-browser/desktop.contribution.ts @@ -11,7 +11,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, Configur import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform'; -import { ToggleSharedProcessAction, ToggleDevToolsAction } from 'vs/workbench/electron-browser/actions/developerActions'; +import { ToggleSharedProcessAction, ToggleDevToolsAction, ConfigureRuntimeArgumentsAction } from 'vs/workbench/electron-browser/actions/developerActions'; import { ZoomResetAction, ZoomOutAction, ZoomInAction, CloseCurrentWindowAction, SwitchWindow, QuickSwitchWindow, ReloadWindowWithExtensionsDisabledAction, NewWindowTabHandler, ShowPreviousWindowTabHandler, ShowNextWindowTabHandler, MoveWindowTabToNewWindowHandler, MergeWindowTabsHandlerHandler, ToggleWindowTabsBarHandler } from 'vs/workbench/electron-browser/actions/windowActions'; import { SaveWorkspaceAsAction, DuplicateWorkspaceInNewWindowAction } from 'vs/workbench/electron-browser/actions/workspaceActions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -98,6 +98,7 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; (function registerDeveloperActions(): void { const developerCategory = nls.localize('developer', "Developer"); registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSharedProcessAction, ToggleSharedProcessAction.ID, ToggleSharedProcessAction.LABEL), 'Developer: Toggle Shared Process', developerCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureRuntimeArgumentsAction, ConfigureRuntimeArgumentsAction.ID, ConfigureRuntimeArgumentsAction.LABEL), 'Developer: Configure Runtime Arguments', developerCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowWithExtensionsDisabledAction, ReloadWindowWithExtensionsDisabledAction.ID, ReloadWindowWithExtensionsDisabledAction.LABEL), 'Developer: Reload With Extensions Disabled', developerCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleDevToolsAction, ToggleDevToolsAction.ID, ToggleDevToolsAction.LABEL), 'Developer: Toggle Developer Tools', developerCategory); diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 5f221e07ffc..9e75febd692 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -89,6 +89,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment this.keybindingsResource = joinPath(this.userRoamingDataHome, 'keybindings.json'); this.keyboardLayoutResource = joinPath(this.userRoamingDataHome, 'keyboardLayout.json'); this.localeResource = joinPath(this.userRoamingDataHome, 'locale.json'); + this.argvResource = joinPath(this.userRoamingDataHome, 'argv.json'); this.backupHome = joinPath(this.userRoamingDataHome, BACKUPS); this.configuration.backupWorkspaceResource = joinPath(this.backupHome, options.workspaceId); this.configuration.connectionToken = options.connectionToken || getCookieValue('vscode-tkn'); @@ -146,6 +147,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment keybindingsResource: URI; keyboardLayoutResource: URI; localeResource: URI; + argvResource: URI; settingsSyncPreviewResource: URI; userDataSyncLogResource: URI; machineSettingsHome: URI; diff --git a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts index 406331cb2bc..e74228ce1dc 100644 --- a/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts +++ b/src/vs/workbench/services/extensions/browser/webWorkerExtensionHostStarter.ts @@ -113,6 +113,10 @@ export class WebWorkerExtensionHostStarter implements IExtensionHostStarter { return undefined; } + enableInspectPort(): Promise { + return Promise.resolve(false); + } + private async _createExtHostInitData(): Promise { const [telemetryInfo, extensionDescriptions] = await Promise.all([this._telemetryService.getTelemetryInfo(), this._extensions]); const workspace = this._contextService.getWorkspace(); diff --git a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts index 14da9c3b8ad..9833bbfb888 100644 --- a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts +++ b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts @@ -256,8 +256,8 @@ export abstract class AbstractExtensionService extends Disposable implements IEx return result; } - public getInspectPort(): number { - return 0; + public getInspectPort(_tryEnableInspector: boolean): Promise { + return Promise.resolve(0); } public async setRemoteEnvironment(env: { [key: string]: string | null }): Promise { diff --git a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts index 3aff4a5e57f..746953e1d39 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts @@ -238,8 +238,11 @@ export class ExtensionHostProcessManager extends Disposable { }); } - public getInspectPort(): number { + public async getInspectPort(tryEnableInspector: boolean): Promise { if (this._extensionHostProcessWorker) { + if (tryEnableInspector) { + await this._extensionHostProcessWorker.enableInspectPort(); + } let port = this._extensionHostProcessWorker.getInspectPort(); if (port) { return port; @@ -248,10 +251,6 @@ export class ExtensionHostProcessManager extends Disposable { return 0; } - public canProfileExtensionHost(): boolean { - return this._extensionHostProcessWorker && Boolean(this._extensionHostProcessWorker.getInspectPort()); - } - public async resolveAuthority(remoteAuthority: string): Promise { const authorityPlusIndex = remoteAuthority.indexOf('+'); if (authorityPlusIndex === -1) { diff --git a/src/vs/workbench/services/extensions/common/extensions.ts b/src/vs/workbench/services/extensions/common/extensions.ts index d68777ae83b..074447cab22 100644 --- a/src/vs/workbench/services/extensions/common/extensions.ts +++ b/src/vs/workbench/services/extensions/common/extensions.ts @@ -89,6 +89,7 @@ export interface IExtensionHostStarter { start(): Promise | null; getInspectPort(): number | undefined; + enableInspectPort(): Promise; dispose(): void; } @@ -212,7 +213,7 @@ export interface IExtensionService { * Return the inspect port or `0`, the latter means inspection * is not possible. */ - getInspectPort(): number; + getInspectPort(tryEnableInspector: boolean): Promise; /** * Restarts the extension host. @@ -270,7 +271,7 @@ export class NullExtensionService implements IExtensionService { getExtension() { return Promise.resolve(undefined); } readExtensionPointContributions(_extPoint: IExtensionPoint): Promise[]> { return Promise.resolve(Object.create(null)); } getExtensionsStatus(): { [id: string]: IExtensionsStatus; } { return Object.create(null); } - getInspectPort(): number { return 0; } + getInspectPort(_tryEnableInspector: boolean): Promise { return Promise.resolve(0); } restartExtensionHost(): void { } async setRemoteEnvironment(_env: { [key: string]: string | null }): Promise { } canAddExtension(): boolean { return false; } diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts index 8dfa1bd4522..83b800cad49 100644 --- a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts @@ -225,6 +225,10 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH return undefined; } + enableInspectPort(): Promise { + return Promise.resolve(false); + } + dispose(): void { super.dispose(); diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index 1963444f46f..b7ac24ab84a 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -16,7 +16,7 @@ import * as platform from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { IRemoteConsoleLog, log } from 'vs/base/common/console'; import { logRemoteEntry } from 'vs/workbench/services/extensions/common/remoteConsoleUtil'; -import { findFreePort, randomPort } from 'vs/base/node/ports'; +import { findFreePort } from 'vs/base/node/ports'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net'; import { generateRandomPipeName, NodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; @@ -45,6 +45,8 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { private readonly _onExit: Emitter<[number, string]> = new Emitter<[number, string]>(); public readonly onExit: Event<[number, string]> = this._onExit.event; + private readonly _onDidSetInspectPort = new Emitter(); + private readonly _toDispose = new DisposableStore(); private readonly _isExtensionDevHost: boolean; @@ -127,10 +129,10 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { if (!this._messageProtocol) { this._messageProtocol = Promise.all([ this._tryListenOnPipe(), - !this._environmentService.args['disable-inspect'] ? this._tryFindDebugPort() : Promise.resolve(null) + this._tryFindDebugPort() ]).then(data => { const pipeName = data[0]; - const portData = data[1]; + const portNumber = data[1]; const opts = { env: objects.mixin(objects.deepClone(process.env), { @@ -151,16 +153,11 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { silent: true }; - if (portData && portData.actual) { + if (portNumber !== 0) { opts.execArgv = [ '--nolazy', - (this._isExtensionDevDebugBrk ? '--inspect-brk=' : '--inspect=') + portData.actual + (this._isExtensionDevDebugBrk ? '--inspect-brk=' : '--inspect=') + portNumber ]; - if (!portData.expected) { - // No one asked for 'inspect' or 'inspect-brk', only us. We add another - // option such that the extension host can manipulate the execArgv array - opts.env.VSCODE_PREVENT_FOREIGN_INSPECT = true; - } } const crashReporterOptions = undefined; // TODO@electron pass this in as options to the extension host after verifying this actually works @@ -198,6 +195,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { } if (!this._inspectPort) { this._inspectPort = Number(inspectorUrlMatch[2]); + this._onDidSetInspectPort.fire(); } } else { console.group('Extension Host'); @@ -218,11 +216,12 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { this._extensionHostProcess.on('exit', (code: number, signal: string) => this._onExtHostProcessExit(code, signal)); // Notify debugger that we are ready to attach to the process if we run a development extension - if (portData) { - if (this._isExtensionDevHost && portData.actual && this._isExtensionDevDebug && this._environmentService.debugExtensionHost.debugId) { - this._extensionHostDebugService.attachSession(this._environmentService.debugExtensionHost.debugId, portData.actual); + if (portNumber) { + if (this._isExtensionDevHost && portNumber && this._isExtensionDevDebug && this._environmentService.debugExtensionHost.debugId) { + this._extensionHostDebugService.attachSession(this._environmentService.debugExtensionHost.debugId, portNumber); } - this._inspectPort = portData.actual; + this._inspectPort = portNumber; + this._onDidSetInspectPort.fire(); } // Help in case we fail to start it @@ -275,29 +274,31 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { /** * Find a free port if extension host debugging is enabled. */ - private _tryFindDebugPort(): Promise<{ expected: number; actual: number }> { - let expected: number; - let startPort = randomPort(); - if (typeof this._environmentService.debugExtensionHost.port === 'number') { - startPort = expected = this._environmentService.debugExtensionHost.port; + private async _tryFindDebugPort(): Promise { + + if (typeof this._environmentService.debugExtensionHost.port !== 'number') { + return 0; } - return new Promise(resolve => { - return findFreePort(startPort, 10 /* try 10 ports */, 5000 /* try up to 5 seconds */).then(port => { - if (!port) { - console.warn('%c[Extension Host] %cCould not find a free port for debugging', 'color: blue', 'color:'); - } else { - if (expected && port !== expected) { - console.warn(`%c[Extension Host] %cProvided debugging port ${expected} is not free, using ${port} instead.`, 'color: blue', 'color:'); - } - if (this._isExtensionDevDebugBrk) { - console.warn(`%c[Extension Host] %cSTOPPED on first line for debugging on port ${port}`, 'color: blue', 'color:'); - } else { - console.info(`%c[Extension Host] %cdebugger listening on port ${port}`, 'color: blue', 'color:'); - } - } - return resolve({ expected, actual: port }); - }); - }); + + const expected = this._environmentService.debugExtensionHost.port; + const port = await findFreePort(expected, 10 /* try 10 ports */, 5000 /* try up to 5 seconds */); + + if (!port) { + console.warn('%c[Extension Host] %cCould not find a free port for debugging', 'color: blue', 'color:'); + return 0; + } + + if (port !== expected) { + console.warn(`%c[Extension Host] %cProvided debugging port ${expected} is not free, using ${port} instead.`, 'color: blue', 'color:'); + } + if (this._isExtensionDevDebugBrk) { + console.warn(`%c[Extension Host] %cSTOPPED on first line for debugging on port ${port}`, 'color: blue', 'color:'); + } else { + console.info(`%c[Extension Host] %cdebugger listening on port ${port}`, 'color: blue', 'color:'); + } + return port; + + } private _tryExtHostHandshake(): Promise { @@ -466,6 +467,37 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { this._onExit.fire([code, signal]); } + public async enableInspectPort(): Promise { + if (typeof this._inspectPort === 'number') { + return true; + } + + if (!this._extensionHostProcess) { + return false; + } + + interface ProcessExt { + _debugProcess?(n: number): any; + } + + if (typeof (process)._debugProcess === 'function') { + // use (undocumented) _debugProcess feature of node + (process)._debugProcess!(this._extensionHostProcess.pid); + await Promise.race([Event.toPromise(this._onDidSetInspectPort.event), timeout(1000)]); + return typeof this._inspectPort === 'number'; + + } else if (!platform.isWindows) { + // use KILL USR1 on non-windows platforms (fallback) + this._extensionHostProcess.kill('SIGUSR1'); + await Promise.race([Event.toPromise(this._onDidSetInspectPort.event), timeout(1000)]); + return typeof this._inspectPort === 'number'; + + } else { + // not supported... + return false; + } + } + public getInspectPort(): number | undefined { return withNullAsUndefined(this._inspectPort); } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 9cc156d3d11..6387493212b 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -537,9 +537,9 @@ export class ExtensionService extends AbstractExtensionService implements IExten this._doHandleExtensionPoints(this._registry.getAllExtensionDescriptions()); } - public getInspectPort(): number { + public async getInspectPort(tryEnableInspector: boolean): Promise { if (this._extensionHostProcessManagers.length > 0) { - return this._extensionHostProcessManagers[0].getInspectPort(); + return this._extensionHostProcessManagers[0].getInspectPort(tryEnableInspector); } return 0; } diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts index 9f5a14f6cb0..bbd3b8e3ef5 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts @@ -275,20 +275,6 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise { const protocol = await createExtHostProtocol(); diff --git a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts index 0b7b04823bd..97a9fcc913b 100644 --- a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts @@ -19,7 +19,6 @@ import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IFileService } from 'vs/platform/files/common/files'; @@ -49,6 +48,7 @@ import { FileUserDataProvider } from 'vs/workbench/services/userData/common/file import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; class TestEnvironmentService extends WorkbenchEnvironmentService { @@ -81,11 +81,12 @@ suite('KeybindingsEditing', () => { instantiationService = new TestInstantiationService(); const environmentService = new TestEnvironmentService(URI.file(testDir)); + + const configService = new TestConfigurationService(); + configService.setUserConfiguration('files', { 'eol': '\n' }); + instantiationService.stub(IEnvironmentService, environmentService); - instantiationService.stub(IConfigurationService, ConfigurationService); - instantiationService.stub(IConfigurationService, 'getValue', { 'eol': '\n' }); - instantiationService.stub(IConfigurationService, 'onDidUpdateConfiguration', () => { }); - instantiationService.stub(IConfigurationService, 'onDidChangeConfiguration', () => { }); + instantiationService.stub(IConfigurationService, configService); instantiationService.stub(IWorkspaceContextService, new TestContextService()); const lifecycleService = new TestLifecycleService(); instantiationService.stub(ILifecycleService, lifecycleService); diff --git a/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts b/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts index 554762af58b..d89964a436b 100644 --- a/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts +++ b/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts @@ -425,13 +425,14 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[] args.push('--pcre2'); } - if (query.isRegExp) { - query.pattern = unicodeEscapesToPCRE2(query.pattern); - } - // Allow $ to match /r/n args.push('--crlf'); + if (query.isRegExp) { + query.pattern = unicodeEscapesToPCRE2(query.pattern); + args.push('--auto-hybrid-regex'); + } + let searchPatternAfterDoubleDashes: Maybe; if (query.isWordMatch) { const regexp = createRegExp(query.pattern, !!query.isRegExp, { wholeWord: query.isWordMatch }); @@ -441,7 +442,6 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[] let fixedRegexpQuery = fixRegexNewline(query.pattern); fixedRegexpQuery = fixNewline(fixedRegexpQuery); args.push('--regexp', fixedRegexpQuery); - args.push('--auto-hybrid-regex'); } else { searchPatternAfterDoubleDashes = query.pattern; args.push('--fixed-strings'); diff --git a/src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts b/src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts index 95495464e6d..ce6bc5f6eba 100644 --- a/src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts +++ b/src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts @@ -30,9 +30,9 @@ export class TextResourcePropertiesService implements ITextResourcePropertiesSer } getEOL(resource?: URI, language?: string): string { - const filesConfiguration = this.configurationService.getValue<{ eol: string }>('files', { overrideIdentifier: language, resource }); - if (filesConfiguration && filesConfiguration.eol && filesConfiguration.eol !== 'auto') { - return filesConfiguration.eol; + const eol = this.configurationService.getValue('files.eol', { overrideIdentifier: language, resource }); + if (eol && eol !== 'auto') { + return eol; } const os = this.getOS(resource); return os === OperatingSystem.Linux || os === OperatingSystem.Macintosh ? '\n' : '\r\n'; diff --git a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts index b5e65780f81..e3368f14cc7 100644 --- a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts @@ -102,7 +102,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { ) { this.container = layoutService.getWorkbenchContainer(); - this.colorThemeStore = new ColorThemeStore(extensionService, ColorThemeData.createLoadedEmptyTheme(DEFAULT_THEME_ID, DEFAULT_THEME_SETTING_VALUE)); + this.colorThemeStore = new ColorThemeStore(extensionService); this.onFileIconThemeChange = new Emitter(); this.iconThemeStore = new FileIconThemeStore(extensionService); this.onColorThemeChange = new Emitter({ leakWarningThreshold: 400 }); diff --git a/src/vs/workbench/services/themes/common/colorThemeStore.ts b/src/vs/workbench/services/themes/common/colorThemeStore.ts index 272338755fc..7253ada3afd 100644 --- a/src/vs/workbench/services/themes/common/colorThemeStore.ts +++ b/src/vs/workbench/services/themes/common/colorThemeStore.ts @@ -57,8 +57,8 @@ export class ColorThemeStore { private readonly onDidChangeEmitter = new Emitter(); public readonly onDidChange: Event = this.onDidChangeEmitter.event; - constructor(@IExtensionService private readonly extensionService: IExtensionService, defaultTheme: ColorThemeData) { - this.extensionsColorThemes = [defaultTheme]; + constructor(@IExtensionService private readonly extensionService: IExtensionService) { + this.extensionsColorThemes = []; this.initialize(); } @@ -69,7 +69,7 @@ export class ColorThemeStore { for (const theme of this.extensionsColorThemes) { previousIds[theme.id] = true; } - this.extensionsColorThemes.length = 1; // remove all but the default theme + this.extensionsColorThemes.length = 0; for (let ext of extensions) { let extensionData = { extensionId: ext.description.identifier.value, @@ -114,11 +114,7 @@ export class ColorThemeStore { } let themeData = ColorThemeData.fromExtensionTheme(theme, colorThemeLocation, extensionData); - if (themeData.id === this.extensionsColorThemes[0].id) { - this.extensionsColorThemes[0] = themeData; - } else { - this.extensionsColorThemes.push(themeData); - } + this.extensionsColorThemes.push(themeData); }); } diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 355b2c62476..803ae1b59af 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -1241,12 +1241,10 @@ export class TestTextResourcePropertiesService implements ITextResourcePropertie ) { } - getEOL(resource: URI): string { - const filesConfiguration = this.configurationService.getValue<{ eol: string }>('files'); - if (filesConfiguration && filesConfiguration.eol) { - if (filesConfiguration.eol !== 'auto') { - return filesConfiguration.eol; - } + getEOL(resource: URI, language?: string): string { + const eol = this.configurationService.getValue('files.eol', { overrideIdentifier: language, resource }); + if (eol && eol !== 'auto') { + return eol; } return (isLinux || isMacintosh) ? '\n' : '\r\n'; } diff --git a/yarn.lock b/yarn.lock index 9c27370a796..8b48f5f6231 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1439,6 +1439,11 @@ chromium-pickle-js@^0.2.0: resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz#04a106672c18b085ab774d983dfa3ea138f22205" integrity sha1-BKEGZywYsIWrd02YPfo+oTjyIgU= +ci-info@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" + integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -2957,6 +2962,11 @@ find-cache-dir@^1.0.0: make-dir "^1.0.0" pkg-dir "^2.0.0" +find-parent-dir@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.0.tgz#33c44b429ab2b2f0646299c5f9f718f376ff8d54" + integrity sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ= + find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" @@ -4039,6 +4049,16 @@ https-proxy-agent@2.2.1, https-proxy-agent@^2.2.1: agent-base "^4.1.0" debug "^3.1.0" +husky@^0.13.1: + version "0.13.4" + resolved "https://registry.yarnpkg.com/husky/-/husky-0.13.4.tgz#48785c5028de3452a51c48c12c4f94b2124a1407" + integrity sha1-SHhcUCjeNFKlHEjBLE+UshJKFAc= + dependencies: + chalk "^1.1.3" + find-parent-dir "^0.3.0" + is-ci "^1.0.9" + normalize-path "^1.0.0" + iconv-lite@0.4.19, iconv-lite@^0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -4281,6 +4301,13 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" +is-ci@^1.0.9: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" + integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== + dependencies: + ci-info "^1.5.0" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -5744,6 +5771,11 @@ normalize-package-data@^2.3.2: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" +normalize-path@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" + integrity sha1-MtDkcvkf80VwHBWoMRAY07CpA3k= + normalize-path@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" @@ -9239,20 +9271,20 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-search@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0.tgz#46659c7c33f9fc268ad3e7e6c5824bb2fdb65852" - integrity sha512-C/v2VvFn3hb1qUgjJPo7LxzxNCLBgNJv8n6v/bH2NqPz32/PNUF+IHu0SFf1TaIH+pydUpKXCtob5a/UyZg/+Q== +xterm-addon-search@0.3.0-beta5: + version "0.3.0-beta5" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.3.0-beta5.tgz#fd53d33a77a0235018479c712be8c12f7c0d083a" + integrity sha512-3GkGc4hST35/4hzgnQPLLvQ29WH7MkZ0mUrBE/Vm1IQum7TnMvWPTkGemwM+wAl4tdBmynNccHJlFeQzaQtVUg== xterm-addon-web-links@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.0.tgz#b408a0be46211d8d4a0bb5e701d8f3c2bd07d473" integrity sha512-dq81c4Pzli2PgKVBgY2REte9sCVibR3df8AP3SEvCTM9uYFnUFxtxzMTplPnc7+rXabVhFdbU6x+rstIk8HNQg== -xterm@4.1.0-beta8: - version "4.1.0-beta8" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.1.0-beta8.tgz#c1ef323ba336d92f5b52302b66f672dfff75b3ef" - integrity sha512-6lf+XVv0qT285w49P92tSYoUB406jdbgdhnPKNzxCIGtGX8kcwK+pHZ8HncDwcEhmTmI4LZ/WXPGtOQJg+onwg== +xterm@4.2.0-beta4: + version "4.2.0-beta4" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.2.0-beta4.tgz#596577f94a1da372119d192363ea2b19d1f8b50c" + integrity sha512-BmkpxCpqdOJoNdIcddkRT8S65sGjgBbWI0uIJNSnzZvj81OKcraMSTmF/ODw0TF/MDLc33Fx9cpDx/D6lQgl8Q== y18n@^3.2.1: version "3.2.1"