diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 91876a89245..80941a45c8e 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -14,60 +14,59 @@ This project incorporates components from the projects listed below. The origina 7. atom/language-sass version 0.61.4 (https://github.com/atom/language-sass) 8. atom/language-shellscript version 0.26.0 (https://github.com/atom/language-shellscript) 9. atom/language-xml version 0.35.2 (https://github.com/atom/language-xml) -10. chriskempson/tomorrow-theme (https://github.com/chriskempson/tomorrow-theme) -11. Colorsublime-Themes version 0.1.0 (https://github.com/Colorsublime/Colorsublime-Themes) -12. daaain/Handlebars version 1.7.1 (https://github.com/daaain/Handlebars) -13. davidrios/pug-tmbundle (https://github.com/davidrios/pug-tmbundle) -14. definitelytyped (https://github.com/DefinitelyTyped/DefinitelyTyped) -15. demyte/language-cshtml version 0.3.0 (https://github.com/demyte/language-cshtml) -16. Document Object Model version 4.0.0 (https://www.w3.org/DOM/) -17. dotnet/csharp-tmLanguage version 0.1.0 (https://github.com/dotnet/csharp-tmLanguage) -18. expand-abbreviation version 0.5.8 (https://github.com/emmetio/expand-abbreviation) -19. fadeevab/make.tmbundle (https://github.com/fadeevab/make.tmbundle) -20. freebroccolo/atom-language-swift (https://github.com/freebroccolo/atom-language-swift) -21. HTML 5.1 W3C Working Draft version 08 October 2015 (http://www.w3.org/TR/2015/WD-html51-20151008/) -22. Ikuyadeu/vscode-R version 0.5.5 (https://github.com/Ikuyadeu/vscode-R) -23. Ionic documentation version 1.2.4 (https://github.com/ionic-team/ionic-site) -24. ionide/ionide-fsgrammar (https://github.com/ionide/ionide-fsgrammar) -25. js-beautify version 1.6.8 (https://github.com/beautify-web/js-beautify) -26. Jxck/assert version 1.0.0 (https://github.com/Jxck/assert) -27. language-docker (https://github.com/moby/moby) -28. language-go version 0.44.3 (https://github.com/atom/language-go) -29. language-less version 0.34.2 (https://github.com/atom/language-less) -30. language-php version 0.43.2 (https://github.com/atom/language-php) -31. language-rust version 0.4.12 (https://github.com/zargony/atom-language-rust) -32. MagicStack/MagicPython version 1.1.1 (https://github.com/MagicStack/MagicPython) -33. marked version 0.5.0 (https://github.com/markedjs/marked) -34. mdn-data version 1.1.12 (https://github.com/mdn/data) -35. Microsoft/TypeScript-TmLanguage version 0.0.1 (https://github.com/Microsoft/TypeScript-TmLanguage) -36. Microsoft/vscode-JSON.tmLanguage (https://github.com/Microsoft/vscode-JSON.tmLanguage) -37. Microsoft/vscode-mssql version 1.4.0 (https://github.com/Microsoft/vscode-mssql) -38. mmims/language-batchfile version 0.7.4 (https://github.com/mmims/language-batchfile) -39. octicons version 8.3.0 (https://github.com/primer/octicons) -40. PowerShell/EditorSyntax (https://github.com/powershell/editorsyntax) -41. promise-polyfill version 8.0.0 (https://github.com/taylorhakes/promise-polyfill) -42. seti-ui version 0.1.0 (https://github.com/jesseweed/seti-ui) -43. shaders-tmLanguage version 0.1.0 (https://github.com/tgjones/shaders-tmLanguage) -44. textmate/asp.vb.net.tmbundle (https://github.com/textmate/asp.vb.net.tmbundle) -45. textmate/c.tmbundle (https://github.com/textmate/c.tmbundle) -46. textmate/diff.tmbundle (https://github.com/textmate/diff.tmbundle) -47. textmate/git.tmbundle (https://github.com/textmate/git.tmbundle) -48. textmate/groovy.tmbundle (https://github.com/textmate/groovy.tmbundle) -49. textmate/html.tmbundle (https://github.com/textmate/html.tmbundle) -50. textmate/ini.tmbundle (https://github.com/textmate/ini.tmbundle) -51. textmate/javascript.tmbundle (https://github.com/textmate/javascript.tmbundle) -52. textmate/lua.tmbundle (https://github.com/textmate/lua.tmbundle) -53. textmate/markdown.tmbundle (https://github.com/textmate/markdown.tmbundle) -54. textmate/perl.tmbundle (https://github.com/textmate/perl.tmbundle) -55. textmate/ruby.tmbundle (https://github.com/textmate/ruby.tmbundle) -56. textmate/yaml.tmbundle (https://github.com/textmate/yaml.tmbundle) -57. TypeScript-TmLanguage version 0.1.8 (https://github.com/Microsoft/TypeScript-TmLanguage) -58. TypeScript-TmLanguage version 1.0.0 (https://github.com/Microsoft/TypeScript-TmLanguage) -59. Unicode version 12.0.0 (http://www.unicode.org/) -60. vscode-logfile-highlighter version 2.4.1 (https://github.com/emilast/vscode-logfile-highlighter) -61. vscode-octicons-font version 1.0.0 (https://github.com/Microsoft/vscode-octicons-font) -62. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift) -63. Web Background Synchronization (https://github.com/WICG/BackgroundSync) +10. Colorsublime-Themes version 0.1.0 (https://github.com/Colorsublime/Colorsublime-Themes) +11. daaain/Handlebars version 1.7.1 (https://github.com/daaain/Handlebars) +12. davidrios/pug-tmbundle (https://github.com/davidrios/pug-tmbundle) +13. definitelytyped (https://github.com/DefinitelyTyped/DefinitelyTyped) +14. demyte/language-cshtml version 0.3.0 (https://github.com/demyte/language-cshtml) +15. Document Object Model version 4.0.0 (https://www.w3.org/DOM/) +16. dotnet/csharp-tmLanguage version 0.1.0 (https://github.com/dotnet/csharp-tmLanguage) +17. expand-abbreviation version 0.5.8 (https://github.com/emmetio/expand-abbreviation) +18. fadeevab/make.tmbundle (https://github.com/fadeevab/make.tmbundle) +19. freebroccolo/atom-language-swift (https://github.com/freebroccolo/atom-language-swift) +20. HTML 5.1 W3C Working Draft version 08 October 2015 (http://www.w3.org/TR/2015/WD-html51-20151008/) +21. Ikuyadeu/vscode-R version 0.5.5 (https://github.com/Ikuyadeu/vscode-R) +22. Ionic documentation version 1.2.4 (https://github.com/ionic-team/ionic-site) +23. ionide/ionide-fsgrammar (https://github.com/ionide/ionide-fsgrammar) +24. js-beautify version 1.6.8 (https://github.com/beautify-web/js-beautify) +25. Jxck/assert version 1.0.0 (https://github.com/Jxck/assert) +26. language-docker (https://github.com/moby/moby) +27. language-go version 0.44.3 (https://github.com/atom/language-go) +28. language-less version 0.34.2 (https://github.com/atom/language-less) +29. language-php version 0.44.1 (https://github.com/atom/language-php) +30. language-rust version 0.4.12 (https://github.com/zargony/atom-language-rust) +31. MagicStack/MagicPython version 1.1.1 (https://github.com/MagicStack/MagicPython) +32. marked version 0.5.0 (https://github.com/markedjs/marked) +33. mdn-data version 1.1.12 (https://github.com/mdn/data) +34. Microsoft/TypeScript-TmLanguage version 0.0.1 (https://github.com/Microsoft/TypeScript-TmLanguage) +35. Microsoft/vscode-JSON.tmLanguage (https://github.com/Microsoft/vscode-JSON.tmLanguage) +36. Microsoft/vscode-mssql version 1.4.0 (https://github.com/Microsoft/vscode-mssql) +37. mmims/language-batchfile version 0.7.5 (https://github.com/mmims/language-batchfile) +38. octicons version 8.3.0 (https://github.com/primer/octicons) +39. PowerShell/EditorSyntax (https://github.com/powershell/editorsyntax) +40. promise-polyfill version 8.0.0 (https://github.com/taylorhakes/promise-polyfill) +41. seti-ui version 0.1.0 (https://github.com/jesseweed/seti-ui) +42. shaders-tmLanguage version 0.1.0 (https://github.com/tgjones/shaders-tmLanguage) +43. textmate/asp.vb.net.tmbundle (https://github.com/textmate/asp.vb.net.tmbundle) +44. textmate/c.tmbundle (https://github.com/textmate/c.tmbundle) +45. textmate/diff.tmbundle (https://github.com/textmate/diff.tmbundle) +46. textmate/git.tmbundle (https://github.com/textmate/git.tmbundle) +47. textmate/groovy.tmbundle (https://github.com/textmate/groovy.tmbundle) +48. textmate/html.tmbundle (https://github.com/textmate/html.tmbundle) +49. textmate/ini.tmbundle (https://github.com/textmate/ini.tmbundle) +50. textmate/javascript.tmbundle (https://github.com/textmate/javascript.tmbundle) +51. textmate/lua.tmbundle (https://github.com/textmate/lua.tmbundle) +52. textmate/markdown.tmbundle (https://github.com/textmate/markdown.tmbundle) +53. textmate/perl.tmbundle (https://github.com/textmate/perl.tmbundle) +54. textmate/ruby.tmbundle (https://github.com/textmate/ruby.tmbundle) +55. textmate/yaml.tmbundle (https://github.com/textmate/yaml.tmbundle) +56. TypeScript-TmLanguage version 0.1.8 (https://github.com/Microsoft/TypeScript-TmLanguage) +57. TypeScript-TmLanguage version 1.0.0 (https://github.com/Microsoft/TypeScript-TmLanguage) +58. Unicode version 12.0.0 (http://www.unicode.org/) +59. vscode-logfile-highlighter version 2.4.1 (https://github.com/emilast/vscode-logfile-highlighter) +60. vscode-octicons-font version 1.0.0 (https://github.com/Microsoft/vscode-octicons-font) +61. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift) +62. Web Background Synchronization (https://github.com/WICG/BackgroundSync) %% atom/language-c NOTICES AND INFORMATION BEGIN HERE @@ -452,22 +451,6 @@ suitability for any purpose. ========================================= END OF atom/language-xml NOTICES AND INFORMATION -%% chriskempson/tomorrow-theme NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (C) 2013 Chris Kempson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF chriskempson/tomorrow-theme NOTICES AND INFORMATION - %% Colorsublime-Themes NOTICES AND INFORMATION BEGIN HERE ========================================= Copyright (c) 2015 Colorsublime.com diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index 26e7bcc9f7e..27f9628768b 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -1,7 +1,7 @@ [ { "name": "ms-vscode.node-debug", - "version": "1.32.2", + "version": "1.32.4", "repo": "https://github.com/Microsoft/vscode-node-debug", "metadata": { "id": "b6ded8fb-a0a0-4c1c-acbd-ab2a3bc995a6", @@ -16,7 +16,7 @@ }, { "name": "ms-vscode.node-debug2", - "version": "1.31.6", + "version": "1.32.0", "repo": "https://github.com/Microsoft/vscode-node-debug2", "metadata": { "id": "36d19e17-7569-4841-a001-947eb18602b2", diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index 529d85c37aa..1770b2c149d 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -64,6 +64,7 @@ const vscodeResources = [ 'out-build/paths.js', 'out-build/vs/**/*.{svg,png,cur,html}', 'out-build/vs/base/common/performance.js', + 'out-build/vs/base/node/languagePacks.js', 'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh}', 'out-build/vs/base/browser/ui/octiconLabel/octicons/**', 'out-build/vs/workbench/browser/media/*-theme.css', diff --git a/build/lib/i18n.js b/build/lib/i18n.js index 8c408417fae..f2340ae2035 100644 --- a/build/lib/i18n.js +++ b/build/lib/i18n.js @@ -1033,7 +1033,7 @@ function prepareI18nPackFiles(externalExtensions, resultingTranslationPaths, pse let extensionsPacks = {}; let errors = []; return event_stream_1.through(function (xlf) { - let project = path.dirname(xlf.relative); + let project = path.basename(path.dirname(xlf.relative)); let resource = path.basename(xlf.relative, '.xlf'); let contents = xlf.contents.toString(); let parsePromise = pseudo ? XLF.parsePseudo(contents) : XLF.parse(contents); diff --git a/build/lib/i18n.ts b/build/lib/i18n.ts index 33864e4e667..ee80c046670 100644 --- a/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -1186,7 +1186,7 @@ export function prepareI18nPackFiles(externalExtensions: Map, resultingT let extensionsPacks: Map = {}; let errors: any[] = []; return through(function (this: ThroughStream, xlf: File) { - let project = path.dirname(xlf.relative); + let project = path.basename(path.dirname(xlf.relative)); let resource = path.basename(xlf.relative, '.xlf'); let contents = xlf.contents.toString(); let parsePromise = pseudo ? XLF.parsePseudo(contents) : XLF.parse(contents); diff --git a/extensions/debug-server-ready/.vscodeignore b/extensions/debug-server-ready/.vscodeignore new file mode 100644 index 00000000000..36e8b0714fa --- /dev/null +++ b/extensions/debug-server-ready/.vscodeignore @@ -0,0 +1,5 @@ +src/** +tsconfig.json +out/** +extension.webpack.config.js +yarn.lock \ No newline at end of file diff --git a/extensions/debug-server-ready/extension.webpack.config.js b/extensions/debug-server-ready/extension.webpack.config.js new file mode 100644 index 00000000000..b474e65cbb1 --- /dev/null +++ b/extensions/debug-server-ready/extension.webpack.config.js @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +'use strict'; + +const withDefaults = require('../shared.webpack.config'); + +module.exports = withDefaults({ + context: __dirname, + entry: { + extension: './src/extension.ts', + }, + resolve: { + mainFields: ['module', 'main'] + } +}); diff --git a/extensions/debug-server-ready/package.json b/extensions/debug-server-ready/package.json new file mode 100644 index 00000000000..7d84a8e27d5 --- /dev/null +++ b/extensions/debug-server-ready/package.json @@ -0,0 +1,74 @@ +{ + "name": "debug-server-ready", + "displayName": "%displayName%", + "description": "%description%", + "version": "1.0.0", + "publisher": "vscode", + "engines": { + "vscode": "^1.32.0" + }, + "activationEvents": [ + "onDebugResolve" + ], + "main": "./out/extension", + "scripts": { + "compile": "gulp compile-extension:debug-server-ready", + "watch": "gulp watch-extension:debug-server-ready" + }, + "contributes": { + "debuggers": [ + { + "type": "*", + "configurationAttributes": { + "launch": { + "properties": { + "serverReadyAction": { + "type": "object", + "markdownDescription": "%debug.server.ready.serverReadyAction.description%", + "default": { + "action": "openExternally" + }, + "properties": { + "pattern": { + "type": "string", + "markdownDescription": "%debug.server.ready.pattern.description%", + "default": "listening on port ([0-9]+)" + }, + "uriFormat": { + "type": "string", + "markdownDescription": "%debug.server.ready.uriFormat.description%", + "default": "http://localhost:%s" + }, + "action": { + "type": "string", + "enum": [ + "openExternally", + "debugWithChrome" + ], + "enumDescriptions": [ + "%debug.server.ready.action.openExternally.description%", + "%debug.server.ready.action.debugWithChrome.description%" + ], + "markdownDescription": "%debug.server.ready.action.description%", + "default": "openExternally" + }, + "webRoot": { + "type": "string", + "markdownDescription": "%debug.server.ready.webRoot.description%", + "default": "${workspaceFolder}" + } + } + } + } + } + } + } + ] + }, + "dependencies": { + "vscode-nls": "^4.0.0" + }, + "devDependencies": { + "@types/node": "8.0.33" + } +} diff --git a/extensions/debug-server-ready/package.nls.json b/extensions/debug-server-ready/package.nls.json new file mode 100644 index 00000000000..e9d2705cfc9 --- /dev/null +++ b/extensions/debug-server-ready/package.nls.json @@ -0,0 +1,12 @@ +{ + "displayName": "Server Ready Action", + "description": "Open URI in browser if server under debugging is ready.", + + "debug.server.ready.serverReadyAction.description": "Act upon a URI when a server program under debugging is ready (indicated by sending output of the form 'listening on port 3000' or 'Now listening on: https://localhost:5001' to the debug console.)", + "debug.server.ready.action.description": "What to do with the URI when the server is ready.", + "debug.server.ready.action.openExternally.description": "Open URI externally with the default application.", + "debug.server.ready.action.debugWithChrome.description": "Start debugging with the 'Debugger for Chrome'.", + "debug.server.ready.pattern.description": "Server is ready if this pattern appears on the debug console. The first capture group must include a URI or a port number.", + "debug.server.ready.uriFormat.description": "A format string used when constructing the URI from a port number. The first '%s' is substituted with the port number.", + "debug.server.ready.webRoot.description": "Value passed to the debug configuration for the 'Debugger for Chrome'." +} diff --git a/extensions/debug-server-ready/src/extension.ts b/extensions/debug-server-ready/src/extension.ts new file mode 100644 index 00000000000..1aecc7ec852 --- /dev/null +++ b/extensions/debug-server-ready/src/extension.ts @@ -0,0 +1,97 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; +//import * as nls from 'vscode-nls'; +import * as util from 'util'; + +const trackers = new Set(); + +const PATTERN = 'listening on.* (https?://\\S+|[0-9]+)'; // matches "listening on port 3000" or "Now listening on: https://localhost:5001" +const URI_FORMAT = 'http://localhost:%s'; +const WEB_ROOT = '${workspaceFolder}'; + +interface ServerReadyAction { + pattern: string; + action?: 'openExternally' | 'debugWithChrome'; + uriFormat?: string; + webRoot?: string; +} + +export function activate(context: vscode.ExtensionContext) { + + context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('*', { + resolveDebugConfiguration(_folder: vscode.WorkspaceFolder | undefined, debugConfiguration: vscode.DebugConfiguration) { + const args: ServerReadyAction = debugConfiguration.serverReadyAction; + if (debugConfiguration.type && args) { + startTrackerForType(context, debugConfiguration.type); + } + return debugConfiguration; + } + })); +} + +function startTrackerForType(context: vscode.ExtensionContext, type: string) { + + if (!trackers.has(type)) { + trackers.add(type); + + // scan debug console output for a PORT message + context.subscriptions.push(vscode.debug.registerDebugAdapterTrackerFactory(type, { + createDebugAdapterTracker(session: vscode.DebugSession) { + const args: ServerReadyAction = session.configuration.serverReadyAction; + if (args) { + const regexp = new RegExp(args.pattern || PATTERN); + let hasFired = false; + return { + onDidSendMessage: m => { + if (!hasFired && m.type === 'event' && m.event === 'output' && m.body.output) { + const result = regexp.exec(m.body.output); + if (result && result.length === 2) { + openExternalWithString(session, result[1]); + hasFired = true; + } + } + } + }; + } + return undefined; + } + })); + } +} + +function openExternalWithString(session: vscode.DebugSession, portOrUriString: string) { + + if (portOrUriString) { + if (/^[0-9]+$/.test(portOrUriString)) { + const args: ServerReadyAction = session.configuration.serverReadyAction; + portOrUriString = util.format(args.uriFormat || URI_FORMAT, portOrUriString); + } + openExternalWithUri(session, portOrUriString); + } +} + +function openExternalWithUri(session: vscode.DebugSession, uri: string) { + + const args: ServerReadyAction = session.configuration.serverReadyAction; + switch (args.action || 'openExternally') { + case 'openExternally': + vscode.env.openExternal(vscode.Uri.parse(uri)); + break; + case 'debugWithChrome': + vscode.debug.startDebugging(session.workspaceFolder, { + type: 'chrome', + name: 'Chrome Debug', + request: 'launch', + url: uri, + webRoot: args.webRoot || WEB_ROOT + }); + break; + default: + // not supported + break; + } +} diff --git a/extensions/debug-server-ready/src/typings/ref.d.ts b/extensions/debug-server-ready/src/typings/ref.d.ts new file mode 100644 index 00000000000..bc057c55878 --- /dev/null +++ b/extensions/debug-server-ready/src/typings/ref.d.ts @@ -0,0 +1,7 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/// +/// diff --git a/extensions/debug-server-ready/tsconfig.json b/extensions/debug-server-ready/tsconfig.json new file mode 100644 index 00000000000..f9b780a0e1c --- /dev/null +++ b/extensions/debug-server-ready/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../shared.tsconfig.json", + "compilerOptions": { + "outDir": "./out", + "downlevelIteration": true + }, + "include": [ + "src/**/*" + ] +} \ No newline at end of file diff --git a/extensions/debug-server-ready/yarn.lock b/extensions/debug-server-ready/yarn.lock new file mode 100644 index 00000000000..6767cb8d8c2 --- /dev/null +++ b/extensions/debug-server-ready/yarn.lock @@ -0,0 +1,13 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/node@8.0.33": + version "8.0.33" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd" + integrity sha512-vmCdO8Bm1ExT+FWfC9sd9r4jwqM7o97gGy2WBshkkXbf/2nLAJQUrZfIhw27yVOtLUev6kSZc4cav/46KbDd8A== + +vscode-nls@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" + integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== diff --git a/extensions/emmet/src/util.ts b/extensions/emmet/src/util.ts index 2b6ab87c98b..c90ff7f5c25 100644 --- a/extensions/emmet/src/util.ts +++ b/extensions/emmet/src/util.ts @@ -96,10 +96,10 @@ export function getMappingForIncludedLanguages(): any { /** * Get the corresponding emmet mode for given vscode language mode * Eg: jsx for typescriptreact/javascriptreact or pug for jade -* If the language is not supported by emmet or has been exlcuded via `exlcudeLanguages` setting, +* If the language is not supported by emmet or has been excluded via `excludeLanguages` setting, * then nothing is returned * -* @param exlcudedLanguages Array of language ids that user has chosen to exlcude for emmet +* @param excludedLanguages Array of language ids that user has chosen to exclude for emmet */ export function getEmmetMode(language: string, excludedLanguages: string[]): string | undefined { if (!language || excludedLanguages.indexOf(language) > -1) { diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index eb45f107f4b..8344525db3d 100755 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1458,8 +1458,7 @@ export class CommandCenter { name.trim().replace(/^\.|\/\.|\.\.|~|\^|:|\/$|\.lock$|\.lock\/|\\|\*|\s|^\s*$|\.$|\[|\]$/g, branchWhitespaceChar) : name; - const rawBranchName = await window.showInputBox({ - value: defaultName, + const rawBranchName = defaultName || await window.showInputBox({ placeHolder: localize('branch name', "Branch name"), prompt: localize('provide branch name', "Please provide a branch name"), ignoreFocusOut: true, @@ -1480,7 +1479,7 @@ export class CommandCenter { } const picks = [new HEADItem(repository), ...createCheckoutItems(repository)]; - const placeHolder = localize('select a ref to create a new branch from', 'Select a ref to create a new branch from'); + const placeHolder = localize('select a ref to create a new branch from', 'Select a ref to create the \'{0}\' branch from', branchName); const target = await window.showQuickPick(picks, { placeHolder }); if (!target) { diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 8446b9041fe..3d81a59c78f 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -1201,7 +1201,7 @@ export class Repository { } async branch(name: string, checkout: boolean, ref?: string): Promise { - const args = checkout ? ['checkout', '-q', '-b', name] : ['branch', '-q', name]; + const args = checkout ? ['checkout', '-q', '-b', name, '--no-track'] : ['branch', '-q', name]; if (ref) { args.push(ref); diff --git a/extensions/html-language-features/client/src/htmlMain.ts b/extensions/html-language-features/client/src/htmlMain.ts index 848ed4c6fad..696bc074c84 100644 --- a/extensions/html-language-features/client/src/htmlMain.ts +++ b/extensions/html-language-features/client/src/htmlMain.ts @@ -47,7 +47,7 @@ export function activate(context: ExtensionContext) { debug: { module: serverModule, transport: TransportKind.ipc, options: debugOptions } }; - let documentSelector = ['html', 'handlebars', 'razor']; + let documentSelector = ['html', 'handlebars']; let embeddedLanguages = { css: true, javascript: true }; let dataPaths = [ @@ -78,7 +78,7 @@ export function activate(context: ExtensionContext) { let param = client.code2ProtocolConverter.asTextDocumentPositionParams(document, position); return client.sendRequest(TagCloseRequest.type, param); }; - disposable = activateTagClosing(tagRequestor, { html: true, handlebars: true, razor: true }, 'html.autoClosingTags'); + disposable = activateTagClosing(tagRequestor, { html: true, handlebars: true }, 'html.autoClosingTags'); toDispose.push(disposable); disposable = client.onTelemetry(e => { @@ -143,21 +143,6 @@ export function activate(context: ExtensionContext) { ], }); - languages.setLanguageConfiguration('razor', { - wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\$\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\s]+)/g, - onEnterRules: [ - { - beforeText: new RegExp(`<(?!(?:${EMPTY_ELEMENTS.join('|')}))([_:\\w][_:\\w-.\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), - afterText: /^<\/([_:\w][_:\w-.\d]*)\s*>/i, - action: { indentAction: IndentAction.IndentOutdent } - }, - { - beforeText: new RegExp(`<(?!(?:${EMPTY_ELEMENTS.join('|')}))(\\w[\\w\\d]*)([^/>]*(?!/)>)[^<]*$`, 'i'), - action: { indentAction: IndentAction.Indent } - } - ], - }); - const regionCompletionRegExpr = /^(\s*)(<(!(-(-\s*(#\w*)?)?)?)?)?$/; languages.registerCompletionItemProvider(documentSelector, { provideCompletionItems(doc, pos) { diff --git a/extensions/html-language-features/package.json b/extensions/html-language-features/package.json index 29be30d1cea..64fe111d64b 100644 --- a/extensions/html-language-features/package.json +++ b/extensions/html-language-features/package.json @@ -12,8 +12,7 @@ "icon": "icons/html.png", "activationEvents": [ "onLanguage:html", - "onLanguage:handlebars", - "onLanguage:razor" + "onLanguage:handlebars" ], "main": "./client/out/htmlMain", "scripts": { diff --git a/extensions/html-language-features/package.nls.json b/extensions/html-language-features/package.nls.json index 9c172ebcb7f..6a436fa5cb3 100644 --- a/extensions/html-language-features/package.nls.json +++ b/extensions/html-language-features/package.nls.json @@ -1,6 +1,6 @@ { "displayName": "HTML Language Features", - "description": "Provides rich language support for HTML, Razor, and Handlebar files", + "description": "Provides rich language support for HTML and Handlebar files", "html.format.enable.desc": "Enable/disable default HTML formatter.", "html.format.wrapLineLength.desc": "Maximum amount of characters per line (0 = disable).", "html.format.unformatted.desc": "List of tags, comma separated, that shouldn't be reformatted. `null` defaults to all tags listed at https://www.w3.org/TR/html5/dom.html#phrasing-content.", diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index 4a1951e41e7..bfc23ebe0bc 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -10,7 +10,7 @@ "main": "./out/htmlServerMain", "dependencies": { "vscode-css-languageservice": "^3.0.13-next.10", - "vscode-html-languageservice": "^2.1.11-next.11", + "vscode-html-languageservice": "^2.1.11", "vscode-languageserver": "^5.1.0", "vscode-languageserver-types": "^3.13.0", "vscode-nls": "^4.0.0", diff --git a/extensions/html-language-features/server/src/htmlServerMain.ts b/extensions/html-language-features/server/src/htmlServerMain.ts index c904afe354c..43ae7d5070c 100644 --- a/extensions/html-language-features/server/src/htmlServerMain.ts +++ b/extensions/html-language-features/server/src/htmlServerMain.ts @@ -175,7 +175,7 @@ connection.onDidChangeConfiguration((change) => { const enableFormatter = globalSettings && globalSettings.html && globalSettings.html.format && globalSettings.html.format.enable; if (enableFormatter) { if (!formatterRegistration) { - const documentSelector: DocumentSelector = [{ language: 'html' }, { language: 'handlebars' }]; // don't register razor, the formatter does more harm than good + const documentSelector: DocumentSelector = [{ language: 'html' }, { language: 'handlebars' }]; formatterRegistration = connection.client.register(DocumentRangeFormattingRequest.type, { documentSelector }); } } else if (formatterRegistration) { diff --git a/extensions/html-language-features/server/yarn.lock b/extensions/html-language-features/server/yarn.lock index e70561f1a73..5173fd2b003 100644 --- a/extensions/html-language-features/server/yarn.lock +++ b/extensions/html-language-features/server/yarn.lock @@ -237,10 +237,10 @@ vscode-css-languageservice@^3.0.13-next.10: vscode-languageserver-types "^3.13.0" vscode-nls "^4.0.0" -vscode-html-languageservice@^2.1.11-next.11: - version "2.1.11-next.11" - resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-2.1.11-next.11.tgz#7dd00c07790d05751d5a40164b6983b0fd8cd02b" - integrity sha512-NOJRP1hCuEORd/Zs7yK4sQBRML6APDZ5zOMvbXRCVk5VyFx+KD0/uWjJWKnvgQMUONEMGD5emSFbSy8h80MtXw== +vscode-html-languageservice@^2.1.11: + version "2.1.11" + resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-2.1.11.tgz#56fc25cf64793a9eaef2f571a0ecd591eaed26c1" + integrity sha512-wfENgWb7JjEhwsRHXhairumuxAGnFcMUwIut5P7SxGwNrJMDXkgfs6OUBZycQpbaXTkMEvwsKNKFqUQppW7P4g== dependencies: vscode-languageserver-types "^3.13.0" vscode-nls "^4.0.0" diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index a48161bb43d..959af9a9794 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -14,7 +14,7 @@ "dependencies": { "jsonc-parser": "^2.0.2", "request-light": "^0.2.4", - "vscode-json-languageservice": "^3.3.0-next.2", + "vscode-json-languageservice": "^3.3.0-next.4", "vscode-languageserver": "^5.1.0", "vscode-nls": "^4.0.0", "vscode-uri": "^1.0.6" diff --git a/extensions/json-language-features/server/src/jsonServerMain.ts b/extensions/json-language-features/server/src/jsonServerMain.ts index a5fc3e6940e..a01a4ea3a3f 100644 --- a/extensions/json-language-features/server/src/jsonServerMain.ts +++ b/extensions/json-language-features/server/src/jsonServerMain.ts @@ -13,7 +13,6 @@ import { xhr, XHRResponse, configure as configureHttpRequests, getErrorStatusDes import * as fs from 'fs'; import URI from 'vscode-uri'; import * as URL from 'url'; -import { startsWith } from './utils/strings'; import { formatError, runSafe, runSafeAsync } from './utils/runner'; import { JSONDocument, JSONSchema, getLanguageService, DocumentLanguageSettings, SchemaConfiguration } from 'vscode-json-languageservice'; import { getLanguageModelCache } from './languageModelCache'; @@ -57,46 +56,51 @@ const workspaceContext = { return URL.resolve(resource, relativePath); } }; +function getSchemaRequestService(handledSchemas: { [schema: string]: boolean }) { -const schemaRequestService = (uri: string): Thenable => { - if (startsWith(uri, 'file://')) { - const fsPath = URI.parse(uri).fsPath; - return new Promise((c, e) => { - fs.readFile(fsPath, 'UTF-8', (err, result) => { - err ? e(err.message || err.toString()) : c(result.toString()); - }); - }); - } else if (startsWith(uri, 'vscode://')) { + return (uri: string): Thenable => { + const protocol = uri.substr(0, uri.indexOf(':')); + + if (!handledSchemas || handledSchemas[protocol]) { + if (protocol === 'file') { + const fsPath = URI.parse(uri).fsPath; + return new Promise((c, e) => { + fs.readFile(fsPath, 'UTF-8', (err, result) => { + err ? e(err.message || err.toString()) : c(result.toString()); + }); + }); + } else if (protocol === 'http' || protocol === 'https') { + if (uri.indexOf('//schema.management.azure.com/') !== -1) { + /* __GDPR__ + "json.schema" : { + "schemaURL" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } + */ + connection.telemetry.logEvent({ + key: 'json.schema', + value: { + schemaURL: uri + } + }); + } + const headers = { 'Accept-Encoding': 'gzip, deflate' }; + return xhr({ url: uri, followRedirects: 5, headers }).then(response => { + return response.responseText; + }, (error: XHRResponse) => { + return Promise.reject(error.responseText || getErrorStatusDescription(error.status) || error.toString()); + }); + } + } return connection.sendRequest(VSCodeContentRequest.type, uri).then(responseText => { return responseText; }, error => { return Promise.reject(error.message); }); - } - if (uri.indexOf('//schema.management.azure.com/') !== -1) { - /* __GDPR__ - "json.schema" : { - "schemaURL" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - connection.telemetry.logEvent({ - key: 'json.schema', - value: { - schemaURL: uri - } - }); - } - const headers = { 'Accept-Encoding': 'gzip, deflate' }; - return xhr({ url: uri, followRedirects: 5, headers }).then(response => { - return response.responseText; - }, (error: XHRResponse) => { - return Promise.reject(error.responseText || getErrorStatusDescription(error.status) || error.toString()); - }); -}; + }; +} // create the JSON language service let languageService = getLanguageService({ - schemaRequestService, workspaceContext, contributions: [], }); @@ -117,8 +121,10 @@ let hierarchicalDocumentSymbolSupport = false; // in the passed params the rootPath of the workspace plus the client capabilities. connection.onInitialize((params: InitializeParams): InitializeResult => { + const handledProtocols = params.initializationOptions && params.initializationOptions['handledSchemaProtocols']; + languageService = getLanguageService({ - schemaRequestService, + schemaRequestService: getSchemaRequestService(handledProtocols), workspaceContext, contributions: [], clientCapabilities: params.capabilities diff --git a/extensions/json-language-features/server/src/utils/strings.ts b/extensions/json-language-features/server/src/utils/strings.ts index 837f7238737..42a617f8a8a 100644 --- a/extensions/json-language-features/server/src/utils/strings.ts +++ b/extensions/json-language-features/server/src/utils/strings.ts @@ -3,20 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -export function startsWith(haystack: string, needle: string): boolean { - if (haystack.length < needle.length) { - return false; - } - - for (let i = 0; i < needle.length; i++) { - if (haystack[i] !== needle[i]) { - return false; - } - } - - return true; -} - /** * Determines if haystack ends with needle. */ diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 598acb7c066..7a974ff4a2b 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -73,10 +73,10 @@ request-light@^0.2.4: https-proxy-agent "^2.2.1" vscode-nls "^4.0.0" -vscode-json-languageservice@^3.3.0-next.2: - version "3.3.0-next.2" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.3.0-next.2.tgz#32ac8546a7b80d910b72b0f18ef591d917fa6938" - integrity sha512-ny4vye7kqJfzm31Gvt/zkrNoav2iyck6njmdtugjWslWx1i8ZPSCa1FyPRajnORJpTXu9VC+2oYl2Vmliuywog== +vscode-json-languageservice@^3.3.0-next.4: + version "3.3.0-next.4" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.3.0-next.4.tgz#e13b2fd5665b754ee94608a506407cd12b63d64d" + integrity sha512-tD8w2SvwERj3392q34xXKA/i76WWK7YwmP9eoLdKvdfMRwXB7a0MYWPoYZD4HycwvavAlbJ2x18vP4G7+BFA+A== dependencies: jsonc-parser "^2.0.2" vscode-languageserver-types "^3.13.0" diff --git a/extensions/markdown-language-features/cgmanifest.json b/extensions/markdown-language-features/cgmanifest.json index 89c68532e25..71df78ef41f 100644 --- a/extensions/markdown-language-features/cgmanifest.json +++ b/extensions/markdown-language-features/cgmanifest.json @@ -1,28 +1,5 @@ { "registrations": [ - { - "component": { - "type": "git", - "git": { - "name": "chriskempson/tomorrow-theme", - "repositoryUrl": "https://github.com/chriskempson/tomorrow-theme", - "commitHash": "0e0d35ac303f99b8aa182091ebeaee81cf2183a0" - } - }, - "licenseDetail": [ - "Copyright (C) 2013 Chris Kempson", - "", - "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,", - "and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:", - "", - "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.", - "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER", - "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." - ], - "license": "MIT", - "version": "0.0.0" - }, { "component": { "type": "git", @@ -52,4 +29,4 @@ } ], "version": 1 -} +} \ No newline at end of file diff --git a/extensions/package.json b/extensions/package.json index 88394d29642..94c17380115 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "3.3.3" + "typescript": "3.3.3333" }, "scripts": { "postinstall": "node ./postinstall" diff --git a/extensions/shared.tsconfig.json b/extensions/shared.tsconfig.json index 1cbda1bf9f0..bb42dd479cf 100644 --- a/extensions/shared.tsconfig.json +++ b/extensions/shared.tsconfig.json @@ -1,11 +1,7 @@ { "compilerOptions": { - "target": "es2017", + "target": "es2018", "module": "commonjs", - "lib": [ - "es6", - "es2015.promise" - ], "strict": true, "alwaysStrict": true, "noImplicitAny": true, diff --git a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts index 4cf76147d16..32c0b020e6b 100644 --- a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts +++ b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as fs from 'fs'; import * as vscode from 'vscode'; import * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; @@ -157,8 +156,7 @@ class GetErrRequest { }; client.executeAsync('geterr', args, _token.token) - .catch(() => true) - .then(() => { + .finally(() => { if (this._done) { return; } @@ -267,10 +265,8 @@ export default class BufferSyncSupport extends Disposable { this.pendingDiagnostics.delete(resource); this.syncedBuffers.delete(resource); syncedBuffer.close(); - if (!fs.existsSync(resource.fsPath)) { - this._onDelete.fire(resource); - this.requestAllDiagnostics(); - } + this._onDelete.fire(resource); + this.requestAllDiagnostics(); } public interuptGetErr(f: () => R): R { diff --git a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts index 9c76d5e50ab..890a30fcc06 100644 --- a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts +++ b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts @@ -55,7 +55,6 @@ export default class TypeScriptServiceClientHost extends Disposable { ) { super(); const handleProjectCreateOrDelete = () => { - this.client.executeWithoutWaitingForResponse('reloadProjects', null); this.triggerAllDiagnostics(); }; const handleProjectChange = () => { diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts index 5875ea81fb0..81c9c2eeadf 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts @@ -10,6 +10,8 @@ import { createRandomFile } from '../utils'; suite('languages namespace tests', () => { + const isWindows = process.platform === 'win32'; + function positionToString(p: vscode.Position) { return `[${p.character}/${p.line}]`; } @@ -93,7 +95,7 @@ suite('languages namespace tests', () => { const uri = await createRandomFile('class A { // http://a.com }', undefined, '.java'); const doc = await vscode.workspace.openTextDocument(uri); - const target = vscode.Uri.parse('file://foo/bar'); + const target = vscode.Uri.file(isWindows ? 'c:\\foo\\bar' : '/foo/bar'); const range = new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 5)); const linkProvider: vscode.DocumentLinkProvider = { diff --git a/extensions/yarn.lock b/extensions/yarn.lock index abf61b0ecfa..568fe29f5bf 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -typescript@3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.3.tgz#f1657fc7daa27e1a8930758ace9ae8da31403221" - integrity sha512-Y21Xqe54TBVp+VDSNbuDYdGw0BpoR/Q6wo/+35M8PAU0vipahnyduJWirxxdxjsAkS7hue53x2zp8gz7F05u0A== +typescript@3.3.3333: + version "3.3.3333" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.3333.tgz#171b2c5af66c59e9431199117a3bcadc66fdcfd6" + integrity sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw== diff --git a/package.json b/package.json index 98fc1ab153c..d392e69ab0c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.32.0", - "distro": "6f5d9db8821add003be71e726b4ef49df83a51b4", + "distro": "d7aadf23b016949c24a43083a0b3deecb8aa81fa", "author": { "name": "Microsoft Corporation" }, @@ -46,7 +46,7 @@ "sudo-prompt": "8.2.0", "v8-inspect-profiler": "^0.0.20", "vscode-chokidar": "1.6.5", - "vscode-debugprotocol": "^1.34.0-pre.0", + "vscode-debugprotocol": "1.34.0", "vscode-nsfw": "1.1.1", "vscode-proxy-agent": "0.4.0", "vscode-ripgrep": "^1.2.5", @@ -145,6 +145,7 @@ "url": "https://github.com/Microsoft/vscode/issues" }, "optionalDependencies": { + "vscode-windows-registry": "1.0.1", "windows-foreground-love": "0.1.0", "windows-mutex": "0.2.1", "windows-process-tree": "0.2.3" diff --git a/src/bootstrap.js b/src/bootstrap.js index af8939f66a1..28e91998f31 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -118,6 +118,36 @@ exports.writeFile = function (file, content) { }); }); }; + +/** + * @param {string} dir + * @returns {Promise} + */ +function mkdir(dir) { + const fs = require('fs'); + + return new Promise((c, e) => fs.mkdir(dir, err => (err && err.code !== 'EEXIST') ? e(err) : c(dir))); +} + +/** + * @param {string} dir + * @returns {Promise} + */ +exports.mkdirp = function mkdirp(dir) { + const path = require('path'); + + return mkdir(dir).then(null, err => { + if (err && err.code === 'ENOENT') { + const parent = path.dirname(dir); + + if (parent !== dir) { // if not arrived at root + return mkdirp(parent).then(() => mkdir(dir)); + } + } + + throw err; + }); +}; //#endregion //#region NLS helpers diff --git a/src/main.js b/src/main.js index d846bcd0173..95390941b16 100644 --- a/src/main.js +++ b/src/main.js @@ -7,6 +7,8 @@ 'use strict'; const perf = require('./vs/base/common/performance'); +const lp = require('./vs/base/node/languagePacks'); + perf.mark('main:started'); const fs = require('fs'); @@ -57,9 +59,11 @@ registerListeners(); */ let nlsConfiguration = undefined; const userDefinedLocale = getUserDefinedLocale(); +const metaDataFile = path.join(__dirname, 'nls.metadata.json'); + userDefinedLocale.then(locale => { if (locale && !nlsConfiguration) { - nlsConfiguration = getNLSConfiguration(locale); + nlsConfiguration = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale); } }); @@ -89,7 +93,7 @@ function onReady() { Promise.all([nodeCachedDataDir.ensureExists(), userDefinedLocale]).then(([cachedDataDir, locale]) => { if (locale && !nlsConfiguration) { - nlsConfiguration = getNLSConfiguration(locale); + nlsConfiguration = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale); } if (!nlsConfiguration) { @@ -129,7 +133,7 @@ function onReady() { // See above the comment about the loader and case sensitiviness appLocale = appLocale.toLowerCase(); - getNLSConfiguration(appLocale).then(nlsConfig => { + lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, appLocale).then(nlsConfig => { if (!nlsConfig) { nlsConfig = { locale: appLocale, availableLanguages: {} }; } @@ -275,7 +279,7 @@ function getNodeCachedDir() { } ensureExists() { - return mkdirp(this.value).then(() => this.value, () => { /*ignore*/ }); + return bootstrap.mkdirp(this.value).then(() => this.value, () => { /*ignore*/ }); } _compute() { @@ -328,101 +332,6 @@ function stripComments(content) { }); } -/** - * @param {string} dir - * @returns {Promise} - */ -function mkdir(dir) { - return new Promise((c, e) => fs.mkdir(dir, err => (err && err.code !== 'EEXIST') ? e(err) : c(dir))); -} - -/** - * @param {string} file - * @returns {Promise} - */ -function exists(file) { - return new Promise(c => fs.exists(file, c)); -} - -/** - * @param {string} file - * @returns {Promise} - */ -function touch(file) { - return new Promise((c, e) => { const d = new Date(); fs.utimes(file, d, d, err => err ? e(err) : c()); }); -} - -/** - * @param {string} file - * @returns {Promise} - */ -function lstat(file) { - return new Promise((c, e) => fs.lstat(file, (err, stats) => err ? e(err) : c(stats))); -} - -/** - * @param {string} dir - * @returns {Promise} - */ -function readdir(dir) { - return new Promise((c, e) => fs.readdir(dir, (err, files) => err ? e(err) : c(files))); -} - -/** - * @param {string} dir - * @returns {Promise} - */ -function rmdir(dir) { - return new Promise((c, e) => fs.rmdir(dir, err => err ? e(err) : c(undefined))); -} - -/** - * @param {string} file - * @returns {Promise} - */ -function unlink(file) { - return new Promise((c, e) => fs.unlink(file, err => err ? e(err) : c(undefined))); -} - -/** - * @param {string} dir - * @returns {Promise} - */ -function mkdirp(dir) { - return mkdir(dir).then(null, err => { - if (err && err.code === 'ENOENT') { - const parent = path.dirname(dir); - - if (parent !== dir) { // if not arrived at root - return mkdirp(parent).then(() => mkdir(dir)); - } - } - - throw err; - }); -} - -/** - * @param {string} location - * @returns {Promise} - */ -function rimraf(location) { - return lstat(location).then(stat => { - if (stat.isDirectory() && !stat.isSymbolicLink()) { - return readdir(location) - .then(children => Promise.all(children.map(child => rimraf(path.join(location, child))))) - .then(() => rmdir(location)); - } else { - return unlink(location); - } - }, err => { - if (err.code === 'ENOENT') { - return undefined; - } - throw err; - }); -} - // 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 @@ -449,175 +358,4 @@ function getUserDefinedLocale() { return undefined; }); } - -/** - * @returns {object} - */ -function getLanguagePackConfigurations() { - const configFile = path.join(userDataPath, 'languagepacks.json'); - try { - return require(configFile); - } catch (err) { - // Do nothing. If we can't read the file we have no - // language pack config. - } - return undefined; -} - -/** - * @param {object} config - * @param {string} locale - */ -function resolveLanguagePackLocale(config, locale) { - try { - while (locale) { - if (config[locale]) { - return locale; - } else { - const index = locale.lastIndexOf('-'); - if (index > 0) { - locale = locale.substring(0, index); - } else { - return undefined; - } - } - } - } catch (err) { - console.error('Resolving language pack configuration failed.', err); - } - return undefined; -} - -/** - * @param {string} locale - */ -function getNLSConfiguration(locale) { - if (locale === 'pseudo') { - return Promise.resolve({ locale: locale, availableLanguages: {}, pseudo: true }); - } - - if (process.env['VSCODE_DEV']) { - return Promise.resolve({ locale: locale, availableLanguages: {} }); - } - - // We have a built version so we have extracted nls file. Try to find - // the right file to use. - - // Check if we have an English or English US locale. If so fall to default since that is our - // English translation (we don't ship *.nls.en.json files) - if (locale && (locale === 'en' || locale === 'en-us')) { - return Promise.resolve({ locale: locale, availableLanguages: {} }); - } - - const initialLocale = locale; - - perf.mark('nlsGeneration:start'); - - const defaultResult = function (locale) { - perf.mark('nlsGeneration:end'); - return Promise.resolve({ locale: locale, availableLanguages: {} }); - }; - try { - const commit = product.commit; - if (!commit) { - return defaultResult(initialLocale); - } - const configs = getLanguagePackConfigurations(); - if (!configs) { - return defaultResult(initialLocale); - } - locale = resolveLanguagePackLocale(configs, locale); - if (!locale) { - return defaultResult(initialLocale); - } - const packConfig = configs[locale]; - let mainPack; - if (!packConfig || typeof packConfig.hash !== 'string' || !packConfig.translations || typeof (mainPack = packConfig.translations['vscode']) !== 'string') { - return defaultResult(initialLocale); - } - return exists(mainPack).then(fileExists => { - if (!fileExists) { - return defaultResult(initialLocale); - } - const packId = packConfig.hash + '.' + locale; - const cacheRoot = path.join(userDataPath, 'clp', packId); - const coreLocation = path.join(cacheRoot, commit); - const translationsConfigFile = path.join(cacheRoot, 'tcf.json'); - const corruptedFile = path.join(cacheRoot, 'corrupted.info'); - const result = { - locale: initialLocale, - availableLanguages: { '*': locale }, - _languagePackId: packId, - _translationsConfigFile: translationsConfigFile, - _cacheRoot: cacheRoot, - _resolvedLanguagePackCoreLocation: coreLocation, - _corruptedFile: corruptedFile - }; - return exists(corruptedFile).then(corrupted => { - // The nls cache directory is corrupted. - let toDelete; - if (corrupted) { - toDelete = rimraf(cacheRoot); - } else { - toDelete = Promise.resolve(undefined); - } - return toDelete.then(() => { - return exists(coreLocation).then(fileExists => { - if (fileExists) { - // We don't wait for this. No big harm if we can't touch - touch(coreLocation).catch(() => { }); - perf.mark('nlsGeneration:end'); - return result; - } - return mkdirp(coreLocation).then(() => { - return Promise.all([bootstrap.readFile(path.join(__dirname, 'nls.metadata.json')), bootstrap.readFile(mainPack)]); - }).then(values => { - const metadata = JSON.parse(values[0]); - const packData = JSON.parse(values[1]).contents; - const bundles = Object.keys(metadata.bundles); - const writes = []; - for (let bundle of bundles) { - const modules = metadata.bundles[bundle]; - const target = Object.create(null); - for (let module of modules) { - const keys = metadata.keys[module]; - const defaultMessages = metadata.messages[module]; - const translations = packData[module]; - let targetStrings; - if (translations) { - targetStrings = []; - for (let i = 0; i < keys.length; i++) { - const elem = keys[i]; - const key = typeof elem === 'string' ? elem : elem.key; - let translatedMessage = translations[key]; - if (translatedMessage === undefined) { - translatedMessage = defaultMessages[i]; - } - targetStrings.push(translatedMessage); - } - } else { - targetStrings = defaultMessages; - } - target[module] = targetStrings; - } - writes.push(bootstrap.writeFile(path.join(coreLocation, bundle.replace(/\//g, '!') + '.nls.json'), JSON.stringify(target))); - } - writes.push(bootstrap.writeFile(translationsConfigFile, JSON.stringify(packConfig.translations))); - return Promise.all(writes); - }).then(() => { - perf.mark('nlsGeneration:end'); - return result; - }).catch(err => { - console.error('Generating translation files failed.', err); - return defaultResult(locale); - }); - }); - }); - }); - }); - } catch (err) { - console.error('Generating translation files failed.', err); - return defaultResult(locale); - } -} -//#endregion +//#endregion \ No newline at end of file diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index c4d5bc85314..315d356b476 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -87,6 +87,7 @@ "./vs/workbench/browser/actions/workspaceActions.ts", "./vs/workbench/browser/actions/workspaceCommands.ts", "./vs/workbench/browser/composite.ts", + "./vs/workbench/browser/contextkeys.ts", "./vs/workbench/browser/editor.ts", "./vs/workbench/browser/panel.ts", "./vs/workbench/browser/part.ts", @@ -124,6 +125,7 @@ "./vs/workbench/common/activity.ts", "./vs/workbench/common/component.ts", "./vs/workbench/common/composite.ts", + "./vs/workbench/common/contextkeys.ts", "./vs/workbench/common/contributions.ts", "./vs/workbench/common/editor.ts", "./vs/workbench/common/editor/binaryEditorModel.ts", @@ -138,29 +140,31 @@ "./vs/workbench/common/viewlet.ts", "./vs/workbench/common/views.ts", "./vs/workbench/contrib/backup/common/backupRestorer.ts", - "./vs/workbench/contrib/cli/electron-browser/cli.contribution.ts", + "./vs/workbench/contrib/cli/node/cli.contribution.ts", + "./vs/workbench/contrib/codeEditor/browser/accessibility/accessibility.ts", + "./vs/workbench/contrib/codeEditor/browser/codeEditor.contribution.ts", + "./vs/workbench/contrib/codeEditor/browser/inspectKeybindings.ts", + "./vs/workbench/contrib/codeEditor/browser/inspectTMScopes/inspectTMScopes.ts", + "./vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint.ts", "./vs/workbench/contrib/codeEditor/browser/largeFileOptimizations.ts", "./vs/workbench/contrib/codeEditor/browser/menuPreventer.ts", + "./vs/workbench/contrib/codeEditor/browser/selectionClipboard.ts", "./vs/workbench/contrib/codeEditor/browser/simpleEditorOptions.ts", - "./vs/workbench/contrib/codeEditor/electron-browser/accessibility.ts", - "./vs/workbench/contrib/codeEditor/electron-browser/inspectKeybindings.ts", - "./vs/workbench/contrib/codeEditor/electron-browser/languageConfiguration/languageConfigurationExtensionPoint.ts", - "./vs/workbench/contrib/codeEditor/electron-browser/selectionClipboard.ts", - "./vs/workbench/contrib/codeEditor/electron-browser/simpleEditorOptions.ts", + "./vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts", + "./vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts", + "./vs/workbench/contrib/codeEditor/browser/toggleMultiCursorModifier.ts", + "./vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts", + "./vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts", + "./vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts", + "./vs/workbench/contrib/codeEditor/browser/workbenchReferenceSearch.ts", + "./vs/workbench/contrib/codeEditor/electron-browser/codeEditor.contribution.ts", "./vs/workbench/contrib/codeEditor/electron-browser/sleepResumeRepaintMinimap.ts", - "./vs/workbench/contrib/codeEditor/electron-browser/suggestEnabledInput.ts", - "./vs/workbench/contrib/codeEditor/electron-browser/textMate/inspectTMScopes.ts", - "./vs/workbench/contrib/codeEditor/electron-browser/toggleMinimap.ts", - "./vs/workbench/contrib/codeEditor/electron-browser/toggleMultiCursorModifier.ts", - "./vs/workbench/contrib/codeEditor/electron-browser/toggleRenderControlCharacter.ts", - "./vs/workbench/contrib/codeEditor/electron-browser/toggleRenderWhitespace.ts", - "./vs/workbench/contrib/codeEditor/electron-browser/toggleWordWrap.ts", "./vs/workbench/contrib/codeinset/common/codeInset.ts", - "./vs/workbench/contrib/comments/common/commentModel.ts", - "./vs/workbench/contrib/comments/electron-browser/commentGlyphWidget.ts", - "./vs/workbench/contrib/comments/electron-browser/commentService.ts", - "./vs/workbench/contrib/comments/electron-browser/reactionsAction.ts", - "./vs/workbench/contrib/comments/electron-browser/simpleCommentEditor.ts", + // "./vs/workbench/contrib/comments/common/commentModel.ts", + // "./vs/workbench/contrib/comments/electron-browser/commentGlyphWidget.ts", + // "./vs/workbench/contrib/comments/electron-browser/commentService.ts", + // "./vs/workbench/contrib/comments/electron-browser/reactionsAction.ts", + // "./vs/workbench/contrib/comments/electron-browser/simpleCommentEditor.ts", "./vs/workbench/contrib/debug/browser/debugANSIHandling.ts", "./vs/workbench/contrib/debug/browser/debugActionItems.ts", "./vs/workbench/contrib/debug/browser/debugContentProvider.ts", @@ -195,30 +199,31 @@ "./vs/workbench/contrib/extensions/electron-browser/extensionsList.ts", "./vs/workbench/contrib/extensions/electron-browser/extensionsUtils.ts", "./vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts", + "./vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsInput.ts", "./vs/workbench/contrib/extensions/node/extensionsWorkbenchService.ts", "./vs/workbench/contrib/extensions/test/common/extensionQuery.test.ts", "./vs/workbench/contrib/feedback/electron-browser/feedback.contribution.ts", "./vs/workbench/contrib/feedback/electron-browser/feedback.ts", "./vs/workbench/contrib/feedback/electron-browser/feedbackStatusbarItem.ts", "./vs/workbench/contrib/files/browser/files.ts", + "./vs/workbench/contrib/files/browser/views/explorerDecorationsProvider.ts", "./vs/workbench/contrib/files/common/explorerModel.ts", + "./vs/workbench/contrib/files/common/explorerService.ts", "./vs/workbench/contrib/files/common/files.ts", - "./vs/workbench/contrib/files/electron-browser/explorerService.ts", - "./vs/workbench/contrib/files/electron-browser/views/explorerDecorationsProvider.ts", "./vs/workbench/contrib/format/browser/format.contribution.ts", - "./vs/workbench/contrib/localizations/electron-browser/localizations.contribution.ts", - "./vs/workbench/contrib/localizations/electron-browser/localizationsActions.ts", - "./vs/workbench/contrib/localizations/electron-browser/minimalTranslations.ts", + "./vs/workbench/contrib/localizations/browser/localizations.contribution.ts", + "./vs/workbench/contrib/localizations/browser/localizationsActions.ts", + "./vs/workbench/contrib/localizations/browser/minimalTranslations.ts", "./vs/workbench/contrib/logs/common/logConstants.ts", - "./vs/workbench/contrib/logs/electron-browser/logs.contribution.ts", - "./vs/workbench/contrib/logs/electron-browser/logsActions.ts", - "./vs/workbench/contrib/markers/electron-browser/constants.ts", - "./vs/workbench/contrib/markers/electron-browser/markers.ts", - "./vs/workbench/contrib/markers/electron-browser/markersFileDecorations.ts", - "./vs/workbench/contrib/markers/electron-browser/markersFilterOptions.ts", - "./vs/workbench/contrib/markers/electron-browser/markersModel.ts", - "./vs/workbench/contrib/markers/electron-browser/markersPanelActions.ts", - "./vs/workbench/contrib/markers/electron-browser/messages.ts", + "./vs/workbench/contrib/logs/common/logs.contribution.ts", + "./vs/workbench/contrib/logs/common/logsActions.ts", + "./vs/workbench/contrib/markers/browser/constants.ts", + "./vs/workbench/contrib/markers/browser/markers.ts", + "./vs/workbench/contrib/markers/browser/markersFileDecorations.ts", + "./vs/workbench/contrib/markers/browser/markersFilterOptions.ts", + "./vs/workbench/contrib/markers/browser/markersModel.ts", + "./vs/workbench/contrib/markers/browser/markersPanelActions.ts", + "./vs/workbench/contrib/markers/browser/messages.ts", "./vs/workbench/contrib/markers/test/electron-browser/markersModel.test.ts", "./vs/workbench/contrib/output/common/output.ts", "./vs/workbench/contrib/output/common/outputLinkComputer.ts", @@ -251,6 +256,7 @@ "./vs/workbench/contrib/search/common/queryBuilder.ts", "./vs/workbench/contrib/search/common/replace.ts", "./vs/workbench/contrib/search/common/search.ts", + "./vs/workbench/contrib/search/common/searchHistoryService.ts", "./vs/workbench/contrib/search/common/searchModel.ts", "./vs/workbench/contrib/search/test/browser/mockSearchTree.ts", "./vs/workbench/contrib/search/test/browser/openFileHandler.test.ts", @@ -307,16 +313,16 @@ "./vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts", "./vs/workbench/contrib/terminal/test/node/terminalCommandTracker.test.ts", "./vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts", - "./vs/workbench/contrib/themes/electron-browser/themes.contribution.ts", + "./vs/workbench/contrib/themes/browser/themes.contribution.ts", "./vs/workbench/contrib/themes/test/electron-browser/themes.test.contribution.ts", - "./vs/workbench/contrib/url/electron-browser/url.contribution.ts", + "./vs/workbench/contrib/url/common/url.contribution.ts", "./vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts", "./vs/workbench/electron-browser/window.ts", "./vs/workbench/services/activity/common/activity.ts", "./vs/workbench/services/backup/common/backup.ts", "./vs/workbench/services/backup/node/backupFileService.ts", "./vs/workbench/services/broadcast/electron-browser/broadcastService.ts", - "./vs/workbench/services/bulkEdit/electron-browser/bulkEditService.ts", + "./vs/workbench/services/bulkEdit/browser/bulkEditService.ts", "./vs/workbench/services/configuration/common/configuration.ts", "./vs/workbench/services/configuration/common/configurationModels.ts", "./vs/workbench/services/configuration/common/jsonEditing.ts", @@ -326,7 +332,7 @@ "./vs/workbench/services/configurationResolver/common/configurationResolver.ts", "./vs/workbench/services/configurationResolver/common/configurationResolverSchema.ts", "./vs/workbench/services/configurationResolver/common/configurationResolverUtils.ts", - "./vs/workbench/services/contextview/electron-browser/contextmenuService.ts", + "./vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts", "./vs/workbench/services/decorations/browser/decorations.ts", "./vs/workbench/services/decorations/browser/decorationsService.ts", "./vs/workbench/services/decorations/test/browser/decorationsService.test.ts", @@ -341,7 +347,6 @@ "./vs/workbench/services/extensions/electron-browser/extensionHost.ts", "./vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts", "./vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler.ts", - "./vs/workbench/services/extensions/electron-browser/runtimeExtensionsInput.ts", "./vs/workbench/services/extensions/node/extensionDescriptionRegistry.ts", "./vs/workbench/services/extensions/node/extensionManagementServerService.ts", "./vs/workbench/services/extensions/node/extensionPoints.ts", @@ -349,8 +354,8 @@ "./vs/workbench/services/extensions/node/proxyIdentifier.ts", "./vs/workbench/services/extensions/node/rpcProtocol.ts", "./vs/workbench/services/extensions/test/node/rpcProtocol.test.ts", - "./vs/workbench/services/files/electron-browser/encoding.ts", - "./vs/workbench/services/files/electron-browser/streams.ts", + "./vs/workbench/services/files/node/encoding.ts", + "./vs/workbench/services/files/node/streams.ts", "./vs/workbench/services/files/test/electron-browser/utils.ts", "./vs/workbench/services/files/test/electron-browser/watcher.test.ts", "./vs/workbench/services/hash/common/hashService.ts", @@ -358,7 +363,7 @@ "./vs/workbench/services/history/browser/history.ts", "./vs/workbench/services/history/common/history.ts", "./vs/workbench/services/integrity/common/integrity.ts", - "./vs/workbench/services/integrity/node/integrityServiceImpl.ts", + "./vs/workbench/services/integrity/node/integrityService.ts", "./vs/workbench/services/keybinding/common/keybindingIO.ts", "./vs/workbench/services/keybinding/common/keyboardMapper.ts", "./vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper.ts", @@ -385,7 +390,6 @@ "./vs/workbench/services/search/common/replace.ts", "./vs/workbench/services/search/common/search.ts", "./vs/workbench/services/search/common/searchHelpers.ts", - "./vs/workbench/services/search/common/searchHistoryService.ts", "./vs/workbench/services/search/node/fileSearch.ts", "./vs/workbench/services/search/node/fileSearchManager.ts", "./vs/workbench/services/search/node/rawSearchService.ts", @@ -406,12 +410,12 @@ "./vs/workbench/services/search/test/node/search.test.ts", "./vs/workbench/services/search/test/node/textSearch.integrationTest.ts", "./vs/workbench/services/search/test/node/textSearchManager.test.ts", + "./vs/workbench/services/textMate/common/TMHelper.ts", + "./vs/workbench/services/textMate/common/textMateService.ts", "./vs/workbench/services/textMate/electron-browser/TMGrammars.ts", - "./vs/workbench/services/textMate/electron-browser/TMHelper.ts", - "./vs/workbench/services/textMate/electron-browser/TMSyntax.ts", "./vs/workbench/services/textMate/electron-browser/textMateService.ts", "./vs/workbench/services/textfile/common/textfiles.ts", - "./vs/workbench/services/textfile/electron-browser/textResourcePropertiesService.ts", + "./vs/workbench/services/textfile/node/textResourcePropertiesService.ts", "./vs/workbench/services/timer/electron-browser/timerService.ts", "./vs/workbench/services/title/common/titleService.ts", "./vs/workbench/services/viewlet/browser/viewlet.ts", @@ -433,6 +437,7 @@ "./vs/workbench/test/electron-browser/api/testRPCProtocol.ts" ], "exclude": [ - "./typings/require-monaco.d.ts" + "./typings/require-monaco.d.ts", + "./vs/workbench/contrib/comments/electron-browser/commentThreadWidget.ts" ] } \ No newline at end of file diff --git a/src/typings/vscode-windows-registry.d.ts b/src/typings/vscode-windows-registry.d.ts new file mode 100644 index 00000000000..9be14daa4b2 --- /dev/null +++ b/src/typings/vscode-windows-registry.d.ts @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode-windows-registry' { + export type HKEY = "HKEY_CURRENT_USER" | "HKEY_LOCAL_MACHINE" | "HKEY_CLASSES_ROOT" | "HKEY_USERS" | "HKEY_CURRENT_CONFIG"; + export function GetStringRegKey(hive: HKEY, path: string, name: string): string | undefined; +} \ No newline at end of file diff --git a/src/vs/base/browser/browser.ts b/src/vs/base/browser/browser.ts index 639ac3d031f..c09210608f3 100644 --- a/src/vs/base/browser/browser.ts +++ b/src/vs/base/browser/browser.ts @@ -5,7 +5,6 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; -import * as platform from 'vs/base/common/platform'; class WindowManager { @@ -72,23 +71,6 @@ class WindowManager { public isFullscreen(): boolean { return this._fullscreen; } - - // --- Accessibility - private _accessibilitySupport = platform.AccessibilitySupport.Unknown; - private readonly _onDidChangeAccessibilitySupport = new Emitter(); - - public readonly onDidChangeAccessibilitySupport: Event = this._onDidChangeAccessibilitySupport.event; - public setAccessibilitySupport(accessibilitySupport: platform.AccessibilitySupport): void { - if (this._accessibilitySupport === accessibilitySupport) { - return; - } - - this._accessibilitySupport = accessibilitySupport; - this._onDidChangeAccessibilitySupport.fire(); - } - public getAccessibilitySupport(): platform.AccessibilitySupport { - return this._accessibilitySupport; - } } /** A zoom index, e.g. 1, 2, 3 */ @@ -126,16 +108,6 @@ export function isFullscreen(): boolean { } export const onDidChangeFullscreen = WindowManager.INSTANCE.onDidChangeFullscreen; -export function setAccessibilitySupport(accessibilitySupport: platform.AccessibilitySupport): void { - WindowManager.INSTANCE.setAccessibilitySupport(accessibilitySupport); -} -export function getAccessibilitySupport(): platform.AccessibilitySupport { - return WindowManager.INSTANCE.getAccessibilitySupport(); -} -export function onDidChangeAccessibilitySupport(callback: () => void): IDisposable { - return WindowManager.INSTANCE.onDidChangeAccessibilitySupport(callback); -} - const userAgent = navigator.userAgent; export const isIE = (userAgent.indexOf('Trident') >= 0); diff --git a/src/vs/base/browser/keyboardEvent.ts b/src/vs/base/browser/keyboardEvent.ts index a6fdce5c7c9..03bdffc95ed 100644 --- a/src/vs/base/browser/keyboardEvent.ts +++ b/src/vs/base/browser/keyboardEvent.ts @@ -179,6 +179,9 @@ export function getCodeForKeyCode(keyCode: KeyCode): number { } export interface IKeyboardEvent { + + readonly _standardKeyboardEventBrand: true; + readonly browserEvent: KeyboardEvent; readonly target: HTMLElement; @@ -206,6 +209,8 @@ const metaKeyMod = (platform.isMacintosh ? KeyMod.CtrlCmd : KeyMod.WinCtrl); export class StandardKeyboardEvent implements IKeyboardEvent { + readonly _standardKeyboardEventBrand = true; + public readonly browserEvent: KeyboardEvent; public readonly target: HTMLElement; diff --git a/src/vs/base/browser/ui/findinput/findInput.ts b/src/vs/base/browser/ui/findinput/findInput.ts index 59275522535..38a5082b141 100644 --- a/src/vs/base/browser/ui/findinput/findInput.ts +++ b/src/vs/base/browser/ui/findinput/findInput.ts @@ -337,7 +337,11 @@ export class FindInput extends Widget { })); if (this._showOptionButtons) { - this.inputBox.inputElement.style.paddingRight = (this.caseSensitive.width() + this.wholeWords.width() + this.regex.width()) + 'px'; + const paddingRight = (this.caseSensitive.width() + this.wholeWords.width() + this.regex.width()) + 'px'; + this.inputBox.inputElement.style.paddingRight = paddingRight; + if (this.inputBox.mirrorElement) { + this.inputBox.mirrorElement.style.paddingRight = paddingRight; + } } // Arrow-Key support to navigate between options diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index 01fe9dcaa36..530a9061b59 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -230,6 +230,10 @@ export class InputBox extends Widget { } } + public get mirrorElement(): HTMLElement { + return this.mirror; + } + public get inputElement(): HTMLInputElement { return this.input; } diff --git a/src/vs/base/browser/ui/list/list.ts b/src/vs/base/browser/ui/list/list.ts index b4a4aa4821f..80dea11ee4a 100644 --- a/src/vs/base/browser/ui/list/list.ts +++ b/src/vs/base/browser/ui/list/list.ts @@ -16,8 +16,8 @@ export interface IListVirtualDelegate { export interface IListRenderer { templateId: string; renderTemplate(container: HTMLElement): TTemplateData; - renderElement(element: T, index: number, templateData: TTemplateData): void; - disposeElement?(element: T, index: number, templateData: TTemplateData): void; + renderElement(element: T, index: number, templateData: TTemplateData, dynamicHeightProbing?: boolean): void; + disposeElement?(element: T, index: number, templateData: TTemplateData, dynamicHeightProbing?: boolean): void; disposeTemplate(templateData: TTemplateData): void; } diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index c35537fa7ea..3d1fe415426 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -35,7 +35,7 @@ class PagedRenderer implements IListRenderer { } } }; } - renderElement(index: number, _: number, data: ITemplateData): void { + renderElement(index: number, _: number, data: ITemplateData, dynamicHeightProbing?: boolean): void { if (data.disposable) { data.disposable.dispose(); } @@ -47,7 +47,7 @@ class PagedRenderer implements IListRenderer implements IListRenderer cts.cancel() }; this.renderer.renderPlaceholder(index, data.data); - promise.then(entry => this.renderer.renderElement(entry, index, data.data!)); + promise.then(entry => this.renderer.renderElement(entry, index, data.data!, dynamicHeightProbing)); } disposeTemplate(data: ITemplateData): void { diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index 73ca98dabcf..3bf44fc334b 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -360,7 +360,7 @@ export class ListView implements ISpliceable, IDisposable { this.eventuallyUpdateScrollDimensions(); if (this.supportDynamicHeights) { - this.rerender(this.scrollTop, this.renderHeight); + this._rerender(this.scrollTop, this.renderHeight); } return deleted.map(i => i.element); @@ -422,6 +422,18 @@ export class ListView implements ISpliceable, IDisposable { } } + rerender(): void { + if (!this.supportDynamicHeights) { + return; + } + + for (const item of this.items) { + item.lastDynamicHeightWidth = undefined; + } + + this._rerender(this.lastRenderTop, this.lastRenderHeight); + } + get length(): number { return this.items.length; } @@ -431,6 +443,16 @@ export class ListView implements ISpliceable, IDisposable { return scrollDimensions.height; } + get firstVisibleIndex(): number { + const range = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight); + return range.start; + } + + get lastVisibleIndex(): number { + const range = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight); + return range.end - 1; + } + element(index: number): T { return this.items[index].element; } @@ -473,7 +495,7 @@ export class ListView implements ISpliceable, IDisposable { this.renderWidth = width; if (this.supportDynamicHeights) { - this.rerender(this.scrollTop, this.renderHeight); + this._rerender(this.scrollTop, this.renderHeight); } if (this.horizontalScrolling) { @@ -710,7 +732,7 @@ export class ListView implements ISpliceable, IDisposable { this.render(e.scrollTop, e.height, e.scrollLeft, e.scrollWidth); if (this.supportDynamicHeights) { - this.rerender(e.scrollTop, e.height); + this._rerender(e.scrollTop, e.height); } } catch (err) { console.error('Got bad scroll event:', e); @@ -973,7 +995,7 @@ export class ListView implements ISpliceable, IDisposable { * Given a stable rendered state, checks every rendered element whether it needs * to be probed for dynamic height. Adjusts scroll height and top if necessary. */ - private rerender(renderTop: number, renderHeight: number): void { + private _rerender(renderTop: number, renderHeight: number): void { const previousRenderRange = this.getRenderRange(renderTop, renderHeight); // Let's remember the second element's position, this helps in scrolling up @@ -1057,14 +1079,20 @@ export class ListView implements ISpliceable, IDisposable { } const size = item.size; - const renderer = this.renderers.get(item.templateId); const row = this.cache.alloc(item.templateId); row.domNode!.style.height = ''; this.rowsContainer.appendChild(row.domNode!); + + const renderer = this.renderers.get(item.templateId); if (renderer) { - renderer.renderElement(item.element, index, row.templateData); + renderer.renderElement(item.element, index, row.templateData, true); + + if (renderer.disposeElement) { + renderer.disposeElement(item.element, index, row.templateData, true); + } } + item.size = row.domNode!.offsetHeight; item.lastDynamicHeightWidth = this.renderWidth; this.rowsContainer.removeChild(row.domNode!); diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 69ccfbbdb3c..cd7312809c6 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -976,20 +976,20 @@ class PipelineRenderer implements IListRenderer { return this.renderers.map(r => r.renderTemplate(container)); } - renderElement(element: T, index: number, templateData: any[]): void { + renderElement(element: T, index: number, templateData: any[], dynamicHeightProbing?: boolean): void { let i = 0; for (const renderer of this.renderers) { - renderer.renderElement(element, index, templateData[i++]); + renderer.renderElement(element, index, templateData[i++], dynamicHeightProbing); } } - disposeElement(element: T, index: number, templateData: any[]): void { + disposeElement(element: T, index: number, templateData: any[], dynamicHeightProbing?: boolean): void { let i = 0; for (const renderer of this.renderers) { if (renderer.disposeElement) { - renderer.disposeElement(element, index, templateData[i]); + renderer.disposeElement(element, index, templateData[i], dynamicHeightProbing); } i += 1; @@ -1276,6 +1276,10 @@ export class List implements ISpliceable, IDisposable { this.view.updateWidth(index); } + rerender(): void { + this.view.rerender(); + } + element(index: number): T { return this.view.element(index); } @@ -1308,6 +1312,14 @@ export class List implements ISpliceable, IDisposable { return this.view.renderHeight; } + get firstVisibleIndex(): number { + return this.view.firstVisibleIndex; + } + + get lastVisibleIndex(): number { + return this.view.lastVisibleIndex; + } + domFocus(): void { this.view.domNode.focus(); } diff --git a/src/vs/base/browser/ui/menu/menubar.ts b/src/vs/base/browser/ui/menu/menubar.ts index f62951a9750..02e64243b56 100644 --- a/src/vs/base/browser/ui/menu/menubar.ts +++ b/src/vs/base/browser/ui/menu/menubar.ts @@ -23,6 +23,7 @@ export interface IMenuBarOptions { enableMnemonics?: boolean; visibility?: string; getKeybinding?: (action: IAction) => ResolvedKeybinding; + alwaysOnMnemonics?: boolean; } export interface MenuBarMenu { @@ -723,7 +724,7 @@ export class MenuBar extends Disposable { if (menuBarMenu.titleElement.children.length) { let child = menuBarMenu.titleElement.children.item(0) as HTMLElement; if (child) { - child.style.textDecoration = visible ? 'underline' : null; + child.style.textDecoration = (this.options.alwaysOnMnemonics || visible) ? 'underline' : null; } } }); @@ -850,7 +851,7 @@ export class MenuBar extends Disposable { let menuOptions: IMenuOptions = { getKeyBinding: this.options.getKeybinding, actionRunner: this.actionRunner, - enableMnemonics: this.mnemonicsInUse && this.options.enableMnemonics, + enableMnemonics: this.options.alwaysOnMnemonics || (this.mnemonicsInUse && this.options.enableMnemonics), ariaLabel: customMenu.buttonElement.attributes['aria-label'].value }; diff --git a/src/vs/base/browser/ui/splitview/panelview.ts b/src/vs/base/browser/ui/splitview/panelview.ts index bc375e34a37..fb9897920a5 100644 --- a/src/vs/base/browser/ui/splitview/panelview.ts +++ b/src/vs/base/browser/ui/splitview/panelview.ts @@ -42,9 +42,10 @@ export abstract class Panel implements IView { private static readonly HEADER_SIZE = 22; readonly element: HTMLElement; + private header: HTMLElement; + private body: HTMLElement; protected _expanded: boolean; - protected disposables: IDisposable[] = []; private expandedSize: number | undefined = undefined; private _headerVisible = true; @@ -52,12 +53,13 @@ export abstract class Panel implements IView { private _maximumBodySize: number; private ariaHeaderLabel: string; private styles: IPanelStyles = {}; - - private header: HTMLElement; + private animationTimer: number | undefined = undefined; private _onDidChange = new Emitter(); readonly onDidChange: Event = this._onDidChange.event; + protected disposables: IDisposable[] = []; + get draggableElement(): HTMLElement { return this.header; } @@ -133,6 +135,17 @@ export abstract class Panel implements IView { this.updateHeader(); this._onDidChange.fire(expanded ? this.expandedSize : undefined); + if (expanded) { + if (typeof this.animationTimer === 'number') { + clearTimeout(this.animationTimer); + } + append(this.element, this.body); + } else { + this.animationTimer = window.setTimeout(() => { + this.body.remove(); + }, 200); + } + return true; } @@ -179,15 +192,8 @@ export abstract class Panel implements IView { domEvent(this.header, 'click') (() => this.setExpanded(!this.isExpanded()), null, this.disposables); - // TODO@Joao move this down to panelview - // onHeaderKeyDown.filter(e => e.keyCode === KeyCode.UpArrow) - // .event(focusPrevious, this, this.disposables); - - // onHeaderKeyDown.filter(e => e.keyCode === KeyCode.DownArrow) - // .event(focusNext, this, this.disposables); - - const body = append(this.element, $('.panel-body')); - this.renderBody(body); + this.body = append(this.element, $('.panel-body')); + this.renderBody(this.body); } layout(height: number): void { @@ -373,7 +379,7 @@ export class PanelView extends Disposable { private panelItems: IPanelItem[] = []; private width: number; private splitview: SplitView; - private animationTimer: number | null = null; + private animationTimer: number | undefined = undefined; private _onDidDrop = this._register(new Emitter<{ from: Panel, to: Panel }>()); readonly onDidDrop: Event<{ from: Panel, to: Panel }> = this._onDidDrop.event; @@ -475,7 +481,7 @@ export class PanelView extends Disposable { addClass(this.el, 'animated'); this.animationTimer = window.setTimeout(() => { - this.animationTimer = null; + this.animationTimer = undefined; removeClass(this.el, 'animated'); }, 200); } diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 521638ebc55..c2d04a057ab 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -47,7 +47,6 @@ export interface IView { readonly maximumSize: number; readonly onDidChange: Event; readonly priority?: LayoutPriority; - readonly snapSize?: number; layout(size: number, orientation: Orientation): void; } @@ -352,7 +351,7 @@ export class SplitView extends Disposable { } else { for (let i = 0; i < this.viewItems.length; i++) { const item = this.viewItems[i]; - item.size = SplitView.clamp(item, Math.round(this.proportions[i] * size)); + item.size = clamp(Math.round(this.proportions[i] * size), item.view.minimumSize, item.view.maximumSize); } } @@ -444,7 +443,7 @@ export class SplitView extends Disposable { } size = typeof size === 'number' ? size : item.size; - size = SplitView.clamp(item, size); + size = clamp(size, item.view.minimumSize, item.view.maximumSize); if (this.inverseAltBehavior && index > 0) { // In this case, we want the view to grow or shrink both sides equally @@ -551,29 +550,27 @@ export class SplitView extends Disposable { const downItems = downIndexes.map(i => this.viewItems[i]); const downSizes = downIndexes.map(i => sizes[i]); - const minDeltaUp = upIndexes.reduce((r, i) => r + ((typeof this.viewItems[i].view.snapSize === 'number' ? 0 : this.viewItems[i].view.minimumSize) - sizes[i]), 0); + const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.minimumSize - sizes[i]), 0); const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - sizes[i]), 0); - const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - (typeof this.viewItems[i].view.snapSize === 'number' ? 0 : this.viewItems[i].view.minimumSize)), 0); + const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.minimumSize), 0); const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.maximumSize), 0); const minDelta = Math.max(minDeltaUp, minDeltaDown, overloadMinDelta); const maxDelta = Math.min(maxDeltaDown, maxDeltaUp, overloadMaxDelta); - const tentativeDelta = clamp(delta, minDelta, maxDelta); - let actualDelta = 0; + delta = clamp(delta, minDelta, maxDelta); - for (let i = 0, deltaUp = tentativeDelta; i < upItems.length; i++) { + for (let i = 0, deltaUp = delta; i < upItems.length; i++) { const item = upItems[i]; - const size = SplitView.clamp(item, upSizes[i] + deltaUp/* , upIndexes[i] === index */); + const size = clamp(upSizes[i] + deltaUp, item.view.minimumSize, item.view.maximumSize); const viewDelta = size - upSizes[i]; - actualDelta += viewDelta; deltaUp -= viewDelta; item.size = size; } - for (let i = 0, deltaDown = actualDelta; i < downItems.length; i++) { + for (let i = 0, deltaDown = delta; i < downItems.length; i++) { const item = downItems[i]; - const size = SplitView.clamp(item, downSizes[i] - deltaDown); + const size = clamp(downSizes[i] - deltaDown, item.view.minimumSize, item.view.maximumSize); const viewDelta = size - downSizes[i]; deltaDown += viewDelta; @@ -583,24 +580,13 @@ export class SplitView extends Disposable { return delta; } - private static clamp(item: IViewItem, size: number): number { - const result = clamp(size, item.view.minimumSize, item.view.maximumSize); - - if (typeof item.view.snapSize !== 'number' || size >= item.view.minimumSize) { - return result; - } - - const snapSize = Math.min(item.view.snapSize, item.view.minimumSize); - return size < snapSize ? 0 : item.view.minimumSize; - } - private distributeEmptySpace(): void { let contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); let emptyDelta = this.size - contentSize; for (let i = this.viewItems.length - 1; emptyDelta !== 0 && i >= 0; i--) { const item = this.viewItems[i]; - const size = SplitView.clamp(item, item.size + emptyDelta); + const size = clamp(item.size + emptyDelta, item.view.minimumSize, item.view.maximumSize); const viewDelta = size - item.size; emptyDelta -= viewDelta; diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index fa30edc24f8..22839784b16 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -14,7 +14,7 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { ITreeModel, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeFilter, ITreeNavigator, ICollapseStateChangeEvent, ITreeDragAndDrop, TreeDragOverBubble, TreeVisibility, TreeFilterResult, ITreeModelSpliceEvent } from 'vs/base/browser/ui/tree/tree'; import { ISpliceable } from 'vs/base/common/sequence'; import { IDragAndDropData, StaticDND, DragAndDropData } from 'vs/base/browser/dnd'; -import { range } from 'vs/base/common/arrays'; +import { range, equals } from 'vs/base/common/arrays'; import { ElementsDragAndDropData } from 'vs/base/browser/ui/list/listView'; import { domEvent } from 'vs/base/browser/event'; import { fuzzyScore, FuzzyScore } from 'vs/base/common/filters'; @@ -233,23 +233,28 @@ class TreeRenderer implements IListRenderer, index: number, templateData: ITreeListTemplateData): void { - this.renderedNodes.set(node, templateData); - this.renderedElements.set(node.element, node); + renderElement(node: ITreeNode, index: number, templateData: ITreeListTemplateData, dynamicHeightProbing?: boolean): void { + if (!dynamicHeightProbing) { + this.renderedNodes.set(node, templateData); + this.renderedElements.set(node.element, node); + } const indent = TreeRenderer.DefaultIndent + (node.depth - 1) * this.indent; templateData.twistie.style.marginLeft = `${indent}px`; this.update(node, templateData); - this.renderer.renderElement(node, index, templateData.templateData); + this.renderer.renderElement(node, index, templateData.templateData, dynamicHeightProbing); } - disposeElement(node: ITreeNode, index: number, templateData: ITreeListTemplateData): void { + disposeElement(node: ITreeNode, index: number, templateData: ITreeListTemplateData, dynamicHeightProbing?: boolean): void { if (this.renderer.disposeElement) { - this.renderer.disposeElement(node, index, templateData.templateData); + this.renderer.disposeElement(node, index, templateData.templateData, dynamicHeightProbing); + } + + if (!dynamicHeightProbing) { + this.renderedNodes.delete(node); + this.renderedElements.delete(node.element); } - this.renderedNodes.delete(node); - this.renderedElements.delete(node.element); } disposeTemplate(templateData: ITreeListTemplateData): void { @@ -397,6 +402,12 @@ class TypeFilterController implements IDisposable { private _filterOnType: boolean; get filterOnType(): boolean { return this._filterOnType; } + private _empty: boolean; + get empty(): boolean { return this._empty; } + + private _onDidChangeEmptyState = new Emitter(); + readonly onDidChangeEmptyState: Event = Event.latch(this._onDidChangeEmptyState.event); + private positionClassName = 'ne'; private domNode: HTMLElement; private messageDomNode: HTMLElement; @@ -408,6 +419,9 @@ class TypeFilterController implements IDisposable { private automaticKeyboardNavigation = true; private triggered = false; + private _onDidChangePattern = new Emitter(); + readonly onDidChangePattern = this._onDidChangePattern.event; + private enabledDisposables: IDisposable[] = []; private disposables: IDisposable[] = []; @@ -485,10 +499,10 @@ class TypeFilterController implements IDisposable { const isPrintableCharEvent = this.keyboardNavigationLabelProvider.mightProducePrintableCharacter ? (e: IKeyboardEvent) => this.keyboardNavigationLabelProvider.mightProducePrintableCharacter!(e) : (e: IKeyboardEvent) => mightProducePrintableCharacter(e); const onKeyDown = Event.chain(domEvent(this.view.getHTMLElement(), 'keydown')) .filter(e => !isInputElement(e.target as HTMLElement) || e.target === this.filterOnTypeDomNode) + .map(e => new StandardKeyboardEvent(e)) .filter(this.keyboardNavigationEventFilter || (() => true)) .filter(() => this.automaticKeyboardNavigation || this.triggered) - .map(e => new StandardKeyboardEvent(e)) - .filter(e => isPrintableCharEvent(e) || ((this._pattern.length > 0 || this.triggered) && ((e.keyCode === KeyCode.Escape || e.keyCode === KeyCode.Backspace) && !e.altKey && !e.ctrlKey && !e.metaKey) || (e.keyCode === KeyCode.Backspace && (isMacintosh ? e.altKey : e.ctrlKey) && !e.shiftKey))) + .filter(e => isPrintableCharEvent(e) || ((this.pattern.length > 0 || this.triggered) && ((e.keyCode === KeyCode.Escape || e.keyCode === KeyCode.Backspace) && !e.altKey && !e.ctrlKey && !e.metaKey) || (e.keyCode === KeyCode.Backspace && (isMacintosh ? e.altKey : e.ctrlKey) && !e.shiftKey))) .forEach(e => { e.stopPropagation(); e.preventDefault(); }) .event; @@ -540,6 +554,8 @@ class TypeFilterController implements IDisposable { } this._pattern = pattern; + this._onDidChangePattern.fire(pattern); + this.filter.pattern = pattern; this.tree.refilter(); @@ -653,13 +669,17 @@ class TypeFilterController implements IDisposable { if (this.pattern && this.tree.options.filterOnType && noMatches) { this.messageDomNode.textContent = localize('empty', "No elements found"); + this._empty = true; } else { this.messageDomNode.innerHTML = ''; + this._empty = false; } toggleClass(this.domNode, 'no-matches', noMatches); this.domNode.title = localize('found', "Matched {0} out of {1} elements", this.filter.matchCount, this.filter.totalCount); this.labelDomNode.textContent = this.pattern.length > 16 ? '…' + this.pattern.substr(this.pattern.length - 16) : this.pattern; + + this._onDidChangeEmptyState.fire(this._empty); } shouldAllowFocus(node: ITreeNode): boolean { @@ -676,6 +696,7 @@ class TypeFilterController implements IDisposable { dispose() { this.disable(); + this._onDidChangePattern.dispose(); this.disposables = dispose(this.disposables); } } @@ -707,7 +728,7 @@ function asTreeContextMenuEvent(event: IListContextMenuEvent { constructor(private identityProvider?: IIdentityProvider) { } set(nodes: ITreeNode[], browserEvent?: UIEvent): void { + if (equals(this.nodes, nodes)) { + return; + } + this.nodes = [...nodes]; this.elements = undefined; this._nodeSet = undefined; @@ -934,7 +959,7 @@ class TreeNodeList extends List> export abstract class AbstractTree implements IDisposable { - private view: TreeNodeList; + protected view: TreeNodeList; private renderers: TreeRenderer[]; protected model: ITreeModel; private focus: Trait; @@ -968,6 +993,7 @@ export abstract class AbstractTree implements IDisposable readonly onWillRefilter: Event = this._onWillRefilter.event; get filterOnType(): boolean { return !!this._options.filterOnType; } + get onDidChangeTypeFilterPattern(): Event { return this.typeFilterController ? this.typeFilterController.onDidChangePattern : Event.None; } // Options TODO@joao expose options only, not Optional<> get openOnSingleClick(): boolean { return typeof this._options.openOnSingleClick === 'undefined' ? true : this._options.openOnSingleClick; } @@ -1067,11 +1093,21 @@ export abstract class AbstractTree implements IDisposable } get contentHeight(): number { + if (this.typeFilterController && this.typeFilterController.filterOnType && this.typeFilterController.empty) { + return 100; + } + return this.view.contentHeight; } get onDidChangeContentHeight(): Event { - return this.view.onDidChangeContentHeight; + let result = this.view.onDidChangeContentHeight; + + if (this.typeFilterController) { + result = Event.any(result, Event.map(this.typeFilterController.onDidChangeEmptyState, () => this.contentHeight)); + } + + return result; } get scrollTop(): number { @@ -1090,6 +1126,18 @@ export abstract class AbstractTree implements IDisposable return this.view.renderHeight; } + get firstVisibleElement(): T { + const index = this.view.firstVisibleIndex; + const node = this.view.element(index); + return node.element; + } + + get lastVisibleElement(): T { + const index = this.view.lastVisibleIndex; + const node = this.view.element(index); + return node.element; + } + domFocus(): void { this.view.domFocus(); } @@ -1211,12 +1259,14 @@ export abstract class AbstractTree implements IDisposable return this.focus.get(); } - open(elements: TRef[]): void { + open(elements: TRef[], browserEvent?: UIEvent): void { const indexes = elements.map(e => this.model.getListIndex(e)); - this.view.open(indexes); + this.view.open(indexes, browserEvent); } reveal(location: TRef, relativeTop?: number): void { + this.model.expandTo(location); + const index = this.model.getListIndex(location); if (index === -1) { diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 54fabcf7def..fe397e7240f 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -87,8 +87,8 @@ class DataTreeRenderer implements ITreeRe return { templateData }; } - renderElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData): void { - this.renderer.renderElement(new AsyncDataTreeNodeWrapper(node), index, templateData.templateData); + renderElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, dynamicHeightProbing?: boolean): void { + this.renderer.renderElement(new AsyncDataTreeNodeWrapper(node), index, templateData.templateData, dynamicHeightProbing); } renderTwistie(element: IAsyncDataTreeNode, twistieElement: HTMLElement): boolean { @@ -96,9 +96,9 @@ class DataTreeRenderer implements ITreeRe return false; } - disposeElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData): void { + disposeElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, dynamicHeightProbing?: boolean): void { if (this.renderer.disposeElement) { - this.renderer.disposeElement(new AsyncDataTreeNodeWrapper(node), index, templateData.templateData); + this.renderer.disposeElement(new AsyncDataTreeNodeWrapper(node), index, templateData.templateData, dynamicHeightProbing); } } @@ -230,7 +230,7 @@ function asObjectTreeOptions(options?: IAsyncDataTreeOpt function asTreeElement(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): ITreeElement> { let collapsed: boolean | undefined; - if (viewStateContext && node.id) { + if (viewStateContext && viewStateContext.viewState.expanded && node.id) { collapsed = viewStateContext.viewState.expanded.indexOf(node.id) === -1; } @@ -251,9 +251,10 @@ export interface IAsyncDataTreeOptions extends IAsyncData } export interface IAsyncDataTreeViewState { - readonly focus: string[]; - readonly selection: string[]; - readonly expanded: string[]; + readonly focus?: string[]; + readonly selection?: string[]; + readonly expanded?: string[]; + readonly scrollTop?: number; } interface IAsyncDataTreeViewStateContext { @@ -292,6 +293,8 @@ export class AsyncDataTree implements IDisposable get onDidFocus(): Event { return this.tree.onDidFocus; } get onDidBlur(): Event { return this.tree.onDidBlur; } + get onDidUpdateOptions(): Event { return this.tree.onDidUpdateOptions; } + get filterOnType(): boolean { return this.tree.filterOnType; } get openOnSingleClick(): boolean { return this.tree.openOnSingleClick; } @@ -371,6 +374,14 @@ export class AsyncDataTree implements IDisposable return this.tree.renderHeight; } + get firstVisibleElement(): T { + return this.tree.firstVisibleElement!.element as T; + } + + get lastVisibleElement(): T { + return this.tree.lastVisibleElement!.element as T; + } + domFocus(): void { this.tree.domFocus(); } @@ -403,6 +414,10 @@ export class AsyncDataTree implements IDisposable this.tree.setFocus(viewStateContext.focus); this.tree.setSelection(viewStateContext.selection); } + + if (viewState && typeof viewState.scrollTop === 'number') { + this.scrollTop = viewState.scrollTop; + } } async updateChildren(element: TInput | T = this.root.element, recursive = true, viewStateContext?: IAsyncDataTreeViewStateContext): Promise { @@ -418,15 +433,24 @@ export class AsyncDataTree implements IDisposable await this.refreshAndRenderNode(this.getDataNode(element), recursive, ChildrenResolutionReason.Refresh, viewStateContext); } + resort(element: TInput | T = this.root.element, recursive = true): void { + this.tree.resort(this.getDataNode(element), recursive); + } + hasNode(element: TInput | T): boolean { return element === this.root.element || this.nodes.has(element as T); } // View - refresh(element: T): void { + rerender(element?: T): void { + if (element === undefined) { + this.tree.rerender(); + return; + } + const node = this.getDataNode(element); - this.tree.refresh(node); + this.tree.rerender(node); } updateWidth(element: T): void { @@ -644,7 +668,7 @@ export class AsyncDataTree implements IDisposable return true; } - if (!viewStateContext || !child.id) { + if (!viewStateContext || !viewStateContext.viewState.expanded || !child.id) { return false; } @@ -776,14 +800,12 @@ export class AsyncDataTree implements IDisposable slow: false }; - if (viewStateContext) { - if (viewStateContext.viewState.focus.indexOf(id) > -1) { - viewStateContext.focus.push(childAsyncDataTreeNode); - } + if (viewStateContext && viewStateContext.viewState.focus && viewStateContext.viewState.focus.indexOf(id) > -1) { + viewStateContext.focus.push(childAsyncDataTreeNode); + } - if (viewStateContext.viewState.selection.indexOf(id) > -1) { - viewStateContext.selection.push(childAsyncDataTreeNode); - } + if (viewStateContext && viewStateContext.viewState.selection && viewStateContext.viewState.selection.indexOf(id) > -1) { + viewStateContext.selection.push(childAsyncDataTreeNode); } return childAsyncDataTreeNode; @@ -791,10 +813,13 @@ export class AsyncDataTree implements IDisposable asyncDataTreeNode.element = element; - if (asyncDataTreeNode.state === AsyncDataTreeNodeState.Loaded || asyncDataTreeNode.hasChildren !== !!this.dataSource.hasChildren(asyncDataTreeNode.element)) { + const hasChildren = this.dataSource.hasChildren(asyncDataTreeNode.element); + + if (asyncDataTreeNode.state === AsyncDataTreeNodeState.Loaded || (asyncDataTreeNode.state !== AsyncDataTreeNodeState.Uninitialized && asyncDataTreeNode.hasChildren !== !!hasChildren)) { asyncDataTreeNode.needsRefresh = true; } + asyncDataTreeNode.hasChildren = hasChildren; return asyncDataTreeNode; }); @@ -856,7 +881,7 @@ export class AsyncDataTree implements IDisposable queue.push(...node.children); } - return { focus, selection, expanded }; + return { focus, selection, expanded, scrollTop: this.scrollTop }; } dispose(): void { diff --git a/src/vs/base/browser/ui/tree/dataTree.ts b/src/vs/base/browser/ui/tree/dataTree.ts index d0379e7b612..d2342d7e85b 100644 --- a/src/vs/base/browser/ui/tree/dataTree.ts +++ b/src/vs/base/browser/ui/tree/dataTree.ts @@ -26,6 +26,7 @@ export class DataTree extends AbstractTree | undefined; + private nodesByIdentity = new Map>(); constructor( container: HTMLElement, @@ -86,22 +87,72 @@ export class DataTree extends AbstractTree boolean | undefined) | undefined; + + if (this.identityProvider) { + isCollapsed = element => { + const id = this.identityProvider!.getId(element).toString(); + const node = this.nodesByIdentity.get(id); + + if (!node) { + return undefined; + } + + return node.collapsed; + }; + } + + this._refresh(element, isCollapsed); + } + + resort(element: T | TInput = this.input!, recursive = true): void { + this.model.resort((element === this.input ? null : element) as T, recursive); } // View - refresh(element: T): void { - this.model.refresh(element); + refresh(element?: T): void { + if (element === undefined) { + this.view.rerender(); + return; + } + + this.model.rerender(element); } // Implementation - private _refresh(element: TInput | T, isCollapsed?: (el: T) => boolean, onDidCreateNode?: (node: ITreeNode) => void): void { - this.model.setChildren((element === this.input ? null : element) as T, this.iterate(element, isCollapsed).elements, onDidCreateNode); + private _refresh(element: TInput | T, isCollapsed?: (el: T) => boolean | undefined, onDidCreateNode?: (node: ITreeNode) => void): void { + let onDidDeleteNode: ((node: ITreeNode) => void) | undefined; + + if (this.identityProvider) { + const insertedElements = new Set(); + + const outerOnDidCreateNode = onDidCreateNode; + onDidCreateNode = (node: ITreeNode) => { + const id = this.identityProvider!.getId(node.element).toString(); + + insertedElements.add(id); + this.nodesByIdentity.set(id, node); + + if (outerOnDidCreateNode) { + outerOnDidCreateNode(node); + } + }; + + onDidDeleteNode = (node: ITreeNode) => { + const id = this.identityProvider!.getId(node.element).toString(); + + if (!insertedElements.has(id)) { + this.nodesByIdentity.delete(id); + } + }; + } + + this.model.setChildren((element === this.input ? null : element) as T, this.iterate(element, isCollapsed).elements, onDidCreateNode, onDidDeleteNode); } - private iterate(element: TInput | T, isCollapsed?: (el: T) => boolean): { elements: Iterator>, size: number } { + private iterate(element: TInput | T, isCollapsed?: (el: T) => boolean | undefined): { elements: Iterator>, size: number } { const children = this.dataSource.getChildren(element); const elements = Iterator.map>(Iterator.fromArray(children), element => { const { elements: children, size } = this.iterate(element, isCollapsed); @@ -144,4 +195,4 @@ export class DataTree extends AbstractTree extends AbstractTree>, options: IIndexTreeOptions): ITreeModel { return new IndexTreeModel(view, this.rootElement, options); } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/tree/indexTreeModel.ts b/src/vs/base/browser/ui/tree/indexTreeModel.ts index dca017dbfb0..a568881e7c2 100644 --- a/src/vs/base/browser/ui/tree/indexTreeModel.ts +++ b/src/vs/base/browser/ui/tree/indexTreeModel.ts @@ -71,8 +71,6 @@ export class IndexTreeModel, TFilterData = voi this.filter = options.filter; this.autoExpandSingleChildren = typeof options.autoExpandSingleChildren === 'undefined' ? false : options.autoExpandSingleChildren; - // this.onDidChangeCollapseState(node => console.log(node.collapsed, node)); - this.root = { parent: undefined, element: rootElement, @@ -177,7 +175,7 @@ export class IndexTreeModel, TFilterData = voi return result; } - refresh(location: number[]): void { + rerender(location: number[]): void { if (location.length === 0) { throw new Error('Invalid tree location'); } @@ -280,6 +278,21 @@ export class IndexTreeModel, TFilterData = voi return result; } + expandTo(location: number[]): void { + this.eventBufferer.bufferEvents(() => { + let node = this.getTreeNode(location); + + while (node.parent) { + node = node.parent; + location = location.slice(0, location.length - 1); + + if (node.collapsed) { + this._setCollapsed(location, false); + } + } + }); + } + refilter(): void { const previousRenderNodeCount = this.root.renderNodeCount; const toInsert = this.updateNodeAfterFilterChange(this.root); @@ -582,4 +595,4 @@ export class IndexTreeModel, TFilterData = voi return this._getLastElementAncestor(node.children[node.children.length - 1]); } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/tree/objectTree.ts b/src/vs/base/browser/ui/tree/objectTree.ts index dcdbe74b15f..1236b065722 100644 --- a/src/vs/base/browser/ui/tree/objectTree.ts +++ b/src/vs/base/browser/ui/tree/objectTree.ts @@ -36,11 +36,20 @@ export class ObjectTree, TFilterData = void> extends return this.model.setChildren(element, children, onDidCreateNode, onDidDeleteNode); } - refresh(element: T): void { - this.model.refresh(element); + rerender(element?: T): void { + if (element === undefined) { + this.view.rerender(); + return; + } + + this.model.rerender(element); + } + + resort(element: T, recursive = true): void { + this.model.resort(element, recursive); } protected createModel(view: ISpliceable>, options: IObjectTreeOptions): ITreeModel { return new ObjectTreeModel(view, options); } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/tree/objectTreeModel.ts b/src/vs/base/browser/ui/tree/objectTreeModel.ts index 3169271298e..b74a2b58709 100644 --- a/src/vs/base/browser/ui/tree/objectTreeModel.ts +++ b/src/vs/base/browser/ui/tree/objectTreeModel.ts @@ -19,7 +19,7 @@ export class ObjectTreeModel, TFilterData extends Non private model: IndexTreeModel; private nodes = new Map>(); - private sorter?: ITreeSorter>; + private sorter?: ITreeSorter<{ element: T; }>; readonly onDidSplice: Event>; readonly onDidChangeCollapseState: Event>; @@ -49,6 +49,15 @@ export class ObjectTreeModel, TFilterData extends Non onDidDeleteNode?: (node: ITreeNode) => void ): Iterator> { const location = this.getElementLocation(element); + return this._setChildren(location, this.preserveCollapseState(children), onDidCreateNode, onDidDeleteNode); + } + + private _setChildren( + location: number[], + children: ISequence> | undefined, + onDidCreateNode?: (node: ITreeNode) => void, + onDidDeleteNode?: (node: ITreeNode) => void + ): Iterator> { const insertedElements = new Set(); const _onDidCreateNode = (node: ITreeNode) => { @@ -73,13 +82,13 @@ export class ObjectTreeModel, TFilterData extends Non return this.model.splice( [...location, 0], Number.MAX_VALUE, - this.preserveCollapseState(children), + children, _onDidCreateNode, _onDidDeleteNode ); } - private preserveCollapseState(elements: ISequence> | undefined): ISequence> { + private preserveCollapseState(elements: ISequence> | undefined): ISequence> { let iterator = elements ? getSequenceIterator(elements) : Iterator.empty>(); if (this.sorter) { @@ -90,11 +99,14 @@ export class ObjectTreeModel, TFilterData extends Non const node = this.nodes.get(treeElement.element); if (!node) { - return treeElement; + return { + ...treeElement, + children: this.preserveCollapseState(treeElement.children) + }; } const collapsible = typeof treeElement.collapsible === 'boolean' ? treeElement.collapsible : node.collapsible; - const collapsed = typeof treeElement.collapsed !== 'undefined' ? treeElement.collapsed : (collapsible && node.collapsed); + const collapsed = typeof treeElement.collapsed !== 'undefined' ? treeElement.collapsed : node.collapsed; return { ...treeElement, @@ -105,9 +117,35 @@ export class ObjectTreeModel, TFilterData extends Non }); } - refresh(element: T): void { + rerender(element: T): void { const location = this.getElementLocation(element); - this.model.refresh(location); + this.model.rerender(location); + } + + resort(element: T | null = null, recursive = true): void { + if (!this.sorter) { + return; + } + + const location = this.getElementLocation(element); + const node = this.model.getNode(location); + + this._setChildren(location, this.resortChildren(node, recursive)); + } + + private resortChildren(node: ITreeNode, recursive: boolean, first = true): ISequence> { + let childrenNodes = Iterator.fromArray(node.children as ITreeNode[]); + + if (recursive || first) { + childrenNodes = Iterator.fromArray(Iterator.collect(childrenNodes).sort(this.sorter!.compare.bind(this.sorter))); + } + + return Iterator.map, ITreeElement>(childrenNodes, node => ({ + element: node.element as T, + collapsible: node.collapsible, + collapsed: node.collapsed, + children: this.resortChildren(node, recursive, false) + })); } getParentElement(ref: T | null = null): T | null { @@ -150,6 +188,11 @@ export class ObjectTreeModel, TFilterData extends Non return this.model.setCollapsed(location, collapsed, recursive); } + expandTo(element: T): void { + const location = this.getElementLocation(element); + this.model.expandTo(location); + } + refilter(): void { this.model.refilter(); } diff --git a/src/vs/base/browser/ui/tree/tree.ts b/src/vs/base/browser/ui/tree/tree.ts index 1cdd610004a..0ce4cfc07e4 100644 --- a/src/vs/base/browser/ui/tree/tree.ts +++ b/src/vs/base/browser/ui/tree/tree.ts @@ -122,6 +122,7 @@ export interface ITreeModel { isCollapsible(location: TRef): boolean; isCollapsed(location: TRef): boolean; setCollapsed(location: TRef, collapsed?: boolean, recursive?: boolean): boolean; + expandTo(location: TRef): void; refilter(): void; } diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 29eafda5275..1a5596aa6b7 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -53,7 +53,7 @@ export namespace Event { * throught the mapping function. */ export function map(event: Event, map: (i: I) => O): Event { - return (listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables); + return snapshot((listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables)); } /** @@ -61,7 +61,7 @@ export namespace Event { * the `each` function per each element. */ export function forEach(event: Event, each: (i: I) => void): Event { - return (listener, thisArgs = null, disposables?) => event(i => { each(i); listener.call(thisArgs, i); }, null, disposables); + return snapshot((listener, thisArgs = null, disposables?) => event(i => { each(i); listener.call(thisArgs, i); }, null, disposables)); } /** @@ -71,7 +71,7 @@ export namespace Event { export function filter(event: Event, filter: (e: T) => boolean): Event; export function filter(event: Event, filter: (e: T | R) => e is R): Event; export function filter(event: Event, filter: (e: T) => boolean): Event { - return (listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables); + return snapshot((listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables)); } /** @@ -110,10 +110,10 @@ export namespace Event { export function snapshot(event: Event): Event { let listener: IDisposable; const emitter = new Emitter({ - onFirstListenerAdd: () => { + onFirstListenerAdd() { listener = event(emitter.fire, emitter); }, - onLastListenerRemove: () => { + onLastListenerRemove() { listener.dispose(); } }); @@ -305,38 +305,34 @@ export namespace Event { class ChainableEvent implements IChainableEvent { - get event(): Event { - return snapshot(this._event); - } - - constructor(private _event: Event) { } + constructor(readonly event: Event) { } map(fn: (i: T) => O): IChainableEvent { - return new ChainableEvent(map(this._event, fn)); + return new ChainableEvent(map(this.event, fn)); } forEach(fn: (i: T) => void): IChainableEvent { - return new ChainableEvent(forEach(this._event, fn)); + return new ChainableEvent(forEach(this.event, fn)); } filter(fn: (e: T) => boolean): IChainableEvent { - return new ChainableEvent(filter(this._event, fn)); + return new ChainableEvent(filter(this.event, fn)); } reduce(merge: (last: R | undefined, event: T) => R, initial?: R): IChainableEvent { - return new ChainableEvent(reduce(this._event, merge, initial)); + return new ChainableEvent(reduce(this.event, merge, initial)); } latch(): IChainableEvent { - return new ChainableEvent(latch(this._event)); + return new ChainableEvent(latch(this.event)); } on(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[]) { - return this._event(listener, thisArgs, disposables); + return this.event(listener, thisArgs, disposables); } once(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[]) { - return once(this._event)(listener, thisArgs, disposables); + return once(this.event)(listener, thisArgs, disposables); } } diff --git a/src/vs/base/common/extpath.ts b/src/vs/base/common/extpath.ts index 5589e35aeb4..eaf31396842 100644 --- a/src/vs/base/common/extpath.ts +++ b/src/vs/base/common/extpath.ts @@ -6,21 +6,12 @@ import { isWindows } from 'vs/base/common/platform'; import { startsWithIgnoreCase, equalsIgnoreCase } from 'vs/base/common/strings'; import { CharCode } from 'vs/base/common/charCode'; -import { sep, posix } from 'vs/base/common/path'; +import { sep } from 'vs/base/common/path'; function isPathSeparator(code: number) { return code === CharCode.Slash || code === CharCode.Backslash; } -const _posixBadPath = /(\/\.\.?\/)|(\/\.\.?)$|^(\.\.?\/)|(\/\/+)|(\\)/; -const _winBadPath = /(\\\.\.?\\)|(\\\.\.?)$|^(\.\.?\\)|(\\\\+)|(\/)/; - -function _isNormal(path: string, win: boolean): boolean { - return win - ? !_winBadPath.test(path) - : !_posixBadPath.test(path); -} - /** * Takes a Windows OS path and changes backward slashes to forward slashes. * This should only be done for OS paths from Windows (or user provided paths potentially from Windows). @@ -30,93 +21,6 @@ export function toSlashes(osPath: string) { return osPath.replace(/[\\/]/g, '/'); } -export function normalizeWithSlashes(path: undefined): undefined; -export function normalizeWithSlashes(path: null): null; -export function normalizeWithSlashes(path: string): string; -export function normalizeWithSlashes(path: string | null | undefined): string | null | undefined { - - if (path === null || path === undefined) { - return path; - } - - const len = path.length; - if (len === 0) { - return '.'; - } - - if (_isNormal(path, false)) { - return path; - } - - const sep = '/'; - const root = getRoot(path, sep); - - // skip the root-portion of the path - let start = root.length; - let skip = false; - let res = ''; - - for (let end = root.length; end <= len; end++) { - - // either at the end or at a path-separator character - if (end === len || isPathSeparator(path.charCodeAt(end))) { - - if (streql(path, start, end, '..')) { - // skip current and remove parent (if there is already something) - let prev_start = res.lastIndexOf(sep); - let prev_part = res.slice(prev_start + 1); - if ((root || prev_part.length > 0) && prev_part !== '..') { - res = prev_start === -1 ? '' : res.slice(0, prev_start); - skip = true; - } - } else if (streql(path, start, end, '.') && (root || res || end < len - 1)) { - // skip current (if there is already something or if there is more to come) - skip = true; - } - - if (!skip) { - let part = path.slice(start, end); - if (res !== '' && res[res.length - 1] !== sep) { - res += sep; - } - res += part; - } - start = end + 1; - skip = false; - } - } - - return root + res; -} - -function streql(value: string, start: number, end: number, other: string): boolean { - return start + other.length === end && value.indexOf(other, start) === start; -} - -export function joinWithSlashes(...parts: string[]): string { - let value = ''; - for (let i = 0; i < parts.length; i++) { - let part = parts[i]; - if (i > 0) { - // add the separater between two parts unless - // there already is one - let last = value.charCodeAt(value.length - 1); - if (!isPathSeparator(last)) { - let next = part.charCodeAt(0); - if (!isPathSeparator(next)) { - value += posix.sep; - } - } - } - value += part; - } - - return normalizeWithSlashes(value); -} - - -// #region extpath - /** * Computes the _root_ this path, like `getRoot('c:\files') === c:\`, * `getRoot('files:///files/path') === files:///`, @@ -323,6 +227,4 @@ export function isEqualOrParent(path: string, candidate: string, ignoreCase?: bo export function isWindowsDriveLetter(char0: number): boolean { return char0 >= CharCode.A && char0 <= CharCode.Z || char0 >= CharCode.a && char0 <= CharCode.z; -} - -// #endregion \ No newline at end of file +} \ No newline at end of file diff --git a/src/vs/base/common/labels.ts b/src/vs/base/common/labels.ts index c1a17aa456b..dc55a8db24a 100644 --- a/src/vs/base/common/labels.ts +++ b/src/vs/base/common/labels.ts @@ -36,7 +36,7 @@ export function getPathLabel(resource: URI | string, userHomeProvider?: IUserHom const hasMultipleRoots = rootProvider.getWorkspace().folders.length > 1; let pathLabel: string; - if (isEqual(baseResource.uri, resource, !isLinux)) { + if (isEqual(baseResource.uri, resource)) { pathLabel = ''; // no label if paths are identical } else { // TODO: isidor use resources.relative diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts index 85168b0d0e4..6755ebaa983 100644 --- a/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts @@ -155,14 +155,3 @@ export const enum OperatingSystem { Linux = 3 } export const OS = (_isMacintosh ? OperatingSystem.Macintosh : (_isWindows ? OperatingSystem.Windows : OperatingSystem.Linux)); - -export const enum AccessibilitySupport { - /** - * This should be the browser case where it is not known if a screen reader is attached or no. - */ - Unknown = 0, - - Disabled = 1, - - Enabled = 2 -} diff --git a/src/vs/base/node/id.ts b/src/vs/base/node/id.ts index 1c7f84fa451..26bbd283fb2 100644 --- a/src/vs/base/node/id.ts +++ b/src/vs/base/node/id.ts @@ -97,7 +97,7 @@ function getMacMachineId(): Promise { // TODO@sbatten: Remove this when getmac is patched setTimeout(() => { resolve(undefined); - }, 1000); + }, 10000); } catch (err) { errors.onUnexpectedError(err); resolve(undefined); diff --git a/src/vs/base/node/languagePacks.d.ts b/src/vs/base/node/languagePacks.d.ts new file mode 100644 index 00000000000..241392e5eca --- /dev/null +++ b/src/vs/base/node/languagePacks.d.ts @@ -0,0 +1,23 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export interface NLSConfiguration { + locale: string; + availableLanguages: { + [key: string]: string; + }; + pseudo?: boolean; +} + +export interface InternalNLSConfiguration extends NLSConfiguration { + _languagePackId: string; + _translationsConfigFile: string; + _cacheRoot: string; + _resolvedLanguagePackCoreLocation: string; + _corruptedFile: string; + _languagePackSupport?: boolean; +} + +export function getNLSConfiguration(commit: string, userDataPath: string, metaDataFile: string, locale: string): Promise; \ No newline at end of file diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js new file mode 100644 index 00000000000..445a6c5f7b3 --- /dev/null +++ b/src/vs/base/node/languagePacks.js @@ -0,0 +1,332 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +//@ts-check + +/** + * @param {NodeRequire} nodeRequire + * @param {typeof import('path')} path + * @param {typeof import('fs')} fs + * @param {typeof import('../common/performance')} perf + */ +function factory(nodeRequire, path, fs, perf) { + + /** + * @param {string} file + * @returns {Promise} + */ + function exists(file) { + return new Promise(c => fs.exists(file, c)); + } + + /** + * @param {string} file + * @returns {Promise} + */ + function touch(file) { + return new Promise((c, e) => { const d = new Date(); fs.utimes(file, d, d, err => err ? e(err) : c()); }); + } + + /** + * @param {string} file + * @returns {Promise} + */ + function lstat(file) { + return new Promise((c, e) => fs.lstat(file, (err, stats) => err ? e(err) : c(stats))); + } + + /** + * @param {string} dir + * @returns {Promise} + */ + function readdir(dir) { + return new Promise((c, e) => fs.readdir(dir, (err, files) => err ? e(err) : c(files))); + } + + /** + * @param {string} dir + * @returns {Promise} + */ + function mkdir(dir) { + return new Promise((c, e) => fs.mkdir(dir, err => (err && err.code !== 'EEXIST') ? e(err) : c(dir))); + } + + /** + * @param {string} dir + * @returns {Promise} + */ + function rmdir(dir) { + return new Promise((c, e) => fs.rmdir(dir, err => err ? e(err) : c(undefined))); + } + + /** + * @param {string} file + * @returns {Promise} + */ + function unlink(file) { + return new Promise((c, e) => fs.unlink(file, err => err ? e(err) : c(undefined))); + } + + /** + * @param {string} location + * @returns {Promise} + */ + function rimraf(location) { + return lstat(location).then(stat => { + if (stat.isDirectory() && !stat.isSymbolicLink()) { + return readdir(location) + .then(children => Promise.all(children.map(child => rimraf(path.join(location, child))))) + .then(() => rmdir(location)); + } else { + return unlink(location); + } + }, err => { + if (err.code === 'ENOENT') { + return undefined; + } + throw err; + }); + } + + /** + * @param {string} dir + * @returns {Promise} + */ + function mkdirp(dir) { + return mkdir(dir).then(null, err => { + if (err && err.code === 'ENOENT') { + const parent = path.dirname(dir); + + if (parent !== dir) { // if not arrived at root + return mkdirp(parent).then(() => mkdir(dir)); + } + } + + throw err; + }); + } + + function readFile(file) { + return new Promise(function (resolve, reject) { + fs.readFile(file, 'utf8', function (err, data) { + if (err) { + reject(err); + return; + } + resolve(data); + }); + }); + } + + /** + * @param {string} file + * @param {string} content + * @returns {Promise} + */ + function writeFile(file, content) { + return new Promise(function (resolve, reject) { + fs.writeFile(file, content, 'utf8', function (err) { + if (err) { + reject(err); + return; + } + resolve(); + }); + }); + } + + + /** + * @param {string} userDataPath + * @returns {object} + */ + function getLanguagePackConfigurations(userDataPath) { + const configFile = path.join(userDataPath, 'languagepacks.json'); + try { + return nodeRequire(configFile); + } catch (err) { + // Do nothing. If we can't read the file we have no + // language pack config. + } + return undefined; + } + + /** + * @param {object} config + * @param {string} locale + */ + function resolveLanguagePackLocale(config, locale) { + try { + while (locale) { + if (config[locale]) { + return locale; + } else { + const index = locale.lastIndexOf('-'); + if (index > 0) { + locale = locale.substring(0, index); + } else { + return undefined; + } + } + } + } catch (err) { + console.error('Resolving language pack configuration failed.', err); + } + return undefined; + } + + /** + * @param {string} commit + * @param {string} userDataPath + * @param {string} metaDataFile + * @param {string} locale + */ + function getNLSConfiguration(commit, userDataPath, metaDataFile, locale) { + if (locale === 'pseudo') { + return Promise.resolve({ locale: locale, availableLanguages: {}, pseudo: true }); + } + + if (process.env['VSCODE_DEV']) { + return Promise.resolve({ locale: locale, availableLanguages: {} }); + } + + // We have a built version so we have extracted nls file. Try to find + // the right file to use. + + // Check if we have an English or English US locale. If so fall to default since that is our + // English translation (we don't ship *.nls.en.json files) + if (locale && (locale === 'en' || locale === 'en-us')) { + return Promise.resolve({ locale: locale, availableLanguages: {} }); + } + + const initialLocale = locale; + + perf.mark('nlsGeneration:start'); + + const defaultResult = function (locale) { + perf.mark('nlsGeneration:end'); + return Promise.resolve({ locale: locale, availableLanguages: {} }); + }; + try { + if (!commit) { + return defaultResult(initialLocale); + } + const configs = getLanguagePackConfigurations(userDataPath); + if (!configs) { + return defaultResult(initialLocale); + } + locale = resolveLanguagePackLocale(configs, locale); + if (!locale) { + return defaultResult(initialLocale); + } + const packConfig = configs[locale]; + let mainPack; + if (!packConfig || typeof packConfig.hash !== 'string' || !packConfig.translations || typeof (mainPack = packConfig.translations['vscode']) !== 'string') { + return defaultResult(initialLocale); + } + return exists(mainPack).then(fileExists => { + if (!fileExists) { + return defaultResult(initialLocale); + } + const packId = packConfig.hash + '.' + locale; + const cacheRoot = path.join(userDataPath, 'clp', packId); + const coreLocation = path.join(cacheRoot, commit); + const translationsConfigFile = path.join(cacheRoot, 'tcf.json'); + const corruptedFile = path.join(cacheRoot, 'corrupted.info'); + const result = { + locale: initialLocale, + availableLanguages: { '*': locale }, + _languagePackId: packId, + _translationsConfigFile: translationsConfigFile, + _cacheRoot: cacheRoot, + _resolvedLanguagePackCoreLocation: coreLocation, + _corruptedFile: corruptedFile + }; + return exists(corruptedFile).then(corrupted => { + // The nls cache directory is corrupted. + let toDelete; + if (corrupted) { + toDelete = rimraf(cacheRoot); + } else { + toDelete = Promise.resolve(undefined); + } + return toDelete.then(() => { + return exists(coreLocation).then(fileExists => { + if (fileExists) { + // We don't wait for this. No big harm if we can't touch + touch(coreLocation).catch(() => { }); + perf.mark('nlsGeneration:end'); + return result; + } + return mkdirp(coreLocation).then(() => { + return Promise.all([readFile(metaDataFile), readFile(mainPack)]); + }).then(values => { + const metadata = JSON.parse(values[0]); + const packData = JSON.parse(values[1]).contents; + const bundles = Object.keys(metadata.bundles); + const writes = []; + for (let bundle of bundles) { + const modules = metadata.bundles[bundle]; + const target = Object.create(null); + for (let module of modules) { + const keys = metadata.keys[module]; + const defaultMessages = metadata.messages[module]; + const translations = packData[module]; + let targetStrings; + if (translations) { + targetStrings = []; + for (let i = 0; i < keys.length; i++) { + const elem = keys[i]; + const key = typeof elem === 'string' ? elem : elem.key; + let translatedMessage = translations[key]; + if (translatedMessage === undefined) { + translatedMessage = defaultMessages[i]; + } + targetStrings.push(translatedMessage); + } + } else { + targetStrings = defaultMessages; + } + target[module] = targetStrings; + } + writes.push(writeFile(path.join(coreLocation, bundle.replace(/\//g, '!') + '.nls.json'), JSON.stringify(target))); + } + writes.push(writeFile(translationsConfigFile, JSON.stringify(packConfig.translations))); + return Promise.all(writes); + }).then(() => { + perf.mark('nlsGeneration:end'); + return result; + }).catch(err => { + console.error('Generating translation files failed.', err); + return defaultResult(locale); + }); + }); + }); + }); + }); + } catch (err) { + console.error('Generating translation files failed.', err); + return defaultResult(locale); + } + } + + return { + getNLSConfiguration + }; +} + + +if (typeof define === 'function') { + // amd + define(['path', 'fs', 'vs/base/common/performance'], function (path, fs, perf) { return factory(require.__$__nodeRequire, path, fs, perf); }); +} else if (typeof module === 'object' && typeof module.exports === 'object') { + const path = require('path'); + const fs = require('fs'); + const perf = require('../common/performance'); + module.exports = factory(require, path, fs, perf); +} else { + throw new Error('Unknown context'); +} \ No newline at end of file diff --git a/src/vs/base/node/processes.ts b/src/vs/base/node/processes.ts index eeaa7c6bc44..0dab519e6a4 100644 --- a/src/vs/base/node/processes.ts +++ b/src/vs/base/node/processes.ts @@ -79,7 +79,8 @@ export function sanitizeProcessEnvironment(env: Platform.IProcessEnvironment): v const keysToRemove = [ /^ELECTRON_.+$/, /^GOOGLE_API_KEY$/, - /^VSCODE_.+$/ + /^VSCODE_.+$/, + /^SNAP(|_.*)$/ ]; const envKeys = Object.keys(env); envKeys.forEach(envKey => { diff --git a/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts b/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts index 294eeb87722..6ceccbd08dc 100644 --- a/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts +++ b/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts @@ -101,4 +101,92 @@ suite('AsyncDataTree', function () { await tree.updateChildren(root); assert.equal(container.querySelectorAll('.monaco-list-row').length, 1); }); + + test('issue #68648', async () => { + const container = document.createElement('div'); + container.style.width = '200px'; + container.style.height = '200px'; + + const delegate = new class implements IListVirtualDelegate { + getHeight() { return 20; } + getTemplateId(element: Element): string { return 'default'; } + }; + + const renderer = new class implements ITreeRenderer { + readonly templateId = 'default'; + renderTemplate(container: HTMLElement): HTMLElement { + return container; + } + renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { + templateData.textContent = element.element.id; + } + disposeTemplate(templateData: HTMLElement): void { + // noop + } + }; + + const getChildrenCalls: string[] = []; + const dataSource = new class implements IAsyncDataSource { + hasChildren(element: Element): boolean { + return !!element.children && element.children.length > 0; + } + getChildren(element: Element): Promise { + getChildrenCalls.push(element.id); + return Promise.resolve(element.children || []); + } + }; + + const identityProvider = new class implements IIdentityProvider { + getId(element: Element) { + return element.id; + } + }; + + const root: Element = { + id: 'root', + children: [{ + id: 'a' + }] + }; + + const _: (id: string) => Element = find.bind(null, root.children); + + const tree = new AsyncDataTree(container, delegate, [renderer], dataSource, { identityProvider }); + tree.layout(200); + + await tree.setInput(root); + assert.deepStrictEqual(getChildrenCalls, ['root']); + + let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; + assert(!hasClass(twistie, 'collapsible')); + assert(!hasClass(twistie, 'collapsed')); + assert(tree.getNode().children[0].collapsed); + + _('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]; + await tree.updateChildren(root); + + assert.deepStrictEqual(getChildrenCalls, ['root', 'root']); + twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; + assert(hasClass(twistie, 'collapsible')); + assert(hasClass(twistie, 'collapsed')); + assert(tree.getNode().children[0].collapsed); + + _('a').children = []; + await tree.updateChildren(root); + + assert.deepStrictEqual(getChildrenCalls, ['root', 'root', 'root']); + twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; + assert(!hasClass(twistie, 'collapsible')); + assert(!hasClass(twistie, 'collapsed')); + assert(tree.getNode().children[0].collapsed); + + _('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]; + await tree.updateChildren(root); + + assert.deepStrictEqual(getChildrenCalls, ['root', 'root', 'root', 'root']); + twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement; + assert(hasClass(twistie, 'collapsible')); + assert(hasClass(twistie, 'collapsed')); + assert(tree.getNode().children[0].collapsed); + }); }); \ No newline at end of file diff --git a/src/vs/base/test/browser/ui/tree/objectTreeModel.test.ts b/src/vs/base/test/browser/ui/tree/objectTreeModel.test.ts index 3e6a1797b01..6a5ec8713c5 100644 --- a/src/vs/base/test/browser/ui/tree/objectTreeModel.test.ts +++ b/src/vs/base/test/browser/ui/tree/objectTreeModel.test.ts @@ -168,4 +168,77 @@ suite('ObjectTreeModel', function () { model.setChildren(null, data); assert.deepEqual(toArray(list), ['father']); }); + + test('sorter', () => { + let compare: (a: string, b: string) => number = (a, b) => a < b ? -1 : 1; + + const list: ITreeNode[] = []; + const model = new ObjectTreeModel(toSpliceable(list), { sorter: { compare(a, b) { return compare(a, b); } } }); + const data = [ + { element: 'cars', children: [{ element: 'sedan' }, { element: 'convertible' }, { element: 'compact' }] }, + { element: 'airplanes', children: [{ element: 'passenger' }, { element: 'jet' }] }, + { element: 'bicycles', children: [{ element: 'dutch' }, { element: 'mountain' }, { element: 'electric' }] }, + ]; + + model.setChildren(null, data); + assert.deepEqual(toArray(list), ['airplanes', 'jet', 'passenger', 'bicycles', 'dutch', 'electric', 'mountain', 'cars', 'compact', 'convertible', 'sedan']); + }); + + test('resort', () => { + let compare: (a: string, b: string) => number = () => 0; + + const list: ITreeNode[] = []; + const model = new ObjectTreeModel(toSpliceable(list), { sorter: { compare(a, b) { return compare(a, b); } } }); + const data = [ + { element: 'cars', children: [{ element: 'sedan' }, { element: 'convertible' }, { element: 'compact' }] }, + { element: 'airplanes', children: [{ element: 'passenger' }, { element: 'jet' }] }, + { element: 'bicycles', children: [{ element: 'dutch' }, { element: 'mountain' }, { element: 'electric' }] }, + ]; + + model.setChildren(null, data); + assert.deepEqual(toArray(list), ['cars', 'sedan', 'convertible', 'compact', 'airplanes', 'passenger', 'jet', 'bicycles', 'dutch', 'mountain', 'electric']); + + // lexicographical + compare = (a, b) => a < b ? -1 : 1; + + // non-recursive + model.resort(null, false); + assert.deepEqual(toArray(list), ['airplanes', 'passenger', 'jet', 'bicycles', 'dutch', 'mountain', 'electric', 'cars', 'sedan', 'convertible', 'compact']); + + // recursive + model.resort(); + assert.deepEqual(toArray(list), ['airplanes', 'jet', 'passenger', 'bicycles', 'dutch', 'electric', 'mountain', 'cars', 'compact', 'convertible', 'sedan']); + + // reverse + compare = (a, b) => a < b ? 1 : -1; + + // scoped + model.resort('cars'); + assert.deepEqual(toArray(list), ['airplanes', 'jet', 'passenger', 'bicycles', 'dutch', 'electric', 'mountain', 'cars', 'sedan', 'convertible', 'compact']); + + // recursive + model.resort(); + assert.deepEqual(toArray(list), ['cars', 'sedan', 'convertible', 'compact', 'bicycles', 'mountain', 'electric', 'dutch', 'airplanes', 'passenger', 'jet']); + }); + + test('expandTo', () => { + const list: ITreeNode[] = []; + const model = new ObjectTreeModel(toSpliceable(list), { collapseByDefault: true }); + + model.setChildren(null, [ + { + element: 0, children: [ + { element: 10, children: [{ element: 100, children: [{ element: 1000 }] }] }, + { element: 11 }, + { element: 12 }, + ] + }, + { element: 1 }, + { element: 2 } + ]); + + assert.deepEqual(toArray(list), [0, 1, 2]); + model.expandTo(1000); + assert.deepEqual(toArray(list), [0, 10, 100, 1000, 11, 12, 1, 2]); + }); }); \ No newline at end of file diff --git a/src/vs/base/test/common/event.test.ts b/src/vs/base/test/common/event.test.ts index 2682f307b22..a08f0aa538c 100644 --- a/src/vs/base/test/common/event.test.ts +++ b/src/vs/base/test/common/event.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { Event, Emitter, EventBufferer, EventMultiplexer, AsyncEmitter, IWaitUntil } from 'vs/base/common/event'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable } from 'vs/base/common/lifecycle'; import * as Errors from 'vs/base/common/errors'; import { timeout } from 'vs/base/common/async'; @@ -777,37 +777,4 @@ suite('Event utils', () => { listener.dispose(); }); - - test('snapshot', () => { - const disposables: IDisposable[] = []; - - const emitter = new Emitter(); - let count = 0; - const event = Event.forEach(emitter.event, () => count++); - - // one listener - event(() => null, null, disposables); - emitter.fire(); - assert.equal(count, 1); - dispose(disposables); - - // two listeners - count = 0; - event(() => null, null, disposables); - event(() => null, null, disposables); - emitter.fire(); - emitter.fire(); - assert.equal(count, 4); // forEach will run *per event* and *per listener* - dispose(disposables); - - // two listeners, with snapshot - count = 0; - const eventSnapshot = Event.snapshot(event); - eventSnapshot(() => null, null, disposables); - eventSnapshot(() => null, null, disposables); - emitter.fire(); - emitter.fire(); - assert.equal(count, 2); // forEach will run only once *per listener* - dispose(disposables); - }); }); diff --git a/src/vs/base/test/common/extpath.test.ts b/src/vs/base/test/common/extpath.test.ts index f5947d06593..7ca9a3c824f 100644 --- a/src/vs/base/test/common/extpath.test.ts +++ b/src/vs/base/test/common/extpath.test.ts @@ -15,53 +15,6 @@ suite('Paths', () => { assert.equal(extpath.toSlashes('/user/far'), '/user/far'); }); - - test('normalize', () => { - assert.equal(extpath.normalizeWithSlashes(''), '.'); - assert.equal(extpath.normalizeWithSlashes('.'), '.'); - assert.equal(extpath.normalizeWithSlashes('.'), '.'); - assert.equal(extpath.normalizeWithSlashes('../../far'), '../../far'); - assert.equal(extpath.normalizeWithSlashes('../bar'), '../bar'); - assert.equal(extpath.normalizeWithSlashes('../far'), '../far'); - assert.equal(extpath.normalizeWithSlashes('./'), './'); - assert.equal(extpath.normalizeWithSlashes('./././'), './'); - assert.equal(extpath.normalizeWithSlashes('./ff/./'), 'ff/'); - assert.equal(extpath.normalizeWithSlashes('./foo'), 'foo'); - assert.equal(extpath.normalizeWithSlashes('/'), '/'); - assert.equal(extpath.normalizeWithSlashes('/..'), '/'); - assert.equal(extpath.normalizeWithSlashes('///'), '/'); - assert.equal(extpath.normalizeWithSlashes('//foo'), '/foo'); - assert.equal(extpath.normalizeWithSlashes('//foo//'), '/foo/'); - assert.equal(extpath.normalizeWithSlashes('/foo'), '/foo'); - assert.equal(extpath.normalizeWithSlashes('/foo/bar.test'), '/foo/bar.test'); - assert.equal(extpath.normalizeWithSlashes('\\\\\\'), '/'); - assert.equal(extpath.normalizeWithSlashes('c:/../ff'), 'c:/ff'); - assert.equal(extpath.normalizeWithSlashes('c:\\./'), 'c:/'); - assert.equal(extpath.normalizeWithSlashes('foo/'), 'foo/'); - assert.equal(extpath.normalizeWithSlashes('foo/../../bar'), '../bar'); - assert.equal(extpath.normalizeWithSlashes('foo/./'), 'foo/'); - assert.equal(extpath.normalizeWithSlashes('foo/./bar'), 'foo/bar'); - assert.equal(extpath.normalizeWithSlashes('foo//'), 'foo/'); - assert.equal(extpath.normalizeWithSlashes('foo//'), 'foo/'); - assert.equal(extpath.normalizeWithSlashes('foo//bar'), 'foo/bar'); - assert.equal(extpath.normalizeWithSlashes('foo//bar/far'), 'foo/bar/far'); - assert.equal(extpath.normalizeWithSlashes('foo/bar/../../far'), 'far'); - assert.equal(extpath.normalizeWithSlashes('foo/bar/../far'), 'foo/far'); - assert.equal(extpath.normalizeWithSlashes('foo/far/../../bar'), 'bar'); - assert.equal(extpath.normalizeWithSlashes('foo/far/../../bar'), 'bar'); - assert.equal(extpath.normalizeWithSlashes('foo/xxx/..'), 'foo'); - assert.equal(extpath.normalizeWithSlashes('foo/xxx/../bar'), 'foo/bar'); - assert.equal(extpath.normalizeWithSlashes('foo/xxx/./..'), 'foo'); - assert.equal(extpath.normalizeWithSlashes('foo/xxx/./../bar'), 'foo/bar'); - assert.equal(extpath.normalizeWithSlashes('foo/xxx/./bar'), 'foo/xxx/bar'); - assert.equal(extpath.normalizeWithSlashes('foo\\bar'), 'foo/bar'); - assert.equal(extpath.normalizeWithSlashes(null), null); - assert.equal(extpath.normalizeWithSlashes(undefined), undefined); - - // https://github.com/Microsoft/vscode/issues/7234 - assert.equal(extpath.joinWithSlashes('/home/aeschli/workspaces/vscode/extensions/css', './syntaxes/css.plist'), '/home/aeschli/workspaces/vscode/extensions/css/syntaxes/css.plist'); - }); - test('getRoot', () => { assert.equal(extpath.getRoot('/user/far'), '/'); @@ -79,33 +32,6 @@ suite('Paths', () => { }); - test('join', () => { - assert.equal(extpath.joinWithSlashes('.', 'bar'), 'bar'); - assert.equal(extpath.joinWithSlashes('../../foo/bar', '../../foo'), '../../foo'); - assert.equal(extpath.joinWithSlashes('../../foo/bar', '../bar/foo'), '../../foo/bar/foo'); - assert.equal(extpath.joinWithSlashes('../foo/bar', '../bar/foo'), '../foo/bar/foo'); - assert.equal(extpath.joinWithSlashes('/', 'bar'), '/bar'); - assert.equal(extpath.joinWithSlashes('//server/far/boo', '../file.txt'), '//server/far/file.txt'); - assert.equal(extpath.joinWithSlashes('/foo/', '/bar'), '/foo/bar'); - assert.equal(extpath.joinWithSlashes('\\\\server\\far\\boo', '../file.txt'), '//server/far/file.txt'); - assert.equal(extpath.joinWithSlashes('\\\\server\\far\\boo', './file.txt'), '//server/far/boo/file.txt'); - assert.equal(extpath.joinWithSlashes('\\\\server\\far\\boo', '.\\file.txt'), '//server/far/boo/file.txt'); - assert.equal(extpath.joinWithSlashes('\\\\server\\far\\boo', 'file.txt'), '//server/far/boo/file.txt'); - assert.equal(extpath.joinWithSlashes('file:///c/users/test', 'test'), 'file:///c/users/test/test'); - assert.equal(extpath.joinWithSlashes('file://localhost/c$/GitDevelopment/express', './settings'), 'file://localhost/c$/GitDevelopment/express/settings'); // unc - assert.equal(extpath.joinWithSlashes('file://localhost/c$/GitDevelopment/express', '.settings'), 'file://localhost/c$/GitDevelopment/express/.settings'); // unc - assert.equal(extpath.joinWithSlashes('foo', '/bar'), 'foo/bar'); - assert.equal(extpath.joinWithSlashes('foo', 'bar'), 'foo/bar'); - assert.equal(extpath.joinWithSlashes('foo', 'bar/'), 'foo/bar/'); - assert.equal(extpath.joinWithSlashes('foo/', '/bar'), 'foo/bar'); - assert.equal(extpath.joinWithSlashes('foo/', '/bar/'), 'foo/bar/'); - assert.equal(extpath.joinWithSlashes('foo/', 'bar'), 'foo/bar'); - assert.equal(extpath.joinWithSlashes('foo/bar', '../bar/foo'), 'foo/bar/foo'); - assert.equal(extpath.joinWithSlashes('foo/bar', './bar/foo'), 'foo/bar/bar/foo'); - assert.equal(extpath.joinWithSlashes('http://localhost/test', '../next'), 'http://localhost/next'); - assert.equal(extpath.joinWithSlashes('http://localhost/test', 'test'), 'http://localhost/test/test'); - }); - test('isUNC', () => { if (platform.isWindows) { assert.ok(!extpath.isUNC('foo')); diff --git a/src/vs/code/electron-browser/issue/issueReporterMain.ts b/src/vs/code/electron-browser/issue/issueReporterMain.ts index cf7a592fff8..ca5ed69d0af 100644 --- a/src/vs/code/electron-browser/issue/issueReporterMain.ts +++ b/src/vs/code/electron-browser/issue/issueReporterMain.ts @@ -10,8 +10,8 @@ import { $ } from 'vs/base/browser/dom'; import * as collections from 'vs/base/common/collections'; import * as browser from 'vs/base/browser/browser'; import { escape } from 'vs/base/common/strings'; -import product from 'vs/platform/node/product'; -import pkg from 'vs/platform/node/package'; +import product from 'vs/platform/product/node/product'; +import pkg from 'vs/platform/product/node/package'; import * as os from 'os'; import { debounce } from 'vs/base/common/decorators'; import * as platform from 'vs/base/common/platform'; @@ -346,7 +346,7 @@ export class IssueReporter extends Disposable { const value = (e.target).value; const problemSourceHelpText = this.getElementById('problem-source-help-text')!; if (value === '') { - this.issueReporterModel.update({ fileOnExtension: undefined, includeExtensions: false }); + this.issueReporterModel.update({ fileOnExtension: undefined }); show(problemSourceHelpText); this.clearSearchResults(); this.render(); @@ -356,7 +356,7 @@ export class IssueReporter extends Disposable { } const fileOnExtension = JSON.parse(value); - this.issueReporterModel.update({ fileOnExtension: fileOnExtension, includeExtensions: !fileOnExtension }); + this.issueReporterModel.update({ fileOnExtension: fileOnExtension }); this.render(); const title = (this.getElementById('issue-title')).value; diff --git a/src/vs/code/electron-browser/issue/issueReporterModel.ts b/src/vs/code/electron-browser/issue/issueReporterModel.ts index b9625ea066f..b918ceff961 100644 --- a/src/vs/code/electron-browser/issue/issueReporterModel.ts +++ b/src/vs/code/electron-browser/issue/issueReporterModel.ts @@ -121,7 +121,7 @@ ${this.getInfos()} } if (this._data.issueType === IssueType.Bug || this._data.issueType === IssueType.PerformanceIssue) { - if (this._data.includeExtensions) { + if (!this._data.fileOnExtension && this._data.includeExtensions) { info += this.generateExtensionsMd(); } } diff --git a/src/vs/code/electron-browser/issue/issueReporterPage.ts b/src/vs/code/electron-browser/issue/issueReporterPage.ts index 70d9888849b..a8f85ec258d 100644 --- a/src/vs/code/electron-browser/issue/issueReporterPage.ts +++ b/src/vs/code/electron-browser/issue/issueReporterPage.ts @@ -19,8 +19,8 @@ export default (): string => `
- -