diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..55b4b4ba37 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,104 @@ +name: CI + +on: [push, pull_request] + +jobs: + linux: + runs-on: ubuntu-latest + env: + CHILD_CONCURRENCY: "1" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v1 + # TODO: rename azure-pipelines/linux/xvfb.init to github-actions + - run: | + sudo apt-get update + sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 + sudo cp build/azure-pipelines/linux/xvfb.init /etc/init.d/xvfb + sudo chmod +x /etc/init.d/xvfb + sudo update-rc.d xvfb defaults + sudo service xvfb start + name: Setup Build Environment + - uses: actions/setup-node@v1 + with: + node-version: 10 + # TODO: cache node modules + - run: yarn --frozen-lockfile + name: Install Dependencies + - run: yarn electron x64 + name: Download Electron + - run: yarn gulp hygiene --skip-tslint + name: Run Hygiene Checks + - run: yarn gulp tslint + name: Run TSLint Checks + - run: yarn monaco-compile-check + name: Run Monaco Editor Checks + - run: yarn compile + name: Compile Sources + - run: yarn download-builtin-extensions + name: Download Built-in Extensions + - run: DISPLAY=:10 ./scripts/test.sh --tfs "Unit Tests" + name: Run Unit Tests + - run: DISPLAY=:10 ./scripts/test-integration.sh --tfs "Integration Tests" + name: Run Integration Tests + + windows: + runs-on: windows-2016 + env: + CHILD_CONCURRENCY: "1" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + with: + node-version: 10 + - uses: actions/setup-python@v1 + with: + python-version: '2.x' + - run: yarn --frozen-lockfile + name: Install Dependencies + - run: yarn electron + name: Download Electron + - run: yarn gulp hygiene --skip-tslint + name: Run Hygiene Checks + - run: yarn gulp tslint + name: Run TSLint Checks + - run: yarn monaco-compile-check + name: Run Monaco Editor Checks + - run: yarn compile + name: Compile Sources + - run: yarn download-builtin-extensions + name: Download Built-in Extensions + - run: .\scripts\test.bat --tfs "Unit Tests" + name: Run Unit Tests + - run: .\scripts\test-integration.bat --tfs "Integration Tests" + name: Run Integration Tests + + darwin: + runs-on: macos-latest + env: + CHILD_CONCURRENCY: "1" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-node@v1 + with: + node-version: 10 + - run: yarn --frozen-lockfile + name: Install Dependencies + - run: yarn electron x64 + name: Download Electron + - run: yarn gulp hygiene --skip-tslint + name: Run Hygiene Checks + - run: yarn gulp tslint + name: Run TSLint Checks + - run: yarn monaco-compile-check + name: Run Monaco Editor Checks + - run: yarn compile + name: Compile Sources + - run: yarn download-builtin-extensions + name: Download Built-in Extensions + - run: ./scripts/test.sh --tfs "Unit Tests" + name: Run Unit Tests + - run: ./scripts/test-integration.sh --tfs "Integration Tests" + name: Run Integration Tests diff --git a/build/azure-pipelines/darwin/continuous-build-darwin.yml b/build/azure-pipelines/darwin/continuous-build-darwin.yml index 86cf6e4411..018b09c48c 100644 --- a/build/azure-pipelines/darwin/continuous-build-darwin.yml +++ b/build/azure-pipelines/darwin/continuous-build-darwin.yml @@ -11,7 +11,7 @@ steps: inputs: versionSpec: "1.x" - script: | - yarn --frozen-lockfile + CHILD_CONCURRENCY=1 yarn --frozen-lockfile displayName: Install Dependencies condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 diff --git a/build/azure-pipelines/linux/continuous-build-linux.yml b/build/azure-pipelines/linux/continuous-build-linux.yml index 7e62edbe87..7ca5db331a 100644 --- a/build/azure-pipelines/linux/continuous-build-linux.yml +++ b/build/azure-pipelines/linux/continuous-build-linux.yml @@ -19,7 +19,7 @@ steps: inputs: versionSpec: "1.x" - script: | - yarn --frozen-lockfile + CHILD_CONCURRENCY=1 yarn --frozen-lockfile displayName: Install Dependencies condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 diff --git a/build/azure-pipelines/win32/continuous-build-win32.yml b/build/azure-pipelines/win32/continuous-build-win32.yml index dc102a4656..f0316915b2 100644 --- a/build/azure-pipelines/win32/continuous-build-win32.yml +++ b/build/azure-pipelines/win32/continuous-build-win32.yml @@ -16,6 +16,8 @@ steps: vstsFeed: '$(ArtifactFeed)' - powershell: | yarn --frozen-lockfile + env: + CHILD_CONCURRENCY: "1" displayName: Install Dependencies condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 diff --git a/extensions/image-preview/media/main.js b/extensions/image-preview/media/main.js index 3b2af6e73a..8843c26bdf 100644 --- a/extensions/image-preview/media/main.js +++ b/extensions/image-preview/media/main.js @@ -138,6 +138,34 @@ updateScale(scale); } + function zoomIn() { + if (scale === 'fit') { + firstZoom(); + } + + let i = 0; + for (; i < zoomLevels.length; ++i) { + if (zoomLevels[i] > scale) { + break; + } + } + updateScale(zoomLevels[i] || MAX_SCALE); + } + + function zoomOut() { + if (scale === 'fit') { + firstZoom(); + } + + let i = zoomLevels.length - 1; + for (; i >= 0; --i) { + if (zoomLevels[i] < scale) { + break; + } + } + updateScale(zoomLevels[i] || MIN_SCALE); + } + window.addEventListener('keydown', (/** @type {KeyboardEvent} */ e) => { if (!image || !hasLoadedImage) { return; @@ -204,21 +232,9 @@ } if (!(isMac ? altPressed : ctrlPressed)) { // zoom in - let i = 0; - for (; i < zoomLevels.length; ++i) { - if (zoomLevels[i] > scale) { - break; - } - } - updateScale(zoomLevels[i] || MAX_SCALE); + zoomIn(); } else { - let i = zoomLevels.length - 1; - for (; i >= 0; --i) { - if (zoomLevels[i] < scale) { - break; - } - } - updateScale(zoomLevels[i] || MIN_SCALE); + zoomOut(); } }); @@ -232,9 +248,6 @@ return; } - e.preventDefault(); - e.stopPropagation(); - if (scale === 'fit') { firstZoom(); } @@ -290,9 +303,18 @@ case 'setScale': updateScale(e.data.scale); break; + case 'setActive': changeActive(e.data.value); break; + + case 'zoomIn': + zoomIn(); + break; + + case 'zoomOut': + zoomOut(); + break; } }); }()); diff --git a/extensions/image-preview/package.json b/extensions/image-preview/package.json index f90152f7bc..c6149de85d 100644 --- a/extensions/image-preview/package.json +++ b/extensions/image-preview/package.json @@ -17,7 +17,9 @@ "Other" ], "activationEvents": [ - "onWebviewEditor:imagePreview.previewEditor" + "onWebviewEditor:imagePreview.previewEditor", + "onCommand:imagePreview.zoomIn", + "onCommand:imagePreview.zoomOut" ], "contributes": { "webviewEditors": [ @@ -32,7 +34,33 @@ } ] } - ] + ], + "commands": [ + { + "command": "imagePreview.zoomIn", + "title": "%command.zoomIn%", + "category": "Image Preview" + }, + { + "command": "imagePreview.zoomOut", + "title": "%command.zoomOut%", + "category": "Image Preview" + } + ], + "menus": { + "commandPalette": [ + { + "command": "imagePreview.zoomIn", + "when": "imagePreviewFocus", + "group": "1_imagePreview" + }, + { + "command": "imagePreview.zoomOut", + "when": "imagePreviewFocus", + "group": "1_imagePreview" + } + ] + } }, "scripts": { "compile": "gulp compile-extension:image-preview", diff --git a/extensions/image-preview/package.nls.json b/extensions/image-preview/package.nls.json index 44359cba8d..304b1df9a3 100644 --- a/extensions/image-preview/package.nls.json +++ b/extensions/image-preview/package.nls.json @@ -1,5 +1,7 @@ { "displayName": "Image Preview", "description": "Provides VS Code's built-in image preview", - "webviewEditors.displayName": "Image Preview" + "webviewEditors.displayName": "Image Preview", + "command.zoomIn": "Zoom in", + "command.zoomOut": "Zoom out" } diff --git a/extensions/image-preview/src/extension.ts b/extensions/image-preview/src/extension.ts index 7d4d49f717..2126e9c1cb 100644 --- a/extensions/image-preview/src/extension.ts +++ b/extensions/image-preview/src/extension.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { Preview } from './preview'; +import { PreviewManager } from './preview'; import { SizeStatusBarEntry } from './sizeStatusBarEntry'; import { ZoomStatusBarEntry } from './zoomStatusBarEntry'; @@ -17,12 +17,22 @@ export function activate(context: vscode.ExtensionContext) { const zoomStatusBarEntry = new ZoomStatusBarEntry(); context.subscriptions.push(zoomStatusBarEntry); + const previewManager = new PreviewManager(extensionRoot, sizeStatusBarEntry, zoomStatusBarEntry); + context.subscriptions.push(vscode.window.registerWebviewEditorProvider( - Preview.viewType, + PreviewManager.viewType, { async resolveWebviewEditor(resource: vscode.Uri, editor: vscode.WebviewEditor): Promise { - // tslint:disable-next-line: no-unused-expression - new Preview(extensionRoot, resource, editor, sizeStatusBarEntry, zoomStatusBarEntry); + previewManager.resolve(resource, editor); } })); + + context.subscriptions.push(vscode.commands.registerCommand('imagePreview.zoomIn', () => { + previewManager.activePreview?.zoomIn(); + })); + + context.subscriptions.push(vscode.commands.registerCommand('imagePreview.zoomOut', () => { + previewManager.activePreview?.zoomOut(); + })); } + diff --git a/extensions/image-preview/src/preview.ts b/extensions/image-preview/src/preview.ts index fd05fd794e..2809c8ac74 100644 --- a/extensions/image-preview/src/preview.ts +++ b/extensions/image-preview/src/preview.ts @@ -11,15 +11,58 @@ import { Scale, ZoomStatusBarEntry } from './zoomStatusBarEntry'; const localize = nls.loadMessageBundle(); + +export class PreviewManager { + + public static readonly viewType = 'imagePreview.previewEditor'; + + private readonly _previews = new Set(); + private _activePreview: Preview | undefined; + + constructor( + private readonly extensionRoot: vscode.Uri, + private readonly sizeStatusBarEntry: SizeStatusBarEntry, + private readonly zoomStatusBarEntry: ZoomStatusBarEntry, + ) { } + + public resolve( + resource: vscode.Uri, + webviewEditor: vscode.WebviewEditor, + ) { + const preview = new Preview(this.extensionRoot, resource, webviewEditor, this.sizeStatusBarEntry, this.zoomStatusBarEntry); + this._previews.add(preview); + this.setActivePreview(preview); + + webviewEditor.onDidDispose(() => { this._previews.delete(preview); }); + + webviewEditor.onDidChangeViewState(() => { + if (webviewEditor.active) { + this.setActivePreview(preview); + } else if (this._activePreview === preview && !webviewEditor.active) { + this.setActivePreview(undefined); + } + }); + } + + public get activePreview() { return this._activePreview; } + + private setActivePreview(value: Preview | undefined): void { + this._activePreview = value; + this.setPreviewActiveContext(!!value); + } + + private setPreviewActiveContext(value: boolean) { + vscode.commands.executeCommand('setContext', 'imagePreviewFocus', value); + } +} + const enum PreviewState { Disposed, Visible, Active, } -export class Preview extends Disposable { - - public static readonly viewType = 'imagePreview.previewEditor'; +class Preview extends Disposable { private readonly id: string = `${Date.now()}-${Math.random().toString()}`; @@ -98,6 +141,18 @@ export class Preview extends Disposable { this.update(); } + public zoomIn() { + if (this._previewState === PreviewState.Active) { + this.webviewEditor.webview.postMessage({ type: 'zoomIn' }); + } + } + + public zoomOut() { + if (this._previewState === PreviewState.Active) { + this.webviewEditor.webview.postMessage({ type: 'zoomOut' }); + } + } + private render() { if (this._previewState !== PreviewState.Disposed) { this.webviewEditor.webview.html = this.getWebiewContents(); diff --git a/package.json b/package.json index bf7bf336df..fc87548c43 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "native-keymap": "2.0.0", "native-watchdog": "1.2.0", "ng2-charts": "^1.6.0", - "node-pty": "0.9.0-beta19", + "node-pty": "0.9.0", "nsfw": "1.2.5", "onigasm-umd": "^2.2.2", "plotly.js-dist": "^1.48.3", diff --git a/remote/package.json b/remote/package.json index fd526a0b24..61022cb0b9 100644 --- a/remote/package.json +++ b/remote/package.json @@ -11,7 +11,7 @@ "iconv-lite": "0.5.0", "jschardet": "1.6.0", "native-watchdog": "1.2.0", - "node-pty": "0.9.0-beta19", + "node-pty": "0.9.0", "nsfw": "1.2.5", "onigasm-umd": "^2.2.2", "semver-umd": "^5.5.3", diff --git a/remote/yarn.lock b/remote/yarn.lock index 8fb560f3ee..325a7be1ce 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -249,7 +249,7 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -nan@^2.0.0, nan@^2.13.2, nan@^2.14.0: +nan@^2.0.0, nan@^2.14.0: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== @@ -264,12 +264,12 @@ node-addon-api@1.6.2: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.6.2.tgz#d8aad9781a5cfc4132cc2fecdbdd982534265217" integrity sha512-479Bjw9nTE5DdBSZZWprFryHGjUaQC31y1wHo19We/k0BZlrmhqQitWoUL0cD8+scljCbIUL+E58oRDEakdGGA== -node-pty@0.9.0-beta19: - version "0.9.0-beta19" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0-beta19.tgz#0fd381b2006f4665c4c2ee0509219e591842371a" - integrity sha512-MkKEvBnauGnzgXNr/oaoWQLVXm1gheIKZs4YQp8883ZiETmbEnpSvD0FU3bELcPXG5VFPRqIGsQJ4KUMBLzkPA== +node-pty@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0.tgz#8f9bcc0d1c5b970a3184ffd533d862c7eb6590a6" + integrity sha512-MBnCQl83FTYOu7B4xWw10AW77AAh7ThCE1VXEv+JeWj8mSpGo+0bwgsV+b23ljBFwEM9OmsOv3kM27iUPPm84g== dependencies: - nan "^2.13.2" + nan "^2.14.0" normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" diff --git a/scripts/sql.sh b/scripts/sql.sh index fcade57786..0bb7250a27 100755 --- a/scripts/sql.sh +++ b/scripts/sql.sh @@ -25,7 +25,7 @@ function code() { test -d node_modules || ./scripts/npm.sh install # Get electron - (test -f "$CODE" && [ $INTENDED_VERSION == $INSTALLED_VERSION ]) || ./node_modules/.bin/gulp electron + yarn electron # Sync built-in extensions node build/lib/builtInExtensions.js diff --git a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css index c9ceb0a65c..e4b41ab482 100644 --- a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css +++ b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css @@ -23,24 +23,6 @@ outline: none; } -.monaco-breadcrumbs .monaco-breadcrumb-item::before { - width: 14px; - height: 16px; - display: inline-block; +.monaco-breadcrumbs .monaco-breadcrumb-item:first-of-type::before { content: ' '; } - -.monaco-breadcrumbs .monaco-breadcrumb-item:not(:nth-child(2))::before { - background-image: url(./tree-collapsed-light.svg); - opacity: .7; - background-size: 16px; - background-position: 50% 50%; -} - -.vs-dark .monaco-breadcrumbs .monaco-breadcrumb-item:not(:nth-child(2))::before { - background-image: url(./tree-collapsed-dark.svg); -} - -.hc-black .monaco-breadcrumbs .monaco-breadcrumb-item:not(:nth-child(2))::before { - background-image: url(./tree-collapsed-hc.svg); -} diff --git a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts index a3b6a7cc90..ce2d9bf1c5 100644 --- a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts +++ b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts @@ -328,7 +328,9 @@ export class BreadcrumbsWidget { item.render(container); container.tabIndex = -1; container.setAttribute('role', 'listitem'); - dom.addClass(container, 'monaco-breadcrumb-item'); + dom.addClasses(container, 'monaco-breadcrumb-item'); + const iconContainer = dom.$('.codicon.codicon-chevron-right'); + container.appendChild(iconContainer); } private _onClick(event: IMouseEvent): void { diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css index 1f4a433995..494225e647 100644 --- a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css @@ -5,7 +5,7 @@ @font-face { font-family: "codicon"; - src: url("./codicon.ttf?10ac421d405314bb3250169d97fc2c62") format("truetype"); + src: url("./codicon.ttf?3a05fcfc657285cdb4cd3eba790b7462") format("truetype"); } .codicon[class*='codicon-'] { @@ -109,258 +109,275 @@ .codicon-clock:before { content: "\ea82" } .codicon-folder:before { content: "\ea83" } .codicon-file-directory:before { content: "\ea83" } +.codicon-symbol-folder:before { content: "\ea83" } .codicon-logo-github:before { content: "\ea84" } .codicon-mark-github:before { content: "\ea84" } .codicon-github:before { content: "\ea84" } .codicon-terminal:before { content: "\ea85" } .codicon-console:before { content: "\ea85" } .codicon-zap:before { content: "\ea86" } -.codicon-event:before { content: "\ea86" } +.codicon-symbol-event:before { content: "\ea86" } .codicon-error:before { content: "\ea87" } .codicon-stop:before { content: "\ea87" } +.codicon-variable:before { content: "\ea88" } +.codicon-symbol-variable:before { content: "\ea88" } +.codicon-array:before { content: "\ea8a" } +.codicon-symbol-array:before { content: "\ea8a" } +.codicon-symbol-module:before { content: "\ea8b" } +.codicon-symbol-package:before { content: "\ea8b" } +.codicon-symbol-namespace:before { content: "\ea8b" } +.codicon-symbol-object:before { content: "\ea8b" } +.codicon-symbol-method:before { content: "\ea8c" } +.codicon-symbol-function:before { content: "\ea8c" } +.codicon-symbol-constructor:before { content: "\ea8c" } +.codicon-symbol-boolean:before { content: "\ea8f" } +.codicon-symbol-null:before { content: "\ea8f" } +.codicon-symbol-numeric:before { content: "\ea90" } +.codicon-symbol-number:before { content: "\ea90" } +.codicon-symbol-structure:before { content: "\ea91" } +.codicon-symbol-struct:before { content: "\ea91" } +.codicon-symbol-parameter:before { content: "\ea92" } +.codicon-symbol-type-parameter:before { content: "\ea92" } +.codicon-symbol-key:before { content: "\ea93" } +.codicon-symbol-string:before { content: "\ea93" } +.codicon-symbol-text:before { content: "\ea93" } +.codicon-symbol-reference:before { content: "\ea94" } +.codicon-go-to-file:before { content: "\ea94" } +.codicon-symbol-enum:before { content: "\ea95" } +.codicon-symbol-value:before { content: "\ea95" } +.codicon-symbol-ruler:before { content: "\ea96" } +.codicon-symbol-unit:before { content: "\ea96" } .codicon-activate-breakpoints:before { content: "\f101" } .codicon-archive:before { content: "\f102" } -.codicon-array:before { content: "\f103" } -.codicon-arrow-both:before { content: "\f104" } -.codicon-arrow-down:before { content: "\f105" } -.codicon-arrow-left:before { content: "\f106" } -.codicon-arrow-right:before { content: "\f107" } -.codicon-arrow-small-down:before { content: "\f108" } -.codicon-arrow-small-left:before { content: "\f109" } -.codicon-arrow-small-right:before { content: "\f10a" } -.codicon-arrow-small-up:before { content: "\f10b" } -.codicon-arrow-up:before { content: "\f10c" } -.codicon-bell:before { content: "\f10d" } -.codicon-bold:before { content: "\f10e" } -.codicon-book:before { content: "\f10f" } -.codicon-bookmark:before { content: "\f110" } -.codicon-boolean:before { content: "\f111" } -.codicon-breakpoint-conditional-unverified:before { content: "\f112" } -.codicon-breakpoint-conditional:before { content: "\f113" } -.codicon-breakpoint-data-unverified:before { content: "\f114" } -.codicon-breakpoint-data:before { content: "\f115" } -.codicon-breakpoint-log-unverified:before { content: "\f116" } -.codicon-breakpoint-log:before { content: "\f117" } -.codicon-briefcase:before { content: "\f118" } -.codicon-broadcast:before { content: "\f119" } -.codicon-browser:before { content: "\f11a" } -.codicon-bug:before { content: "\f11b" } -.codicon-calendar:before { content: "\f11c" } -.codicon-case-sensitive:before { content: "\f11d" } -.codicon-check:before { content: "\f11e" } -.codicon-checklist:before { content: "\f11f" } -.codicon-chevron-down:before { content: "\f120" } -.codicon-chevron-left:before { content: "\f121" } -.codicon-chevron-right:before { content: "\f122" } -.codicon-chevron-up:before { content: "\f123" } -.codicon-chrome-close:before { content: "\f124" } -.codicon-chrome-maximize:before { content: "\f125" } -.codicon-chrome-minimize:before { content: "\f126" } -.codicon-chrome-restore:before { content: "\f127" } -.codicon-circle-outline:before { content: "\f128" } -.codicon-circle-slash:before { content: "\f129" } -.codicon-circuit-board:before { content: "\f12a" } -.codicon-class:before { content: "\f12b" } -.codicon-clear-all:before { content: "\f12c" } -.codicon-clippy:before { content: "\f12d" } -.codicon-close-all:before { content: "\f12e" } -.codicon-cloud-download:before { content: "\f12f" } -.codicon-cloud-upload:before { content: "\f130" } -.codicon-code:before { content: "\f131" } -.codicon-collapse-all:before { content: "\f132" } -.codicon-color-mode:before { content: "\f133" } -.codicon-color:before { content: "\f134" } -.codicon-comment-discussion:before { content: "\f135" } -.codicon-compare-changes:before { content: "\f136" } -.codicon-constant:before { content: "\f137" } -.codicon-continue:before { content: "\f138" } -.codicon-credit-card:before { content: "\f139" } -.codicon-current-and-breakpoint:before { content: "\f13a" } -.codicon-current:before { content: "\f13b" } -.codicon-dash:before { content: "\f13c" } -.codicon-dashboard:before { content: "\f13d" } -.codicon-database:before { content: "\f13e" } -.codicon-debug-disconnect:before { content: "\f13f" } -.codicon-debug-pause:before { content: "\f140" } -.codicon-debug-restart:before { content: "\f141" } -.codicon-debug-start:before { content: "\f142" } -.codicon-debug-step-into:before { content: "\f143" } -.codicon-debug-step-out:before { content: "\f144" } -.codicon-debug-step-over:before { content: "\f145" } -.codicon-debug-stop:before { content: "\f146" } -.codicon-debug:before { content: "\f147" } -.codicon-device-camera-video:before { content: "\f148" } -.codicon-device-camera:before { content: "\f149" } -.codicon-device-mobile:before { content: "\f14a" } -.codicon-diff-added:before { content: "\f14b" } -.codicon-diff-ignored:before { content: "\f14c" } -.codicon-diff-modified:before { content: "\f14d" } -.codicon-diff-removed:before { content: "\f14e" } -.codicon-diff-renamed:before { content: "\f14f" } -.codicon-diff:before { content: "\f150" } -.codicon-discard:before { content: "\f151" } -.codicon-editor-layout:before { content: "\f152" } -.codicon-ellipsis:before { content: "\f153" } -.codicon-empty-window:before { content: "\f154" } -.codicon-enumerator-member:before { content: "\f155" } -.codicon-enumerator:before { content: "\f156" } -.codicon-exclude:before { content: "\f157" } -.codicon-extensions:before { content: "\f158" } -.codicon-eye-closed:before { content: "\f159" } -.codicon-field:before { content: "\f15a" } -.codicon-file-binary:before { content: "\f15b" } -.codicon-file-code:before { content: "\f15c" } -.codicon-file-media:before { content: "\f15d" } -.codicon-file-pdf:before { content: "\f15e" } -.codicon-file-submodule:before { content: "\f15f" } -.codicon-file-symlink-directory:before { content: "\f160" } -.codicon-file-symlink-file:before { content: "\f161" } -.codicon-file-zip:before { content: "\f162" } -.codicon-files:before { content: "\f163" } -.codicon-filter:before { content: "\f164" } -.codicon-flame:before { content: "\f165" } -.codicon-fold-down:before { content: "\f166" } -.codicon-fold-up:before { content: "\f167" } -.codicon-fold:before { content: "\f168" } -.codicon-folder-active:before { content: "\f169" } -.codicon-folder-opened:before { content: "\f16a" } -.codicon-gear:before { content: "\f16b" } -.codicon-gift:before { content: "\f16c" } -.codicon-gist-secret:before { content: "\f16d" } -.codicon-gist:before { content: "\f16e" } -.codicon-git-commit:before { content: "\f16f" } -.codicon-git-compare:before { content: "\f170" } -.codicon-git-merge:before { content: "\f171" } -.codicon-github-action:before { content: "\f172" } -.codicon-github-alt:before { content: "\f173" } -.codicon-globe:before { content: "\f174" } -.codicon-go-to-file:before { content: "\f175" } -.codicon-grabber:before { content: "\f176" } -.codicon-graph:before { content: "\f177" } -.codicon-gripper:before { content: "\f178" } -.codicon-heart:before { content: "\f179" } -.codicon-home:before { content: "\f17a" } -.codicon-horizontal-rule:before { content: "\f17b" } -.codicon-hubot:before { content: "\f17c" } -.codicon-inbox:before { content: "\f17d" } -.codicon-interface:before { content: "\f17e" } -.codicon-issue-closed:before { content: "\f17f" } -.codicon-issue-reopened:before { content: "\f180" } -.codicon-issues:before { content: "\f181" } -.codicon-italic:before { content: "\f182" } -.codicon-jersey:before { content: "\f183" } -.codicon-json:before { content: "\f184" } -.codicon-kebab-vertical:before { content: "\f185" } -.codicon-key:before { content: "\f186" } -.codicon-keyword:before { content: "\f187" } -.codicon-law:before { content: "\f188" } -.codicon-lightbulb-autofix:before { content: "\f189" } -.codicon-link-external:before { content: "\f18a" } -.codicon-link:before { content: "\f18b" } -.codicon-list-ordered:before { content: "\f18c" } -.codicon-list-unordered:before { content: "\f18d" } -.codicon-live-share:before { content: "\f18e" } -.codicon-loading:before { content: "\f18f" } -.codicon-location:before { content: "\f190" } -.codicon-mail-read:before { content: "\f191" } -.codicon-mail:before { content: "\f192" } -.codicon-markdown:before { content: "\f193" } -.codicon-megaphone:before { content: "\f194" } -.codicon-mention:before { content: "\f195" } -.codicon-method:before { content: "\f196" } -.codicon-milestone:before { content: "\f197" } -.codicon-misc:before { content: "\f198" } -.codicon-mortar-board:before { content: "\f199" } -.codicon-move:before { content: "\f19a" } -.codicon-multiple-windows:before { content: "\f19b" } -.codicon-mute:before { content: "\f19c" } -.codicon-namespace:before { content: "\f19d" } -.codicon-no-newline:before { content: "\f19e" } -.codicon-note:before { content: "\f19f" } -.codicon-numeric:before { content: "\f1a0" } -.codicon-octoface:before { content: "\f1a1" } -.codicon-open-preview:before { content: "\f1a2" } -.codicon-operator:before { content: "\f1a3" } -.codicon-package:before { content: "\f1a4" } -.codicon-paintcan:before { content: "\f1a5" } -.codicon-parameter:before { content: "\f1a6" } -.codicon-pin:before { content: "\f1a7" } -.codicon-play:before { content: "\f1a8" } -.codicon-plug:before { content: "\f1a9" } -.codicon-preserve-case:before { content: "\f1aa" } -.codicon-preview:before { content: "\f1ab" } -.codicon-project:before { content: "\f1ac" } -.codicon-property:before { content: "\f1ad" } -.codicon-pulse:before { content: "\f1ae" } -.codicon-question:before { content: "\f1af" } -.codicon-quote:before { content: "\f1b0" } -.codicon-radio-tower:before { content: "\f1b1" } -.codicon-reactions:before { content: "\f1b2" } -.codicon-references:before { content: "\f1b3" } -.codicon-refresh:before { content: "\f1b4" } -.codicon-regex:before { content: "\f1b5" } -.codicon-remote:before { content: "\f1b6" } -.codicon-remove:before { content: "\f1b7" } -.codicon-replace-all:before { content: "\f1b8" } -.codicon-replace:before { content: "\f1b9" } -.codicon-repo-clone:before { content: "\f1ba" } -.codicon-repo-force-push:before { content: "\f1bb" } -.codicon-repo-pull:before { content: "\f1bc" } -.codicon-repo-push:before { content: "\f1bd" } -.codicon-report:before { content: "\f1be" } -.codicon-request-changes:before { content: "\f1bf" } -.codicon-rocket:before { content: "\f1c0" } -.codicon-root-folder-opened:before { content: "\f1c1" } -.codicon-root-folder:before { content: "\f1c2" } -.codicon-rss:before { content: "\f1c3" } -.codicon-ruby:before { content: "\f1c4" } -.codicon-ruler:before { content: "\f1c5" } -.codicon-save-all:before { content: "\f1c6" } -.codicon-save-as:before { content: "\f1c7" } -.codicon-save:before { content: "\f1c8" } -.codicon-screen-full:before { content: "\f1c9" } -.codicon-screen-normal:before { content: "\f1ca" } -.codicon-search-stop:before { content: "\f1cb" } -.codicon-selection:before { content: "\f1cc" } -.codicon-server:before { content: "\f1cd" } -.codicon-settings:before { content: "\f1ce" } -.codicon-shield:before { content: "\f1cf" } -.codicon-smiley:before { content: "\f1d0" } -.codicon-snippet:before { content: "\f1d1" } -.codicon-sort-precedence:before { content: "\f1d2" } -.codicon-split-horizontal:before { content: "\f1d3" } -.codicon-split-vertical:before { content: "\f1d4" } -.codicon-squirrel:before { content: "\f1d5" } -.codicon-star-full:before { content: "\f1d6" } -.codicon-star-half:before { content: "\f1d7" } -.codicon-string:before { content: "\f1d8" } -.codicon-structure:before { content: "\f1d9" } -.codicon-tasklist:before { content: "\f1da" } -.codicon-telescope:before { content: "\f1db" } -.codicon-text-size:before { content: "\f1dc" } -.codicon-three-bars:before { content: "\f1dd" } -.codicon-thumbsdown:before { content: "\f1de" } -.codicon-thumbsup:before { content: "\f1df" } -.codicon-tools:before { content: "\f1e0" } -.codicon-triangle-down:before { content: "\f1e1" } -.codicon-triangle-left:before { content: "\f1e2" } -.codicon-triangle-right:before { content: "\f1e3" } -.codicon-triangle-up:before { content: "\f1e4" } -.codicon-twitter:before { content: "\f1e5" } -.codicon-unfold:before { content: "\f1e6" } -.codicon-unlock:before { content: "\f1e7" } -.codicon-unmute:before { content: "\f1e8" } -.codicon-unverified:before { content: "\f1e9" } -.codicon-variable:before { content: "\f1ea" } -.codicon-verified:before { content: "\f1eb" } -.codicon-versions:before { content: "\f1ec" } -.codicon-vm-active:before { content: "\f1ed" } -.codicon-vm-outline:before { content: "\f1ee" } -.codicon-vm-running:before { content: "\f1ef" } -.codicon-watch:before { content: "\f1f0" } -.codicon-whitespace:before { content: "\f1f1" } -.codicon-whole-word:before { content: "\f1f2" } -.codicon-window:before { content: "\f1f3" } -.codicon-word-wrap:before { content: "\f1f4" } -.codicon-zoom-in:before { content: "\f1f5" } -.codicon-zoom-out:before { content: "\f1f6" } +.codicon-arrow-both:before { content: "\f103" } +.codicon-arrow-down:before { content: "\f104" } +.codicon-arrow-left:before { content: "\f105" } +.codicon-arrow-right:before { content: "\f106" } +.codicon-arrow-small-down:before { content: "\f107" } +.codicon-arrow-small-left:before { content: "\f108" } +.codicon-arrow-small-right:before { content: "\f109" } +.codicon-arrow-small-up:before { content: "\f10a" } +.codicon-arrow-up:before { content: "\f10b" } +.codicon-bell:before { content: "\f10c" } +.codicon-bold:before { content: "\f10d" } +.codicon-book:before { content: "\f10e" } +.codicon-bookmark:before { content: "\f10f" } +.codicon-breakpoint-conditional-unverified:before { content: "\f110" } +.codicon-breakpoint-conditional:before { content: "\f111" } +.codicon-breakpoint-data-unverified:before { content: "\f112" } +.codicon-breakpoint-data:before { content: "\f113" } +.codicon-breakpoint-log-unverified:before { content: "\f114" } +.codicon-breakpoint-log:before { content: "\f115" } +.codicon-briefcase:before { content: "\f116" } +.codicon-broadcast:before { content: "\f117" } +.codicon-browser:before { content: "\f118" } +.codicon-bug:before { content: "\f119" } +.codicon-calendar:before { content: "\f11a" } +.codicon-case-sensitive:before { content: "\f11b" } +.codicon-check:before { content: "\f11c" } +.codicon-checklist:before { content: "\f11d" } +.codicon-chevron-down:before { content: "\f11e" } +.codicon-chevron-left:before { content: "\f11f" } +.codicon-chevron-right:before { content: "\f120" } +.codicon-chevron-up:before { content: "\f121" } +.codicon-chrome-close:before { content: "\f122" } +.codicon-chrome-maximize:before { content: "\f123" } +.codicon-chrome-minimize:before { content: "\f124" } +.codicon-chrome-restore:before { content: "\f125" } +.codicon-circle-outline:before { content: "\f126" } +.codicon-circle-slash:before { content: "\f127" } +.codicon-circuit-board:before { content: "\f128" } +.codicon-clear-all:before { content: "\f129" } +.codicon-clippy:before { content: "\f12a" } +.codicon-close-all:before { content: "\f12b" } +.codicon-cloud-download:before { content: "\f12c" } +.codicon-cloud-upload:before { content: "\f12d" } +.codicon-code:before { content: "\f12e" } +.codicon-collapse-all:before { content: "\f12f" } +.codicon-color-mode:before { content: "\f130" } +.codicon-comment-discussion:before { content: "\f131" } +.codicon-compare-changes:before { content: "\f132" } +.codicon-continue:before { content: "\f133" } +.codicon-credit-card:before { content: "\f134" } +.codicon-current-and-breakpoint:before { content: "\f135" } +.codicon-current:before { content: "\f136" } +.codicon-dash:before { content: "\f137" } +.codicon-dashboard:before { content: "\f138" } +.codicon-database:before { content: "\f139" } +.codicon-debug-disconnect:before { content: "\f13a" } +.codicon-debug-pause:before { content: "\f13b" } +.codicon-debug-restart:before { content: "\f13c" } +.codicon-debug-start:before { content: "\f13d" } +.codicon-debug-step-into:before { content: "\f13e" } +.codicon-debug-step-out:before { content: "\f13f" } +.codicon-debug-step-over:before { content: "\f140" } +.codicon-debug-stop:before { content: "\f141" } +.codicon-debug:before { content: "\f142" } +.codicon-device-camera-video:before { content: "\f143" } +.codicon-device-camera:before { content: "\f144" } +.codicon-device-mobile:before { content: "\f145" } +.codicon-diff-added:before { content: "\f146" } +.codicon-diff-ignored:before { content: "\f147" } +.codicon-diff-modified:before { content: "\f148" } +.codicon-diff-removed:before { content: "\f149" } +.codicon-diff-renamed:before { content: "\f14a" } +.codicon-diff:before { content: "\f14b" } +.codicon-discard:before { content: "\f14c" } +.codicon-editor-layout:before { content: "\f14d" } +.codicon-ellipsis:before { content: "\f14e" } +.codicon-empty-window:before { content: "\f14f" } +.codicon-exclude:before { content: "\f150" } +.codicon-extensions:before { content: "\f151" } +.codicon-eye-closed:before { content: "\f152" } +.codicon-file-binary:before { content: "\f153" } +.codicon-file-code:before { content: "\f154" } +.codicon-file-media:before { content: "\f155" } +.codicon-file-pdf:before { content: "\f156" } +.codicon-file-submodule:before { content: "\f157" } +.codicon-file-symlink-directory:before { content: "\f158" } +.codicon-file-symlink-file:before { content: "\f159" } +.codicon-file-zip:before { content: "\f15a" } +.codicon-files:before { content: "\f15b" } +.codicon-filter:before { content: "\f15c" } +.codicon-flame:before { content: "\f15d" } +.codicon-fold-down:before { content: "\f15e" } +.codicon-fold-up:before { content: "\f15f" } +.codicon-fold:before { content: "\f160" } +.codicon-folder-active:before { content: "\f161" } +.codicon-folder-opened:before { content: "\f162" } +.codicon-gear:before { content: "\f163" } +.codicon-gift:before { content: "\f164" } +.codicon-gist-secret:before { content: "\f165" } +.codicon-gist:before { content: "\f166" } +.codicon-git-commit:before { content: "\f167" } +.codicon-git-compare:before { content: "\f168" } +.codicon-git-merge:before { content: "\f169" } +.codicon-github-action:before { content: "\f16a" } +.codicon-github-alt:before { content: "\f16b" } +.codicon-globe:before { content: "\f16c" } +.codicon-grabber:before { content: "\f16d" } +.codicon-graph:before { content: "\f16e" } +.codicon-gripper:before { content: "\f16f" } +.codicon-heart:before { content: "\f170" } +.codicon-home:before { content: "\f171" } +.codicon-horizontal-rule:before { content: "\f172" } +.codicon-hubot:before { content: "\f173" } +.codicon-inbox:before { content: "\f174" } +.codicon-issue-closed:before { content: "\f175" } +.codicon-issue-reopened:before { content: "\f176" } +.codicon-issues:before { content: "\f177" } +.codicon-italic:before { content: "\f178" } +.codicon-jersey:before { content: "\f179" } +.codicon-json:before { content: "\f17a" } +.codicon-kebab-vertical:before { content: "\f17b" } +.codicon-law:before { content: "\f17c" } +.codicon-lightbulb-autofix:before { content: "\f17d" } +.codicon-link-external:before { content: "\f17e" } +.codicon-link:before { content: "\f17f" } +.codicon-list-ordered:before { content: "\f180" } +.codicon-list-unordered:before { content: "\f181" } +.codicon-live-share:before { content: "\f182" } +.codicon-loading:before { content: "\f183" } +.codicon-location:before { content: "\f184" } +.codicon-mail-read:before { content: "\f185" } +.codicon-mail:before { content: "\f186" } +.codicon-markdown:before { content: "\f187" } +.codicon-megaphone:before { content: "\f188" } +.codicon-mention:before { content: "\f189" } +.codicon-milestone:before { content: "\f18a" } +.codicon-mortar-board:before { content: "\f18b" } +.codicon-move:before { content: "\f18c" } +.codicon-multiple-windows:before { content: "\f18d" } +.codicon-mute:before { content: "\f18e" } +.codicon-no-newline:before { content: "\f18f" } +.codicon-note:before { content: "\f190" } +.codicon-octoface:before { content: "\f191" } +.codicon-open-preview:before { content: "\f192" } +.codicon-package:before { content: "\f193" } +.codicon-paintcan:before { content: "\f194" } +.codicon-pin:before { content: "\f195" } +.codicon-play:before { content: "\f196" } +.codicon-plug:before { content: "\f197" } +.codicon-preserve-case:before { content: "\f198" } +.codicon-preview:before { content: "\f199" } +.codicon-project:before { content: "\f19a" } +.codicon-pulse:before { content: "\f19b" } +.codicon-question:before { content: "\f19c" } +.codicon-quote:before { content: "\f19d" } +.codicon-radio-tower:before { content: "\f19e" } +.codicon-reactions:before { content: "\f19f" } +.codicon-references:before { content: "\f1a0" } +.codicon-refresh:before { content: "\f1a1" } +.codicon-regex:before { content: "\f1a2" } +.codicon-remote:before { content: "\f1a3" } +.codicon-remove:before { content: "\f1a4" } +.codicon-replace-all:before { content: "\f1a5" } +.codicon-replace:before { content: "\f1a6" } +.codicon-repo-clone:before { content: "\f1a7" } +.codicon-repo-force-push:before { content: "\f1a8" } +.codicon-repo-pull:before { content: "\f1a9" } +.codicon-repo-push:before { content: "\f1aa" } +.codicon-report:before { content: "\f1ab" } +.codicon-request-changes:before { content: "\f1ac" } +.codicon-rocket:before { content: "\f1ad" } +.codicon-root-folder-opened:before { content: "\f1ae" } +.codicon-root-folder:before { content: "\f1af" } +.codicon-rss:before { content: "\f1b0" } +.codicon-ruby:before { content: "\f1b1" } +.codicon-save-all:before { content: "\f1b2" } +.codicon-save-as:before { content: "\f1b3" } +.codicon-save:before { content: "\f1b4" } +.codicon-screen-full:before { content: "\f1b5" } +.codicon-screen-normal:before { content: "\f1b6" } +.codicon-search-stop:before { content: "\f1b7" } +.codicon-selection:before { content: "\f1b8" } +.codicon-server:before { content: "\f1b9" } +.codicon-settings:before { content: "\f1ba" } +.codicon-shield:before { content: "\f1bb" } +.codicon-smiley:before { content: "\f1bc" } +.codicon-sort-precedence:before { content: "\f1bd" } +.codicon-split-horizontal:before { content: "\f1be" } +.codicon-split-vertical:before { content: "\f1bf" } +.codicon-squirrel:before { content: "\f1c0" } +.codicon-star-full:before { content: "\f1c1" } +.codicon-star-half:before { content: "\f1c2" } +.codicon-symbol-class:before { content: "\f1c3" } +.codicon-symbol-color:before { content: "\f1c4" } +.codicon-symbol-constant:before { content: "\f1c5" } +.codicon-symbol-enum-member:before { content: "\f1c6" } +.codicon-symbol-field:before { content: "\f1c7" } +.codicon-symbol-file:before { content: "\f1c8" } +.codicon-symbol-interface:before { content: "\f1c9" } +.codicon-symbol-keyword:before { content: "\f1ca" } +.codicon-symbol-misc:before { content: "\f1cb" } +.codicon-symbol-operator:before { content: "\f1cc" } +.codicon-symbol-property:before { content: "\f1cd" } +.codicon-symbol-snippet:before { content: "\f1ce" } +.codicon-tasklist:before { content: "\f1cf" } +.codicon-telescope:before { content: "\f1d0" } +.codicon-text-size:before { content: "\f1d1" } +.codicon-three-bars:before { content: "\f1d2" } +.codicon-thumbsdown:before { content: "\f1d3" } +.codicon-thumbsup:before { content: "\f1d4" } +.codicon-tools:before { content: "\f1d5" } +.codicon-triangle-down:before { content: "\f1d6" } +.codicon-triangle-left:before { content: "\f1d7" } +.codicon-triangle-right:before { content: "\f1d8" } +.codicon-triangle-up:before { content: "\f1d9" } +.codicon-twitter:before { content: "\f1da" } +.codicon-unfold:before { content: "\f1db" } +.codicon-unlock:before { content: "\f1dc" } +.codicon-unmute:before { content: "\f1dd" } +.codicon-unverified:before { content: "\f1de" } +.codicon-verified:before { content: "\f1df" } +.codicon-versions:before { content: "\f1e0" } +.codicon-vm-active:before { content: "\f1e1" } +.codicon-vm-outline:before { content: "\f1e2" } +.codicon-vm-running:before { content: "\f1e3" } +.codicon-watch:before { content: "\f1e4" } +.codicon-whitespace:before { content: "\f1e5" } +.codicon-whole-word:before { content: "\f1e6" } +.codicon-window:before { content: "\f1e7" } +.codicon-word-wrap:before { content: "\f1e8" } +.codicon-zoom-in:before { content: "\f1e9" } +.codicon-zoom-out:before { content: "\f1ea" } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf index 93e1eec8e2..beeea24d95 100644 Binary files a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf and b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf differ diff --git a/src/vs/base/browser/ui/iconLabel/iconlabel.css b/src/vs/base/browser/ui/iconLabel/iconlabel.css index 819fe8e62f..5fa0615f0d 100644 --- a/src/vs/base/browser/ui/iconLabel/iconlabel.css +++ b/src/vs/base/browser/ui/iconLabel/iconlabel.css @@ -20,6 +20,7 @@ padding-right: 6px; width: 16px; height: 22px; + line-height: inherit !important; display: inline-block; /* fonts icons */ diff --git a/src/vs/base/common/extpath.ts b/src/vs/base/common/extpath.ts index 7483613ee8..1aa143a93c 100644 --- a/src/vs/base/common/extpath.ts +++ b/src/vs/base/common/extpath.ts @@ -8,7 +8,7 @@ import { startsWithIgnoreCase, equalsIgnoreCase, endsWith, rtrim } from 'vs/base import { CharCode } from 'vs/base/common/charCode'; import { sep, posix, isAbsolute, join, normalize } from 'vs/base/common/path'; -function isPathSeparator(code: number) { +export function isPathSeparator(code: number) { return code === CharCode.Slash || code === CharCode.Backslash; } @@ -282,4 +282,4 @@ export function isRootOrDriveLetter(path: string): boolean { } return pathNormalized === posix.sep; -} \ No newline at end of file +} diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts index d1ba3da319..4381cc7777 100644 --- a/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -246,7 +246,8 @@ export function relativePath(from: URI, to: URI, ignoreCase = hasToIgnoreCase(fr } /** - * Resolves a absolute or relative path against a base URI. + * Resolves an absolute or relative path against a base URI. + * The path can be relative or absolute posix or a Windows path */ export function resolvePath(base: URI, path: string): URI { if (base.scheme === Schemas.file) { @@ -256,6 +257,12 @@ export function resolvePath(base: URI, path: string): URI { path: newURI.path }); } + if (path.indexOf('/') === -1) { // no slashes? it's likely a Windows path + path = extpath.toSlashes(path); + if (/^[a-zA-Z]:(\/|$)/.test(path)) { // starts with a drive letter + path = '/' + path; + } + } return base.with({ path: paths.posix.resolve(base.path, path) }); @@ -353,4 +360,4 @@ export function toLocalResource(resource: URI, authority: string | undefined): U } return resource.with({ scheme: Schemas.file }); -} \ No newline at end of file +} diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 068687d2c3..dad6301dc0 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { CharCode } from 'vs/base/common/charCode'; +import { Constants } from 'vs/base/common/uint'; export function isFalsyOrWhitespace(str: string | undefined): boolean { if (!str || typeof str !== 'string') { @@ -487,6 +488,190 @@ export function isLowSurrogate(charCode: number): boolean { return (0xDC00 <= charCode && charCode <= 0xDFFF); } +/** + * get the code point that begins at offset `offset` + */ +export function getNextCodePoint(str: string, len: number, offset: number): number { + const charCode = str.charCodeAt(offset); + if (isHighSurrogate(charCode) && offset + 1 < len) { + const nextCharCode = str.charCodeAt(offset + 1); + if (isLowSurrogate(nextCharCode)) { + return ((charCode - 0xD800) << 10) + (nextCharCode - 0xDC00) + 0x10000; + } + } + return charCode; +} + +/** + * get the code point that ends right before offset `offset` + */ +function getPrevCodePoint(str: string, offset: number): number { + const charCode = str.charCodeAt(offset - 1); + if (isLowSurrogate(charCode) && offset > 1) { + const prevCharCode = str.charCodeAt(offset - 2); + if (isHighSurrogate(prevCharCode)) { + return ((prevCharCode - 0xD800) << 10) + (charCode - 0xDC00) + 0x10000; + } + } + return charCode; +} + +export function nextCharLength(str: string, offset: number): number { + const initialOffset = offset; + const len = str.length; + + let codePoint = getNextCodePoint(str, len, offset); + offset += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + + while (offset < len) { + codePoint = getNextCodePoint(str, len, offset); + if (!isUnicodeMark(codePoint)) { + break; + } + offset += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + } + + return (offset - initialOffset); +} + +export function prevCharLength(str: string, offset: number): number { + const initialOffset = offset; + + let codePoint = getPrevCodePoint(str, offset); + offset -= (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + + while (offset > 0 && isUnicodeMark(codePoint)) { + codePoint = getPrevCodePoint(str, offset); + offset -= (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + } + + return (initialOffset - offset); +} + +function _getCharContainingOffset(str: string, offset: number): [number, number] { + const len = str.length; + const initialOffset = offset; + const initialCodePoint = getNextCodePoint(str, len, offset); + offset += (initialCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + + // extend to the right + while (offset < len) { + const nextCodePoint = getNextCodePoint(str, len, offset); + if (!isUnicodeMark(nextCodePoint)) { + break; + } + offset += (nextCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + } + const endOffset = offset; + + // extend to the left + offset = initialOffset; + let codePoint = initialCodePoint; + + while (offset > 0 && isUnicodeMark(codePoint)) { + codePoint = getPrevCodePoint(str, offset); + offset -= (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + } + + return [offset, endOffset]; +} + +export function getCharContainingOffset(str: string, offset: number): [number, number] { + if (offset > 0 && isLowSurrogate(str.charCodeAt(offset))) { + return _getCharContainingOffset(str, offset - 1); + } + return _getCharContainingOffset(str, offset); +} + +export function isUnicodeMark(codePoint: number): boolean { + return MarkClassifier.getInstance().isUnicodeMark(codePoint); +} + +class MarkClassifier { + + private static _INSTANCE: MarkClassifier | null = null; + + public static getInstance(): MarkClassifier { + if (!MarkClassifier._INSTANCE) { + MarkClassifier._INSTANCE = new MarkClassifier(); + } + return MarkClassifier._INSTANCE; + } + + private arr: Uint8Array; + + constructor() { + // generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-mark-test.js + const ranges = [ + 0x0300, 0x036F, 0x0483, 0x0489, 0x0591, 0x05BD, 0x05BF, 0x05BF, 0x05C1, 0x05C2, 0x05C4, 0x05C5, + 0x05C7, 0x05C7, 0x0610, 0x061A, 0x064B, 0x065F, 0x0670, 0x0670, 0x06D6, 0x06DC, 0x06DF, 0x06E4, + 0x06E7, 0x06E8, 0x06EA, 0x06ED, 0x0711, 0x0711, 0x0730, 0x074A, 0x07A6, 0x07B0, 0x07EB, 0x07F3, + 0x07FD, 0x07FD, 0x0816, 0x0819, 0x081B, 0x0823, 0x0825, 0x0827, 0x0829, 0x082D, 0x0859, 0x085B, + 0x08D3, 0x08E1, 0x08E3, 0x0903, 0x093A, 0x093C, 0x093E, 0x094F, 0x0951, 0x0957, 0x0962, 0x0963, + 0x0981, 0x0983, 0x09BC, 0x09BC, 0x09BE, 0x09CD, 0x09D7, 0x09D7, 0x09E2, 0x09E3, 0x09FE, 0x0A03, + 0x0A3C, 0x0A51, 0x0A70, 0x0A71, 0x0A75, 0x0A75, 0x0A81, 0x0A83, 0x0ABC, 0x0ABC, 0x0ABE, 0x0ACD, + 0x0AE2, 0x0AE3, 0x0AFA, 0x0B03, 0x0B3C, 0x0B3C, 0x0B3E, 0x0B57, 0x0B62, 0x0B63, 0x0B82, 0x0B82, + 0x0BBE, 0x0BCD, 0x0BD7, 0x0BD7, 0x0C00, 0x0C04, 0x0C3E, 0x0C56, 0x0C62, 0x0C63, 0x0C81, 0x0C83, + 0x0CBC, 0x0CBC, 0x0CBE, 0x0CD6, 0x0CE2, 0x0CE3, 0x0D00, 0x0D03, 0x0D3B, 0x0D3C, 0x0D3E, 0x0D4D, + 0x0D57, 0x0D57, 0x0D62, 0x0D63, 0x0D81, 0x0D83, 0x0DCA, 0x0DDF, 0x0DF2, 0x0DF3, 0x0E31, 0x0E31, + 0x0E34, 0x0E3A, 0x0E47, 0x0E4E, 0x0EB1, 0x0EB1, 0x0EB4, 0x0EBC, 0x0EC8, 0x0ECD, 0x0F18, 0x0F19, + 0x0F35, 0x0F35, 0x0F37, 0x0F37, 0x0F39, 0x0F39, 0x0F3E, 0x0F3F, 0x0F71, 0x0F84, 0x0F86, 0x0F87, + 0x0F8D, 0x0FBC, 0x0FC6, 0x0FC6, 0x102B, 0x103E, 0x1056, 0x1059, 0x105E, 0x1060, 0x1062, 0x1064, + 0x1067, 0x106D, 0x1071, 0x1074, 0x1082, 0x108D, 0x108F, 0x108F, 0x109A, 0x109D, 0x135D, 0x135F, + 0x1712, 0x1714, 0x1732, 0x1734, 0x1752, 0x1753, 0x1772, 0x1773, 0x17B4, 0x17D3, 0x17DD, 0x17DD, + 0x180B, 0x180D, 0x1885, 0x1886, 0x18A9, 0x18A9, 0x1920, 0x193B, 0x1A17, 0x1A1B, 0x1A55, 0x1A7F, + 0x1AB0, 0x1B04, 0x1B34, 0x1B44, 0x1B6B, 0x1B73, 0x1B80, 0x1B82, 0x1BA1, 0x1BAD, 0x1BE6, 0x1BF3, + 0x1C24, 0x1C37, 0x1CD0, 0x1CD2, 0x1CD4, 0x1CE8, 0x1CED, 0x1CED, 0x1CF4, 0x1CF4, 0x1CF7, 0x1CF9, + 0x1DC0, 0x1DFF, 0x20D0, 0x20F0, 0x2CEF, 0x2CF1, 0x2D7F, 0x2D7F, 0x2DE0, 0x2DFF, 0x302A, 0x302F, + 0x3099, 0x309A, 0xA66F, 0xA672, 0xA674, 0xA67D, 0xA69E, 0xA69F, 0xA6F0, 0xA6F1, 0xA802, 0xA802, + 0xA806, 0xA806, 0xA80B, 0xA80B, 0xA823, 0xA827, 0xA82C, 0xA82C, 0xA880, 0xA881, 0xA8B4, 0xA8C5, + 0xA8E0, 0xA8F1, 0xA8FF, 0xA8FF, 0xA926, 0xA92D, 0xA947, 0xA953, 0xA980, 0xA983, 0xA9B3, 0xA9C0, + 0xA9E5, 0xA9E5, 0xAA29, 0xAA36, 0xAA43, 0xAA43, 0xAA4C, 0xAA4D, 0xAA7B, 0xAA7D, 0xAAB0, 0xAAB0, + 0xAAB2, 0xAAB4, 0xAAB7, 0xAAB8, 0xAABE, 0xAABF, 0xAAC1, 0xAAC1, 0xAAEB, 0xAAEF, 0xAAF5, 0xAAF6, + 0xABE3, 0xABEA, 0xABEC, 0xABED, 0xFB1E, 0xFB1E, 0xFE00, 0xFE0F, 0xFE20, 0xFE2F, 0x101FD, 0x101FD, + 0x102E0, 0x102E0, 0x10376, 0x1037A, 0x10A01, 0x10A0F, 0x10A38, 0x10A3F, 0x10AE5, 0x10AE6, 0x10D24, 0x10D27, + 0x10EAB, 0x10EAC, 0x10F46, 0x10F50, 0x11000, 0x11002, 0x11038, 0x11046, 0x1107F, 0x11082, 0x110B0, 0x110BA, + 0x11100, 0x11102, 0x11127, 0x11134, 0x11145, 0x11146, 0x11173, 0x11173, 0x11180, 0x11182, 0x111B3, 0x111C0, + 0x111C9, 0x111CC, 0x111CE, 0x111CF, 0x1122C, 0x11237, 0x1123E, 0x1123E, 0x112DF, 0x112EA, 0x11300, 0x11303, + 0x1133B, 0x1133C, 0x1133E, 0x1134D, 0x11357, 0x11357, 0x11362, 0x11374, 0x11435, 0x11446, 0x1145E, 0x1145E, + 0x114B0, 0x114C3, 0x115AF, 0x115C0, 0x115DC, 0x115DD, 0x11630, 0x11640, 0x116AB, 0x116B7, 0x1171D, 0x1172B, + 0x1182C, 0x1183A, 0x11930, 0x1193E, 0x11940, 0x11940, 0x11942, 0x11943, 0x119D1, 0x119E0, 0x119E4, 0x119E4, + 0x11A01, 0x11A0A, 0x11A33, 0x11A39, 0x11A3B, 0x11A3E, 0x11A47, 0x11A47, 0x11A51, 0x11A5B, 0x11A8A, 0x11A99, + 0x11C2F, 0x11C3F, 0x11C92, 0x11CB6, 0x11D31, 0x11D45, 0x11D47, 0x11D47, 0x11D8A, 0x11D97, 0x11EF3, 0x11EF6, + 0x16AF0, 0x16AF4, 0x16B30, 0x16B36, 0x16F4F, 0x16F4F, 0x16F51, 0x16F92, 0x16FE4, 0x16FF1, 0x1BC9D, 0x1BC9E, + 0x1D165, 0x1D169, 0x1D16D, 0x1D172, 0x1D17B, 0x1D182, 0x1D185, 0x1D18B, 0x1D1AA, 0x1D1AD, 0x1D242, 0x1D244, + 0x1DA00, 0x1DA36, 0x1DA3B, 0x1DA6C, 0x1DA75, 0x1DA75, 0x1DA84, 0x1DA84, 0x1DA9B, 0x1E02A, 0x1E130, 0x1E136, + 0x1E2EC, 0x1E2EF, 0x1E8D0, 0x1E8D6, 0x1E944, 0x1E94A, 0xE0100, 0xE01EF + ]; + + const maxCodePoint = ranges[ranges.length - 1]; + const arrLen = Math.ceil(maxCodePoint / 8); + const arr = new Uint8Array(arrLen); + + for (let i = 0, len = ranges.length / 2; i < len; i++) { + const from = ranges[2 * i]; + const to = ranges[2 * i + 1]; + + for (let j = from; j <= to; j++) { + const div8 = j >>> 3; + const mod8 = j & 7; + arr[div8] = arr[div8] | (1 << mod8); + } + } + + this.arr = arr; + } + + public isUnicodeMark(codePoint: number): boolean { + const div8 = codePoint >>> 3; + const mod8 = codePoint & 7; + if (div8 >= this.arr.length) { + return false; + } + return (this.arr[div8] & (1 << mod8)) ? true : false; + } +} + /** * Generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-rtl-test.js */ @@ -502,7 +687,7 @@ export function containsRTL(str: string): boolean { /** * Generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-emoji-test.js */ -const CONTAINS_EMOJI = /(?:[\u231A\u231B\u23F0\u23F3\u2600-\u27BF\u2B50\u2B55]|\uD83C[\uDDE6-\uDDFF\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F\uDE80-\uDEF8]|\uD83E[\uDD00-\uDDE6])/; +const CONTAINS_EMOJI = /(?:[\u231A\u231B\u23F0\u23F3\u2600-\u27BF\u2B50\u2B55]|\uD83C[\uDDE6-\uDDFF\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F\uDE80-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD00-\uDDFF\uDE70-\uDE73\uDE78-\uDE82\uDE90-\uDE95])/; export function containsEmoji(str: string): boolean { return CONTAINS_EMOJI.test(str); @@ -572,6 +757,18 @@ export function isFullWidthCharacter(charCode: number): boolean { ); } +/** + * A fast function (therefore imprecise) to check if code points are emojis. + * Generated using https://github.com/alexandrudima/unicode-utils/blob/master/generate-emoji-test.js + */ +export function isEmojiImprecise(x: number): boolean { + return ( + (x >= 0x1F1E6 && x <= 0x1F1FF) || (x >= 9728 && x <= 10175) || (x >= 127744 && x <= 128591) + || (x >= 128640 && x <= 128764) || (x >= 128992 && x <= 129003) || (x >= 129280 && x <= 129535) + || (x >= 129648 && x <= 129651) || (x >= 129656 && x <= 129666) || (x >= 129680 && x <= 129685) + ); +} + /** * Given a string and a max length returns a shorted version. Shorting * happens at favorable positions - such as whitespace or punctuation characters. diff --git a/src/vs/base/common/uint.ts b/src/vs/base/common/uint.ts index 2351a96e8e..1d901602ba 100644 --- a/src/vs/base/common/uint.ts +++ b/src/vs/base/common/uint.ts @@ -35,7 +35,7 @@ export const enum Constants { */ MAX_UINT_32 = 4294967295, // 2^32 - 1 - + UNICODE_SUPPLEMENTARY_PLANE_BEGIN = 0x010000 } export function toUint8(v: number): number { diff --git a/src/vs/base/parts/quickopen/browser/quickopen.css b/src/vs/base/parts/quickopen/browser/quickopen.css index c0aa02169e..0dbbd40c1f 100644 --- a/src/vs/base/parts/quickopen/browser/quickopen.css +++ b/src/vs/base/parts/quickopen/browser/quickopen.css @@ -70,7 +70,8 @@ width: 16px; height: 16px; margin-right: 4px; - display: inline-block; + display: flex; + align-items: center; vertical-align: middle; flex-shrink: 0; } @@ -161,4 +162,4 @@ .monaco-quick-open-widget .quick-open-tree .monaco-highlighted-label .highlight { font-weight: bold; -} \ No newline at end of file +} diff --git a/src/vs/base/test/common/resources.test.ts b/src/vs/base/test/common/resources.test.ts index 9bfebd9a6e..449d4cac11 100644 --- a/src/vs/base/test/common/resources.test.ts +++ b/src/vs/base/test/common/resources.test.ts @@ -8,7 +8,7 @@ import { URI } from 'vs/base/common/uri'; import { isWindows } from 'vs/base/common/platform'; import { toSlashes } from 'vs/base/common/extpath'; import { startsWith } from 'vs/base/common/strings'; -import { isAbsolute } from 'vs/base/common/path'; +import { win32, posix } from 'vs/base/common/path'; suite('Resources', () => { @@ -294,7 +294,8 @@ suite('Resources', () => { const actual = resolvePath(u1, path); assertEqualURI(actual, expected, `from ${u1.toString()} and ${path}`); - if (!isAbsolute(path)) { + const p = path.indexOf('/') !== -1 ? posix : win32; + if (!p.isAbsolute(path)) { let expectedPath = isWindows ? toSlashes(path) : path; expectedPath = startsWith(expectedPath, './') ? expectedPath.substr(2) : expectedPath; assert.equal(relativePath(u1, actual), expectedPath, `relativePath (${u1.toString()}) on actual (${actual.toString()}) should be to path (${expectedPath})`); @@ -335,6 +336,10 @@ suite('Resources', () => { assertResolve(URI.parse('foo://server/foo/bar'), 'file.js', URI.parse('foo://server/foo/bar/file.js')); assertResolve(URI.parse('foo://server/foo/bar'), './file.js', URI.parse('foo://server/foo/bar/file.js')); assertResolve(URI.parse('foo://server/foo/bar'), './file.js', URI.parse('foo://server/foo/bar/file.js')); + assertResolve(URI.parse('foo://server/foo/bar'), 'c:\\a1\\b1', URI.parse('foo://server/c:/a1/b1')); + assertResolve(URI.parse('foo://server/foo/bar'), 'c:\\', URI.parse('foo://server/c:')); + + }); test('isEqual', () => { diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts index 482ed40369..ac95d50d3f 100644 --- a/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts @@ -206,6 +206,8 @@ class WorkspaceProvider implements IWorkspaceProvider { static QUERY_PARAM_FOLDER = 'folder'; static QUERY_PARAM_WORKSPACE = 'workspace'; + static QUERY_PARAM_PAYLOAD = 'payload'; + constructor( public readonly workspace: IWorkspace, public readonly payload: object @@ -216,27 +218,7 @@ class WorkspaceProvider implements IWorkspaceProvider { return; // return early if workspace and environment is not changing and we are reusing window } - // Empty - let targetHref: string | undefined = undefined; - if (!workspace) { - targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_EMPTY_WINDOW}=true`; - } - - // Folder - else if (isFolderToOpen(workspace)) { - targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_FOLDER}=${workspace.folderUri.path}`; - } - - // Workspace - else if (isWorkspaceToOpen(workspace)) { - targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_WORKSPACE}=${workspace.workspaceUri.path}`; - } - - // Environment - if (options?.payload) { - targetHref += `&payload=${encodeURIComponent(JSON.stringify(options.payload))}`; - } - + const targetHref = this.createTargetUrl(workspace, options); if (targetHref) { if (options?.reuse) { window.location.href = targetHref; @@ -250,6 +232,32 @@ class WorkspaceProvider implements IWorkspaceProvider { } } + private createTargetUrl(workspace: IWorkspace, options?: { reuse?: boolean, payload?: object }): string | undefined { + + // Empty + let targetHref: string | undefined = undefined; + if (!workspace) { + targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_EMPTY_WINDOW}=true`; + } + + // Folder + else if (isFolderToOpen(workspace)) { + targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_FOLDER}=${encodeURIComponent(workspace.folderUri.toString())}`; + } + + // Workspace + else if (isWorkspaceToOpen(workspace)) { + targetHref = `${document.location.origin}${document.location.pathname}?${WorkspaceProvider.QUERY_PARAM_WORKSPACE}=${encodeURIComponent(workspace.workspaceUri.toString())}`; + } + + // Append payload if any + if (options?.payload) { + targetHref += `&${WorkspaceProvider.QUERY_PARAM_PAYLOAD}=${encodeURIComponent(JSON.stringify(options.payload))}`; + } + + return targetHref; + } + private isSame(workspaceA: IWorkspace, workspaceB: IWorkspace): boolean { if (!workspaceA || !workspaceB) { return workspaceA === workspaceB; // both empty @@ -276,32 +284,49 @@ class WorkspaceProvider implements IWorkspaceProvider { throw new Error('Missing web configuration element'); } - const options: IWorkbenchConstructionOptions & { folderUri?: UriComponents, workspaceUri?: UriComponents } = JSON.parse(configElementAttribute); - - // Determine workspace to open + // Find workspace to open and payload + let foundWorkspace = false; let workspace: IWorkspace; - if (options.folderUri) { - workspace = { folderUri: URI.revive(options.folderUri) }; - } else if (options.workspaceUri) { - workspace = { workspaceUri: URI.revive(options.workspaceUri) }; - } else { - workspace = undefined; - } - - // Find payload let payload = Object.create(null); - if (document.location.search) { - const query = document.location.search.substring(1); - const vars = query.split('&'); - for (let p of vars) { - const pair = p.split('='); - if (pair.length === 2) { - const [key, value] = pair; - if (key === 'payload') { - payload = JSON.parse(decodeURIComponent(value)); - break; - } - } + + const query = new URL(document.location.href).searchParams; + query.forEach((value, key) => { + switch (key) { + + // Folder + case WorkspaceProvider.QUERY_PARAM_FOLDER: + workspace = { folderUri: URI.parse(value) }; + foundWorkspace = true; + break; + + // Workspace + case WorkspaceProvider.QUERY_PARAM_WORKSPACE: + workspace = { workspaceUri: URI.parse(value) }; + foundWorkspace = true; + break; + + // Empty + case WorkspaceProvider.QUERY_PARAM_EMPTY_WINDOW: + workspace = undefined; + foundWorkspace = true; + break; + + // Payload + case WorkspaceProvider.QUERY_PARAM_PAYLOAD: + payload = JSON.parse(value); + break; + } + }); + + // If no workspace is provided through the URL, check for config attribute from server + const options: IWorkbenchConstructionOptions & { folderUri?: UriComponents, workspaceUri?: UriComponents } = JSON.parse(configElementAttribute); + if (!foundWorkspace) { + if (options.folderUri) { + workspace = { folderUri: URI.revive(options.folderUri) }; + } else if (options.workspaceUri) { + workspace = { workspaceUri: URI.revive(options.workspaceUri) }; + } else { + workspace = undefined; } } diff --git a/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts b/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts index ba55ed943a..3c01e05ca6 100644 --- a/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts +++ b/src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts @@ -118,7 +118,6 @@ export class ViewCursor { private _prepareRender(ctx: RenderingContext): ViewCursorRenderData | null { let textContent = ''; - let textContentClassName = ''; if (this._cursorStyle === TextEditorCursorStyle.Line || this._cursorStyle === TextEditorCursorStyle.LineThin) { const visibleRange = ctx.visibleRangeForPosition(this._position); @@ -126,26 +125,32 @@ export class ViewCursor { // Outside viewport return null; } + let width: number; if (this._cursorStyle === TextEditorCursorStyle.Line) { width = dom.computeScreenAwareSize(this._lineCursorWidth > 0 ? this._lineCursorWidth : 2); if (width > 2) { const lineContent = this._context.model.getLineContent(this._position.lineNumber); - textContent = lineContent.charAt(this._position.column - 1); + const nextCharLength = strings.nextCharLength(lineContent, this._position.column - 1); + textContent = lineContent.substr(this._position.column - 1, nextCharLength); } } else { width = dom.computeScreenAwareSize(1); } + let left = visibleRange.left; if (width >= 2 && left >= 1) { // try to center cursor left -= 1; } + const top = ctx.getVerticalOffsetForLineNumber(this._position.lineNumber) - ctx.bigNumbersDelta; - return new ViewCursorRenderData(top, left, width, this._lineHeight, textContent, textContentClassName); + return new ViewCursorRenderData(top, left, width, this._lineHeight, textContent, ''); } - const visibleRangeForCharacter = ctx.linesVisibleRangesForRange(new Range(this._position.lineNumber, this._position.column, this._position.lineNumber, this._position.column + 1), false); + const lineContent = this._context.model.getLineContent(this._position.lineNumber); + const nextCharLength = strings.nextCharLength(lineContent, this._position.column - 1); + const visibleRangeForCharacter = ctx.linesVisibleRangesForRange(new Range(this._position.lineNumber, this._position.column, this._position.lineNumber, this._position.column + nextCharLength), false); if (!visibleRangeForCharacter || visibleRangeForCharacter.length === 0 || visibleRangeForCharacter[0].ranges.length === 0) { // Outside viewport @@ -155,12 +160,10 @@ export class ViewCursor { const range = visibleRangeForCharacter[0].ranges[0]; const width = range.width < 1 ? this._typicalHalfwidthCharacterWidth : range.width; + let textContentClassName = ''; if (this._cursorStyle === TextEditorCursorStyle.Block) { const lineData = this._context.model.getViewLineData(this._position.lineNumber); - textContent = lineData.content.charAt(this._position.column - 1); - if (strings.isHighSurrogate(lineData.content.charCodeAt(this._position.column - 1))) { - textContent += lineData.content.charAt(this._position.column); - } + textContent = lineContent.substr(this._position.column - 1, nextCharLength); const tokenIndex = lineData.tokens.findTokenIndexAtOffset(this._position.column - 1); textContentClassName = lineData.tokens.getClassName(tokenIndex); } diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index 73afd31947..8e7cc019b7 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -173,6 +173,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { private _isHandling: boolean; private _isDoingComposition: boolean; + private _selectionsWhenCompositionStarted: Selection[] | null; private _columnSelectData: IColumnSelectData | null; private _autoClosedActions: AutoClosedAction[]; private _prevEditOperationType: EditOperationType; @@ -188,6 +189,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._isHandling = false; this._isDoingComposition = false; + this._selectionsWhenCompositionStarted = null; this._columnSelectData = null; this._autoClosedActions = []; this._prevEditOperationType = EditOperationType.Other; @@ -667,6 +669,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { if (handlerId === H.CompositionStart) { this._isDoingComposition = true; + this._selectionsWhenCompositionStarted = this.getSelections().slice(0); return; } @@ -757,7 +760,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { if (!this._isDoingComposition && source === 'keyboard') { // composition finishes, let's check if we need to auto complete if necessary. const autoClosedCharacters = AutoClosedAction.getAllAutoClosedCharacters(this._autoClosedActions); - this._executeEditOperation(TypeOperations.compositionEndWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), autoClosedCharacters)); + this._executeEditOperation(TypeOperations.compositionEndWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this._selectionsWhenCompositionStarted, this.getSelections(), autoClosedCharacters)); + this._selectionsWhenCompositionStarted = null; } } @@ -765,19 +769,17 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { if (!this._isDoingComposition && source === 'keyboard') { // If this event is coming straight from the keyboard, look for electric characters and enter - for (let i = 0, len = text.length; i < len; i++) { - let charCode = text.charCodeAt(i); - let chr: string; - if (strings.isHighSurrogate(charCode) && i + 1 < len) { - chr = text.charAt(i) + text.charAt(i + 1); - i++; - } else { - chr = text.charAt(i); - } + const len = text.length; + let offset = 0; + while (offset < len) { + const charLength = strings.nextCharLength(text, offset); + const chr = text.substr(offset, charLength); // Here we must interpret each typed character individually const autoClosedCharacters = AutoClosedAction.getAllAutoClosedCharacters(this._autoClosedActions); this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), autoClosedCharacters, chr)); + + offset += charLength; } } else { diff --git a/src/vs/editor/common/controller/cursorCommon.ts b/src/vs/editor/common/controller/cursorCommon.ts index b900ebb780..7b40ac0ced 100644 --- a/src/vs/editor/common/controller/cursorCommon.ts +++ b/src/vs/editor/common/controller/cursorCommon.ts @@ -19,6 +19,7 @@ import { IAutoClosingPair, StandardAutoClosingPairConditional } from 'vs/editor/ import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { VerticalRevealType } from 'vs/editor/common/view/viewEvents'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; +import { Constants } from 'vs/base/common/uint'; export interface IColumnSelectData { isReal: boolean; @@ -509,66 +510,53 @@ export class EditOperationResult { */ export class CursorColumns { - public static isLowSurrogate(model: ICursorSimpleModel, lineNumber: number, charOffset: number): boolean { - let lineContent = model.getLineContent(lineNumber); - if (charOffset < 0 || charOffset >= lineContent.length) { - return false; - } - return strings.isLowSurrogate(lineContent.charCodeAt(charOffset)); - } - - public static isHighSurrogate(model: ICursorSimpleModel, lineNumber: number, charOffset: number): boolean { - let lineContent = model.getLineContent(lineNumber); - if (charOffset < 0 || charOffset >= lineContent.length) { - return false; - } - return strings.isHighSurrogate(lineContent.charCodeAt(charOffset)); - } - - public static isInsideSurrogatePair(model: ICursorSimpleModel, lineNumber: number, column: number): boolean { - return this.isHighSurrogate(model, lineNumber, column - 2); - } - public static visibleColumnFromColumn(lineContent: string, column: number, tabSize: number): number { - let endOffset = lineContent.length; - if (endOffset > column - 1) { - endOffset = column - 1; - } + const lineContentLength = lineContent.length; + const endOffset = column - 1 < lineContentLength ? column - 1 : lineContentLength; let result = 0; - for (let i = 0; i < endOffset; i++) { - let charCode = lineContent.charCodeAt(i); - if (charCode === CharCode.Tab) { - result = this.nextRenderTabStop(result, tabSize); - } else if (strings.isFullWidthCharacter(charCode)) { - result = result + 2; + let i = 0; + while (i < endOffset) { + const codePoint = strings.getNextCodePoint(lineContent, endOffset, i); + i += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + + if (codePoint === CharCode.Tab) { + result = CursorColumns.nextRenderTabStop(result, tabSize); } else { - result = result + 1; + while (i < endOffset) { + const nextCodePoint = strings.getNextCodePoint(lineContent, endOffset, i); + if (!strings.isUnicodeMark(nextCodePoint)) { + break; + } + i += (nextCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + } + if (strings.isFullWidthCharacter(codePoint) || strings.isEmojiImprecise(codePoint)) { + result = result + 2; + } else { + result = result + 1; + } } } return result; } public static toStatusbarColumn(lineContent: string, column: number, tabSize: number): number { - let endOffset = lineContent.length; - if (endOffset > column - 1) { - endOffset = column - 1; - } + const lineContentLength = lineContent.length; + const endOffset = column - 1 < lineContentLength ? column - 1 : lineContentLength; let result = 0; - for (let i = 0; i < endOffset; i++) { - let charCode = lineContent.charCodeAt(i); - if (charCode === CharCode.Tab) { - result = this.nextRenderTabStop(result, tabSize); + let i = 0; + while (i < endOffset) { + const codePoint = strings.getNextCodePoint(lineContent, endOffset, i); + i += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + + if (codePoint === CharCode.Tab) { + result = CursorColumns.nextRenderTabStop(result, tabSize); } else { - if (strings.isHighSurrogate(charCode)) { - result = result + 1; - i = i + 1; - } else { - result = result + 1; - } + result = result + 1; } } + return result + 1; } @@ -584,29 +572,43 @@ export class CursorColumns { const lineLength = lineContent.length; let beforeVisibleColumn = 0; - for (let i = 0; i < lineLength; i++) { - let charCode = lineContent.charCodeAt(i); + let beforeColumn = 1; + let i = 0; + while (i < lineLength) { + const codePoint = strings.getNextCodePoint(lineContent, lineLength, i); + i += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); let afterVisibleColumn: number; - if (charCode === CharCode.Tab) { - afterVisibleColumn = this.nextRenderTabStop(beforeVisibleColumn, tabSize); - } else if (strings.isFullWidthCharacter(charCode)) { - afterVisibleColumn = beforeVisibleColumn + 2; + if (codePoint === CharCode.Tab) { + afterVisibleColumn = CursorColumns.nextRenderTabStop(beforeVisibleColumn, tabSize); } else { - afterVisibleColumn = beforeVisibleColumn + 1; + while (i < lineLength) { + const nextCodePoint = strings.getNextCodePoint(lineContent, lineLength, i); + if (!strings.isUnicodeMark(nextCodePoint)) { + break; + } + i += (nextCodePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1); + } + if (strings.isFullWidthCharacter(codePoint) || strings.isEmojiImprecise(codePoint)) { + afterVisibleColumn = beforeVisibleColumn + 2; + } else { + afterVisibleColumn = beforeVisibleColumn + 1; + } } + const afterColumn = i + 1; if (afterVisibleColumn >= visibleColumn) { - let prevDelta = visibleColumn - beforeVisibleColumn; - let afterDelta = afterVisibleColumn - visibleColumn; - if (afterDelta < prevDelta) { - return i + 2; + const beforeDelta = visibleColumn - beforeVisibleColumn; + const afterDelta = afterVisibleColumn - visibleColumn; + if (afterDelta < beforeDelta) { + return afterColumn; } else { - return i + 1; + return beforeColumn; } } beforeVisibleColumn = afterVisibleColumn; + beforeColumn = afterColumn; } // walked the entire string diff --git a/src/vs/editor/common/controller/cursorMoveOperations.ts b/src/vs/editor/common/controller/cursorMoveOperations.ts index 42bb54bc8a..ae92799250 100644 --- a/src/vs/editor/common/controller/cursorMoveOperations.ts +++ b/src/vs/editor/common/controller/cursorMoveOperations.ts @@ -6,6 +6,7 @@ import { CursorColumns, CursorConfiguration, ICursorSimpleModel, SingleCursorState } from 'vs/editor/common/controller/cursorCommon'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; +import * as strings from 'vs/base/common/strings'; export class CursorPosition { _cursorPositionBrand: void; @@ -23,21 +24,19 @@ export class CursorPosition { export class MoveOperations { - public static left(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition { - + public static leftPosition(model: ICursorSimpleModel, lineNumber: number, column: number): Position { if (column > model.getLineMinColumn(lineNumber)) { - if (CursorColumns.isLowSurrogate(model, lineNumber, column - 2)) { - // character before column is a low surrogate - column = column - 2; - } else { - column = column - 1; - } + column = column - strings.prevCharLength(model.getLineContent(lineNumber), column - 1); } else if (lineNumber > 1) { lineNumber = lineNumber - 1; column = model.getLineMaxColumn(lineNumber); } + return new Position(lineNumber, column); + } - return new CursorPosition(lineNumber, column, 0); + public static left(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition { + const pos = MoveOperations.leftPosition(model, lineNumber, column); + return new CursorPosition(pos.lineNumber, pos.column, 0); } public static moveLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, noOfColumns: number): SingleCursorState { @@ -57,21 +56,19 @@ export class MoveOperations { return cursor.move(inSelectionMode, lineNumber, column, 0); } - public static right(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition { - + public static rightPosition(model: ICursorSimpleModel, lineNumber: number, column: number): Position { if (column < model.getLineMaxColumn(lineNumber)) { - if (CursorColumns.isHighSurrogate(model, lineNumber, column - 1)) { - // character after column is a high surrogate - column = column + 2; - } else { - column = column + 1; - } + column = column + strings.nextCharLength(model.getLineContent(lineNumber), column - 1); } else if (lineNumber < model.getLineCount()) { lineNumber = lineNumber + 1; column = model.getLineMinColumn(lineNumber); } + return new Position(lineNumber, column); + } - return new CursorPosition(lineNumber, column, 0); + public static right(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition { + const pos = MoveOperations.rightPosition(model, lineNumber, column); + return new CursorPosition(pos.lineNumber, pos.column, 0); } public static moveRight(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, noOfColumns: number): SingleCursorState { @@ -102,15 +99,9 @@ export class MoveOperations { column = model.getLineMaxColumn(lineNumber); } else { column = Math.min(model.getLineMaxColumn(lineNumber), column); - if (CursorColumns.isInsideSurrogatePair(model, lineNumber, column)) { - column = column - 1; - } } } else { column = CursorColumns.columnFromVisibleColumn2(config, model, lineNumber, currentVisibleColumn); - if (CursorColumns.isInsideSurrogatePair(model, lineNumber, column)) { - column = column - 1; - } } leftoverVisibleColumns = currentVisibleColumn - CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize); @@ -160,15 +151,9 @@ export class MoveOperations { column = model.getLineMinColumn(lineNumber); } else { column = Math.min(model.getLineMaxColumn(lineNumber), column); - if (CursorColumns.isInsideSurrogatePair(model, lineNumber, column)) { - column = column - 1; - } } } else { column = CursorColumns.columnFromVisibleColumn2(config, model, lineNumber, currentVisibleColumn); - if (CursorColumns.isInsideSurrogatePair(model, lineNumber, column)) { - column = column - 1; - } } leftoverVisibleColumns = currentVisibleColumn - CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize); diff --git a/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts index b3e77ffc2e..8461aeb721 100644 --- a/src/vs/editor/common/controller/cursorTypeOperations.ts +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -755,7 +755,12 @@ export class TypeOperations { /** * This is very similar with typing, but the character is already in the text buffer! */ - public static compositionEndWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[]): EditOperationResult | null { + public static compositionEndWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selectionsWhenCompositionStarted: Selection[] | null, selections: Selection[], autoClosedCharacters: Range[]): EditOperationResult | null { + if (!selectionsWhenCompositionStarted || Selection.selectionsArrEqual(selectionsWhenCompositionStarted, selections)) { + // no content was typed + return null; + } + let ch: string | null = null; // extract last typed character for (const selection of selections) { diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index 00f196a815..04a368d187 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -895,11 +895,9 @@ export class TextModel extends Disposable implements model.ITextModel { } if (strict) { - if (column > 1) { - const charCodeBefore = this._buffer.getLineCharCode(lineNumber, column - 2); - if (strings.isHighSurrogate(charCodeBefore)) { - return false; - } + const [charStartOffset,] = strings.getCharContainingOffset(this._buffer.getLineContent(lineNumber), column - 1); + if (column !== charStartOffset + 1) { + return false; } } @@ -932,12 +930,9 @@ export class TextModel extends Disposable implements model.ITextModel { } if (strict) { - // If the position would end up in the middle of a high-low surrogate pair, - // we move it to before the pair - // !!At this point, column > 1 - const charCodeBefore = this._buffer.getLineCharCode(lineNumber, column - 2); - if (strings.isHighSurrogate(charCodeBefore)) { - return new Position(lineNumber, column - 1); + const [charStartOffset,] = strings.getCharContainingOffset(this._buffer.getLineContent(lineNumber), column - 1); + if (column !== charStartOffset + 1) { + return new Position(lineNumber, charStartOffset + 1); } } @@ -974,17 +969,23 @@ export class TextModel extends Disposable implements model.ITextModel { } if (strict) { - const charCodeBeforeStart = (startColumn > 1 ? this._buffer.getLineCharCode(startLineNumber, startColumn - 2) : 0); - const charCodeBeforeEnd = (endColumn > 1 && endColumn <= this._buffer.getLineLength(endLineNumber) ? this._buffer.getLineCharCode(endLineNumber, endColumn - 2) : 0); - - const startInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeStart); - const endInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeEnd); - - if (!startInsideSurrogatePair && !endInsideSurrogatePair) { - return true; + const startLineContent = this._buffer.getLineContent(startLineNumber); + if (startColumn < startLineContent.length + 1) { + const [charStartOffset,] = strings.getCharContainingOffset(startLineContent, startColumn - 1); + if (startColumn !== charStartOffset + 1) { + return false; + } } - return false; + if (endColumn >= 2) { + const endLineContent = (endLineNumber === startLineNumber ? startLineContent : this._buffer.getLineContent(endLineNumber)); + const [, charEndOffset] = strings.getCharContainingOffset(endLineContent, endColumn - 2); + if (endColumn !== charEndOffset + 1) { + return false; + } + } + + return true; } return true; @@ -1004,37 +1005,32 @@ export class TextModel extends Disposable implements model.ITextModel { const end = this._validatePosition(_range.endLineNumber, _range.endColumn, false); const startLineNumber = start.lineNumber; - const startColumn = start.column; + let startColumn = start.column; const endLineNumber = end.lineNumber; - const endColumn = end.column; + let endColumn = end.column; + const isEmpty = (startLineNumber === endLineNumber && startColumn === endColumn); - const charCodeBeforeStart = (startColumn > 1 ? this._buffer.getLineCharCode(startLineNumber, startColumn - 2) : 0); - const charCodeBeforeEnd = (endColumn > 1 && endColumn <= this._buffer.getLineLength(endLineNumber) ? this._buffer.getLineCharCode(endLineNumber, endColumn - 2) : 0); - - const startInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeStart); - const endInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeEnd); - - if (!startInsideSurrogatePair && !endInsideSurrogatePair) { - return new Range(startLineNumber, startColumn, endLineNumber, endColumn); + const startLineContent = this._buffer.getLineContent(startLineNumber); + if (startColumn < startLineContent.length + 1) { + const [charStartOffset,] = strings.getCharContainingOffset(startLineContent, startColumn - 1); + if (startColumn !== charStartOffset + 1) { + if (isEmpty) { + // do not expand a collapsed range, simply move it to a valid location + return new Range(startLineNumber, charStartOffset + 1, startLineNumber, charStartOffset + 1); + } + startColumn = charStartOffset + 1; + } } - if (startLineNumber === endLineNumber && startColumn === endColumn) { - // do not expand a collapsed range, simply move it to a valid location - return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn - 1); + if (endColumn >= 2) { + const endLineContent = (endLineNumber === startLineNumber ? startLineContent : this._buffer.getLineContent(endLineNumber)); + const [, charEndOffset] = strings.getCharContainingOffset(endLineContent, endColumn - 2); + if (endColumn !== charEndOffset + 1) { + endColumn = charEndOffset + 1; + } } - if (startInsideSurrogatePair && endInsideSurrogatePair) { - // expand range at both ends - return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn + 1); - } - - if (startInsideSurrogatePair) { - // only expand range at the start - return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn); - } - - // only expand range at the end - return new Range(startLineNumber, startColumn, endLineNumber, endColumn + 1); + return new Range(startLineNumber, startColumn, endLineNumber, endColumn); } public modifyPosition(rawPosition: IPosition, offset: number): Position { diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 8072e0ed1a..eebbf31657 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -954,7 +954,7 @@ export namespace SymbolKinds { * @internal */ export function toCssClassName(kind: SymbolKind, inline?: boolean): string { - return `symbol-icon ${inline ? 'inline' : 'block'} ${byKind.get(kind) || 'property'}`; + return `codicon ${inline ? 'inline' : 'block'} codicon-symbol-${byKind.get(kind) || 'property'}`; } } diff --git a/src/vs/editor/contrib/bracketMatching/bracketMatching.ts b/src/vs/editor/contrib/bracketMatching/bracketMatching.ts index 3a1aaf2591..0893c54610 100644 --- a/src/vs/editor/contrib/bracketMatching/bracketMatching.ts +++ b/src/vs/editor/contrib/bracketMatching/bracketMatching.ts @@ -94,10 +94,12 @@ type Brackets = [Range, Range]; class BracketsData { public readonly position: Position; public readonly brackets: Brackets | null; + public readonly options: ModelDecorationOptions; - constructor(position: Position, brackets: Brackets | null) { + constructor(position: Position, brackets: Brackets | null, options: ModelDecorationOptions) { this.position = position; this.brackets = brackets; + this.options = options; } } @@ -245,8 +247,7 @@ export class BracketMatchingController extends Disposable implements editorCommo } } - - private static readonly _DECORATION_OPTIONS = ModelDecorationOptions.register({ + private static readonly _DECORATION_OPTIONS_WITH_OVERVIEW_RULER = ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, className: 'bracket-match', overviewRuler: { @@ -255,6 +256,11 @@ export class BracketMatchingController extends Disposable implements editorCommo } }); + private static readonly _DECORATION_OPTIONS_WITHOUT_OVERVIEW_RULER = ModelDecorationOptions.register({ + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + className: 'bracket-match' + }); + private _updateBrackets(): void { if (!this._matchBrackets) { return; @@ -262,11 +268,11 @@ export class BracketMatchingController extends Disposable implements editorCommo this._recomputeBrackets(); let newDecorations: IModelDeltaDecoration[] = [], newDecorationsLen = 0; - for (let i = 0, len = this._lastBracketsData.length; i < len; i++) { - let brackets = this._lastBracketsData[i].brackets; + for (const bracketData of this._lastBracketsData) { + let brackets = bracketData.brackets; if (brackets) { - newDecorations[newDecorationsLen++] = { range: brackets[0], options: BracketMatchingController._DECORATION_OPTIONS }; - newDecorations[newDecorationsLen++] = { range: brackets[1], options: BracketMatchingController._DECORATION_OPTIONS }; + newDecorations[newDecorationsLen++] = { range: brackets[0], options: bracketData.options }; + newDecorations[newDecorationsLen++] = { range: brackets[1], options: bracketData.options }; } } @@ -325,10 +331,12 @@ export class BracketMatchingController extends Disposable implements editorCommo newData[newDataLen++] = previousData[previousIndex]; } else { let brackets = model.matchBracket(position); + let options = BracketMatchingController._DECORATION_OPTIONS_WITH_OVERVIEW_RULER; if (!brackets) { brackets = model.findEnclosingBrackets(position); + options = BracketMatchingController._DECORATION_OPTIONS_WITHOUT_OVERVIEW_RULER; } - newData[newDataLen++] = new BracketsData(position, brackets); + newData[newDataLen++] = new BracketsData(position, brackets, options); } } diff --git a/src/vs/editor/contrib/caretOperations/transpose.ts b/src/vs/editor/contrib/caretOperations/transpose.ts index f440043a57..03a962d4e7 100644 --- a/src/vs/editor/contrib/caretOperations/transpose.ts +++ b/src/vs/editor/contrib/caretOperations/transpose.ts @@ -5,57 +5,17 @@ import * as nls from 'vs/nls'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { isHighSurrogate, isLowSurrogate } from 'vs/base/common/strings'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction } from 'vs/editor/browser/editorExtensions'; import { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand'; -import { IPosition, Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { ICommand } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; -import { ITextModel } from 'vs/editor/common/model'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { MoveOperations } from 'vs/editor/common/controller/cursorMoveOperations'; class TransposeLettersAction extends EditorAction { - private positionLeftOf(start: IPosition, model: ITextModel): Position { - let column = start.column; - let lineNumber = start.lineNumber; - - if (column > model.getLineMinColumn(lineNumber)) { - if (isLowSurrogate(model.getLineContent(lineNumber).charCodeAt(column - 2))) { - // character before column is a low surrogate - column = column - 2; - } else { - column = column - 1; - } - } else if (lineNumber > 1) { - lineNumber = lineNumber - 1; - column = model.getLineMaxColumn(lineNumber); - } - - return new Position(lineNumber, column); - } - - private positionRightOf(start: IPosition, model: ITextModel): Position { - let column = start.column; - let lineNumber = start.lineNumber; - - if (column < model.getLineMaxColumn(lineNumber)) { - if (isHighSurrogate(model.getLineContent(lineNumber).charCodeAt(column - 1))) { - // character after column is a high surrogate - column = column + 2; - } else { - column = column + 1; - } - } else if (lineNumber < model.getLineCount()) { - lineNumber = lineNumber + 1; - column = 0; - } - - return new Position(lineNumber, column); - } - constructor() { super({ id: 'editor.action.transposeLetters', @@ -101,10 +61,10 @@ class TransposeLettersAction extends EditorAction { // otherwise, transpose left and right chars let endPosition = (column === lastColumn) ? selection.getPosition() : - this.positionRightOf(selection.getPosition(), model); + MoveOperations.rightPosition(model, selection.getPosition().lineNumber, selection.getPosition().column); - let middlePosition = this.positionLeftOf(endPosition, model); - let beginPosition = this.positionLeftOf(middlePosition, model); + let middlePosition = MoveOperations.leftPosition(model, endPosition.lineNumber, endPosition.column); + let beginPosition = MoveOperations.leftPosition(model, middlePosition.lineNumber, middlePosition.column); let leftChar = model.getValueInRange(Range.fromPositions(beginPosition, middlePosition)); let rightChar = model.getValueInRange(Range.fromPositions(middlePosition, endPosition)); diff --git a/src/vs/editor/contrib/cursorUndo/cursorUndo.ts b/src/vs/editor/contrib/cursorUndo/cursorUndo.ts index d9f35bc5a3..b0bfe023b3 100644 --- a/src/vs/editor/contrib/cursorUndo/cursorUndo.ts +++ b/src/vs/editor/contrib/cursorUndo/cursorUndo.ts @@ -68,25 +68,27 @@ export class CursorUndoRedoController extends Disposable implements IEditorContr this._undoStack = []; this._redoStack = []; this._prevState = null; + this._pushStateIfNecessary(); })); - this._register(editor.onDidChangeCursorSelection((e) => { + this._register(editor.onDidChangeCursorSelection(() => this._pushStateIfNecessary())); + } - const newState = new CursorState(this._editor.getSelections()!); + private _pushStateIfNecessary(): void { + const newState = new CursorState(this._editor.getSelections()!); - if (!this._isCursorUndoRedo && this._prevState) { - const isEqualToLastUndoStack = (this._undoStack.length > 0 && this._undoStack[this._undoStack.length - 1].equals(this._prevState)); - if (!isEqualToLastUndoStack) { - this._undoStack.push(this._prevState); - this._redoStack = []; - if (this._undoStack.length > 50) { - // keep the cursor undo stack bounded - this._undoStack.shift(); - } + if (!this._isCursorUndoRedo && this._prevState) { + const isEqualToLastUndoStack = (this._undoStack.length > 0 && this._undoStack[this._undoStack.length - 1].equals(this._prevState)); + if (!isEqualToLastUndoStack) { + this._undoStack.push(this._prevState); + this._redoStack = []; + if (this._undoStack.length > 50) { + // keep the cursor undo stack bounded + this._undoStack.shift(); } } + } - this._prevState = newState; - })); + this._prevState = newState; } public cursorUndo(): void { @@ -119,8 +121,8 @@ export class CursorUndo extends EditorAction { constructor() { super({ id: 'cursorUndo', - label: nls.localize('cursor.undo', "Soft Undo"), - alias: 'Soft Undo', + label: nls.localize('cursor.undo', "Cursor Undo"), + alias: 'Cursor Undo', precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, @@ -139,8 +141,8 @@ export class CursorRedo extends EditorAction { constructor() { super({ id: 'cursorRedo', - label: nls.localize('cursor.redo', "Soft Redo"), - alias: 'Soft Redo', + label: nls.localize('cursor.redo', "Cursor Redo"), + alias: 'Cursor Redo', precondition: undefined }); } diff --git a/src/vs/editor/contrib/documentSymbols/media/boolean-dark.svg b/src/vs/editor/contrib/documentSymbols/media/boolean-dark.svg deleted file mode 100644 index e009568b13..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/boolean-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/boolean-light.svg b/src/vs/editor/contrib/documentSymbols/media/boolean-light.svg deleted file mode 100644 index 06613f8bed..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/boolean-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/class-dark.svg b/src/vs/editor/contrib/documentSymbols/media/class-dark.svg deleted file mode 100644 index a71e221f6b..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/class-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/class-light.svg b/src/vs/editor/contrib/documentSymbols/media/class-light.svg deleted file mode 100644 index aa106f18f8..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/class-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/constant-dark.svg b/src/vs/editor/contrib/documentSymbols/media/constant-dark.svg deleted file mode 100644 index 0e90ecafcd..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/constant-dark.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/constant-light.svg b/src/vs/editor/contrib/documentSymbols/media/constant-light.svg deleted file mode 100644 index 1a369c1d8a..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/constant-light.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/enumerator-dark.svg b/src/vs/editor/contrib/documentSymbols/media/enumerator-dark.svg deleted file mode 100644 index 82d4ff29c4..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/enumerator-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/enumerator-item-dark.svg b/src/vs/editor/contrib/documentSymbols/media/enumerator-item-dark.svg deleted file mode 100644 index 23c697fdf1..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/enumerator-item-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/enumerator-item-light.svg b/src/vs/editor/contrib/documentSymbols/media/enumerator-item-light.svg deleted file mode 100644 index a99045d335..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/enumerator-item-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/enumerator-light.svg b/src/vs/editor/contrib/documentSymbols/media/enumerator-light.svg deleted file mode 100644 index e2441a0dc1..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/enumerator-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/event-dark.svg b/src/vs/editor/contrib/documentSymbols/media/event-dark.svg deleted file mode 100644 index 051bef316e..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/event-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/event-light.svg b/src/vs/editor/contrib/documentSymbols/media/event-light.svg deleted file mode 100644 index 712344d1f9..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/event-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/field-dark.svg b/src/vs/editor/contrib/documentSymbols/media/field-dark.svg deleted file mode 100644 index 15623061c5..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/field-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/field-light.svg b/src/vs/editor/contrib/documentSymbols/media/field-light.svg deleted file mode 100644 index 72dd79504f..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/field-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/file-dark.svg b/src/vs/editor/contrib/documentSymbols/media/file-dark.svg deleted file mode 100644 index 5ed5762a1f..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/file-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/file-light.svg b/src/vs/editor/contrib/documentSymbols/media/file-light.svg deleted file mode 100644 index ad54e13b1b..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/file-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/indexer-dark.svg b/src/vs/editor/contrib/documentSymbols/media/indexer-dark.svg deleted file mode 100644 index e92131d3d0..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/indexer-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/indexer-light.svg b/src/vs/editor/contrib/documentSymbols/media/indexer-light.svg deleted file mode 100644 index 207899642c..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/indexer-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/interface-dark.svg b/src/vs/editor/contrib/documentSymbols/media/interface-dark.svg deleted file mode 100644 index 6d482b2abd..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/interface-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/interface-light.svg b/src/vs/editor/contrib/documentSymbols/media/interface-light.svg deleted file mode 100644 index a397dd00b0..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/interface-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/keyword-dark.svg b/src/vs/editor/contrib/documentSymbols/media/keyword-dark.svg deleted file mode 100644 index 70ba6ea933..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/keyword-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/keyword-light.svg b/src/vs/editor/contrib/documentSymbols/media/keyword-light.svg deleted file mode 100644 index fc57528a3e..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/keyword-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/method-dark.svg b/src/vs/editor/contrib/documentSymbols/media/method-dark.svg deleted file mode 100644 index 970d7b6148..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/method-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/method-light.svg b/src/vs/editor/contrib/documentSymbols/media/method-light.svg deleted file mode 100644 index 403a9b90dd..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/method-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/namespace-dark.svg b/src/vs/editor/contrib/documentSymbols/media/namespace-dark.svg deleted file mode 100644 index 9a725bb41f..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/namespace-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/namespace-light.svg b/src/vs/editor/contrib/documentSymbols/media/namespace-light.svg deleted file mode 100644 index 1339da7ce2..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/namespace-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/numeric-dark.svg b/src/vs/editor/contrib/documentSymbols/media/numeric-dark.svg deleted file mode 100644 index a1573df010..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/numeric-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/numeric-light.svg b/src/vs/editor/contrib/documentSymbols/media/numeric-light.svg deleted file mode 100644 index ea0e56e022..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/numeric-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/operator-dark.svg b/src/vs/editor/contrib/documentSymbols/media/operator-dark.svg deleted file mode 100644 index 957f5f44f1..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/operator-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/operator-light.svg b/src/vs/editor/contrib/documentSymbols/media/operator-light.svg deleted file mode 100644 index bf6ed57996..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/operator-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/outlineTree.css b/src/vs/editor/contrib/documentSymbols/media/outlineTree.css index 11c363fcde..586448c7f7 100644 --- a/src/vs/editor/contrib/documentSymbols/media/outlineTree.css +++ b/src/vs/editor/contrib/documentSymbols/media/outlineTree.css @@ -39,3 +39,7 @@ font-size: 14px; opacity: 0.4; } + +.monaco-list .outline-element .outline-element-icon { + margin-right: 4px; +} diff --git a/src/vs/editor/contrib/documentSymbols/media/property-dark.svg b/src/vs/editor/contrib/documentSymbols/media/property-dark.svg deleted file mode 100644 index 23e07ffa19..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/property-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/property-light.svg b/src/vs/editor/contrib/documentSymbols/media/property-light.svg deleted file mode 100644 index be642dd152..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/property-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/snippet-dark.svg b/src/vs/editor/contrib/documentSymbols/media/snippet-dark.svg deleted file mode 100644 index 79799f98c2..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/snippet-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/snippet-light.svg b/src/vs/editor/contrib/documentSymbols/media/snippet-light.svg deleted file mode 100644 index 45fa3a001e..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/snippet-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/string-dark.svg b/src/vs/editor/contrib/documentSymbols/media/string-dark.svg deleted file mode 100644 index 80fb9d6567..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/string-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/string-light.svg b/src/vs/editor/contrib/documentSymbols/media/string-light.svg deleted file mode 100644 index 02a0282e90..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/string-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/structure-dark.svg b/src/vs/editor/contrib/documentSymbols/media/structure-dark.svg deleted file mode 100644 index 13766a5dce..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/structure-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/structure-light.svg b/src/vs/editor/contrib/documentSymbols/media/structure-light.svg deleted file mode 100644 index c96bcfa61b..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/structure-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css b/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css index 0a450315ca..28ad84c3a8 100644 --- a/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css +++ b/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css @@ -9,9 +9,9 @@ } .monaco-workbench .symbol-icon.inline { - background-position: left center; - padding-left: 20px; - background-size: 16px 16px; + display: flex; + align-items: center; + padding-left: 0; } .monaco-workbench .symbol-icon.block { @@ -22,267 +22,3 @@ min-width: 16px; background-position: center; } - -/* default icons */ -.monaco-workbench .symbol-icon { - background-image: url('field-light.svg'); - background-repeat: no-repeat; -} -.vs-dark .monaco-workbench .symbol-icon, -.hc-black .monaco-workbench .symbol-icon { - background-image: url('field-dark.svg'); -} - -/* constant */ -.monaco-workbench .symbol-icon.constant { - background-image: url('constant-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.constant, -.hc-black .monaco-workbench .symbol-icon.constant { - background-image: url('constant-dark.svg'); -} - -/* enum */ -.monaco-workbench .symbol-icon.enum { - background-image: url('enumerator-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.enum, -.hc-black .monaco-workbench .symbol-icon.enum { - background-image: url('enumerator-dark.svg'); -} - -/* enum-member */ -.monaco-workbench .symbol-icon.enum-member { - background-image: url('enumerator-item-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.enum-member, -.hc-black .monaco-workbench .symbol-icon.enum-member { - background-image: url('enumerator-item-dark.svg'); -} - -/* struct */ -.monaco-workbench .symbol-icon.struct { - background-image: url('structure-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.struct, -.hc-black .monaco-workbench .symbol-icon.struct { - background-image: url('structure-dark.svg'); -} - -/* event */ -.monaco-workbench .symbol-icon.event { - background-image: url('event-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.event, -.hc-black .monaco-workbench .symbol-icon.event { - background-image: url('event-dark.svg'); -} - -/* operator */ -.monaco-workbench .symbol-icon.operator { - background-image: url('operator-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.operator, -.hc-black .monaco-workbench .symbol-icon.operator { - background-image: url('operator-dark.svg'); -} - -/* type paramter */ -.monaco-workbench .symbol-icon.type-parameter { - background-image: url('template-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.type-parameter, -.hc-black .monaco-workbench .symbol-icon.type-parameter { - background-image: url('template-dark.svg'); -} - -/* boolean, null */ -.monaco-workbench .symbol-icon.boolean { - background-image: url('boolean-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.boolean, -.hc-black .monaco-workbench .symbol-icon.boolean { - background-image: url('boolean-dark.svg'); -} - -/* null */ -.monaco-workbench .symbol-icon.null { - background-image: url('boolean-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.null, -.hc-black .monaco-workbench .symbol-icon.null { - background-image: url('boolean-dark.svg'); -} - -/* class */ -.monaco-workbench .symbol-icon.class { - background-image: url('class-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.class, -.hc-black .monaco-workbench .symbol-icon.class { - background-image: url('class-dark.svg'); -} - -/* constructor */ -.monaco-workbench .symbol-icon.constructor { - background-image: url('method-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.constructor, -.hc-black .monaco-workbench .symbol-icon.constructor { - background-image: url('method-dark.svg'); -} - -/* file */ -.monaco-workbench .symbol-icon.file { - background-image: url('file-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.file, -.hc-black .monaco-workbench .symbol-icon.file { - background-image: url('file-dark.svg'); -} - -/* field */ -.monaco-workbench .symbol-icon.field { - background-image: url('field-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.field, -.hc-black .monaco-workbench .symbol-icon.field { - background-image: url('field-dark.svg'); -} - -/* variable */ -.monaco-workbench .symbol-icon.variable { - background-image: url('variable-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.variable, -.hc-black .monaco-workbench .symbol-icon.variable { - background-image: url('variable-dark.svg'); -} - -/* array */ -.monaco-workbench .symbol-icon.array { - background-image: url('indexer-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.array, -.hc-black .monaco-workbench .symbol-icon.array { - background-image: url('indexer-dark.svg'); -} - -/* keyword */ -/* todo@joh not used? */ -.monaco-workbench .symbol-icon.keyword { - background-image: url('keyword-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.keyword, -.hc-black .monaco-workbench .symbol-icon.keyword { - background-image: url('keyword-dark.svg'); -} - -/* interface */ -.monaco-workbench .symbol-icon.interface { - background-image: url('interface-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.interface, -.hc-black .monaco-workbench .symbol-icon.interface { - background-image: url('interface-dark.svg'); -} - -/* method */ -.monaco-workbench .symbol-icon.method { - background-image: url('method-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.method, -.hc-black .monaco-workbench .symbol-icon.method { - background-image: url('method-dark.svg'); -} - -/* function */ -.monaco-workbench .symbol-icon.function { - background-image: url('method-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.function, -.hc-black .monaco-workbench .symbol-icon.function { - background-image: url('method-dark.svg'); -} - -/* object */ -.monaco-workbench .symbol-icon.object { - background-image: url('namespace-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.object, -.hc-black .monaco-workbench .symbol-icon.object { - background-image: url('namespace-dark.svg'); -} - -/* namespace */ -.monaco-workbench .symbol-icon.namespace { - background-image: url('namespace-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.namespace, -.hc-black .monaco-workbench .symbol-icon.namespace { - background-image: url('namespace-dark.svg'); -} - -/* package */ -.monaco-workbench .symbol-icon.package { - background-image: url('namespace-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.package, -.hc-black .monaco-workbench .symbol-icon.package { - background-image: url('namespace-dark.svg'); -} - -/* module */ -.monaco-workbench .symbol-icon.module { - background-image: url('namespace-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.module, -.hc-black .monaco-workbench .symbol-icon.module { - background-image: url('namespace-dark.svg'); -} - -/* number */ -.monaco-workbench .symbol-icon.number { - background-image: url('numeric-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.number, -.hc-black .monaco-workbench .symbol-icon.number { - background-image: url('numeric-dark.svg'); -} - -/* property */ -.monaco-workbench .symbol-icon.property { - background-image: url('property-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.property, -.hc-black .monaco-workbench .symbol-icon.property { - background-image: url('property-dark.svg'); -} - -/* snippet */ -/* todo@joh unused? */ -.monaco-workbench .symbol-icon.snippet { - background-image: url('snippet-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.snippet, -.hc-black .monaco-workbench .symbol-icon.snippet { - background-image: url('snippet-dark.svg'); -} - -/* string */ -.monaco-workbench .symbol-icon.string { - background-image: url('string-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.string, -.hc-black .monaco-workbench .symbol-icon.string { - background-image: url('string-dark.svg'); -} - -/* key */ -.monaco-workbench .symbol-icon.key { - background-image: url('string-light.svg'); -} -.vs-dark .monaco-workbench .symbol-icon.key, -.hc-black .monaco-workbench .symbol-icon.key { - background-image: url('string-dark.svg'); -} diff --git a/src/vs/editor/contrib/documentSymbols/media/template-dark.svg b/src/vs/editor/contrib/documentSymbols/media/template-dark.svg deleted file mode 100644 index 425ced36f0..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/template-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/template-light.svg b/src/vs/editor/contrib/documentSymbols/media/template-light.svg deleted file mode 100644 index 496d8f7c85..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/template-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/variable-dark.svg b/src/vs/editor/contrib/documentSymbols/media/variable-dark.svg deleted file mode 100644 index 687fcabfff..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/variable-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/media/variable-light.svg b/src/vs/editor/contrib/documentSymbols/media/variable-light.svg deleted file mode 100644 index ede7e9434d..0000000000 --- a/src/vs/editor/contrib/documentSymbols/media/variable-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/documentSymbols/outlineTree.ts b/src/vs/editor/contrib/documentSymbols/outlineTree.ts index 2eddbe96c4..d56f906b9e 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineTree.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineTree.ts @@ -19,8 +19,8 @@ import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { OutlineConfigKeys } from 'vs/editor/contrib/documentSymbols/outline'; import { MarkerSeverity } from 'vs/platform/markers/common/markers'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { listErrorForeground, listWarningForeground } from 'vs/platform/theme/common/colorRegistry'; +import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; +import { registerColor, listErrorForeground, listWarningForeground, foreground } from 'vs/platform/theme/common/colorRegistry'; import { IdleValue } from 'vs/base/common/async'; export type OutlineItem = OutlineGroup | OutlineElement; @@ -56,6 +56,7 @@ export class OutlineElementTemplate { constructor( readonly container: HTMLElement, readonly iconLabel: IconLabel, + readonly iconClass: HTMLElement, readonly decoration: HTMLElement, ) { } } @@ -110,9 +111,11 @@ export class OutlineElementRenderer implements ITreeRenderer, index: number, template: OutlineElementTemplate): void { @@ -125,7 +128,8 @@ export class OutlineElementRenderer implements ITreeRenderer= 0) { options.extraClasses.push(`deprecated`); @@ -273,3 +277,398 @@ export class OutlineDataSource implements IDataSource return values(element.children); } } + +export const SYMBOL_ICON_ARRAY_FOREGROUND = registerColor('symbolIcon.arrayForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.arrayForeground', 'The foreground color for array symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_BOOLEAN_FOREGROUND = registerColor('symbolIcon.booleanForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.booleanForeground', 'The foreground color for boolean symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_CLASS_FOREGROUND = registerColor('symbolIcon.classForeground', { + dark: '#EE9D28', + light: '#D67E00', + hc: '#EE9D28' +}, localize('symbolIcon.classForeground', 'The foreground color for class symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_CONSTANT_FOREGROUND = registerColor('symbolIcon.contstantForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.contstantForeground', 'The foreground color for contstant symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_CONSTRUCTOR_FOREGROUND = registerColor('symbolIcon.constructorForeground', { + dark: '#B180D7', + light: '#652D90', + hc: '#B180D7' +}, localize('symbolIcon.constructorForeground', 'The foreground color for constructor symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_ENUMERATOR_FOREGROUND = registerColor('symbolIcon.enumeratorForeground', { + dark: '#EE9D28', + light: '#D67E00', + hc: '#EE9D28' +}, localize('symbolIcon.enumeratorForeground', 'The foreground color for enumerator symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_ENUMERATOR_MEMBER_FOREGROUND = registerColor('symbolIcon.enumeratorMemberForeground', { + dark: '#75BEFF', + light: '#007ACC', + hc: '#75BEFF' +}, localize('symbolIcon.enumeratorMemberForeground', 'The foreground color for enumerator member symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_EVENT_FOREGROUND = registerColor('symbolIcon.eventForeground', { + dark: '#EE9D28', + light: '#D67E00', + hc: '#EE9D28' +}, localize('symbolIcon.eventForeground', 'The foreground color for event symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_FIELD_FOREGROUND = registerColor('symbolIcon.fieldForeground', { + dark: '#75BEFF', + light: '#007ACC', + hc: '#75BEFF' +}, localize('symbolIcon.fieldForeground', 'The foreground color for field symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_FILE_FOREGROUND = registerColor('symbolIcon.fileForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.fileForeground', 'The foreground color for file symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_FUNCTION_FOREGROUND = registerColor('symbolIcon.functionForeground', { + dark: '#B180D7', + light: '#652D90', + hc: '#B180D7' +}, localize('symbolIcon.functionForeground', 'The foreground color for function symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_INTERFACE_FOREGROUND = registerColor('symbolIcon.interfaceForeground', { + dark: '#75BEFF', + light: '#007ACC', + hc: '#75BEFF' +}, localize('symbolIcon.interfaceForeground', 'The foreground color for interface symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_KEY_FOREGROUND = registerColor('symbolIcon.keyForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.keyForeground', 'The foreground color for key symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_METHOD_FOREGROUND = registerColor('symbolIcon.methodForeground', { + dark: '#B180D7', + light: '#652D90', + hc: '#B180D7' +}, localize('symbolIcon.methodForeground', 'The foreground color for method symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_MODULE_FOREGROUND = registerColor('symbolIcon.moduleForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.moduleForeground', 'The foreground color for module symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_NAMESPACE_FOREGROUND = registerColor('symbolIcon.namespaceForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.namespaceForeground', 'The foreground color for namespace symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_NULL_FOREGROUND = registerColor('symbolIcon.nullForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.nullForeground', 'The foreground color for null symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_NUMBER_FOREGROUND = registerColor('symbolIcon.numberForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.numberForeground', 'The foreground color for number symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_OBJECT_FOREGROUND = registerColor('symbolIcon.objectForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.objectForeground', 'The foreground color for object symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_OPERATOR_FOREGROUND = registerColor('symbolIcon.operatorForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.operatorForeground', 'The foreground color for operator symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_PACKAGE_FOREGROUND = registerColor('symbolIcon.packageForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.packageForeground', 'The foreground color for package symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_PROPERTY_FOREGROUND = registerColor('symbolIcon.propertyForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.propertyForeground', 'The foreground color for property symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_STRING_FOREGROUND = registerColor('symbolIcon.stringForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.stringForeground', 'The foreground color for string symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_STRUCT_FOREGROUND = registerColor('symbolIcon.structForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.structForeground', 'The foreground color for struct symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_TYPEPARAMETER_FOREGROUND = registerColor('symbolIcon.typeParameterForeground', { + dark: foreground, + light: foreground, + hc: foreground +}, localize('symbolIcon.typeParameterForeground', 'The foreground color for type parameter symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +export const SYMBOL_ICON_VARIABLE_FOREGROUND = registerColor('symbolIcon.variableForeground', { + dark: '#75BEFF', + light: '#007ACC', + hc: '#75BEFF' +}, localize('symbolIcon.variableForeground', 'The foreground color for variable symbols. These symbols appear in the outline, breadcrumb, and suggest widget.')); + +registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { + + const symbolIconArrayColor = theme.getColor(SYMBOL_ICON_ARRAY_FOREGROUND); + if (symbolIconArrayColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-array { + color: ${symbolIconArrayColor} !important; + } + `); + } + + const symbolIconBooleanColor = theme.getColor(SYMBOL_ICON_BOOLEAN_FOREGROUND); + if (symbolIconBooleanColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-boolean { + color: ${symbolIconBooleanColor} !important; + } + `); + } + + const symbolIconClassColor = theme.getColor(SYMBOL_ICON_CLASS_FOREGROUND); + if (symbolIconClassColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-class { + color: ${symbolIconClassColor} !important; + } + `); + } + + const symbolIconMethodColor = theme.getColor(SYMBOL_ICON_METHOD_FOREGROUND); + if (symbolIconMethodColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-method { + color: ${symbolIconMethodColor} !important; + } + `); + } + + const symbolIconConstantColor = theme.getColor(SYMBOL_ICON_CONSTANT_FOREGROUND); + if (symbolIconConstantColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-constant { + color: ${symbolIconConstantColor} !important; + } + `); + } + + const symbolIconConstructorColor = theme.getColor(SYMBOL_ICON_CONSTRUCTOR_FOREGROUND); + if (symbolIconConstructorColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-constructor { + color: ${symbolIconConstructorColor} !important; + } + `); + } + + const symbolIconEnumeratorColor = theme.getColor(SYMBOL_ICON_ENUMERATOR_FOREGROUND); + if (symbolIconEnumeratorColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-value, + .monaco-workbench .codicon-symbol-enum { + color: ${symbolIconEnumeratorColor} !important; + } + `); + } + + const symbolIconEnumeratorMemberColor = theme.getColor(SYMBOL_ICON_ENUMERATOR_MEMBER_FOREGROUND); + if (symbolIconEnumeratorMemberColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-enum-member { + color: ${symbolIconEnumeratorMemberColor} !important; + } + `); + } + + const symbolIconEventColor = theme.getColor(SYMBOL_ICON_EVENT_FOREGROUND); + if (symbolIconEventColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-event { + color: ${symbolIconEventColor} !important; + } + `); + } + + const symbolIconFieldColor = theme.getColor(SYMBOL_ICON_FIELD_FOREGROUND); + if (symbolIconFieldColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-field { + color: ${symbolIconFieldColor} !important; + } + `); + } + + const symbolIconFileColor = theme.getColor(SYMBOL_ICON_FILE_FOREGROUND); + if (symbolIconFileColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-file { + color: ${symbolIconFileColor} !important; + } + `); + } + + const symbolIconFunctionColor = theme.getColor(SYMBOL_ICON_FUNCTION_FOREGROUND); + if (symbolIconFunctionColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-function { + color: ${symbolIconFunctionColor} !important; + } + `); + } + + const symbolIconInterfaceColor = theme.getColor(SYMBOL_ICON_INTERFACE_FOREGROUND); + if (symbolIconInterfaceColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-interface { + color: ${symbolIconInterfaceColor} !important; + } + `); + } + + const symbolIconKeyColor = theme.getColor(SYMBOL_ICON_KEY_FOREGROUND); + if (symbolIconKeyColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-key { + color: ${symbolIconKeyColor} !important; + } + `); + } + + const symbolIconModuleColor = theme.getColor(SYMBOL_ICON_MODULE_FOREGROUND); + if (symbolIconModuleColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-module { + color: ${symbolIconModuleColor} !important; + } + `); + } + + const outlineNamespaceColor = theme.getColor(SYMBOL_ICON_NAMESPACE_FOREGROUND); + if (outlineNamespaceColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-namespace { + color: ${outlineNamespaceColor} !important; + } + `); + } + + const symbolIconNullColor = theme.getColor(SYMBOL_ICON_NULL_FOREGROUND); + if (symbolIconNullColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-null { + color: ${symbolIconNullColor} !important; + } + `); + } + + const symbolIconNumberColor = theme.getColor(SYMBOL_ICON_NUMBER_FOREGROUND); + if (symbolIconNumberColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-number { + color: ${symbolIconNumberColor} !important; + } + `); + } + + const symbolIconObjectColor = theme.getColor(SYMBOL_ICON_OBJECT_FOREGROUND); + if (symbolIconObjectColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-object { + color: ${symbolIconObjectColor} !important; + } + `); + } + + const symbolIconOperatorColor = theme.getColor(SYMBOL_ICON_OPERATOR_FOREGROUND); + if (symbolIconOperatorColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-operator { + color: ${symbolIconOperatorColor} !important; + } + `); + } + + const symbolIconPackageColor = theme.getColor(SYMBOL_ICON_PACKAGE_FOREGROUND); + if (symbolIconPackageColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-package { + color: ${symbolIconPackageColor} !important; + } + `); + } + + const symbolIconPropertyColor = theme.getColor(SYMBOL_ICON_PROPERTY_FOREGROUND); + if (symbolIconPropertyColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-property { + color: ${symbolIconPropertyColor} !important; + } + `); + } + + const symbolIconStringColor = theme.getColor(SYMBOL_ICON_STRING_FOREGROUND); + if (symbolIconStringColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-string { + color: ${symbolIconStringColor} !important; + } + `); + } + + const symbolIconStructColor = theme.getColor(SYMBOL_ICON_STRUCT_FOREGROUND); + if (symbolIconStructColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-struct { + color: ${symbolIconStructColor} !important; + } + `); + } + + const symbolIconTypeParameterColor = theme.getColor(SYMBOL_ICON_TYPEPARAMETER_FOREGROUND); + if (symbolIconTypeParameterColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-type-parameter { + color: ${symbolIconTypeParameterColor} !important; + } + `); + } + + const symbolIconVariableColor = theme.getColor(SYMBOL_ICON_VARIABLE_FOREGROUND); + if (symbolIconVariableColor) { + collector.addRule(` + .monaco-workbench .codicon-symbol-variable { + color: ${symbolIconVariableColor} !important; + } + `); + } + +}); diff --git a/src/vs/editor/contrib/multicursor/multicursor.ts b/src/vs/editor/contrib/multicursor/multicursor.ts index 2b1162aa86..4e5db3b092 100644 --- a/src/vs/editor/contrib/multicursor/multicursor.ts +++ b/src/vs/editor/contrib/multicursor/multicursor.ts @@ -27,6 +27,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { overviewRulerSelectionHighlightForeground } from 'vs/platform/theme/common/colorRegistry'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; import { EditorOption } from 'vs/editor/common/config/editorOptions'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; export class InsertCursorAbove extends EditorAction { @@ -747,7 +748,7 @@ export class CompatChangeAll extends MultiCursorSelectionControllerAction { id: 'editor.action.changeAll', label: nls.localize('changeAll.label', "Change All Occurrences"), alias: 'Change All Occurrences', - precondition: EditorContextKeys.writable, + precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.editorTextFocus), kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.CtrlCmd | KeyCode.F2, diff --git a/src/vs/editor/contrib/suggest/media/class-dark.svg b/src/vs/editor/contrib/suggest/media/class-dark.svg deleted file mode 100644 index a71e221f6b..0000000000 --- a/src/vs/editor/contrib/suggest/media/class-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/class-light.svg b/src/vs/editor/contrib/suggest/media/class-light.svg deleted file mode 100644 index aa106f18f8..0000000000 --- a/src/vs/editor/contrib/suggest/media/class-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/close-dark.svg b/src/vs/editor/contrib/suggest/media/close-dark.svg deleted file mode 100644 index 556e2e2099..0000000000 --- a/src/vs/editor/contrib/suggest/media/close-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/close-light.svg b/src/vs/editor/contrib/suggest/media/close-light.svg deleted file mode 100644 index c84816a032..0000000000 --- a/src/vs/editor/contrib/suggest/media/close-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/color-dark.svg b/src/vs/editor/contrib/suggest/media/color-dark.svg deleted file mode 100644 index 0914abcdbd..0000000000 --- a/src/vs/editor/contrib/suggest/media/color-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/color-light.svg b/src/vs/editor/contrib/suggest/media/color-light.svg deleted file mode 100644 index ca089a1bf2..0000000000 --- a/src/vs/editor/contrib/suggest/media/color-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/constant-dark.svg b/src/vs/editor/contrib/suggest/media/constant-dark.svg deleted file mode 100644 index 0e90ecafcd..0000000000 --- a/src/vs/editor/contrib/suggest/media/constant-dark.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/editor/contrib/suggest/media/constant-light.svg b/src/vs/editor/contrib/suggest/media/constant-light.svg deleted file mode 100644 index 1a369c1d8a..0000000000 --- a/src/vs/editor/contrib/suggest/media/constant-light.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/editor/contrib/suggest/media/enumerator-dark.svg b/src/vs/editor/contrib/suggest/media/enumerator-dark.svg deleted file mode 100644 index 82d4ff29c4..0000000000 --- a/src/vs/editor/contrib/suggest/media/enumerator-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/enumerator-item-dark.svg b/src/vs/editor/contrib/suggest/media/enumerator-item-dark.svg deleted file mode 100644 index 23c697fdf1..0000000000 --- a/src/vs/editor/contrib/suggest/media/enumerator-item-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/enumerator-item-light.svg b/src/vs/editor/contrib/suggest/media/enumerator-item-light.svg deleted file mode 100644 index a99045d335..0000000000 --- a/src/vs/editor/contrib/suggest/media/enumerator-item-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/enumerator-light.svg b/src/vs/editor/contrib/suggest/media/enumerator-light.svg deleted file mode 100644 index e2441a0dc1..0000000000 --- a/src/vs/editor/contrib/suggest/media/enumerator-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/event-dark.svg b/src/vs/editor/contrib/suggest/media/event-dark.svg deleted file mode 100644 index 712344d1f9..0000000000 --- a/src/vs/editor/contrib/suggest/media/event-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/event-light.svg b/src/vs/editor/contrib/suggest/media/event-light.svg deleted file mode 100644 index 712344d1f9..0000000000 --- a/src/vs/editor/contrib/suggest/media/event-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/field-dark.svg b/src/vs/editor/contrib/suggest/media/field-dark.svg deleted file mode 100644 index 15623061c5..0000000000 --- a/src/vs/editor/contrib/suggest/media/field-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/field-light.svg b/src/vs/editor/contrib/suggest/media/field-light.svg deleted file mode 100644 index 72dd79504f..0000000000 --- a/src/vs/editor/contrib/suggest/media/field-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/file-dark.svg b/src/vs/editor/contrib/suggest/media/file-dark.svg deleted file mode 100644 index 5ed5762a1f..0000000000 --- a/src/vs/editor/contrib/suggest/media/file-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/file-light.svg b/src/vs/editor/contrib/suggest/media/file-light.svg deleted file mode 100644 index ad54e13b1b..0000000000 --- a/src/vs/editor/contrib/suggest/media/file-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/folder-dark.svg b/src/vs/editor/contrib/suggest/media/folder-dark.svg deleted file mode 100644 index 43d454e7e5..0000000000 --- a/src/vs/editor/contrib/suggest/media/folder-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/folder-light.svg b/src/vs/editor/contrib/suggest/media/folder-light.svg deleted file mode 100644 index 8daecdac6a..0000000000 --- a/src/vs/editor/contrib/suggest/media/folder-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/info-dark.svg b/src/vs/editor/contrib/suggest/media/info-dark.svg deleted file mode 100644 index 3f2d84fa64..0000000000 --- a/src/vs/editor/contrib/suggest/media/info-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/info-light.svg b/src/vs/editor/contrib/suggest/media/info-light.svg deleted file mode 100644 index f25ac7c78d..0000000000 --- a/src/vs/editor/contrib/suggest/media/info-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/interface-dark.svg b/src/vs/editor/contrib/suggest/media/interface-dark.svg deleted file mode 100644 index 6d482b2abd..0000000000 --- a/src/vs/editor/contrib/suggest/media/interface-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/interface-light.svg b/src/vs/editor/contrib/suggest/media/interface-light.svg deleted file mode 100644 index a397dd00b0..0000000000 --- a/src/vs/editor/contrib/suggest/media/interface-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/keyword-dark.svg b/src/vs/editor/contrib/suggest/media/keyword-dark.svg deleted file mode 100644 index 70ba6ea933..0000000000 --- a/src/vs/editor/contrib/suggest/media/keyword-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/keyword-light.svg b/src/vs/editor/contrib/suggest/media/keyword-light.svg deleted file mode 100644 index fc57528a3e..0000000000 --- a/src/vs/editor/contrib/suggest/media/keyword-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/method-dark.svg b/src/vs/editor/contrib/suggest/media/method-dark.svg deleted file mode 100644 index 970d7b6148..0000000000 --- a/src/vs/editor/contrib/suggest/media/method-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/method-light.svg b/src/vs/editor/contrib/suggest/media/method-light.svg deleted file mode 100644 index 403a9b90dd..0000000000 --- a/src/vs/editor/contrib/suggest/media/method-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/namespace-dark.svg b/src/vs/editor/contrib/suggest/media/namespace-dark.svg deleted file mode 100644 index 9a725bb41f..0000000000 --- a/src/vs/editor/contrib/suggest/media/namespace-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/namespace-light.svg b/src/vs/editor/contrib/suggest/media/namespace-light.svg deleted file mode 100644 index 1339da7ce2..0000000000 --- a/src/vs/editor/contrib/suggest/media/namespace-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/operator-dark.svg b/src/vs/editor/contrib/suggest/media/operator-dark.svg deleted file mode 100644 index 957f5f44f1..0000000000 --- a/src/vs/editor/contrib/suggest/media/operator-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/operator-light.svg b/src/vs/editor/contrib/suggest/media/operator-light.svg deleted file mode 100644 index bf6ed57996..0000000000 --- a/src/vs/editor/contrib/suggest/media/operator-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/property-dark.svg b/src/vs/editor/contrib/suggest/media/property-dark.svg deleted file mode 100644 index 23e07ffa19..0000000000 --- a/src/vs/editor/contrib/suggest/media/property-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/property-light.svg b/src/vs/editor/contrib/suggest/media/property-light.svg deleted file mode 100644 index be642dd152..0000000000 --- a/src/vs/editor/contrib/suggest/media/property-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/reference-dark.svg b/src/vs/editor/contrib/suggest/media/reference-dark.svg deleted file mode 100644 index ed302ae139..0000000000 --- a/src/vs/editor/contrib/suggest/media/reference-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/reference-light.svg b/src/vs/editor/contrib/suggest/media/reference-light.svg deleted file mode 100644 index 392a840c5e..0000000000 --- a/src/vs/editor/contrib/suggest/media/reference-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/ruler-dark.svg b/src/vs/editor/contrib/suggest/media/ruler-dark.svg deleted file mode 100644 index 1957dbad34..0000000000 --- a/src/vs/editor/contrib/suggest/media/ruler-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/ruler-light.svg b/src/vs/editor/contrib/suggest/media/ruler-light.svg deleted file mode 100644 index bc321cdffa..0000000000 --- a/src/vs/editor/contrib/suggest/media/ruler-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/snippet-dark.svg b/src/vs/editor/contrib/suggest/media/snippet-dark.svg deleted file mode 100644 index 79799f98c2..0000000000 --- a/src/vs/editor/contrib/suggest/media/snippet-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/snippet-light.svg b/src/vs/editor/contrib/suggest/media/snippet-light.svg deleted file mode 100644 index 45fa3a001e..0000000000 --- a/src/vs/editor/contrib/suggest/media/snippet-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/string-dark.svg b/src/vs/editor/contrib/suggest/media/string-dark.svg deleted file mode 100644 index 80fb9d6567..0000000000 --- a/src/vs/editor/contrib/suggest/media/string-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/string-light.svg b/src/vs/editor/contrib/suggest/media/string-light.svg deleted file mode 100644 index 02a0282e90..0000000000 --- a/src/vs/editor/contrib/suggest/media/string-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/structure-dark.svg b/src/vs/editor/contrib/suggest/media/structure-dark.svg deleted file mode 100644 index 13766a5dce..0000000000 --- a/src/vs/editor/contrib/suggest/media/structure-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/structure-light.svg b/src/vs/editor/contrib/suggest/media/structure-light.svg deleted file mode 100644 index c96bcfa61b..0000000000 --- a/src/vs/editor/contrib/suggest/media/structure-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index 8116d49e5d..001e1819f7 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -110,28 +110,22 @@ /** Icon styles **/ -.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore { +.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .codicon-close, +.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore::before { + color: inherit; opacity: 0.6; - background-position: center center; - background-repeat: no-repeat; - background-size: 70%; + font-size: 14px; + margin-left: 4px; cursor: pointer; } -.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close { - background-image: url('./close-light.svg'); +.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .codicon-close { position: absolute; - top: 0; - right: 0; - margin-right: 5px; + top: 2px; + right: 2px; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore { - background-image: url('./info-light.svg'); -} - -.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close:hover, +.monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .codicon-close:hover, .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore:hover { opacity: 1; } @@ -193,45 +187,17 @@ display: none; } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon { + display: flex; + align-items: center; + margin-right: 4px; +} + .monaco-editor .suggest-widget.no-icons .monaco-list .monaco-list-row .icon, -.monaco-editor .suggest-widget.no-icons .monaco-list .monaco-list-row .monaco-icon-label.suggest-icon::before { +.monaco-editor .suggest-widget.no-icons .monaco-list .monaco-list-row .suggest-icon::before { display: none; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.suggest-icon::before { - content: ' '; - background-repeat: no-repeat; - background-position: center; - background-size: 75%; -} - -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.method::before, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.function::before, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constructor::before { background-image: url('method-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.field::before { background-image: url('field-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.event::before { background-image: url('event-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.operator::before { background-image: url('operator-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.variable::before { background-image: url('variable-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.class::before { background-image: url('class-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.interface::before { background-image: url('interface-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.struct::before { background-image: url('structure-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.type-parameter::before { background-image: url('template-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.module::before { background-image: url('namespace-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.property::before { background-image: url('property-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.unit::before { background-image: url('ruler-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constant::before { background-image: url('constant-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.value::before, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum::before { background-image: url('enumerator-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum-member::before { background-image: url('enumerator-item-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.keyword::before { background-image: url('keyword-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.text::before { background-image: url('string-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.color::before { background-image: url('color-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.file::before { background-image: url('file-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.reference::before { background-image: url('reference-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.snippet::before { background-image: url('snippet-light.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.customcolor::before { background-image: none; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.folder::before { background-image: url('folder-light.svg'); } - .monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.customcolor .colorspan { margin: 0 0 0 0.3em; border: 0.1em solid #000; @@ -313,90 +279,3 @@ border-radius: 3px; padding: 0 0.4em; } - -/* High Contrast and Dark Theming */ - -.monaco-editor.vs-dark .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close, -.monaco-editor.hc-black .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close { - background-image: url('./close-dark.svg'); -} - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore { - background-image: url('./info-dark.svg'); -} - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.method::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.method::before, -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.function::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.function::before, -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constructor::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constructor::before { background-image: url('method-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.field::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.field::before { background-image: url('field-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.event::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.event::before { background-image: url('event-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.operator::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.operator::before { background-image: url('operator-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.variable::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.variable::before { background-image: url('variable-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.class::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.class::before { background-image: url('class-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.interface::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.interface::before { background-image: url('interface-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.struct::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.struct::before { background-image: url('structure-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.type-parameter::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.type-parameter::before { background-image: url('template-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.module::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.module::before { background-image: url('namespace-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.property::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.property::before { background-image: url('property-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.unit::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.unit::before { background-image: url('ruler-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constant::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constant::before { background-image: url('constant-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.value::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.value::before, -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum::before { background-image: url('enumerator-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum-member::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum-member::before { background-image: url('enumerator-item-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.keyword::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.keyword::before { background-image: url('keyword-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.text::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.text::before { background-image: url('string-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.color::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.color::before { background-image: url('color-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.file::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.file::before { background-image: url('file-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.reference::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.reference::before { background-image: url('reference-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.snippet::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.snippet::before { background-image: url('snippet-dark.svg'); } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.customcolor::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.customcolor::before { background-image: none; } - -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.folder::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.folder::before { background-image: url('folder-dark.svg'); } diff --git a/src/vs/editor/contrib/suggest/media/template-dark.svg b/src/vs/editor/contrib/suggest/media/template-dark.svg deleted file mode 100644 index 425ced36f0..0000000000 --- a/src/vs/editor/contrib/suggest/media/template-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/template-light.svg b/src/vs/editor/contrib/suggest/media/template-light.svg deleted file mode 100644 index 496d8f7c85..0000000000 --- a/src/vs/editor/contrib/suggest/media/template-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/variable-dark.svg b/src/vs/editor/contrib/suggest/media/variable-dark.svg deleted file mode 100644 index 687fcabfff..0000000000 --- a/src/vs/editor/contrib/suggest/media/variable-dark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/media/variable-light.svg b/src/vs/editor/contrib/suggest/media/variable-light.svg deleted file mode 100644 index ede7e9434d..0000000000 --- a/src/vs/editor/contrib/suggest/media/variable-light.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 84b3eba2cc..ff2edb3aa7 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -10,7 +10,7 @@ import * as strings from 'vs/base/common/strings'; import { Event, Emitter } from 'vs/base/common/event'; import { onUnexpectedError } from 'vs/base/common/errors'; import { IDisposable, dispose, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; -import { addClass, append, $, hide, removeClass, show, toggleClass, getDomNodePagePosition, hasClass, addDisposableListener, addStandardDisposableListener } from 'vs/base/browser/dom'; +import { addClass, append, $, hide, removeClass, show, toggleClass, getDomNodePagePosition, hasClass, addDisposableListener, addStandardDisposableListener, addClasses } from 'vs/base/browser/dom'; import { IListVirtualDelegate, IListEvent, IListRenderer, IListMouseEvent, IListGestureEvent } from 'vs/base/browser/ui/list/list'; import { List } from 'vs/base/browser/ui/list/listWidget'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; @@ -48,6 +48,7 @@ interface ISuggestionTemplateData { icon: HTMLElement; colorspan: HTMLElement; iconLabel: IconLabel; + iconContainer: HTMLElement; typeLabel: HTMLElement; readMore: HTMLElement; disposables: DisposableStore; @@ -116,12 +117,14 @@ class Renderer implements IListRenderer const text = append(container, $('.contents')); const main = append(text, $('.main')); + data.iconContainer = append(main, $('.icon-label.codicon')); + data.iconLabel = new IconLabel(main, { supportHighlights: true, supportCodicons: true }); data.disposables.add(data.iconLabel); data.typeLabel = append(main, $('span.type-label')); - data.readMore = append(main, $('span.readMore')); + data.readMore = append(main, $('span.readMore.codicon.codicon-info')); data.readMore.title = nls.localize('readMore', "Read More...{0}", this.triggerKeybindingLabel); const configureFont = () => { @@ -169,11 +172,13 @@ class Renderer implements IListRenderer if (suggestion.kind === CompletionItemKind.Color && extractColor(element, color)) { // special logic for 'color' completion items data.icon.className = 'icon customcolor'; + data.iconContainer.className = 'icon customcolor'; data.colorspan.style.backgroundColor = color[0]; } else if (suggestion.kind === CompletionItemKind.File && this._themeService.getIconTheme().hasFileIcons) { // special logic for 'file' completion items data.icon.className = 'icon hide'; + data.iconContainer.className = 'icon hide'; const labelClasses = getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.label }), FileKind.FILE); const detailClasses = getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.detail }), FileKind.FILE); labelOptions.extraClasses = labelClasses.length > detailClasses.length ? labelClasses : detailClasses; @@ -181,6 +186,7 @@ class Renderer implements IListRenderer } else if (suggestion.kind === CompletionItemKind.Folder && this._themeService.getIconTheme().hasFolderIcons) { // special logic for 'folder' completion items data.icon.className = 'icon hide'; + data.iconContainer.className = 'icon hide'; labelOptions.extraClasses = flatten([ getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.label }), FileKind.FOLDER), getIconClasses(this._modelService, this._modeService, URI.from({ scheme: 'fake', path: suggestion.detail }), FileKind.FOLDER) @@ -188,9 +194,8 @@ class Renderer implements IListRenderer } else { // normal icon data.icon.className = 'icon hide'; - labelOptions.extraClasses = [ - `suggest-icon ${completionKindToCssClass(suggestion.kind)}` - ]; + data.iconContainer.className = ''; + addClasses(data.iconContainer, `suggest-icon codicon codicon-symbol-${completionKindToCssClass(suggestion.kind)}`); } if (suggestion.tags && suggestion.tags.indexOf(CompletionItemTag.Deprecated) >= 0) { @@ -267,7 +272,7 @@ class SuggestionDetails { this.disposables.add(this.scrollbar); this.header = append(this.body, $('.header')); - this.close = append(this.header, $('span.close')); + this.close = append(this.header, $('span.codicon.codicon-close')); this.close.title = nls.localize('readLess', "Read less...{0}", this.triggerKeybindingLabel); this.type = append(this.header, $('p.type')); diff --git a/src/vs/editor/test/browser/controller/cursor.test.ts b/src/vs/editor/test/browser/controller/cursor.test.ts index a7dec000dd..4aff37d49c 100644 --- a/src/vs/editor/test/browser/controller/cursor.test.ts +++ b/src/vs/editor/test/browser/controller/cursor.test.ts @@ -726,6 +726,45 @@ suite('Editor Controller - Cursor', () => { }); }); + test('combining marks', () => { + withTestCodeEditor([ + 'abcabc', + 'ãããããã', + '辻󠄀辻󠄀辻󠄀', + 'பு', + ], {}, (editor, cursor) => { + + cursor.setSelections('test', [new Selection(2, 1, 2, 1)]); + moveRight(cursor); + assertCursor(cursor, new Position(2, 3)); + moveLeft(cursor); + assertCursor(cursor, new Position(2, 1)); + + cursor.setSelections('test', [new Selection(3, 1, 3, 1)]); + moveRight(cursor); + assertCursor(cursor, new Position(3, 4)); + moveLeft(cursor); + assertCursor(cursor, new Position(3, 1)); + + cursor.setSelections('test', [new Selection(4, 1, 4, 1)]); + moveRight(cursor); + assertCursor(cursor, new Position(4, 3)); + moveLeft(cursor); + assertCursor(cursor, new Position(4, 1)); + + cursor.setSelections('test', [new Selection(1, 3, 1, 3)]); + moveDown(cursor); + assertCursor(cursor, new Position(2, 5)); + moveDown(cursor); + assertCursor(cursor, new Position(3, 4)); + moveUp(cursor); + assertCursor(cursor, new Position(2, 5)); + moveUp(cursor); + assertCursor(cursor, new Position(1, 3)); + + }); + }); + test('issue #4905 - column select is biased to the right', () => { const model = createTextModel([ 'var gulp = require("gulp");', @@ -4990,6 +5029,26 @@ suite('autoClosingPairs', () => { mode.dispose(); }); + test('issue #82701: auto close does not execute when IME is canceled via backspace', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '{}' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + cursor.setSelections('test', [new Selection(1, 2, 1, 2)]); + + // Typing a + backspace + cursorCommand(cursor, H.CompositionStart, null, 'keyboard'); + cursorCommand(cursor, H.Type, { text: 'a' }, 'keyboard'); + cursorCommand(cursor, H.ReplacePreviousChar, { replaceCharCnt: 1, text: '' }, 'keyboard'); + cursorCommand(cursor, H.CompositionEnd, null, 'keyboard'); + assert.equal(model.getValue(), '{}'); + }); + mode.dispose(); + }); + test('issue #20891: All cursors should do the same thing', () => { let mode = new AutoClosingMode(); usingCursor({ diff --git a/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts b/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts index 08afa4604f..6c45af4585 100644 --- a/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts +++ b/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts @@ -168,7 +168,7 @@ suite('CursorMove', () => { testColumnFromVisibleColumn('baz', 4, 3, 4); testColumnFromVisibleColumn('📚az', 4, 0, 1); - testColumnFromVisibleColumn('📚az', 4, 1, 2); + testColumnFromVisibleColumn('📚az', 4, 1, 1); testColumnFromVisibleColumn('📚az', 4, 2, 3); testColumnFromVisibleColumn('📚az', 4, 3, 4); testColumnFromVisibleColumn('📚az', 4, 4, 5); diff --git a/src/vs/editor/test/common/model/textModel.test.ts b/src/vs/editor/test/common/model/textModel.test.ts index 255953c175..84021b31eb 100644 --- a/src/vs/editor/test/common/model/textModel.test.ts +++ b/src/vs/editor/test/common/model/textModel.test.ts @@ -743,6 +743,87 @@ suite('Editor Model - TextModel', () => { assert.deepEqual(m.validatePosition(new Position(2, 1.5)), new Position(2, 1), 'h'); }); + function assertValidatePosition(m: TextModel, lineNumber: number, column: number, expectedColumn: number): void { + const input = new Position(lineNumber, column); + const actual = m.validatePosition(input); + const expected = new Position(lineNumber, expectedColumn); + assert.deepEqual(actual, expected, `validatePosition for ${input}, got ${actual}, expected ${expected}`); + } + + function assertValidateRange(m: TextModel, input: Range, expected: Range): void { + const actual = m.validateRange(input); + assert.deepEqual(actual, expected, `validateRange for ${input}, got ${actual}, expected ${expected}`); + } + + test('combining marks', () => { + const m = TextModel.createFromString([ + 'abcabc', + 'ãããããã', + '辻󠄀辻󠄀辻󠄀', + 'புபுபு', + ].join('\n')); + + assertValidatePosition(m, 2, 1, 1); + assertValidatePosition(m, 2, 2, 1); + assertValidatePosition(m, 2, 3, 3); + assertValidatePosition(m, 2, 4, 3); + assertValidatePosition(m, 2, 5, 5); + assertValidatePosition(m, 2, 6, 5); + assertValidatePosition(m, 2, 7, 7); + assertValidatePosition(m, 2, 8, 7); + assertValidatePosition(m, 2, 9, 9); + assertValidatePosition(m, 2, 10, 9); + assertValidatePosition(m, 2, 11, 11); + assertValidatePosition(m, 2, 12, 11); + assertValidatePosition(m, 2, 13, 13); + assertValidatePosition(m, 2, 14, 13); + + assertValidatePosition(m, 3, 1, 1); + assertValidatePosition(m, 3, 2, 1); + assertValidatePosition(m, 3, 3, 1); + assertValidatePosition(m, 3, 4, 4); + assertValidatePosition(m, 3, 5, 4); + assertValidatePosition(m, 3, 6, 4); + assertValidatePosition(m, 3, 7, 7); + assertValidatePosition(m, 3, 8, 7); + assertValidatePosition(m, 3, 9, 7); + assertValidatePosition(m, 3, 10, 10); + + assertValidatePosition(m, 4, 1, 1); + assertValidatePosition(m, 4, 2, 1); + assertValidatePosition(m, 4, 3, 3); + assertValidatePosition(m, 4, 4, 3); + assertValidatePosition(m, 4, 5, 5); + assertValidatePosition(m, 4, 6, 5); + assertValidatePosition(m, 4, 7, 7); + + assertValidateRange(m, new Range(2, 1, 2, 1), new Range(2, 1, 2, 1)); + assertValidateRange(m, new Range(2, 1, 2, 2), new Range(2, 1, 2, 3)); + assertValidateRange(m, new Range(2, 1, 2, 3), new Range(2, 1, 2, 3)); + assertValidateRange(m, new Range(2, 1, 2, 4), new Range(2, 1, 2, 5)); + assertValidateRange(m, new Range(2, 1, 2, 5), new Range(2, 1, 2, 5)); + assertValidateRange(m, new Range(2, 2, 2, 2), new Range(2, 1, 2, 1)); + assertValidateRange(m, new Range(2, 2, 2, 3), new Range(2, 1, 2, 3)); + assertValidateRange(m, new Range(2, 2, 2, 4), new Range(2, 1, 2, 5)); + assertValidateRange(m, new Range(2, 2, 2, 5), new Range(2, 1, 2, 5)); + + assertValidateRange(m, new Range(3, 1, 3, 1), new Range(3, 1, 3, 1)); + assertValidateRange(m, new Range(3, 1, 3, 2), new Range(3, 1, 3, 4)); + assertValidateRange(m, new Range(3, 1, 3, 3), new Range(3, 1, 3, 4)); + assertValidateRange(m, new Range(3, 1, 3, 4), new Range(3, 1, 3, 4)); + assertValidateRange(m, new Range(3, 1, 3, 5), new Range(3, 1, 3, 7)); + assertValidateRange(m, new Range(3, 1, 3, 6), new Range(3, 1, 3, 7)); + assertValidateRange(m, new Range(3, 1, 3, 7), new Range(3, 1, 3, 7)); + assertValidateRange(m, new Range(3, 2, 3, 2), new Range(3, 1, 3, 1)); + assertValidateRange(m, new Range(3, 2, 3, 3), new Range(3, 1, 3, 4)); + assertValidateRange(m, new Range(3, 2, 3, 4), new Range(3, 1, 3, 4)); + assertValidateRange(m, new Range(3, 2, 3, 5), new Range(3, 1, 3, 7)); + assertValidateRange(m, new Range(3, 2, 3, 6), new Range(3, 1, 3, 7)); + assertValidateRange(m, new Range(3, 2, 3, 7), new Range(3, 1, 3, 7)); + + m.dispose(); + }); + test('issue #71480: validateRange handle floats', () => { let m = TextModel.createFromString('line one\nline two'); diff --git a/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts b/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts index 38f96bddec..7ad5efcdf5 100644 --- a/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts +++ b/src/vs/platform/files/node/watcher/nsfw/nsfwWatcherService.ts @@ -244,14 +244,14 @@ export class NsfwWatcherService implements IWatcherService { } private log(message: string) { - this._onLogMessage.fire({ type: 'trace', message: `[File Watcher (nswf)] ` + message }); + this._onLogMessage.fire({ type: 'trace', message: `[File Watcher (nsfw)] ` + message }); } private warn(message: string) { - this._onLogMessage.fire({ type: 'warn', message: `[File Watcher (nswf)] ` + message }); + this._onLogMessage.fire({ type: 'warn', message: `[File Watcher (nsfw)] ` + message }); } private error(message: string) { - this._onLogMessage.fire({ type: 'error', message: `[File Watcher (nswf)] ` + message }); + this._onLogMessage.fire({ type: 'error', message: `[File Watcher (nsfw)] ` + message }); } } diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index d0e070a0a4..0a4b3c53c9 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -5241,6 +5241,22 @@ declare module 'vscode' { options?: ShellExecutionOptions; } + /** + * Class used to execute an extension callback as a task. + */ + export class CustomExecution { + /** + * Constructs a CustomExecution task object. The callback will be executed the task is run, at which point the + * extension should return the Pseudoterminal it will "run in". The task should wait to do further execution until + * [Pseudoterminal.open](#Pseudoterminal.open) is called. Task cancellation should be handled using + * [Pseudoterminal.close](#Pseudoterminal.close). When the task is complete fire + * [Pseudoterminal.onDidClose](#Pseudoterminal.onDidClose). + * @param process The [Pseudoterminal](#Pseudoterminal) to be used by the task to display output. + * @param callback The callback that will be called when the task is started by a user. + */ + constructor(callback: () => Thenable); + } + /** * The scope of a task. */ @@ -5283,7 +5299,7 @@ declare module 'vscode' { * or '$eslint'. Problem matchers can be contributed by an extension using * the `problemMatchers` extension point. */ - constructor(taskDefinition: TaskDefinition, scope: WorkspaceFolder | TaskScope.Global | TaskScope.Workspace, name: string, source: string, execution?: ProcessExecution | ShellExecution, problemMatchers?: string | string[]); + constructor(taskDefinition: TaskDefinition, scope: WorkspaceFolder | TaskScope.Global | TaskScope.Workspace, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]); /** * ~~Creates a new task.~~ @@ -5318,7 +5334,7 @@ declare module 'vscode' { /** * The task's execution engine */ - execution?: ProcessExecution | ShellExecution; + execution?: ProcessExecution | ShellExecution | CustomExecution; /** * Whether the task is a background task or not. @@ -6259,8 +6275,11 @@ declare module 'vscode' { export const uiKind: UIKind; /** - * Opens an *external* item, e.g. a http(s) or mailto-link, using the - * default application. + * Opens a link externally using the default application. Depending on the + * used scheme this can be: + * * a browser (`http:`, `https:`) + * * a mail client (`mailto:`) + * * VSCode itself (`vscode:` from `vscode.env.uriScheme`) * * *Note* that [`showTextDocument`](#window.showTextDocument) is the right * way to open a text document inside the editor, not this function. @@ -6285,7 +6304,7 @@ declare module 'vscode' { * a system or user action — for example, in remote cases, a user may close a port forwardng tunnel * that was opened by `asExternalUri`. * - * Note: uris passed through `openExternal` are automatically resolved and you should not call `asExternalUri` + * *Note* that uris passed through `openExternal` are automatically resolved and you should not call `asExternalUri` * on them. * * @return A uri that can be used on the client machine. diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 27859e238c..578f98b272 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -895,48 +895,15 @@ declare module 'vscode' { //#endregion //#region CustomExecution - /** - * Class used to execute an extension callback as a task. - */ - export class CustomExecution { - /** - * Constructs a CustomExecution task object. The callback will be executed the task is run, at which point the - * extension should return the Pseudoterminal it will "run in". The task should wait to do further execution until - * [Pseudoterminal.open](#Pseudoterminal.open) is called. Task cancellation should be handled using - * [Pseudoterminal.close](#Pseudoterminal.close). When the task is complete fire - * [Pseudoterminal.onDidClose](#Pseudoterminal.onDidClose). - * @param process The [Pseudoterminal](#Pseudoterminal) to be used by the task to display output. - * @param callback The callback that will be called when the task is started by a user. - */ - constructor(callback: () => Thenable); - } + /** * A task to execute */ export class Task2 extends Task { - /** - * Creates a new task. - * - * @param definition The task definition as defined in the taskDefinitions extension point. - * @param scope Specifies the task's scope. It is either a global or a workspace task or a task for a specific workspace folder. - * @param name The task's name. Is presented in the user interface. - * @param source The task's source (e.g. 'gulp', 'npm', ...). Is presented in the user interface. - * @param execution The process or shell execution. - * @param problemMatchers the names of problem matchers to use, like '$tsc' - * or '$eslint'. Problem matchers can be contributed by an extension using - * the `problemMatchers` extension point. - */ - constructor(taskDefinition: TaskDefinition, scope: WorkspaceFolder | TaskScope.Global | TaskScope.Workspace, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]); - - /** - * The task's execution engine - */ - execution2?: ProcessExecution | ShellExecution | CustomExecution; + detail?: string; } - //#endregion - //#region Tasks export interface TaskPresentationOptions { /** * Controls whether the task is executed in a specific terminal group using split panes. diff --git a/src/vs/workbench/api/browser/mainThreadTask.ts b/src/vs/workbench/api/browser/mainThreadTask.ts index fd26e7cb99..6a5bcfc4a3 100644 --- a/src/vs/workbench/api/browser/mainThreadTask.ts +++ b/src/vs/workbench/api/browser/mainThreadTask.ts @@ -323,6 +323,9 @@ namespace TaskDTO { if (task.configurationProperties.group) { result.group = task.configurationProperties.group; } + if (task.configurationProperties.detail) { + result.detail = task.configurationProperties.detail; + } if (!ConfiguringTask.is(task) && task.command) { if (task.command.runtime === RuntimeType.Process) { result.execution = ProcessExecutionDTO.from(task.command); @@ -380,6 +383,7 @@ namespace TaskDTO { group: task.group, isBackground: !!task.isBackground, problemMatchers: task.problemMatchers.slice(), + detail: task.detail } ); return result; diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 4f0b42adc7..fe402c9bce 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1198,7 +1198,7 @@ export interface ExtHostTerminalServiceShape { $acceptTerminalTitleChange(id: number, name: string): void; $acceptTerminalDimensions(id: number, cols: number, rows: number): void; $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void; - $spawnExtHostProcess(id: number, shellLaunchConfig: IShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; + $spawnExtHostProcess(id: number, shellLaunchConfig: IShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents | undefined, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void; $acceptProcessInput(id: number, data: string): void; $acceptProcessResize(id: number, cols: number, rows: number): void; diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 9aa296b0e2..26e006ae98 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -740,14 +740,14 @@ class SuggestAdapter { // 'insertText'-logic if (item.textEdit) { - result.h = item.textEdit.newText; + result[extHostProtocol.ISuggestDataDtoField.insertText] = item.textEdit.newText; } else if (typeof item.insertText === 'string') { - result.h = item.insertText; + result[extHostProtocol.ISuggestDataDtoField.insertText] = item.insertText; } else if (item.insertText instanceof SnippetString) { - result.h = item.insertText.value; - result.i! |= modes.CompletionItemInsertTextRule.InsertAsSnippet; + result[extHostProtocol.ISuggestDataDtoField.insertText] = item.insertText.value; + result[extHostProtocol.ISuggestDataDtoField.insertTextRules]! |= modes.CompletionItemInsertTextRule.InsertAsSnippet; } // 'overwrite[Before|After]'-logic @@ -757,7 +757,7 @@ class SuggestAdapter { } else if (item.range) { range = item.range; } - result.j = typeConvert.Range.from(range); + result[extHostProtocol.ISuggestDataDtoField.range] = typeConvert.Range.from(range); if (range && (!range.isSingleLine || range.start.line !== position.line)) { console.warn('INVALID text edit -> must be single line and on the same line'); diff --git a/src/vs/workbench/api/common/extHostRequireInterceptor.ts b/src/vs/workbench/api/common/extHostRequireInterceptor.ts index 6a1cb5a048..669f1e4725 100644 --- a/src/vs/workbench/api/common/extHostRequireInterceptor.ts +++ b/src/vs/workbench/api/common/extHostRequireInterceptor.ts @@ -62,7 +62,7 @@ export abstract class RequireInterceptor { this.register(new SqlopsNodeModuleFactory(this._apiFactory.sqlops, extensionPaths)); // {{SQL CARBON EDIT}} // add node module this.register(this._instaService.createInstance(KeytarNodeModuleFactory)); if (this._initData.remote.isRemote) { - this.register(this._instaService.createInstance(OpenNodeModuleFactory, extensionPaths)); + this.register(this._instaService.createInstance(OpenNodeModuleFactory, extensionPaths, this._initData.environment.appUriScheme)); } } @@ -233,6 +233,7 @@ class OpenNodeModuleFactory implements INodeModuleFactory { constructor( private readonly _extensionPaths: TernarySearchTree, + private readonly _appUriScheme: string, @IExtHostRpcService rpcService: IExtHostRpcService, ) { @@ -247,7 +248,7 @@ class OpenNodeModuleFactory implements INodeModuleFactory { } if (uri.scheme === 'http' || uri.scheme === 'https') { return mainThreadWindow.$openUri(uri, { allowTunneling: true }); - } else if (uri.scheme === 'mailto') { + } else if (uri.scheme === 'mailto' || uri.scheme === this._appUriScheme) { return mainThreadWindow.$openUri(uri, {}); } return this.callOriginal(target, options); diff --git a/src/vs/workbench/api/common/extHostTask.ts b/src/vs/workbench/api/common/extHostTask.ts index 47952ed61e..417bc4b63e 100644 --- a/src/vs/workbench/api/common/extHostTask.ts +++ b/src/vs/workbench/api/common/extHostTask.ts @@ -225,8 +225,8 @@ export namespace TaskDTO { execution = ProcessExecutionDTO.from(value.execution); } else if (value.execution instanceof types.ShellExecution) { execution = ShellExecutionDTO.from(value.execution); - } else if ((value).execution2 && (value).execution2 instanceof types.CustomExecution) { - execution = CustomExecutionDTO.from((value).execution2); + } else if (value.execution && value.execution instanceof types.CustomExecution) { + execution = CustomExecutionDTO.from(value.execution); } const definition: tasks.TaskDefinitionDTO | undefined = TaskDefinitionDTO.from(value.definition); @@ -261,6 +261,7 @@ export namespace TaskDTO { problemMatchers: value.problemMatchers, hasDefinedMatchers: (value as types.Task).hasDefinedMatchers, runOptions: (value).runOptions ? (value).runOptions : { reevaluateOnRerun: true }, + detail: (value).detail }; return result; } @@ -303,6 +304,9 @@ export namespace TaskDTO { if (value._id) { result._id = value._id; } + if (value.detail) { + result.detail = value.detail; + } return result; } } @@ -574,7 +578,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { } if (CustomExecutionDTO.is(resolvedTaskDTO.execution)) { - await this.addCustomExecution(resolvedTaskDTO, resolvedTask, true); + await this.addCustomExecution(resolvedTaskDTO, resolvedTask, true); } return await this.resolveTaskInternal(resolvedTaskDTO); @@ -588,12 +592,12 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { return this._handleCounter++; } - protected async addCustomExecution(taskDTO: tasks.TaskDTO, task: vscode.Task2, isProvided: boolean): Promise { + protected async addCustomExecution(taskDTO: tasks.TaskDTO, task: vscode.Task, isProvided: boolean): Promise { const taskId = await this._proxy.$createTaskId(taskDTO); if (!isProvided && !this._providedCustomExecutions2.has(taskId)) { this._notProvidedCustomExecutions.add(taskId); } - this._providedCustomExecutions2.set(taskId, (task).execution2); + this._providedCustomExecutions2.set(taskId, task.execution); } protected async getTaskExecution(execution: tasks.TaskExecutionDTO | string, task?: vscode.Task): Promise { @@ -675,7 +679,7 @@ export class WorkerExtHostTask extends ExtHostTaskBase { // in the provided custom execution map that is cleaned up after the // task is executed. if (CustomExecutionDTO.is(dto.execution)) { - await this.addCustomExecution(dto, task, false); + await this.addCustomExecution(dto, task, false); } else { throw new Error('Not implemented'); } @@ -697,7 +701,7 @@ export class WorkerExtHostTask extends ExtHostTaskBase { // The ID is calculated on the main thread task side, so, let's call into it here. // We need the task id's pre-computed for custom task executions because when OnDidStartTask // is invoked, we have to be able to map it back to our data. - taskIdPromises.push(this.addCustomExecution(taskDTO, task, true)); + taskIdPromises.push(this.addCustomExecution(taskDTO, task, true)); } else { console.warn('Only custom execution tasks supported.'); } diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index c28531703e..d5c66e025a 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -1815,6 +1815,7 @@ export class Task implements vscode.Task2 { private _group: TaskGroup | undefined; private _presentationOptions: vscode.TaskPresentationOptions; private _runOptions: vscode.RunOptions; + private _detail: string | undefined; constructor(definition: vscode.TaskDefinition, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]); constructor(definition: vscode.TaskDefinition, scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder, name: string, source: string, execution?: ProcessExecution | ShellExecution | CustomExecution, problemMatchers?: string | string[]); @@ -1928,19 +1929,11 @@ export class Task implements vscode.Task2 { this._name = value; } - get execution(): ProcessExecution | ShellExecution | undefined { - return (this._execution instanceof CustomExecution) ? undefined : this._execution; - } - - set execution(value: ProcessExecution | ShellExecution | undefined) { - this.execution2 = value; - } - - get execution2(): ProcessExecution | ShellExecution | CustomExecution | undefined { + get execution(): ProcessExecution | ShellExecution | CustomExecution | undefined { return this._execution; } - set execution2(value: ProcessExecution | ShellExecution | CustomExecution | undefined) { + set execution(value: ProcessExecution | ShellExecution | CustomExecution | undefined) { if (value === null) { value = undefined; } @@ -2009,6 +2002,17 @@ export class Task implements vscode.Task2 { this._group = value; } + get detail(): string | undefined { + return this._detail; + } + + set detail(value: string | undefined) { + if (value === null) { + value = undefined; + } + this._detail = value; + } + get presentationOptions(): vscode.TaskPresentationOptions { return this._presentationOptions; } diff --git a/src/vs/workbench/api/common/shared/tasks.ts b/src/vs/workbench/api/common/shared/tasks.ts index 4444283185..57052f322a 100644 --- a/src/vs/workbench/api/common/shared/tasks.ts +++ b/src/vs/workbench/api/common/shared/tasks.ts @@ -89,6 +89,7 @@ export interface TaskDTO { isBackground?: boolean; source: TaskSourceDTO; group?: string; + detail?: string; presentationOptions?: TaskPresentationOptionsDTO; problemMatchers: string[]; hasDefinedMatchers: boolean; diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index 3a97868f54..74f73a419a 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -57,7 +57,7 @@ export class ExtHostTask extends ExtHostTaskBase { // in the provided custom execution map that is cleaned up after the // task is executed. if (CustomExecutionDTO.is(dto.execution)) { - await this.addCustomExecution(dto, task, false); + await this.addCustomExecution(dto, task, false); } return this._proxy.$executeTask(dto).then(value => this.getTaskExecution(value, task)); diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index dd0e36a8de..e0c74f33f5 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -123,7 +123,7 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService { this._variableResolver = new ExtHostVariableResolverService(workspaceFolders || [], this._extHostDocumentsAndEditors, configProvider); } - public async $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise { + public async $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents | undefined, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise { const shellLaunchConfig: IShellLaunchConfig = { name: shellLaunchConfigDto.name, executable: shellLaunchConfigDto.executable, @@ -156,16 +156,21 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService { } const activeWorkspaceRootUri = URI.revive(activeWorkspaceRootUriComponents); - // Get the environment - const apiLastActiveWorkspace = await this._extHostWorkspace.getWorkspaceFolder(activeWorkspaceRootUri); - const lastActiveWorkspace = apiLastActiveWorkspace ? { - uri: apiLastActiveWorkspace.uri, - name: apiLastActiveWorkspace.name, - index: apiLastActiveWorkspace.index, - toResource: () => { - throw new Error('Not implemented'); + let lastActiveWorkspace: IWorkspaceFolder | null = null; + if (activeWorkspaceRootUriComponents && activeWorkspaceRootUri) { + // Get the environment + const apiLastActiveWorkspace = await this._extHostWorkspace.getWorkspaceFolder(activeWorkspaceRootUri); + if (apiLastActiveWorkspace) { + lastActiveWorkspace = { + uri: apiLastActiveWorkspace.uri, + name: apiLastActiveWorkspace.name, + index: apiLastActiveWorkspace.index, + toResource: () => { + throw new Error('Not implemented'); + } + }; } - } as IWorkspaceFolder : null; + } // Get the initial cwd const terminalConfig = configProvider.getConfiguration('terminal.integrated'); diff --git a/src/vs/workbench/browser/actions/workspaceActions.ts b/src/vs/workbench/browser/actions/workspaceActions.ts index f36e93fca7..0916b16193 100644 --- a/src/vs/workbench/browser/actions/workspaceActions.ts +++ b/src/vs/workbench/browser/actions/workspaceActions.ts @@ -13,7 +13,7 @@ import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/c import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL, PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { MenuRegistry, MenuId, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { WorkbenchStateContext, SupportsWorkspacesContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys'; +import { WorkbenchStateContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; @@ -22,6 +22,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; export class OpenFileAction extends Action { @@ -195,14 +196,74 @@ export class GlobalRemoveRootFolderAction extends Action { } } +export class SaveWorkspaceAsAction extends Action { + + static readonly ID = 'workbench.action.saveWorkspaceAs'; + static readonly LABEL = nls.localize('saveWorkspaceAsAction', "Save Workspace As..."); + + constructor( + id: string, + label: string, + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, + @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService + + ) { + super(id, label); + } + + async run(): Promise { + const configPathUri = await this.workspaceEditingService.pickNewWorkspacePath(); + if (configPathUri) { + switch (this.contextService.getWorkbenchState()) { + case WorkbenchState.EMPTY: + case WorkbenchState.FOLDER: + const folders = this.contextService.getWorkspace().folders.map(folder => ({ uri: folder.uri })); + return this.workspaceEditingService.createAndEnterWorkspace(folders, configPathUri); + case WorkbenchState.WORKSPACE: + return this.workspaceEditingService.saveAndEnterWorkspace(configPathUri); + } + } + } +} + +export class DuplicateWorkspaceInNewWindowAction extends Action { + + static readonly ID = 'workbench.action.duplicateWorkspaceInNewWindow'; + static readonly LABEL = nls.localize('duplicateWorkspaceInNewWindow', "Duplicate Workspace in New Window"); + + constructor( + id: string, + label: string, + @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, + @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService, + @IHostService private readonly hostService: IHostService, + @IWorkspacesService private readonly workspacesService: IWorkspacesService, + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService + ) { + super(id, label); + } + + async run(): Promise { + const folders = this.workspaceContextService.getWorkspace().folders; + const remoteAuthority = this.environmentService.configuration.remoteAuthority; + + const newWorkspace = await this.workspacesService.createUntitledWorkspace(folders, remoteAuthority); + await this.workspaceEditingService.copyWorkspaceSettings(newWorkspace); + + return this.hostService.openWindow([{ workspaceUri: newWorkspace.configPath }], { forceNewWindow: true }); + } +} + // --- Actions Registration const registry = Registry.as(Extensions.WorkbenchActions); const workspacesCategory = nls.localize('workspaces', "Workspaces"); -registry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory, SupportsWorkspacesContext); -registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRemoveRootFolderAction, GlobalRemoveRootFolderAction.ID, GlobalRemoveRootFolderAction.LABEL), 'Workspaces: Remove Folder from Workspace...', workspacesCategory, SupportsWorkspacesContext); -registry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'Workspaces: Close Workspace', workspacesCategory, SupportsWorkspacesContext); +registry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRemoveRootFolderAction, GlobalRemoveRootFolderAction.ID, GlobalRemoveRootFolderAction.LABEL), 'Workspaces: Remove Folder from Workspace...', workspacesCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'Workspaces: Close Workspace', workspacesCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace As...', workspacesCategory); +registry.registerWorkbenchAction(new SyncActionDescriptor(DuplicateWorkspaceInNewWindowAction, DuplicateWorkspaceInNewWindowAction.ID, DuplicateWorkspaceInNewWindowAction.LABEL), 'Workspaces: Duplicate Workspace in New Window', workspacesCategory); // --- Menu Registration @@ -216,8 +277,16 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { id: ADD_ROOT_FOLDER_COMMAND_ID, title: nls.localize({ key: 'miAddFolderToWorkspace', comment: ['&& denotes a mnemonic'] }, "A&&dd Folder to Workspace...") }, - order: 1, - when: SupportsWorkspacesContext + order: 1 +}); + +MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + group: '3_workspace', + command: { + id: SaveWorkspaceAsAction.ID, + title: nls.localize('miSaveWorkspaceAs', "Save Workspace As...") + }, + order: 2 }); MenuRegistry.appendMenuItem(MenuId.CommandPalette, { @@ -246,5 +315,5 @@ MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { title: nls.localize({ key: 'miCloseWorkspace', comment: ['&& denotes a mnemonic'] }, "Close &&Workspace") }, order: 3, - when: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('workspace'), SupportsWorkspacesContext) + when: ContextKeyExpr.and(WorkbenchStateContext.isEqualTo('workspace')) }); diff --git a/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts index bce987e2a5..ff6b983fc1 100644 --- a/src/vs/workbench/browser/contextkeys.ts +++ b/src/vs/workbench/browser/contextkeys.ts @@ -38,8 +38,6 @@ export const RemoteConnectionState = new RawContextKey<'' | 'initializing' | 'di export const HasMacNativeTabsContext = new RawContextKey('hasMacNativeTabs', false); -export const SupportsWorkspacesContext = new RawContextKey('supportsWorkspaces', true); - export const IsDevelopmentContext = new RawContextKey('isDevelopment', false); export const WorkbenchStateContext = new RawContextKey('workbenchState', undefined); @@ -107,11 +105,6 @@ export class WorkbenchContextKeysHandler extends Disposable { // Development IsDevelopmentContext.bindTo(this.contextKeyService).set(!this.environmentService.isBuilt || this.environmentService.isExtensionDevelopment); - // Workspaces Support - // - web: only if already in workspace state - // - desktop: always - SupportsWorkspacesContext.bindTo(this.contextKeyService).set(isWeb ? this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE : true); - // Editors this.activeEditorContext = ActiveEditorContext.bindTo(this.contextKeyService); this.activeEditorIsSaveable = ActiveEditorIsSaveableContext.bindTo(this.contextKeyService); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 285ea4f192..e85e702866 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -260,8 +260,6 @@ export class ActivitybarPart extends Part implements IActivityBarService { this.createGlobalActivityActionBar(globalActivities); - this.element.style.display = this.layoutService.isVisible(Parts.ACTIVITYBAR_PART) ? '' : 'none'; - return this.content; } diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index e1acaf49ce..4d4df21944 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -402,7 +402,7 @@ export class CompositeBar extends Widget implements ICompositeBar { () => this.model.activeItem ? this.model.activeItem.id : undefined, (compositeId: string) => { const item = this.model.findItem(compositeId); - return item?.activity?.[0].badge; + return item?.activity[0]?.badge; }, this.options.getOnCompositeClickAction, this.options.colors diff --git a/src/vs/workbench/browser/parts/editor/media/breadcrumbscontrol.css b/src/vs/workbench/browser/parts/editor/media/breadcrumbscontrol.css index 520925d9cf..8c87edc151 100644 --- a/src/vs/workbench/browser/parts/editor/media/breadcrumbscontrol.css +++ b/src/vs/workbench/browser/parts/editor/media/breadcrumbscontrol.css @@ -17,7 +17,7 @@ text-decoration-line: underline; } -.monaco-workbench .monaco-breadcrumb-item.shows-symbol-icon .symbol-icon.block { +.monaco-workbench .monaco-breadcrumb-item.shows-symbol-icon .codicon[class*='codicon-symbol-'] { padding-right: 6px; } diff --git a/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css b/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css index 45c48cc9bf..75424d5f88 100644 --- a/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css +++ b/src/vs/workbench/browser/parts/editor/media/tabstitlecontrol.css @@ -275,8 +275,11 @@ } .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item::before { - min-width: 16px; + width: 16px; height: 22px; + display: flex; + align-items: center; + justify-content: center; } .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:last-child { diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index 258b4ed7fb..290440d64b 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -48,6 +48,7 @@ import { toLocalISOString } from 'vs/base/common/date'; import { IndexedDBLogProvider } from 'vs/workbench/services/log/browser/indexedDBLogProvider'; import { InMemoryLogProvider } from 'vs/workbench/services/log/common/inMemoryLogProvider'; import { isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows'; +import { getWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces'; class BrowserMain extends Disposable { @@ -292,7 +293,7 @@ class BrowserMain extends Disposable { // Multi-root workspace if (workspace && isWorkspaceToOpen(workspace)) { - return { id: hash(workspace.workspaceUri.toString()).toString(16), configPath: workspace.workspaceUri }; + return getWorkspaceIdentifier(workspace.workspaceUri); } // Single-folder workspace diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index ace68ab0cf..b193f88f52 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -289,6 +289,13 @@ export class DebugService implements IDebugService { throw new Error(nls.localize({ key: 'compoundMustHaveConfigurations', comment: ['compound indicates a "compounds" configuration item', '"configurations" is an attribute and should not be localized'] }, "Compound must have \"configurations\" attribute set in order to start multiple configurations.")); } + if (compound.preLaunchTask) { + const taskResult = await this.runTaskAndCheckErrors(launch?.workspace || this.contextService.getWorkspace(), compound.preLaunchTask); + if (taskResult === TaskRunResult.Failure) { + this.endInitializingState(); + return false; + } + } const values = await Promise.all(compound.configurations.map(configData => { const name = typeof configData === 'string' ? configData : configData.name; @@ -394,10 +401,10 @@ export class DebugService implements IDebugService { return false; } - const workspace = launch ? launch.workspace : undefined; + const workspace = launch ? launch.workspace : this.contextService.getWorkspace(); const taskResult = await this.runTaskAndCheckErrors(workspace, resolvedConfig.preLaunchTask); if (taskResult === TaskRunResult.Success) { - return this.doCreateSession(workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, options); + return this.doCreateSession(launch?.workspace, { resolved: resolvedConfig, unresolved: unresolvedConfig }, options); } return false; } catch (err) { @@ -701,7 +708,7 @@ export class DebugService implements IDebugService { //---- task management - private async runTaskAndCheckErrors(root: IWorkspaceFolder | undefined, taskId: string | TaskIdentifier | undefined): Promise { + private async runTaskAndCheckErrors(root: IWorkspaceFolder | IWorkspace | undefined, taskId: string | TaskIdentifier | undefined): Promise { try { const taskSummary = await this.runTask(root, taskId); diff --git a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts index 50ac7f49df..643798de80 100644 --- a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts @@ -571,21 +571,18 @@ export class RawDebugSession implements IDisposable { const args: string[] = []; for (let arg of vscodeArgs.args) { - if (arg.prefix) { - const a2 = (arg.prefix || '') + (arg.path || ''); - const match = /^--(.+)=(.+)$/.exec(a2); - if (match && match.length === 3) { - const key = match[1]; - let value = match[2]; + const a2 = (arg.prefix || '') + (arg.path || ''); + const match = /^--(.+)=(.+)$/.exec(a2); + if (match && match.length === 3) { + const key = match[1]; + let value = match[2]; - if ((key === 'file-uri' || key === 'folder-uri') && !isUri(arg.path)) { - value = URI.file(value).toString(); - } - - args.push(`--${key}=${value}`); - } else { - args.push(a2); + if ((key === 'file-uri' || key === 'folder-uri') && !isUri(arg.path)) { + value = URI.file(value).toString(); } + args.push(`--${key}=${value}`); + } else { + args.push(a2); } } diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index e42d6f6ae1..e4f01e01ce 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -505,6 +505,7 @@ export interface IConfig extends IEnvConfig { export interface ICompound { name: string; + preLaunchTask?: string | TaskIdentifier; configurations: (string | { name: string, folder: string })[]; } diff --git a/src/vs/workbench/contrib/debug/common/debugSchemas.ts b/src/vs/workbench/contrib/debug/common/debugSchemas.ts index 3ec967bcb0..7d401c4a09 100644 --- a/src/vs/workbench/contrib/debug/common/debugSchemas.ts +++ b/src/vs/workbench/contrib/debug/common/debugSchemas.ts @@ -190,6 +190,11 @@ export const launchSchema: IJSONSchema = { }] }, description: nls.localize('app.launch.json.compounds.configurations', "Names of configurations that will be started as part of this compound.") + }, + preLaunchTask: { + type: 'string', + default: '', + description: nls.localize('compoundPrelaunchTask', "Task to run before any of the compound configurations start.") } }, default: defaultCompound diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index f03be25070..3384ab1e25 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -23,7 +23,7 @@ import { ResourceContextKey } from 'vs/workbench/common/resources'; import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService'; import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; -import { SupportsWorkspacesContext, IsWebContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys'; +import { IsWebContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { OpenFileFolderAction, OpenFileAction, OpenFolderAction, OpenWorkspaceAction } from 'vs/workbench/browser/actions/workspaceActions'; import { ActiveEditorIsSaveableContext } from 'vs/workbench/common/editor'; @@ -496,7 +496,7 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { id: ADD_ROOT_FOLDER_COMMAND_ID, title: ADD_ROOT_FOLDER_LABEL }, - when: ContextKeyExpr.and(ExplorerRootContext, SupportsWorkspacesContext) + when: ContextKeyExpr.and(ExplorerRootContext) }); MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { @@ -506,7 +506,7 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { id: REMOVE_ROOT_FOLDER_COMMAND_ID, title: REMOVE_ROOT_FOLDER_LABEL }, - when: ContextKeyExpr.and(ExplorerRootContext, ExplorerFolderContext, SupportsWorkspacesContext) + when: ContextKeyExpr.and(ExplorerRootContext, ExplorerFolderContext) }); MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index 947680e9da..50bde81d73 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -581,7 +581,8 @@ class OpenEditorRenderer implements IListRenderer().explorer.decorations, - descriptionVerbosity: Verbosity.MEDIUM + descriptionVerbosity: Verbosity.MEDIUM, + title: editor.editor.getTitle(Verbosity.LONG) }); } diff --git a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts index 0d189e94c8..915d5e586d 100644 --- a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts @@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri'; import { EncodingMode, ConfirmResult, EditorInput, IFileEditorInput, ITextEditorModel, Verbosity, IRevertOptions } from 'vs/workbench/common/editor'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; -import { FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; +import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; import { ITextFileService, AutoSaveMode, ModelState, TextFileModelChangeEvent, LoadReason, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IReference } from 'vs/base/common/lifecycle'; @@ -48,7 +48,8 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { @IInstantiationService private readonly instantiationService: IInstantiationService, @ITextFileService private readonly textFileService: ITextFileService, @ITextModelService private readonly textModelResolverService: ITextModelService, - @ILabelService private readonly labelService: ILabelService + @ILabelService private readonly labelService: ILabelService, + @IFileService private readonly fileService: IFileService ) { super(); @@ -72,6 +73,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { this._register(this.textFileService.models.onModelReverted(e => this.onDirtyStateChange(e))); this._register(this.textFileService.models.onModelOrphanedChanged(e => this.onModelOrphanedChanged(e))); this._register(this.labelService.onDidChangeFormatters(() => FileEditorInput.MEMOIZER.clear())); + this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(() => FileEditorInput.MEMOIZER.clear())); } private onDirtyStateChange(e: TextFileModelChangeEvent): void { diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css index 62d8487bf4..f44008484f 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css +++ b/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css @@ -44,7 +44,16 @@ padding: 0px 8px; border-radius: 2px; position: absolute; - right: 10px; + right: 35px; + top: 0; +} + +.settings-editor > .settings-header > .search-container > .settings-clear-widget { + margin: 6px 0px; + padding: 0px 8px; + border-radius: 2px; + position: absolute; + right: 0px; top: 0; } diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 4b421f45b9..f641763207 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -39,11 +39,13 @@ import { AbstractSettingRenderer, ISettingLinkClickEvent, ISettingOverrideClickE import { ISettingsEditorViewState, parseQuery, SearchResultIdx, SearchResultModel, SettingsTreeElement, SettingsTreeGroupChild, SettingsTreeGroupElement, SettingsTreeModel, SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels'; import { settingsTextInputBorder } from 'vs/workbench/contrib/preferences/browser/settingsWidgets'; import { createTOCIterator, TOCTree, TOCTreeModel } from 'vs/workbench/contrib/preferences/browser/tocTree'; -import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, EXTENSION_SETTING_TAG, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU } from 'vs/workbench/contrib/preferences/common/preferences'; +import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, EXTENSION_SETTING_TAG, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS } from 'vs/workbench/contrib/preferences/common/preferences'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IPreferencesService, ISearchResult, ISettingsEditorModel, ISettingsEditorOptions, SettingsEditorOptions, SettingValueType } from 'vs/workbench/services/preferences/common/preferences'; import { SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput'; import { Settings2EditorModel } from 'vs/workbench/services/preferences/common/preferencesModels'; +import { Action } from 'vs/base/common/actions'; +import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; function createGroupIterator(group: SettingsTreeGroupElement): Iterator> { const groupsIt = Iterator.fromArray(group.children); @@ -132,6 +134,9 @@ export class SettingsEditor2 extends BaseEditor { private scheduledRefreshes: Map; private lastFocusedSettingElement: string | null = null; + private actionBar: ActionBar; + private actionsContainer: HTMLElement; + /** Don't spam warnings */ private hasWarnedMissingSettings = false; @@ -385,11 +390,18 @@ export class SettingsEditor2 extends BaseEditor { this.searchWidget.setValue(query.trim()); } + clearSearch(): void { + this.clearSearchResults(); + this.focusSearch(); + } + private createHeader(parent: HTMLElement): void { this.headerContainer = DOM.append(parent, $('.settings-header')); const searchContainer = DOM.append(this.headerContainer, $('.search-container')); + const clearInputAction = new Action(SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, localize('clearInput', "Clear Settings Search Input"), 'codicon-clear-all', false, () => { this.clearSearch(); return Promise.resolve(null); }); + const searchBoxLabel = localize('SearchSettings.AriaLabel', "Search settings"); this.searchWidget = this._register(this.instantiationService.createInstance(SuggestEnabledInput, `${SettingsEditor2.ID}.searchbox`, searchContainer, { triggerCharacters: ['@'], @@ -425,13 +437,26 @@ export class SettingsEditor2 extends BaseEditor { this.countElement.style.borderColor = border; })); - this._register(this.searchWidget.onInputDidChange(() => this.onSearchInputChanged())); + this._register(this.searchWidget.onInputDidChange(() => { + const searchVal = this.searchWidget.getValue(); + clearInputAction.enabled = !!searchVal; + this.onSearchInputChanged(); + })); const headerControlsContainer = DOM.append(this.headerContainer, $('.settings-header-controls')); const targetWidgetContainer = DOM.append(headerControlsContainer, $('.settings-target-container')); this.settingsTargetsWidget = this._register(this.instantiationService.createInstance(SettingsTargetsWidget, targetWidgetContainer, { enableRemoteSettings: true })); this.settingsTargetsWidget.settingsTarget = ConfigurationTarget.USER_LOCAL; this.settingsTargetsWidget.onDidTargetChange(target => this.onDidSettingsTargetChange(target)); + + this.actionsContainer = DOM.append(searchContainer, DOM.$('.settings-clear-widget')); + + this.actionBar = this._register(new ActionBar(this.actionsContainer, { + animated: false, + actionViewItemProvider: (action: Action) => { return undefined; } + })); + + this.actionBar.push([clearInputAction], { label: false, icon: true }); } private onDidSettingsTargetChange(target: SettingsTarget): void { diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 96a27de58e..b445e1ba12 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -245,7 +245,7 @@ export class SearchView extends ViewletPanel { if (this.searchWidget.isReplaceActive()) { this.searchWidget.focusReplaceAllAction(); } else { - this.searchWidget.focusRegexAction(); + this.searchWidget.isReplaceShown() ? this.searchWidget.replaceInput.focusOnPreserve() : this.searchWidget.focusRegexAction(); } dom.EventHelper.stop(e); } diff --git a/src/vs/workbench/contrib/search/browser/searchWidget.ts b/src/vs/workbench/contrib/search/browser/searchWidget.ts index 8440e1d6b5..6b40a1b55f 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -389,6 +389,7 @@ export class SearchWidget extends Widget { this.replaceInputFocusTracker = this._register(dom.trackFocus(this.replaceInput.inputBox.inputElement)); this._register(this.replaceInputFocusTracker.onDidFocus(() => this.replaceInputBoxFocused.set(true))); this._register(this.replaceInputFocusTracker.onDidBlur(() => this.replaceInputBoxFocused.set(false))); + this._register(this.replaceInput.onPreserveCaseKeyDown((keyboardEvent: IKeyboardEvent) => this.onPreserveCaseKeyDown(keyboardEvent))); } triggerReplaceAll(): Promise { @@ -495,6 +496,15 @@ export class SearchWidget extends Widget { } private onRegexKeyDown(keyboardEvent: IKeyboardEvent) { + if (keyboardEvent.equals(KeyCode.Tab)) { + if (this.isReplaceShown()) { + this.replaceInput.focusOnPreserve(); + keyboardEvent.preventDefault(); + } + } + } + + private onPreserveCaseKeyDown(keyboardEvent: IKeyboardEvent) { if (keyboardEvent.equals(KeyCode.Tab)) { if (this.isReplaceActive()) { this.focusReplaceAllAction(); @@ -503,6 +513,10 @@ export class SearchWidget extends Widget { } keyboardEvent.preventDefault(); } + else if (KeyMod.Shift | KeyCode.Tab) { + this.focusRegexAction(); + keyboardEvent.preventDefault(); + } } private onReplaceInputKeyDown(keyboardEvent: IKeyboardEvent) { diff --git a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts index 4d19dda33e..3e22c5022a 100644 --- a/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts +++ b/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts @@ -81,6 +81,7 @@ import { find } from 'vs/base/common/arrays'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; const QUICKOPEN_HISTORY_LIMIT_CONFIG = 'task.quickOpen.history'; +const QUICKOPEN_DETAIL_CONFIG = 'task.quickOpen.detail'; export namespace ConfigureTaskAction { export const ID = 'workbench.action.tasks.configureTaskRunner'; @@ -744,7 +745,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer } if (CustomTask.is(task)) { let configProperties: TaskConfig.ConfigurationProperties = task._source.config.element; - return configProperties.problemMatcher === undefined && !task.hasDefinedMatchers; + const type: string = (configProperties).type; + return configProperties.problemMatcher === undefined && !task.hasDefinedMatchers && (Types.isStringArray(settingValue) && (settingValue.indexOf(type) < 0)); } return false; } @@ -1297,7 +1299,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer this.notificationService.prompt(Severity.Warning, nls.localize('TaskSystem.slowProvider', "The {0} task provider is slow. The extension that provides {0} tasks may provide a setting to disable it, or you can disable all tasks providers", type), [settings, disableAll, dontShow]); } - }, 1000); + }, 2000); } }); } @@ -1876,6 +1878,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer return true; } + private showDetail(): boolean { + return this.configurationService.getValue(QUICKOPEN_DETAIL_CONFIG); + } + private createTaskQuickPickEntries(tasks: Task[], group: boolean = false, sort: boolean = false, selectedEntry?: TaskQuickPickEntry): TaskQuickPickEntry[] { if (tasks === undefined || tasks === null || tasks.length === 0) { return []; @@ -1892,7 +1898,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer description = workspaceFolder.name; } } - return { label: task._label, description, task }; + + return { label: task._label, description, task, detail: this.showDetail() ? task.configurationProperties.detail : undefined }; }; function fillEntries(entries: QuickPickInput[], tasks: Task[], groupLabel: string): void { if (tasks.length) { diff --git a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts index 87dc49ef91..388a4f97db 100644 --- a/src/vs/workbench/contrib/tasks/browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/browser/task.contribution.ts @@ -358,5 +358,10 @@ configurationRegistry.registerConfiguration({ type: 'number', default: 30, minimum: 0, maximum: 30 }, + 'task.quickOpen.detail': { + markdownDescription: nls.localize('task.quickOpen.detail', "Controls whether to show the task detail for task that have a detail in the Run Task quick pick."), + type: 'boolean', + default: true + } } }); diff --git a/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts b/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts index abe55620d4..5af470eb9d 100644 --- a/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts +++ b/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts @@ -89,6 +89,11 @@ const dependsOrder: IJSONSchema = { description: nls.localize('JsonSchema.tasks.dependsOrder', 'Determines the order of the dependsOn tasks for this task. Note that this property is not recursive.') }; +const detail: IJSONSchema = { + type: 'string', + description: nls.localize('JsonSchema.tasks.detail', 'An optional description of a task that shows in the Run Task quick pick as a detail.') +}; + const presentation: IJSONSchema = { type: 'object', default: { @@ -365,7 +370,8 @@ let taskConfiguration: IJSONSchema = { }, runOptions: Objects.deepClone(runOptions), dependsOn: Objects.deepClone(dependsOn), - dependsOrder: Objects.deepClone(dependsOrder) + dependsOrder: Objects.deepClone(dependsOrder), + detail: Objects.deepClone(detail), } }; @@ -425,6 +431,7 @@ taskDescriptionProperties.presentation = Objects.deepClone(presentation); taskDescriptionProperties.terminal = terminal; taskDescriptionProperties.group = Objects.deepClone(group); taskDescriptionProperties.runOptions = Objects.deepClone(runOptions); +taskDescriptionProperties.detail = detail; taskDescriptionProperties.taskName.deprecationMessage = nls.localize( 'JsonSchema.tasks.taskName.deprecated', 'The task\'s name property is deprecated. Use the label property instead.' diff --git a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts index d63689eeba..52cb5e1364 100644 --- a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts +++ b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts @@ -309,6 +309,11 @@ export interface ConfigurationProperties { */ group?: string | GroupKind; + /** + * A description of the task. + */ + detail?: string; + /** * The other tasks the task depend on */ @@ -1326,6 +1331,9 @@ namespace ConfigurationProperties { if (configProblemMatcher !== undefined) { result.problemMatchers = configProblemMatcher; } + if (external.detail) { + result.detail = external.detail; + } return isEmpty(result) ? undefined : result; } @@ -1587,6 +1595,7 @@ namespace CustomTask { assignProperty(resultConfigProps, configuredProps.configurationProperties, 'dependsOn'); assignProperty(resultConfigProps, configuredProps.configurationProperties, 'problemMatchers'); assignProperty(resultConfigProps, configuredProps.configurationProperties, 'promptOnClose'); + assignProperty(resultConfigProps, configuredProps.configurationProperties, 'detail'); result.command.presentation = CommandConfiguration.PresentationOptions.assignProperties( result.command.presentation!, configuredProps.configurationProperties.presentation)!; result.command.options = CommandOptions.assignProperties(result.command.options, configuredProps.configurationProperties.options); @@ -1598,6 +1607,7 @@ namespace CustomTask { fillProperty(resultConfigProps, contributedConfigProps, 'dependsOn'); fillProperty(resultConfigProps, contributedConfigProps, 'problemMatchers'); fillProperty(resultConfigProps, contributedConfigProps, 'promptOnClose'); + fillProperty(resultConfigProps, contributedConfigProps, 'detail'); result.command.presentation = CommandConfiguration.PresentationOptions.fillProperties( result.command.presentation!, contributedConfigProps.presentation)!; result.command.options = CommandOptions.fillProperties(result.command.options, contributedConfigProps.options); diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index 173ec046e3..c2b69aca0a 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -504,6 +504,11 @@ export interface ConfigurationProperties { */ dependsOrder?: DependsOrder; + /** + * A description of the task. + */ + detail?: string; + /** * The problem watchers to use for this task */ diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index c8797854d4..997ce22b35 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -219,10 +219,11 @@ configurationRegistry.registerConfiguration({ }, 'terminal.integrated.rightClickBehavior': { type: 'string', - enum: ['default', 'copyPaste', 'selectWord'], + enum: ['default', 'copyPaste', 'paste', 'selectWord'], enumDescriptions: [ nls.localize('terminal.integrated.rightClickBehavior.default', "Show the context menu."), nls.localize('terminal.integrated.rightClickBehavior.copyPaste', "Copy when there is a selection, otherwise paste."), + nls.localize('terminal.integrated.rightClickBehavior.paste', "Paste on right click."), nls.localize('terminal.integrated.rightClickBehavior.selectWord', "Select the word under the cursor and show the context menu.") ], default: platform.isMacintosh ? 'selectWord' : platform.isWindows ? 'copyPaste' : 'default', @@ -361,9 +362,7 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextTermina actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousTerminalAction, FocusPreviousTerminalAction.ID, FocusPreviousTerminalAction.LABEL), 'Terminal: Focus Previous Terminal', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(TerminalPasteAction, TerminalPasteAction.ID, TerminalPasteAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_V, - linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V }, - // Don't apply to Mac since cmd+v works - mac: { primary: 0 } + linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_V } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Paste into Active Terminal', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectAllTerminalAction, SelectAllTerminalAction.ID, SelectAllTerminalAction.LABEL, { // Don't use ctrl+a by default as that would override the common go to start diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 4994514eb1..1530c7f0b8 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -144,7 +144,7 @@ export interface ITerminalService { preparePathForTerminalAsync(path: string, executable: string | undefined, title: string): Promise; extHostReady(remoteAuthority: string): void; - requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; + requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI | undefined, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts index 54bb231389..6576483fd7 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalPanel.ts @@ -218,12 +218,13 @@ export class TerminalPanel extends Panel { terminal.focus(); } } else if (event.which === 3) { - if (this._terminalService.configHelper.config.rightClickBehavior === 'copyPaste') { + const rightClickBehavior = this._terminalService.configHelper.config.rightClickBehavior; + if (rightClickBehavior === 'copyPaste' || rightClickBehavior === 'paste') { const terminal = this._terminalService.getActiveInstance(); if (!terminal) { return; } - if (terminal.hasSelection()) { + if (rightClickBehavior === 'copyPaste' && terminal.hasSelection()) { await terminal.copySelection(); terminal.clearSelection(); } else { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts index 55b546b3ea..36be0aa641 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy.ts @@ -48,7 +48,7 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal constructor( public terminalId: number, shellLaunchConfig: IShellLaunchConfig, - activeWorkspaceRootUri: URI, + activeWorkspaceRootUri: URI | undefined, cols: number, rows: number, configHelper: ITerminalConfigHelper, diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 0fdfe68bfa..5b2f93e166 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -134,7 +134,7 @@ export class TerminalService implements ITerminalService { return activeInstance ? activeInstance : this.createTerminal(undefined); } - public requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void { + public requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI | undefined, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void { this._extensionService.whenInstalledExtensionsRegistered().then(async () => { // Wait for the remoteAuthority to be ready (and listening for events) before firing // the event to spawn the ext host process diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index b2afc3e9fe..b8138fba75 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -88,7 +88,7 @@ export interface ITerminalConfiguration { macOptionIsMeta: boolean; macOptionClickForcesSelection: boolean; rendererType: 'auto' | 'canvas' | 'dom'; - rightClickBehavior: 'default' | 'copyPaste' | 'selectWord'; + rightClickBehavior: 'default' | 'copyPaste' | 'paste' | 'selectWord'; cursorBlinking: boolean; cursorStyle: string; drawBoldTextInBrightColors: boolean; @@ -343,7 +343,7 @@ export interface ITerminalProcessExtHostProxy extends IDisposable { export interface ISpawnExtHostProcessRequest { proxy: ITerminalProcessExtHostProxy; shellLaunchConfig: IShellLaunchConfig; - activeWorkspaceRootUri: URI; + activeWorkspaceRootUri: URI | undefined; cols: number; rows: number; isWorkspaceShellAllowed: boolean; diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js index e2dad2524f..63541521d7 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/main.js +++ b/src/vs/workbench/contrib/webview/browser/pre/main.js @@ -479,6 +479,7 @@ newFrame.contentWindow.addEventListener('click', handleInnerClick); newFrame.contentWindow.addEventListener('auxclick', handleAuxClick); newFrame.contentWindow.addEventListener('keydown', handleInnerKeydown); + newFrame.contentWindow.addEventListener('contextmenu', e => e.preventDefault()); if (host.onIframeLoaded) { host.onIframeLoaded(newFrame); diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index 3f5a9640f6..155c3fb23d 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -92,9 +92,13 @@ export class IFrameWebview extends BaseWebview implements Web } private preprocessHtml(value: string): string { - return value.replace(/(["'])vscode-resource:(\/\/([^\s'"]+?)(?=\/))?([^\s'"]+?)(["'])/gi, (_, startQuote, _1, scheme, path, endQuote) => { - return `${startQuote}${this.externalEndpoint}/vscode-resource/${scheme || ''}${path}${endQuote}`; - }); + return value + .replace(/(["'])vscode-resource:(\/\/([^\s\/'"]+?)(?=\/))?([^\s'"]+?)(["'])/gi, (match, startQuote, _1, scheme, path, endQuote) => { + if (scheme) { + return `${startQuote}${this.externalEndpoint}/vscode-resource/${scheme}${path}${endQuote}`; + } + return `${startQuote}${this.externalEndpoint}/vscode-resource/file${path}${endQuote}`; + }); } protected get extraContentOptions() { diff --git a/src/vs/workbench/electron-browser/actions/workspaceActions.ts b/src/vs/workbench/electron-browser/actions/workspaceActions.ts deleted file mode 100644 index eb26b3b4c9..0000000000 --- a/src/vs/workbench/electron-browser/actions/workspaceActions.ts +++ /dev/null @@ -1,70 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Action } from 'vs/base/common/actions'; -import * as nls from 'vs/nls'; -import { IHostService } from 'vs/workbench/services/host/browser/host'; -import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; -import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; - -export class SaveWorkspaceAsAction extends Action { - - static readonly ID = 'workbench.action.saveWorkspaceAs'; - static readonly LABEL = nls.localize('saveWorkspaceAsAction', "Save Workspace As..."); - - constructor( - id: string, - label: string, - @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService - - ) { - super(id, label); - } - - async run(): Promise { - const configPathUri = await this.workspaceEditingService.pickNewWorkspacePath(); - if (configPathUri) { - switch (this.contextService.getWorkbenchState()) { - case WorkbenchState.EMPTY: - case WorkbenchState.FOLDER: - const folders = this.contextService.getWorkspace().folders.map(folder => ({ uri: folder.uri })); - return this.workspaceEditingService.createAndEnterWorkspace(folders, configPathUri); - case WorkbenchState.WORKSPACE: - return this.workspaceEditingService.saveAndEnterWorkspace(configPathUri); - } - } - } -} - -export class DuplicateWorkspaceInNewWindowAction extends Action { - - static readonly ID = 'workbench.action.duplicateWorkspaceInNewWindow'; - static readonly LABEL = nls.localize('duplicateWorkspaceInNewWindow', "Duplicate Workspace in New Window"); - - constructor( - id: string, - label: string, - @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, - @IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService, - @IHostService private readonly hostService: IHostService, - @IWorkspacesService private readonly workspacesService: IWorkspacesService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService - ) { - super(id, label); - } - - async run(): Promise { - const folders = this.workspaceContextService.getWorkspace().folders; - const remoteAuthority = this.environmentService.configuration.remoteAuthority; - - const newWorkspace = await this.workspacesService.createUntitledWorkspace(folders, remoteAuthority); - await this.workspaceEditingService.copyWorkspaceSettings(newWorkspace); - - return this.hostService.openWindow([{ workspaceUri: newWorkspace.configPath }], { forceNewWindow: true }); - } -} diff --git a/src/vs/workbench/electron-browser/desktop.contribution.ts b/src/vs/workbench/electron-browser/desktop.contribution.ts index 936f946794..c6ea30c7b5 100644 --- a/src/vs/workbench/electron-browser/desktop.contribution.ts +++ b/src/vs/workbench/electron-browser/desktop.contribution.ts @@ -13,12 +13,11 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform'; import { ToggleSharedProcessAction, ToggleDevToolsAction, ConfigureRuntimeArgumentsAction } from 'vs/workbench/electron-browser/actions/developerActions'; import { ZoomResetAction, ZoomOutAction, ZoomInAction, CloseCurrentWindowAction, SwitchWindow, QuickSwitchWindow, ReloadWindowWithExtensionsDisabledAction, NewWindowTabHandler, ShowPreviousWindowTabHandler, ShowNextWindowTabHandler, MoveWindowTabToNewWindowHandler, MergeWindowTabsHandlerHandler, ToggleWindowTabsBarHandler } from 'vs/workbench/electron-browser/actions/windowActions'; -import { SaveWorkspaceAsAction, DuplicateWorkspaceInNewWindowAction } from 'vs/workbench/electron-browser/actions/workspaceActions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { SupportsWorkspacesContext, IsMacContext, HasMacNativeTabsContext, IsDevelopmentContext } from 'vs/workbench/browser/contextkeys'; +import { IsMacContext, HasMacNativeTabsContext, IsDevelopmentContext } from 'vs/workbench/browser/contextkeys'; import { NoEditorsVisibleContext, SingleEditorGroupsContext } from 'vs/workbench/common/editor'; import { IElectronService } from 'vs/platform/electron/node/electron'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; @@ -68,14 +67,6 @@ import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/browser/exten }); })(); - // Actions: Workspaces - (function registerWorkspaceActions(): void { - const workspacesCategory = nls.localize('workspaces', "Workspaces"); - - registry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace As...', workspacesCategory, SupportsWorkspacesContext); - registry.registerWorkbenchAction(new SyncActionDescriptor(DuplicateWorkspaceInNewWindowAction, DuplicateWorkspaceInNewWindowAction.ID, DuplicateWorkspaceInNewWindowAction.LABEL), 'Workspaces: Duplicate Workspace in New Window', workspacesCategory, SupportsWorkspacesContext); - })(); - // Actions: macOS Native Tabs (function registerMacOSNativeTabsActions(): void { if (isMacintosh) { @@ -117,18 +108,7 @@ import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/browser/exten // Menu (function registerMenu(): void { - MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '3_workspace', - command: { - id: SaveWorkspaceAsAction.ID, - title: nls.localize('miSaveWorkspaceAs', "Save Workspace As...") - }, - order: 2, - when: SupportsWorkspacesContext - }); - - // {{SQL CARBON EDIT}} - Add install VSIX menu item - MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { + MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { // {{SQL CARBON EDIT}} - Add install VSIX menu item group: '5.1_installExtension', command: { id: InstallVSIXAction.ID, diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 48c435b0bd..9eff28903b 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -153,7 +153,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { for (const handler of this.openEditorHandlers) { const result = handler(event.editor, event.options, group); - const override = result ? result.override : undefined; + const override = result?.override; if (override) { event.prevent((() => override.then(editor => withNullAsUndefined(editor)))); break; @@ -162,9 +162,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { } get activeControl(): IVisibleEditor | undefined { - const activeGroup = this.editorGroupService.activeGroup; - - return activeGroup ? activeGroup.activeControl : undefined; + return this.editorGroupService.activeGroup?.activeControl; } get activeTextEditorWidget(): ICodeEditor | IDiffEditor | undefined { diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 8a3bd8ebe4..25e3da30f3 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -91,6 +91,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment this.keyboardLayoutResource = joinPath(this.userRoamingDataHome, 'keyboardLayout.json'); this.argvResource = joinPath(this.userRoamingDataHome, 'argv.json'); this.backupHome = joinPath(this.userRoamingDataHome, BACKUPS); + this.untitledWorkspacesHome = joinPath(this.userRoamingDataHome, 'Workspaces'); this.configuration.backupWorkspaceResource = joinPath(this.backupHome, options.workspaceId); this.configuration.connectionToken = options.connectionToken || getCookieValue('vscode-tkn'); @@ -99,8 +100,6 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment break: false }; - this.untitledWorkspacesHome = URI.from({ scheme: Schemas.untitled, path: 'Workspaces' }); - // Fill in selected extra environmental properties if (options.workspaceProvider && Array.isArray(options.workspaceProvider.payload)) { const environment = serializableToMap(options.workspaceProvider.payload); @@ -207,7 +206,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment get webviewExternalEndpoint(): string { // TODO: get fallback from product.json return (this.options.webviewEndpoint || 'https://{{uuid}}.vscode-webview-test.com/{{commit}}') - .replace('{{commit}}', product.commit || '211fa02efe8c041fd7baa8ec3dce199d5185aa44'); + .replace('{{commit}}', product.commit || 'c58aaab8a1cc22a7139b761166a0d4f37d41e998'); } get webviewResourceRoot(): string { diff --git a/src/vs/workbench/services/environment/node/environmentService.ts b/src/vs/workbench/services/environment/node/environmentService.ts index a338f71122..334d9896a7 100644 --- a/src/vs/workbench/services/environment/node/environmentService.ts +++ b/src/vs/workbench/services/environment/node/environmentService.ts @@ -20,7 +20,7 @@ export class WorkbenchEnvironmentService extends EnvironmentService implements I get webviewExternalEndpoint(): string { const baseEndpoint = 'https://{{uuid}}.vscode-webview-test.com/{{commit}}'; - return baseEndpoint.replace('{{commit}}', product.commit || '211fa02efe8c041fd7baa8ec3dce199d5185aa44'); + return baseEndpoint.replace('{{commit}}', product.commit || 'c58aaab8a1cc22a7139b761166a0d4f37d41e998'); } readonly webviewResourceRoot = 'vscode-resource://{{resource}}'; diff --git a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts index 398a350117..96d5768491 100644 --- a/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/browser/extensionUrlHandler.ts @@ -142,7 +142,7 @@ class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { } if (showConfirm) { - let uriString = uri.toString(); + let uriString = uri.toString(false); // {{SQL CARBON EDIT}} - Begin // Dialog service starts truncating words longer than 80 characters and adds ellipses to it. diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index d831ca073f..046f380d7e 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -7,7 +7,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { URI, UriComponents } from 'vs/base/common/uri'; import { IEditor } from 'vs/editor/common/editorCommon'; import { ITextEditorOptions, IResourceInput, ITextEditorSelection } from 'vs/platform/editor/common/editor'; -import { IEditorInput, IEditor as IBaseEditor, Extensions as EditorExtensions, EditorInput, IEditorCloseEvent, IEditorInputFactoryRegistry, toResource, Extensions as EditorInputExtensions, IFileInputFactory, IEditorIdentifier } from 'vs/workbench/common/editor'; +import { IEditorInput, IEditor as IBaseEditor, Extensions as EditorExtensions, EditorInput, IEditorCloseEvent, IEditorInputFactoryRegistry, toResource, IEditorIdentifier } from 'vs/workbench/common/editor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; import { FileChangesEvent, IFileService, FileChangeType, FILES_EXCLUDE_CONFIG } from 'vs/platform/files/common/files'; @@ -125,8 +125,6 @@ export class HistoryService extends Disposable implements IHistoryService { private loaded: boolean; private resourceFilter: ResourceGlobMatcher; - private fileInputFactory: IFileInputFactory; - private canNavigateBackContextKey: IContextKey; private canNavigateForwardContextKey: IContextKey; private canNavigateToLastEditLocationContextKey: IContextKey; @@ -149,8 +147,6 @@ export class HistoryService extends Disposable implements IHistoryService { this.canNavigateForwardContextKey = (new RawContextKey('canNavigateForward', false)).bindTo(this.contextKeyService); this.canNavigateToLastEditLocationContextKey = (new RawContextKey('canNavigateToLastEditLocation', false)).bindTo(this.contextKeyService); - this.fileInputFactory = Registry.as(EditorInputExtensions.EditorInputFactories).getFileInputFactory(); - this.index = -1; this.lastIndex = -1; this.stack = []; @@ -486,7 +482,7 @@ export class HistoryService extends Disposable implements IHistoryService { } private handleEditorEventInHistory(editor?: IBaseEditor): void { - const input = editor ? editor.input : undefined; + const input = editor?.input; // Ensure we have at least a name to show and not configured to exclude input if (!input || !input.getName() || !this.include(input)) { @@ -738,8 +734,9 @@ export class HistoryService extends Disposable implements IHistoryService { } private preferResourceInput(input: IEditorInput): IEditorInput | IResourceInput { - if (this.fileInputFactory.isFileInput(input)) { - return { resource: input.getResource() }; + const resource = input.getResource(); + if (resource && this.fileService.canHandleResource(resource)) { + return { resource: resource }; } return input; diff --git a/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index 4ba782f8e6..1d6cb967f0 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -13,7 +13,6 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWorkspaceContextService, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { isEqual, basenameOrAuthority, isEqualOrParent, basename, joinPath, dirname } from 'vs/base/common/resources'; -import { isWindows } from 'vs/base/common/platform'; import { tildify, getPathLabel } from 'vs/base/common/labels'; import { ltrim, endsWith } from 'vs/base/common/strings'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, WORKSPACE_EXTENSION, toWorkspaceIdentifier, isWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; @@ -71,7 +70,7 @@ const sepRegexp = /\//g; const labelMatchingRegexp = /\$\{(scheme|authority|path|(query)\.(.+?))\}/g; function hasDriveLetter(path: string): boolean { - return !!(isWindows && path && path[2] === ':'); + return !!(path && path[2] === ':'); } class ResourceLabelFormattersHandler implements IWorkbenchContribution { diff --git a/src/vs/workbench/services/progress/browser/media/progressService.css b/src/vs/workbench/services/progress/browser/media/progressService.css index c7e5960f2b..cc899d47dd 100644 --- a/src/vs/workbench/services/progress/browser/media/progressService.css +++ b/src/vs/workbench/services/progress/browser/media/progressService.css @@ -11,8 +11,13 @@ padding-right: 5px; } -.monaco-workbench .progress-badge > .badge-content { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCIgdmlld0JveD0iMiAyIDE0IDE0IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDIgMiAxNCAxNCI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTkgMTZjLTMuODYgMC03LTMuMTQtNy03czMuMTQtNyA3LTdjMy44NTkgMCA3IDMuMTQxIDcgN3MtMy4xNDEgNy03IDd6bTAtMTIuNmMtMy4wODggMC01LjYgMi41MTMtNS42IDUuNnMyLjUxMiA1LjYgNS42IDUuNiA1LjYtMi41MTIgNS42LTUuNi0yLjUxMi01LjYtNS42LTUuNnptMy44NiA3LjFsLTMuMTYtMS44OTZ2LTMuODA0aC0xLjR2NC41OTZsMy44NCAyLjMwNS43Mi0xLjIwMXoiLz48L3N2Zz4="); - background-position: center center; - background-repeat: no-repeat; +.monaco-workbench .progress-badge > .badge-content::before { + -webkit-mask: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCIgdmlld0JveD0iMiAyIDE0IDE0IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDIgMiAxNCAxNCI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTkgMTZjLTMuODYgMC03LTMuMTQtNy03czMuMTQtNyA3LTdjMy44NTkgMCA3IDMuMTQxIDcgN3MtMy4xNDEgNy03IDd6bTAtMTIuNmMtMy4wODggMC01LjYgMi41MTMtNS42IDUuNnMyLjUxMiA1LjYgNS42IDUuNiA1LjYtMi41MTIgNS42LTUuNi0yLjUxMi01LjYtNS42LTUuNnptMy44NiA3LjFsLTMuMTYtMS44OTZ2LTMuODA0aC0xLjR2NC41OTZsMy44NCAyLjMwNS43Mi0xLjIwMXoiLz48L3N2Zz4="); + width: 14px; + height: 14px; + position: absolute; + top: 1px; + left: 1px; + background-color: currentColor; + content: ''; } diff --git a/src/vs/workbench/services/workspaces/browser/workspaces.ts b/src/vs/workbench/services/workspaces/browser/workspaces.ts new file mode 100644 index 0000000000..722f8220f1 --- /dev/null +++ b/src/vs/workbench/services/workspaces/browser/workspaces.ts @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { URI } from 'vs/base/common/uri'; +import { hash } from 'vs/base/common/hash'; + +export function getWorkspaceIdentifier(workspacePath: URI): IWorkspaceIdentifier { + return { + id: hash(workspacePath.toString()).toString(16), + configPath: workspacePath + }; +} diff --git a/src/vs/workbench/services/workspaces/browser/workspacesService.ts b/src/vs/workbench/services/workspaces/browser/workspacesService.ts index 7bb7a85a96..db573c09c0 100644 --- a/src/vs/workbench/services/workspaces/browser/workspacesService.ts +++ b/src/vs/workbench/services/workspaces/browser/workspacesService.ts @@ -4,13 +4,19 @@ *--------------------------------------------------------------------------------------------*/ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IWorkspacesService, IWorkspaceFolderCreationData, IWorkspaceIdentifier, IEnterWorkspaceResult, IRecentlyOpened, restoreRecentlyOpened, IRecent, isRecentFile, isRecentFolder, toStoreData } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspacesService, IWorkspaceFolderCreationData, IWorkspaceIdentifier, IEnterWorkspaceResult, IRecentlyOpened, restoreRecentlyOpened, IRecent, isRecentFile, isRecentFolder, toStoreData, IStoredWorkspaceFolder, getStoredWorkspaceFolder, WORKSPACE_EXTENSION, IStoredWorkspace } from 'vs/platform/workspaces/common/workspaces'; import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { ILogService } from 'vs/platform/log/common/log'; import { Disposable } from 'vs/base/common/lifecycle'; +import { getWorkspaceIdentifier } from 'vs/workbench/services/workspaces/browser/workspaces'; +import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IFileService } from 'vs/platform/files/common/files'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { joinPath } from 'vs/base/common/resources'; +import { VSBuffer } from 'vs/base/common/buffer'; export class BrowserWorkspacesService extends Disposable implements IWorkspacesService { @@ -25,6 +31,9 @@ export class BrowserWorkspacesService extends Disposable implements IWorkspacesS @IStorageService private readonly storageService: IStorageService, @IWorkspaceContextService private readonly workspaceService: IWorkspaceContextService, @ILogService private readonly logService: ILogService, + @IHostService private readonly hostService: IHostService, + @IFileService private readonly fileService: IFileService, + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService ) { super(); @@ -113,20 +122,41 @@ export class BrowserWorkspacesService extends Disposable implements IWorkspacesS //#region Workspace Management - enterWorkspace(path: URI): Promise { - throw new Error('Untitled workspaces are currently unsupported in Web'); + async enterWorkspace(path: URI): Promise { + + // Open workspace in same window + await this.hostService.openWindow([{ workspaceUri: path }], { forceReuseWindow: true }); + + return { + workspace: await this.getWorkspaceIdentifier(path) + }; } - createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise { - throw new Error('Untitled workspaces are currently unsupported in Web'); + async createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise { + const randomId = (Date.now() + Math.round(Math.random() * 1000)).toString(); + const newUntitledWorkspacePath = joinPath(this.environmentService.untitledWorkspacesHome, `${randomId}.${WORKSPACE_EXTENSION}`); + + // Build array of workspace folders to store + const storedWorkspaceFolder: IStoredWorkspaceFolder[] = []; + if (folders) { + for (const folder of folders) { + storedWorkspaceFolder.push(getStoredWorkspaceFolder(folder.uri, folder.name, this.environmentService.untitledWorkspacesHome)); + } + } + + // Store at untitled workspaces location + const storedWorkspace: IStoredWorkspace = { folders: storedWorkspaceFolder, remoteAuthority }; + await this.fileService.writeFile(newUntitledWorkspacePath, VSBuffer.fromString(JSON.stringify(storedWorkspace, null, '\t'))); + + return this.getWorkspaceIdentifier(newUntitledWorkspacePath); } deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise { - throw new Error('Untitled workspaces are currently unsupported in Web'); + return this.fileService.del(workspace.configPath); } - getWorkspaceIdentifier(workspacePath: URI): Promise { - throw new Error('Untitled workspaces are currently unsupported in Web'); + async getWorkspaceIdentifier(workspacePath: URI): Promise { + return getWorkspaceIdentifier(workspacePath); } //#endregion diff --git a/yarn.lock b/yarn.lock index fcb1d5bbb4..823525a352 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5917,12 +5917,12 @@ node-pre-gyp@^0.10.0: semver "^5.3.0" tar "^4" -node-pty@0.9.0-beta19: - version "0.9.0-beta19" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0-beta19.tgz#0fd381b2006f4665c4c2ee0509219e591842371a" - integrity sha512-MkKEvBnauGnzgXNr/oaoWQLVXm1gheIKZs4YQp8883ZiETmbEnpSvD0FU3bELcPXG5VFPRqIGsQJ4KUMBLzkPA== +node-pty@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0.tgz#8f9bcc0d1c5b970a3184ffd533d862c7eb6590a6" + integrity sha512-MBnCQl83FTYOu7B4xWw10AW77AAh7ThCE1VXEv+JeWj8mSpGo+0bwgsV+b23ljBFwEM9OmsOv3kM27iUPPm84g== dependencies: - nan "^2.13.2" + nan "^2.14.0" node.extend@~1.1.2: version "1.1.8"