diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 012854c7309..19111126b93 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -4,8 +4,8 @@ about: Suggest an idea for this project --- + - diff --git a/.github/commands.json b/.github/commands.json index 10d2daa7da4..c721ac8d001 100644 --- a/.github/commands.json +++ b/.github/commands.json @@ -127,14 +127,6 @@ "action": "updateLabels", "addLabel": "~needs more info" }, - { - "type": "label", - "name": "~needs version info", - "action": "updateLabels", - "addLabel": "needs more info", - "removeLabel": "~needs version info", - "comment": "Thanks for creating this issue! We figured it's missing some basic information, such as a version number, or in some other way doesn't follow our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines. Please take the time to review these and update the issue.\n\nHappy Coding!" - }, { "type": "label", "name": "~needs more info", @@ -163,5 +155,135 @@ "name": "*off-topic", "action": "close", "comment": "Thanks for creating this issue. We think this issue is unactionable or unrelated to the goals of this project. Please follow our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines.\n\nHappy Coding!" + }, + { + "type": "comment", + "name": "extPython", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "close", + "addLabel": "*caused-by-extension", + "comment": "It looks like this is caused by the Python extension. Please file it with the repository [here](https://github.com/Microsoft/vscode-python). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!" + }, + { + "type": "comment", + "name": "extC", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "close", + "addLabel": "*caused-by-extension", + "comment": "It looks like this is caused by the C extension. Please file it with the repository [here](https://github.com/Microsoft/vscode-cpptools). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!" + }, + { + "type": "comment", + "name": "extC++", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "close", + "addLabel": "*caused-by-extension", + "comment": "It looks like this is caused by the C++ extension. Please file it with the repository [here](https://github.com/Microsoft/vscode-cpptools). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!" + }, + { + "type": "comment", + "name": "extTS", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "close", + "addLabel": "*caused-by-extension", + "comment": "It looks like this is caused by the TypeScript language service. Please file it with the repository [here](https://github.com/microsoft/TypeScript/). Make sure to check their [contributing guidelines](https://github.com/microsoft/TypeScript/blob/master/CONTRIBUTING.md) and provide relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!" + }, + { + "type": "comment", + "name": "extJS", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "close", + "addLabel": "*caused-by-extension", + "comment": "It looks like this is caused by the TypeScript/JavaScript language service. Please file it with the repository [here](https://github.com/microsoft/TypeScript/). Make sure to check their [contributing guidelines](https://github.com/microsoft/TypeScript/blob/master/CONTRIBUTING.md) and provide relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!" + }, + { + "type": "comment", + "name": "extC#", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "close", + "addLabel": "*caused-by-extension", + "comment": "It looks like this is caused by the C# extension. Please file it with the repository [here](https://github.com/OmniSharp/omnisharp-vscode.git). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!" + }, + { + "type": "comment", + "name": "extGo", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "close", + "addLabel": "*caused-by-extension", + "comment": "It looks like this is caused by the Go extension. Please file it with the repository [here](https://github.com/microsoft/vscode-go). Make sure to check their [contributing guidelines](https://github.com/microsoft/vscode-go/blob/master/CONTRIBUTING.md) and provide relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!" + }, + { + "type": "comment", + "name": "extPowershell", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "close", + "addLabel": "*caused-by-extension", + "comment": "It looks like this is caused by the Powershell extension. Please file it with the repository [here](https://github.com/PowerShell/vscode-powershell). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!" + }, + { + "type": "comment", + "name": "extLiveShare", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "close", + "addLabel": "*caused-by-extension", + "comment": "It looks like this is caused by the LiveShare extension. Please file it with the repository [here](https://github.com/MicrosoftDocs/live-share). Make sure to check their [contributing guidelines](https://github.com/MicrosoftDocs/live-share/blob/master/CONTRIBUTING.md) and provide relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!" + }, + { + "type": "comment", + "name": "extDocker", + "allowUsers": [ + "cleidigh", + "usernamehw", + "gjsjohnmurray", + "IllusionMH" + ], + "action": "close", + "addLabel": "*caused-by-extension", + "comment": "It looks like this is caused by the Docker extension. Please file it with the repository [here](https://github.com/microsoft/vscode-docker). Make sure to check their issue reporting template and provide them relevant information such as the extension version you're using. See also our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines for more information.\n\nHappy Coding!" } ] diff --git a/.github/workflows/commands.yml b/.github/workflows/commands.yml index 2c83f2de595..96f761b5fed 100644 --- a/.github/workflows/commands.yml +++ b/.github/workflows/commands.yml @@ -13,7 +13,7 @@ jobs: uses: actions/checkout@v2 with: repository: 'JacksonKearl/vscode-triage-github-actions' - ref: v3 + ref: v6 - name: Run Commands uses: ./commands with: diff --git a/.github/workflows/copycat.yml b/.github/workflows/copycat.yml index f92272065a9..ec89bb9b772 100644 --- a/.github/workflows/copycat.yml +++ b/.github/workflows/copycat.yml @@ -11,7 +11,7 @@ jobs: uses: actions/checkout@v2 with: repository: 'JacksonKearl/vscode-triage-github-actions' - ref: v3 + ref: v6 - name: Run CopyCat (JacksonKearl/testissues) uses: ./copycat with: diff --git a/.github/workflows/needs-version-info.yml b/.github/workflows/needs-version-info.yml index b457f65e98d..812507ae748 100644 --- a/.github/workflows/needs-version-info.yml +++ b/.github/workflows/needs-version-info.yml @@ -1,7 +1,7 @@ name: Needs Version Info on: issues: - types: [opened] + types: [opened, edited] jobs: main: @@ -11,10 +11,13 @@ jobs: uses: actions/checkout@v2 with: repository: 'JacksonKearl/vscode-triage-github-actions' - ref: v3 - # - name: Run Needs Version Info - # uses: ./needs-more-info - # with: - # token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} - # matcher: '\b(\d\.\d{2,3}\.\d|insiders?|1\.\d\d\d?)\b' - # label: ~needs version info + ref: v6 + - name: Run Needs Version Info + uses: ./needs-more-info + with: + token: ${{secrets.VSCODE_ISSUE_TRIAGE_BOT_PAT}} + matcher: '\b(\d\.\d{2,3}\.\d|insiders?|1\.\d\d\d?)\b' + tags: NEEDS_VERSION_INFO_IGNORE + bots: vscodebot|vscode-triage-bot + comment: "Thanks for creating this issue! We detected it's missing some basic information, such as your VS Code and operating system versions, or in some other way doesn't follow our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines. Please take the time to review these guidelines and update the issue.\n\nThis comment will go away once sufficient information is included in your issue.\n\nHappy Coding!" + label: needs more info diff --git a/extensions/git/package.json b/extensions/git/package.json index e299d60c118..7077d7e128c 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -1821,7 +1821,7 @@ "@types/byline": "4.2.31", "@types/file-type": "^5.2.1", "@types/mocha": "2.2.43", - "@types/node": "^12.11.7", + "@types/node": "^12.12.31", "@types/which": "^1.0.28", "mocha": "^3.2.0", "mocha-junit-reporter": "^1.23.3", diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 6f40f62e4a2..851036b15f4 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { promises as fs, exists } from 'fs'; +import { promises as fs, exists, realpath } from 'fs'; import * as path from 'path'; import * as os from 'os'; import * as cp from 'child_process'; @@ -18,7 +18,6 @@ import { detectEncoding } from './encoding'; import { Ref, RefType, Branch, Remote, GitErrorCodes, LogOptions, Change, Status, CommitOptions } from './api/git'; import * as byline from 'byline'; import { StringDecoder } from 'string_decoder'; -import { promisify } from 'util'; // https://github.com/microsoft/vscode/issues/65693 const MAX_CLI_LENGTH = 30000; @@ -436,10 +435,13 @@ export class Git { const [, letter] = match; try { - const result = await promisify(cp.exec)(`wmic logicaldisk where 'drivetype=4 and deviceid="${letter}:"' get deviceid,providername`); - match = /([A-Z]):\s+(.*?)\s*$/m.exec(result?.stdout.toString() ?? ''); - if (match !== null) { - const [, , networkPath] = match; + const networkPath = await new Promise(resolve => + realpath.native(`${letter}:`, { encoding: 'utf8' }, (err, resolvedPath) => + // eslint-disable-next-line eqeqeq + resolve(err != null ? undefined : resolvedPath), + ), + ); + if (networkPath !== undefined) { return path.normalize( repoUri.fsPath.replace(networkPath, `${letter.toLowerCase()}:`), ); diff --git a/extensions/git/yarn.lock b/extensions/git/yarn.lock index ac135e43a80..17866c54593 100644 --- a/extensions/git/yarn.lock +++ b/extensions/git/yarn.lock @@ -26,10 +26,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb" integrity sha512-El3+WJk2D/ppWNd2X05aiP5l2k4EwF7KwheknQZls+I26eSICoWRhRIJ56jGgw2dqNGQ5LtNajmBU2ajS28EvQ== -"@types/node@^12.11.7": - version "12.11.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.7.tgz#57682a9771a3f7b09c2497f28129a0462966524a" - integrity sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA== +"@types/node@^12.12.31": + version "12.12.31" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.31.tgz#d6b4f9645fee17f11319b508fb1001797425da51" + integrity sha512-T+wnJno8uh27G9c+1T+a1/WYCHzLeDqtsGJkoEdSp2X8RTh3oOCZQcUnjAx90CS8cmmADX51O0FI/tu9s0yssg== "@types/which@^1.0.28": version "1.0.28" diff --git a/extensions/github-authentication/package.json b/extensions/github-authentication/package.json index 254516ee527..bf2d01cbe3f 100644 --- a/extensions/github-authentication/package.json +++ b/extensions/github-authentication/package.json @@ -22,7 +22,8 @@ "postinstall": "node build/postinstall.js" }, "dependencies": { - "uuid": "^3.3.3" + "uuid": "^3.3.3", + "vscode-nls": "^4.1.2" }, "devDependencies": { "@types/keytar": "^4.4.2", diff --git a/extensions/github-authentication/src/common/keychain.ts b/extensions/github-authentication/src/common/keychain.ts index c687febb442..9a3c0c662d2 100644 --- a/extensions/github-authentication/src/common/keychain.ts +++ b/extensions/github-authentication/src/common/keychain.ts @@ -6,8 +6,11 @@ // keytar depends on a native module shipped in vscode, so this is // how we load it import * as keytarType from 'keytar'; -import { env } from 'vscode'; +import * as vscode from 'vscode'; import Logger from './logger'; +import * as nls from 'vscode-nls'; + +const localize = nls.loadMessageBundle(); function getKeytar(): Keytar | undefined { try { @@ -25,7 +28,7 @@ export type Keytar = { deletePassword: typeof keytarType['deletePassword']; }; -const SERVICE_ID = `${env.uriScheme}-github.login`; +const SERVICE_ID = `${vscode.env.uriScheme}-github.login`; const ACCOUNT_ID = 'account'; export class Keychain { @@ -46,6 +49,11 @@ export class Keychain { } catch (e) { // Ignore Logger.error(`Setting token failed: ${e}`); + const troubleshooting = localize('troubleshooting', "Troubleshooting Guide"); + const result = await vscode.window.showErrorMessage(localize('keychainWriteError', "Writing login information to the keychain failed with error '{0}'.", e.message), troubleshooting); + if (result === troubleshooting) { + vscode.env.openExternal(vscode.Uri.parse('https://code.visualstudio.com/docs/editor/settings-sync#_troubleshooting-keychain-issues')); + } } } diff --git a/extensions/github-authentication/yarn.lock b/extensions/github-authentication/yarn.lock index dcab74a1fea..c1f0b96f5b5 100644 --- a/extensions/github-authentication/yarn.lock +++ b/extensions/github-authentication/yarn.lock @@ -436,6 +436,11 @@ uuid@^3.3.3: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +vscode-nls@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167" + integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw== + which-pm-runs@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" diff --git a/extensions/vscode-account/src/keychain.ts b/extensions/vscode-account/src/keychain.ts index 465a160fef7..a52de4ff64c 100644 --- a/extensions/vscode-account/src/keychain.ts +++ b/extensions/vscode-account/src/keychain.ts @@ -6,8 +6,11 @@ // keytar depends on a native module shipped in vscode, so this is // how we load it import * as keytarType from 'keytar'; -import { env } from 'vscode'; +import * as vscode from 'vscode'; import Logger from './logger'; +import * as nls from 'vscode-nls'; + +const localize = nls.loadMessageBundle(); function getKeytar(): Keytar | undefined { try { @@ -25,7 +28,7 @@ export type Keytar = { deletePassword: typeof keytarType['deletePassword']; }; -const SERVICE_ID = `${env.uriScheme}-vscode.login`; +const SERVICE_ID = `${vscode.env.uriScheme}-vscode.login`; const ACCOUNT_ID = 'account'; export class Keychain { @@ -46,6 +49,11 @@ export class Keychain { } catch (e) { // Ignore Logger.error(`Setting token failed: ${e}`); + const troubleshooting = localize('troubleshooting', "Troubleshooting Guide"); + const result = await vscode.window.showErrorMessage(localize('keychainWriteError', "Writing login information to the keychain failed with error '{0}'.", e.message), troubleshooting); + if (result === troubleshooting) { + vscode.env.openExternal(vscode.Uri.parse('https://code.visualstudio.com/docs/editor/settings-sync#_troubleshooting-keychain-issues')); + } } } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css index fa4cf90414d..8175175caea 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?3d9ee7d873425ff0bc441f48a1de0c54") format("truetype"); + src: url("./codicon.ttf?70edf2c63384951357ed8517386759dd") format("truetype"); } .codicon[class*='codicon-'] { diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf index a3c15e7e4b8..7f910daafb2 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/menu/menubar.ts b/src/vs/base/browser/ui/menu/menubar.ts index fa92216ab12..56770df25b3 100644 --- a/src/vs/base/browser/ui/menu/menubar.ts +++ b/src/vs/base/browser/ui/menu/menubar.ts @@ -21,6 +21,7 @@ import { asArray } from 'vs/base/common/arrays'; import { ScanCodeUtils, ScanCode } from 'vs/base/common/scanCode'; import { isMacintosh } from 'vs/base/common/platform'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; +import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; const $ = DOM.$; @@ -90,7 +91,7 @@ export class MenuBar extends Disposable { private menuStyle: IMenuStyles | undefined; private overflowLayoutScheduled: IDisposable | undefined = undefined; - constructor(private container: HTMLElement, private options: IMenuBarOptions = {}) { + constructor(private container: HTMLElement, private options: IMenuBarOptions = {}, private compactMenuActions?: IAction[]) { super(); this.container.setAttribute('role', 'menubar'); @@ -490,6 +491,11 @@ export class MenuBar extends Disposable { this.container.insertBefore(this.overflowMenu.buttonElement, this.menuCache[this.numMenusShown].buttonElement); this.overflowMenu.buttonElement.style.visibility = 'visible'; } + + if (this.compactMenuActions && this.compactMenuActions.length) { + this.overflowMenu.actions.push(new Separator()); + this.overflowMenu.actions.push(...this.compactMenuActions); + } } else { DOM.removeNode(this.overflowMenu.buttonElement); this.container.appendChild(this.overflowMenu.buttonElement); diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 44080044e77..e767a6f3d1d 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -417,9 +417,9 @@ export interface CompletionItemLabel { name: string; /** - * The signature without the return type. Render after `name`. + * The parameters without the return type. Render after `name`. */ - signature?: string; + parameters?: string; /** * The fully qualified name, like package name or file path. Rendered after `signature`. diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 541d5bf3bb8..6973a14bff2 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -63,7 +63,7 @@ interface ISuggestionTemplateData { colorspan: HTMLElement; iconLabel: IconLabel; iconContainer: HTMLElement; - signatureLabel: HTMLElement; + parametersLabel: HTMLElement; qualifierLabel: HTMLElement; /** * Showing either `CompletionItem#details` or `CompletionItemLabel#type` @@ -151,7 +151,7 @@ class ItemRenderer implements IListRenderer { + public async save(options?: ISaveOptions): Promise { + return !!await this.saveCustomEditor(options); + } + + public async saveCustomEditor(_options?: ISaveOptions): Promise { if (!this._editable) { - return false; + return undefined; } + // TODO: handle save untitled case await createCancelablePromise(token => this._proxy.$onSave(this._editorResource, this.viewType, token)); this.change(() => { this._savePoint = this._currentEditIndex; }); - return true; + return this._editorResource; } - public async saveAs(resource: URI, targetResource: URI, _options?: ISaveOptions): Promise { + public async saveCustomEditorAs(resource: URI, targetResource: URI, _options?: ISaveOptions): Promise { if (this._editable) { await this._proxy.$onSaveAs(this._editorResource, this.viewType, targetResource); this.change(() => { diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index ce78f773f7e..cc9bc2d5270 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -4,17 +4,38 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import { ExtHostNotebookShape, IMainContext, MainThreadNotebookShape, MainContext, NotebookCellOutputsSplice, CellKind, CellOutputKind } from 'vs/workbench/api/common/extHost.protocol'; -import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { Disposable as VSCodeDisposable } from './extHostTypes'; -import { URI, UriComponents } from 'vs/base/common/uri'; -import { DisposableStore, Disposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { readonly } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; -import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; -import { INotebookDisplayOrder, ITransformedDisplayOutputDto, IOrderedMimeType, IStreamOutput, IErrorOutput, mimeTypeSupportedByCore, sortMimeTypes, diff, CellUri, ICellEditOperation, INotebookEditData, CellEditType, NotebookCellsChangedEvent, ICellInsertEdit, NotebookCellsSplice2 } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ISplice } from 'vs/base/common/sequence'; +import { URI, UriComponents } from 'vs/base/common/uri'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { CellKind, CellOutputKind, ExtHostNotebookShape, IMainContext, MainContext, MainThreadNotebookShape, NotebookCellOutputsSplice, NotebookCellsSplice } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; +import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; +import { CellUri, diff, IErrorOutput, INotebookDisplayOrder, IOrderedMimeType, IOutput, IStreamOutput, ITransformedDisplayOutputDto, mimeTypeSupportedByCore, sortMimeTypes, NotebookCellsChangedEvent, NotebookCellsSplice2, ICellEditOperation, INotebookEditData, CellEditType, ICellInsertEdit } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { Disposable as VSCodeDisposable } from './extHostTypes'; + +interface IObservable { + proxy: T; + onDidChange: Event; +} + +function getObservable(obj: T): IObservable { + const onDidChange = new Emitter(); + const proxy = new Proxy(obj, { + set(target: T, p: PropertyKey, value: any, _receiver: any): boolean { + target[p as keyof T] = value; + onDidChange.fire(); + return true; + } + }); + + return { + proxy, + onDidChange: onDidChange.event + }; +} const notebookDocumentMetadataDefaults: vscode.NotebookDocumentMetadata = { editable: true, @@ -22,7 +43,7 @@ const notebookDocumentMetadataDefaults: vscode.NotebookDocumentMetadata = { cellRunnable: true }; -export class ExtHostCell implements vscode.NotebookCell { +export class ExtHostCell extends Disposable implements vscode.NotebookCell { private originalSource: string[]; private _outputs: any[]; @@ -31,6 +52,9 @@ export class ExtHostCell implements vscode.NotebookCell { private _textDocument: vscode.TextDocument | undefined; private _initalVersion: number = -1; private _outputMapping = new Set(); + private _metadata: vscode.NotebookCellMetadata; + + private _metadataChangeListener: IDisposable; get source() { if (this._textDocument && this._initalVersion !== this._textDocument?.version) { @@ -49,11 +73,18 @@ export class ExtHostCell implements vscode.NotebookCell { public cellKind: CellKind, public language: string, outputs: any[], - private _metadata: vscode.NotebookCellMetadata | undefined, + _metadata: vscode.NotebookCellMetadata | undefined, private _proxy: MainThreadNotebookShape ) { + super(); this.originalSource = this._content.split(/\r|\n|\r\n/g); this._outputs = outputs; + + const observableMetadata = getObservable(_metadata || {} as any); + this._metadata = observableMetadata.proxy; + this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => { + this.updateMetadata(); + })); } get outputs() { @@ -84,13 +115,18 @@ export class ExtHostCell implements vscode.NotebookCell { } set metadata(newMetadata: vscode.NotebookCellMetadata | undefined) { - const newMetadataWithDefaults: vscode.NotebookCellMetadata | undefined = newMetadata ? { - editable: newMetadata.editable, - runnable: newMetadata.runnable - } : undefined; + this._metadataChangeListener.dispose(); + const observableMetadata = getObservable(newMetadata || {} as any); // TODO defaults + this._metadata = observableMetadata.proxy; + this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => { + this.updateMetadata(); + })); - this._metadata = newMetadataWithDefaults; - this._proxy.$updateNotebookCellMetadata(this.viewType, this.documentUri, this.handle, newMetadataWithDefaults); + this.updateMetadata(); + } + + private updateMetadata(): Promise { + return this._proxy.$updateNotebookCellMetadata(this.viewType, this.documentUri, this.handle, this._metadata); } getContent(): string { diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 7ce3ecf2590..bd37ed95bd0 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -1362,7 +1362,7 @@ export enum CompletionItemTag { export interface CompletionItemLabel { name: string; - signature?: string; + parameters?: string; qualifier?: string; type?: string; } diff --git a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts index 0575e3ef666..d5866d1a844 100644 --- a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -509,6 +509,16 @@ export class CustomMenubarControl extends MenubarControl { } if (firstTime) { + const webActions = []; + const webMenu = this.menuService.createMenu(MenuId.WebMenuActions, this.contextKeyService); + for (const groups of webMenu.getActions()) { + const [, actions] = groups; + for (const action of actions) { + action.label = mnemonicMenuLabel(this.calculateActionLabel(action)); + webActions.push(action); + } + } + this.menubar = this._register(new MenuBar( this.container, { enableMnemonics: this.currentEnableMenuBarMnemonics, @@ -516,7 +526,7 @@ export class CustomMenubarControl extends MenubarControl { visibility: this.currentMenubarVisibility, getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id), compactMode: this.currentCompactMenuMode - })); + }, webActions.length > 0 ? webActions : undefined)); this.accessibilityService.alwaysUnderlineAccessKeys().then(val => { this.alwaysOnMnemonics = val; diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index ac179e3e6a0..4ea2241fd0f 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -1022,7 +1022,11 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { if (this.dimension) { const totalWeight = this.viewsModel.visibleViewDescriptors.reduce((totalWeight, { weight }) => totalWeight + (weight || 20), 0); for (const viewDescriptor of this.viewsModel.visibleViewDescriptors) { - sizes.set(viewDescriptor.id, this.dimension.height * (viewDescriptor.weight || 20) / totalWeight); + if (this.orientation === Orientation.VERTICAL) { + sizes.set(viewDescriptor.id, this.dimension.height * (viewDescriptor.weight || 20) / totalWeight); + } else { + sizes.set(viewDescriptor.id, this.dimension.width * (viewDescriptor.weight || 20) / totalWeight); + } } } return sizes; diff --git a/src/vs/workbench/browser/parts/views/views.ts b/src/vs/workbench/browser/parts/views/views.ts index 53b16946f97..0c7981859e3 100644 --- a/src/vs/workbench/browser/parts/views/views.ts +++ b/src/vs/workbench/browser/parts/views/views.ts @@ -7,7 +7,7 @@ import 'vs/css!./media/views'; import { Disposable, IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IViewDescriptorService, ViewContainer, IViewDescriptor, IViewContainersRegistry, Extensions as ViewExtensions, IView, ViewContainerLocation, IViewsService, IViewPaneContainer, getVisbileViewContextKey } from 'vs/workbench/common/views'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { Event, Emitter } from 'vs/base/common/event'; @@ -34,6 +34,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { URI } from 'vs/base/common/uri'; import { IProgressIndicator } from 'vs/platform/progress/common/progress'; +import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys'; export interface IViewState { visibleGlobal: boolean | undefined; @@ -101,30 +102,46 @@ export class ContributableViewsModel extends Disposable { } setVisible(id: string, visible: boolean, size?: number): void { - const { visibleIndex, viewDescriptor, state } = this.find(id); + this.doSetVisible([{ id, visible, size }]); + } - if (!viewDescriptor.canToggleVisibility) { - throw new Error(`Can't toggle this view's visibility`); + protected doSetVisible(viewDescriptors: { id: string, visible: boolean, size?: number }[]): void { + const added: IAddedViewDescriptorRef[] = []; + const removed: IViewDescriptorRef[] = []; + + for (const { id, visible, size } of viewDescriptors) { + const { visibleIndex, viewDescriptor, state } = this.find(id); + + if (!viewDescriptor.canToggleVisibility) { + throw new Error(`Can't toggle this view's visibility`); + } + + if (this.isViewDescriptorVisible(viewDescriptor) === visible) { + return; + } + + if (viewDescriptor.workspace) { + state.visibleWorkspace = visible; + } else { + state.visibleGlobal = visible; + } + + if (typeof size === 'number') { + state.size = size; + } + + if (visible) { + added.push({ index: visibleIndex, viewDescriptor, size: state.size, collapsed: !!state.collapsed }); + } else { + removed.push({ index: visibleIndex, viewDescriptor }); + } } - if (this.isViewDescriptorVisible(viewDescriptor) === visible) { - return; + if (added.length) { + this._onDidAdd.fire(added); } - - if (viewDescriptor.workspace) { - state.visibleWorkspace = visible; - } else { - state.visibleGlobal = visible; - } - - if (typeof size === 'number') { - state.size = size; - } - - if (visible) { - this._onDidAdd.fire([{ index: visibleIndex, viewDescriptor, size: state.size, collapsed: !!state.collapsed }]); - } else { - this._onDidRemove.fire([{ index: visibleIndex, viewDescriptor }]); + if (removed.length) { + this._onDidRemove.fire(removed); } } @@ -318,6 +335,7 @@ export class PersistentContributableViewsModel extends ContributableViewsModel { viewletStateStorageId: string, @IViewDescriptorService viewDescriptorService: IViewDescriptorService, @IStorageService storageService: IStorageService, + @IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService ) { const globalViewsStateStorageId = `${viewletStateStorageId}.hidden`; const viewStates = PersistentContributableViewsModel.loadViewsStates(viewletStateStorageId, globalViewsStateStorageId, storageService); @@ -334,6 +352,30 @@ export class PersistentContributableViewsModel extends ContributableViewsModel { Event.map(this.onDidMove, ({ from, to }) => [from, to]), Event.map(this.onDidChangeViewState, viewDescriptorRef => [viewDescriptorRef])) (viewDescriptorRefs => this.saveViewsStates())); + + storageKeysSyncRegistryService.registerStorageKey({ key: this.globalViewsStateStorageId, version: 1 }); + this._globalViewsStatesValue = this.getStoredGlobalViewsStatesValue(); + this._register(this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e))); + } + + private onDidStorageChange(e: IWorkspaceStorageChangeEvent): void { + if (e.key === this.globalViewsStateStorageId && e.scope === StorageScope.GLOBAL + && this.globalViewsStatesValue !== this.getStoredGlobalViewsStatesValue() /* This checks if current window changed the value or not */) { + this._globalViewsStatesValue = undefined; + const storedViewsVisibilityStates = PersistentContributableViewsModel.loadGlobalViewsState(this.globalViewsStateStorageId, this.storageService, StorageScope.GLOBAL); + const changedViews: { id: string, visible: boolean }[] = []; + for (const [id, state] of storedViewsVisibilityStates) { + const viewState = this.viewStates.get(id); + if (viewState) { + if (viewState.visibleGlobal !== !state.isHidden) { + changedViews.push({ id, visible: !state.isHidden }); + } + } + } + if (changedViews.length) { + this.doSetVisible(changedViews); + } + } } private saveViewsStates(): void { @@ -372,9 +414,32 @@ export class PersistentContributableViewsModel extends ContributableViewsModel { order: !viewDescriptor.workspace && viewState ? viewState.order : undefined }); } - this.storageService.store(this.globalViewsStateStorageId, JSON.stringify(values(storedViewsVisibilityStates)), StorageScope.GLOBAL); + this.globalViewsStatesValue = JSON.stringify(values(storedViewsVisibilityStates)); } + private _globalViewsStatesValue: string | undefined; + private get globalViewsStatesValue(): string { + if (!this._globalViewsStatesValue) { + this._globalViewsStatesValue = this.getStoredGlobalViewsStatesValue(); + } + + return this._globalViewsStatesValue; + } + + private set globalViewsStatesValue(globalViewsStatesValue: string) { + if (this.globalViewsStatesValue !== globalViewsStatesValue) { + this._globalViewsStatesValue = globalViewsStatesValue; + this.setStoredGlobalViewsStatesValue(globalViewsStatesValue); + } + } + + private getStoredGlobalViewsStatesValue(): string { + return this.storageService.get(this.globalViewsStateStorageId, StorageScope.GLOBAL, '[]'); + } + + private setStoredGlobalViewsStatesValue(value: string): void { + this.storageService.store(this.globalViewsStateStorageId, value, StorageScope.GLOBAL); + } private static loadViewsStates(workspaceViewsStateStorageId: string, globalViewsStateStorageId: string, storageService: IStorageService): Map { const viewStates = new Map(); diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts index c978c9b9332..bca1f295ea2 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditorInput.ts @@ -6,6 +6,7 @@ import { memoize } from 'vs/base/common/decorators'; import { Lazy } from 'vs/base/common/lazy'; import { IReference } from 'vs/base/common/lifecycle'; +import { Schemas } from 'vs/base/common/network'; import { basename } from 'vs/base/common/path'; import { isEqual } from 'vs/base/common/resources'; import { assertIsDefined } from 'vs/base/common/types'; @@ -99,6 +100,10 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { return this._modelRef ? this._modelRef.object.isReadonly() : false; } + public isUntitled(): boolean { + return this.resource.scheme === Schemas.untitled; + } + public isDirty(): boolean { if (!this._modelRef) { return false; @@ -120,8 +125,16 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { public async save(groupId: GroupIdentifier, options?: ISaveOptions): Promise { const modelRef = assertIsDefined(this._modelRef); - const result = await modelRef.object.save(options); - return result ? this : undefined; + const target = await modelRef.object.saveCustomEditor(options); + if (!target) { + return undefined; // save cancelled + } + + if (!isEqual(target, this.resource)) { + return this.customEditorService.createInput(target, this.viewType, groupId); + } + + return this; } public async saveAs(groupId: GroupIdentifier, options?: ISaveOptions): Promise { @@ -133,7 +146,7 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { return undefined; // save cancelled } - if (!await modelRef.object.saveAs(this._editorResource, target, options)) { + if (!await modelRef.object.saveCustomEditorAs(this._editorResource, target, options)) { return undefined; } @@ -160,29 +173,29 @@ export class CustomEditorInput extends LazilyResolvedWebviewEditorInput { } move(group: GroupIdentifier, newResource: URI): { editor: IEditorInput } | undefined { + // See if we can keep using the same custom editor provider const editorInfo = this.customEditorService.getCustomEditor(this.viewType); if (editorInfo?.matches(newResource)) { - // We can keep using the same custom editor provider - - if (!this._moveHandler) { - return { - editor: this.customEditorService.createInput(newResource, this.viewType, group), - }; - } - - this._moveHandler(newResource); - const newEditor = this.instantiationService.createInstance(CustomEditorInput, - newResource, - this.viewType, - this.id, - new Lazy(() => undefined!)); // this webview is replaced in the transfer call - this.transfer(newEditor); - newEditor.updateGroup(group); - return { editor: newEditor }; - } else { - // const possible = this.customEditorService.getContributedCustomEditors(newResource); - return { editor: this.editorService.createEditorInput({ resource: newResource, forceFile: true }) }; + return { editor: this.doMove(group, newResource) }; } + + return { editor: this.editorService.createEditorInput({ resource: newResource, forceFile: true }) }; + } + + private doMove(group: GroupIdentifier, newResource: URI): IEditorInput { + if (!this._moveHandler) { + return this.customEditorService.createInput(newResource, this.viewType, group); + } + + this._moveHandler(newResource); + const newEditor = this.instantiationService.createInstance(CustomEditorInput, + newResource, + this.viewType, + this.id, + new Lazy(() => undefined!)); // this webview is replaced in the transfer call + this.transfer(newEditor); + newEditor.updateGroup(group); + return newEditor; } public undo(): void { diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts index 5a7671b374c..bac827f57cd 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts @@ -327,8 +327,8 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ private async handleMovedFileInOpenedFileEditors(_oldResource: URI, newResource: URI): Promise { // See if the new resource can be opened in a custom editor - const possibleEditors = this.getAllCustomEditors(newResource).allEditors; - if (!possibleEditors.length) { + const possibleEditors = this.getAllCustomEditors(newResource); + if (!possibleEditors.allEditors.length) { return; } @@ -354,19 +354,25 @@ export class CustomEditorService extends Disposable implements ICustomEditorServ return; } - // If there is, show a single prompt for all editors to see if the user wants to re-open them - // - // TODO: instead of prompting eagerly, it'd likly be better to replace all the editors with - // ones that would prompt when they first become visible - await new Promise(resolve => setTimeout(resolve, 50)); - const pickedViewType = await this.showOpenWithPrompt(newResource); - if (!pickedViewType) { + let viewType: string | undefined; + if (possibleEditors.defaultEditor) { + viewType = possibleEditors.defaultEditor.id; + } else { + // If there is, show a single prompt for all editors to see if the user wants to re-open them + // + // TODO: instead of prompting eagerly, it'd likly be better to replace all the editors with + // ones that would prompt when they first become visible + await new Promise(resolve => setTimeout(resolve, 50)); + viewType = await this.showOpenWithPrompt(newResource); + } + + if (!viewType) { return; } for (const [group, entries] of editorsToReplace) { this.editorService.replaceEditors(entries.map(editor => { - const replacement = this.createInput(newResource, pickedViewType, group); + const replacement = this.createInput(newResource, viewType!, group); return { editor, replacement, diff --git a/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts b/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts index 7c7a65b2d63..b8068cd840a 100644 --- a/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts +++ b/src/vs/workbench/contrib/customEditor/browser/extensionPoint.ts @@ -26,7 +26,15 @@ interface IWebviewEditorsExtensionPoint { const webviewEditorsContribution: IJSONSchema = { description: nls.localize('contributes.customEditors', 'Contributed custom editors.'), type: 'array', - defaultSnippets: [{ body: [{ viewType: '', displayName: '' }] }], + defaultSnippets: [{ + body: [{ + [WebviewEditorContribution.viewType]: '$1', + [WebviewEditorContribution.displayName]: '$2', + [WebviewEditorContribution.selector]: [{ + filenamePattern: '$3' + }], + }] + }], items: { type: 'object', required: [ @@ -48,6 +56,11 @@ const webviewEditorsContribution: IJSONSchema = { description: nls.localize('contributes.selector', 'Set of globs that the custom editor is enabled for.'), items: { type: 'object', + defaultSnippets: [{ + body: { + filenamePattern: '$1', + } + }], properties: { filenamePattern: { type: 'string', @@ -64,7 +77,7 @@ const webviewEditorsContribution: IJSONSchema = { CustomEditorPriority.option, CustomEditorPriority.builtin, ], - enumDescriptions: [ + markdownEnumDescriptions: [ nls.localize('contributes.priority.default', 'Editor is automatically used for a resource if no other default custom editors are registered for it.'), nls.localize('contributes.priority.option', 'Editor is not automatically used but can be selected by a user.'), nls.localize('contributes.priority.builtin', 'Editor automatically used if no other `default` or `builtin` editors are registered for the resource.'), diff --git a/src/vs/workbench/contrib/customEditor/common/customEditor.ts b/src/vs/workbench/contrib/customEditor/common/customEditor.ts index b37462d357c..38f8fa7a896 100644 --- a/src/vs/workbench/contrib/customEditor/common/customEditor.ts +++ b/src/vs/workbench/contrib/customEditor/common/customEditor.ts @@ -57,8 +57,8 @@ export interface ICustomEditorModel extends IDisposable { revert(options?: IRevertOptions): Promise; - save(options?: ISaveOptions): Promise; - saveAs(resource: URI, targetResource: URI, currentOptions?: ISaveOptions): Promise; + saveCustomEditor(options?: ISaveOptions): Promise; + saveCustomEditorAs(resource: URI, targetResource: URI, currentOptions?: ISaveOptions): Promise; } export const enum CustomEditorPriority { diff --git a/src/vs/workbench/contrib/customEditor/common/customTextEditorModel.ts b/src/vs/workbench/contrib/customEditor/common/customTextEditorModel.ts index a041fa249df..76e5d082964 100644 --- a/src/vs/workbench/contrib/customEditor/common/customTextEditorModel.ts +++ b/src/vs/workbench/contrib/customEditor/common/customTextEditorModel.ts @@ -68,11 +68,11 @@ export class CustomTextEditorModel extends Disposable implements ICustomEditorMo return this.textFileService.revert(this.resource, options); } - public async save(options?: ISaveOptions): Promise { - return !!await this.textFileService.save(this.resource, options); + public saveCustomEditor(options?: ISaveOptions): Promise { + return this.textFileService.save(this.resource, options); } - public async saveAs(resource: URI, targetResource: URI, options?: ISaveOptions): Promise { + public async saveCustomEditorAs(resource: URI, targetResource: URI, options?: ISaveOptions): Promise { return !!await this.textFileService.saveAs(resource, targetResource, options); } } diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 94b4de17e86..7b195dab638 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -149,10 +149,12 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { if (item && item.label) { let insertTextRules: CompletionItemInsertTextRule | undefined = undefined; let insertText = item.text || item.label; - if (typeof item.selectionStart === 'number' && typeof item.selectionLength === 'number') { + if (typeof item.selectionStart === 'number') { // If a debug completion item sets a selection we need to use snippets to make sure the selection is selected #90974 insertTextRules = CompletionItemInsertTextRule.InsertAsSnippet; - insertText = insertText.substr(0, item.selectionStart) + '${1:' + insertText.substr(item.selectionStart, item.selectionLength) + '}$0' + insertText.substr(item.selectionStart + item.selectionLength); + const selectionLength = typeof item.selectionLength === 'number' ? item.selectionLength : 0; + const placeholder = selectionLength > 0 ? '${1:' + insertText.substr(item.selectionStart, selectionLength) + '}$0' : '$0'; + insertText = insertText.substr(0, item.selectionStart) + placeholder + insertText.substr(item.selectionStart + selectionLength); } suggestions.push({ diff --git a/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts b/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts index a03705bc2d0..72196fa380c 100644 --- a/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts +++ b/src/vs/workbench/contrib/localizations/browser/localizations.contribution.ts @@ -26,11 +26,14 @@ import { minimumTranslatedStrings } from 'vs/workbench/contrib/localizations/bro import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; +import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys'; // Register action to configure locale and related settings const registry = Registry.as(Extensions.WorkbenchActions); registry.registerWorkbenchAction(SyncActionDescriptor.create(ConfigureLocaleAction, ConfigureLocaleAction.ID, ConfigureLocaleAction.LABEL), 'Configure Display Language'); +const LANGUAGEPACK_SUGGESTION_IGNORE_STORAGE_KEY = 'extensionsAssistant/languagePackSuggestionIgnore'; + export class LocalizationWorkbenchContribution extends Disposable implements IWorkbenchContribution { constructor( @INotificationService private readonly notificationService: INotificationService, @@ -41,9 +44,12 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IExtensionGalleryService private readonly galleryService: IExtensionGalleryService, @IViewletService private readonly viewletService: IViewletService, - @ITelemetryService private readonly telemetryService: ITelemetryService + @ITelemetryService private readonly telemetryService: ITelemetryService, + @IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService ) { super(); + + storageKeysSyncRegistryService.registerStorageKey({ key: LANGUAGEPACK_SUGGESTION_IGNORE_STORAGE_KEY, version: 1 }); this.checkAndInstall(); this._register(this.extensionManagementService.onDidInstallExtension(e => this.onDidInstallExtension(e))); } @@ -76,7 +82,7 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo private checkAndInstall(): void { const language = platform.language; const locale = platform.locale; - const languagePackSuggestionIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/languagePackSuggestionIgnore', StorageScope.GLOBAL, '[]')); + const languagePackSuggestionIgnoreList = JSON.parse(this.storageService.get(LANGUAGEPACK_SUGGESTION_IGNORE_STORAGE_KEY, StorageScope.GLOBAL, '[]')); if (!this.galleryService.isEnabled()) { return; @@ -167,7 +173,7 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo run: () => { languagePackSuggestionIgnoreList.push(language); this.storageService.store( - 'extensionsAssistant/languagePackSuggestionIgnore', + LANGUAGEPACK_SUGGESTION_IGNORE_STORAGE_KEY, JSON.stringify(languagePackSuggestionIgnoreList), StorageScope.GLOBAL ); diff --git a/src/vs/workbench/contrib/notebook/browser/constants.ts b/src/vs/workbench/contrib/notebook/browser/constants.ts index 47f1360e76c..3fe4d2a5005 100644 --- a/src/vs/workbench/contrib/notebook/browser/constants.ts +++ b/src/vs/workbench/contrib/notebook/browser/constants.ts @@ -20,11 +20,11 @@ export const COPY_CELL_DOWN_COMMAND_ID = 'workbench.notebook.cell.copyDown'; export const EXECUTE_CELL_COMMAND_ID = 'workbench.notebook.cell.execute'; // Cell sizing related -export const CELL_MARGIN = 32; +export const CELL_MARGIN = 20; +export const CELL_RUN_GUTTER = 32; // TODO should be dynamic based on execution order width, and runnable enablement export const EDITOR_TOP_PADDING = 8; export const EDITOR_BOTTOM_PADDING = 8; export const EDITOR_TOOLBAR_HEIGHT = 22; -export const RUN_BUTTON_WIDTH = 20; // Cell context keys export const NOTEBOOK_CELL_TYPE_CONTEXT_KEY = 'notebookCellType'; // code, markdown diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts index 490334e53cc..a556413769c 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/notebookActions.ts @@ -16,6 +16,7 @@ import { CellRenderTemplate, CellEditState, ICellViewModel, INotebookEditor, KEY import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService'; import { CellKind, NOTEBOOK_EDITOR_CURSOR_BOUNDARY } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; const enum CellToolbarOrder { MoveCellUp, @@ -709,9 +710,9 @@ registerAction2(class extends Action2 { id: 'workbench.action.notebook.cursorDown', title: 'Notebook Cursor Move Down', keybinding: { - when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, ContextKeyExpr.has(InputFocusedContextKey), NOTEBOOK_EDITOR_CURSOR_BOUNDARY.notEqualsTo('top'), NOTEBOOK_EDITOR_CURSOR_BOUNDARY.notEqualsTo('none')), + when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, ContextKeyExpr.has(InputFocusedContextKey), EditorContextKeys.editorTextFocus, NOTEBOOK_EDITOR_CURSOR_BOUNDARY.notEqualsTo('top'), NOTEBOOK_EDITOR_CURSOR_BOUNDARY.notEqualsTo('none')), primary: KeyCode.DownArrow, - weight: KeybindingWeight.WorkbenchContrib + weight: KeybindingWeight.EditorContrib // smaller than Suggest Widget, etc } }); } @@ -748,9 +749,9 @@ registerAction2(class extends Action2 { id: 'workbench.action.notebook.cursorUp', title: 'Notebook Cursor Move Up', keybinding: { - when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, ContextKeyExpr.has(InputFocusedContextKey), NOTEBOOK_EDITOR_CURSOR_BOUNDARY.notEqualsTo('bottom'), NOTEBOOK_EDITOR_CURSOR_BOUNDARY.notEqualsTo('none')), + when: ContextKeyExpr.and(NOTEBOOK_EDITOR_FOCUSED, ContextKeyExpr.has(InputFocusedContextKey), EditorContextKeys.editorTextFocus, NOTEBOOK_EDITOR_CURSOR_BOUNDARY.notEqualsTo('bottom'), NOTEBOOK_EDITOR_CURSOR_BOUNDARY.notEqualsTo('none')), primary: KeyCode.UpArrow, - weight: KeybindingWeight.WorkbenchContrib + weight: KeybindingWeight.EditorContrib // smaller than Suggest Widget, etc }, }); } diff --git a/src/vs/workbench/contrib/notebook/browser/notebook.css b/src/vs/workbench/contrib/notebook/browser/notebook.css index 2ceb08ede12..4f3cc32c1ba 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebook.css +++ b/src/vs/workbench/contrib/notebook/browser/notebook.css @@ -30,7 +30,7 @@ position: relative; } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .cell { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell { display: flex; } @@ -87,16 +87,16 @@ } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row { overflow: visible !important; } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:focus-within { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:focus-within { z-index: 10; } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .menu { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .menu { position: absolute; left: 0; top: 28px; @@ -107,40 +107,65 @@ } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .menu.mouseover, -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:hover .menu { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .menu.mouseover, +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .menu { visibility: visible; } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list .monaco-list-row:hover { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover { outline: none !important; } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list .monaco-list-row.selected, -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list .monaco-list-row.focused { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.selected, +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused { outline: none !important; } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .menu.mouseover, -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .menu:hover { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .menu.mouseover, +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .menu:hover { cursor: pointer; } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > .monaco-toolbar { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row > .monaco-toolbar { visibility: hidden; margin-right: 24px; } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row .cell .run-button-container .monaco-toolbar { - margin-top: 8px; +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell .run-button-container { + position: relative; +} + +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell .run-button-container .monaco-toolbar { + margin-top: 5px; visibility: hidden; } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:hover .cell .run-button-container .monaco-toolbar, -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.focused .cell .run-button-container .monaco-toolbar { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell .run-button-container .monaco-toolbar .codicon-play { + margin-right: 8px; +} + +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .cell.runnable .run-button-container .monaco-toolbar, +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused .cell.runnable .run-button-container .monaco-toolbar { visibility: visible; } +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell .run-button-container .execution-count-label { + position: absolute; + top: 2px; + font-size: 12px; + visibility: visible; + white-space: pre; + width: 100%; + text-align: center; + padding-right: 2px; + box-sizing: border-box; +} + +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .cell .run-button-container .execution-count-label, +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused .cell .run-button-container .execution-count-label { + visibility: hidden; +} + .monaco-workbench .part.editor > .content .notebook-editor .cell .cell-editor-container { position: relative; } @@ -149,13 +174,13 @@ top: 0px; } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.focused .monaco-toolbar, -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:hover .monaco-toolbar { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused .monaco-toolbar, +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .monaco-toolbar { visibility: visible; } -.monaco-workbench .part.editor > .content .notebook-editor .monaco-tree.focused.no-focused-item:focus:before, -.monaco-workbench .part.editor > .content .notebook-editor .monaco-list:not(.element-focused):focus:before { + +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list:not(.element-focused):focus:before { outline: none !important; } @@ -167,7 +192,7 @@ width: 6px; border-left-width: 2px; border-left-style: solid; - left: 28px; + left: 20px; top: 22px; bottom: 8px; visibility: hidden; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index ddc254d4914..0561b30203a 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -250,6 +250,7 @@ export interface CellRenderTemplate { focusIndicator?: HTMLElement; runToolbar?: ToolBar; runButtonContainer?: HTMLElement; + executionOrderLabel?: HTMLElement; editingContainer?: HTMLElement; outputContainer?: HTMLElement; editor?: CodeEditorWidget; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts index 2ff040ac26d..ece54679c3e 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts @@ -40,7 +40,7 @@ import { NotebookViewModel, INotebookEditorViewState, IModelDecorationsChangeAcc import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; import { Range } from 'vs/editor/common/core/range'; -import { CELL_MARGIN, RUN_BUTTON_WIDTH } from 'vs/workbench/contrib/notebook/browser/constants'; +import { CELL_MARGIN, CELL_RUN_GUTTER } from 'vs/workbench/contrib/notebook/browser/constants'; import { Color, RGBA } from 'vs/base/common/color'; import { NotebookEventDispatcher, NotebookLayoutChangedEvent } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher'; @@ -791,8 +791,10 @@ registerThemingParticipant((theme, collector) => { } // Cell Margin - collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > div.cell { padding: 8px ${CELL_MARGIN}px 8px ${CELL_MARGIN}px; }`); - collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { margin: 8px ${CELL_MARGIN}px 8px ${CELL_MARGIN + RUN_BUTTON_WIDTH}px }`); + collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > div.cell { margin: 8px ${CELL_MARGIN}px 8px ${CELL_MARGIN}px; }`); + collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .output { margin: 8px ${CELL_MARGIN}px 8px ${CELL_MARGIN + CELL_RUN_GUTTER}px }`); - collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .cell-editor-container { width: calc(100% - ${RUN_BUTTON_WIDTH}px); }`); + collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .cell-editor-container { width: calc(100% - ${CELL_RUN_GUTTER}px); }`); + collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > div.cell.markdown { padding-left: ${CELL_RUN_GUTTER}px; }`); + collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell .run-button-container { width: ${CELL_RUN_GUTTER}px; }`); }); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 5de42eec35f..30457c3e612 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -15,7 +15,7 @@ import { IOutput } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IWebviewService, WebviewElement } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewResourceScheme } from 'vs/workbench/contrib/webview/common/resourceLoader'; import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel'; -import { CELL_MARGIN } from 'vs/workbench/contrib/notebook/browser/constants'; +import { CELL_MARGIN, CELL_RUN_GUTTER } from 'vs/workbench/contrib/notebook/browser/constants'; import { Emitter, Event } from 'vs/base/common/event'; import { IOpenerService } from 'vs/platform/opener/common/opener'; @@ -44,11 +44,13 @@ export interface ICreationRequestMessage { id: string; outputId: string; top: number; + left: number; } export interface IContentWidgetTopRequest { id: string; top: number; + left: number; } export interface IViewScrollTopRequestMessage { @@ -201,6 +203,7 @@ export class BackLayerWebView extends Disposable { let outputNode = document.createElement('div'); outputNode.style.position = 'absolute'; outputNode.style.top = event.data.top + 'px'; + outputNode.style.left = event.data.left + 'px'; outputNode.id = outputId; let content = event.data.content; @@ -342,7 +345,8 @@ export class BackLayerWebView extends Disposable { return { id: id, - top: outputOffset + top: outputOffset, + left: CELL_RUN_GUTTER }; }); @@ -366,7 +370,8 @@ export class BackLayerWebView extends Disposable { content: shadowContent, id: cell.id, outputId: outputId, - top: initialTop + top: initialTop, + left: CELL_RUN_GUTTER }; this.webview.sendMessage(message); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index f929aa939fb..64e4b09bd97 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -6,6 +6,7 @@ import { getZoomLevel } from 'vs/base/browser/browser'; import * as DOM from 'vs/base/browser/dom'; import { IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; +import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar'; import { IAction } from 'vs/base/common/actions'; import { DisposableStore } from 'vs/base/common/lifecycle'; @@ -16,15 +17,16 @@ import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; -import { MenuItemAction, IMenu } from 'vs/platform/actions/common/actions'; +import { IMenu, MenuItemAction } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_PADDING, NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, NOTEBOOK_CELL_TYPE_CONTEXT_KEY, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY } from 'vs/workbench/contrib/notebook/browser/constants'; -import { CellRenderTemplate, CellRunState, ICellViewModel, INotebookEditor, CellEditState } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; +import { EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_PADDING, NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY, NOTEBOOK_CELL_TYPE_CONTEXT_KEY } from 'vs/workbench/contrib/notebook/browser/constants'; +import { ExecuteCellAction, INotebookCellActionContext } from 'vs/workbench/contrib/notebook/browser/contrib/notebookActions'; +import { CellEditState, CellRenderTemplate, CellRunState, ICellViewModel, INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellMenus } from 'vs/workbench/contrib/notebook/browser/view/renderers/cellMenus'; import { CodeCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/codeCell'; import { StatefullMarkdownCell } from 'vs/workbench/contrib/notebook/browser/view/renderers/markdownCell'; @@ -32,8 +34,6 @@ import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewMod import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel'; import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; import { CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -import { INotebookCellActionContext, ExecuteCellAction } from 'vs/workbench/contrib/notebook/browser/contrib/notebookActions'; -import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; const $ = DOM.$; @@ -221,8 +221,8 @@ export class MarkdownCellRenderer extends AbstractCellRenderer implements IListR const contextKeyService = this.contextKeyService.createScoped(templateData.container); contextKeyService.createKey(NOTEBOOK_CELL_TYPE_CONTEXT_KEY, 'markdown'); const cellEditableKey = contextKeyService.createKey(NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, !!(element.metadata?.editable)); - elementDisposable.add(element.onDidChangeMetadata((e) => { - cellEditableKey.set(!!e?.editable); + elementDisposable.add(element.onDidChangeMetadata(() => { + cellEditableKey.set(!!element.metadata?.editable); })); const editModeKey = contextKeyService.createKey(NOTEBOOK_CELL_MARKDOWN_EDIT_MODE_CONTEXT_KEY, element.editState === CellEditState.Editing); @@ -286,6 +286,8 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende ])(); disposables.add(runToolbar); + const executionOrderLabel = DOM.append(runButtonContainer, $('div.execution-count-label')); + const editorContainer = DOM.append(cellContainer, $('.cell-editor-container')); const editor = this.instantiationService.createInstance(CodeEditorWidget, editorContainer, { ...this.editorOptions, @@ -314,6 +316,7 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende toolbar, runToolbar, runButtonContainer, + executionOrderLabel, outputContainer, editor, disposables, @@ -352,21 +355,36 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende } })); + function renderExecutionOrder() { + const executionOrdeerLabel = typeof element.metadata?.executionOrder === 'number' ? `[ ${element.metadata.executionOrder} ]` : + '[ ]'; + templateData.executionOrderLabel!.innerText = executionOrdeerLabel; + } + + const contextKeyService = this.contextKeyService.createScoped(templateData.container); + contextKeyService.createKey(NOTEBOOK_CELL_TYPE_CONTEXT_KEY, 'code'); + const cellEditableKey = contextKeyService.createKey(NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, !!(element.metadata?.editable)); + + const updateForMetadata = () => { + const metadata = element.getEvaluatedMetadata(this.notebookEditor.viewModel!.notebookDocument.metadata); + DOM.toggleClass(templateData.cellContainer, 'runnable', !!metadata.runnable); + renderExecutionOrder(); + cellEditableKey.set(!!metadata.editable); + }; + + updateForMetadata(); + elementDisposable.add(element.onDidChangeMetadata(() => { + updateForMetadata(); + })); + + this.setupCellToolbarActions(contextKeyService, templateData, elementDisposable); + const toolbarContext = { cell: element, cellTemplate: templateData, notebookEditor: this.notebookEditor, $mid: 12 }; - - const contextKeyService = this.contextKeyService.createScoped(templateData.container); - contextKeyService.createKey(NOTEBOOK_CELL_TYPE_CONTEXT_KEY, 'code'); - const cellEditableKey = contextKeyService.createKey(NOTEBOOK_CELL_EDITABLE_CONTEXT_KEY, !!(element.metadata?.editable)); - elementDisposable.add(element.onDidChangeMetadata((e) => { - cellEditableKey.set(!!e?.editable); - })); - - this.setupCellToolbarActions(contextKeyService, templateData, elementDisposable); templateData.toolbar.context = toolbarContext; templateData.runToolbar!.context = toolbarContext; } diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts index 590c42bde7a..fa892305352 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/codeCell.ts @@ -83,7 +83,7 @@ export class CodeCell extends Disposable { })); templateData.editor?.updateOptions({ readOnly: !(viewCell.getEvaluatedMetadata(notebookEditor.viewModel?.metadata).editable) }); - this._register(viewCell.onDidChangeMetadata((e) => { + this._register(viewCell.onDidChangeMetadata(() => { templateData.editor?.updateOptions({ readOnly: !(viewCell.getEvaluatedMetadata(notebookEditor.viewModel?.metadata).editable) }); })); diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel.ts index b8059864ff2..683be531879 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/baseCellViewModel.ts @@ -32,8 +32,8 @@ export abstract class BaseCellViewModel extends Disposable { readonly onDidChangeEditorAttachState = this._onDidChangeEditorAttachState.event; protected readonly _onDidChangeCursorSelection: Emitter = this._register(new Emitter()); public readonly onDidChangeCursorSelection: Event = this._onDidChangeCursorSelection.event; - protected readonly _onDidChangeMetadata: Emitter = this._register(new Emitter()); - public readonly onDidChangeMetadata: Event = this._onDidChangeMetadata.event; + protected readonly _onDidChangeMetadata: Emitter = this._register(new Emitter()); + public readonly onDidChangeMetadata: Event = this._onDidChangeMetadata.event; protected readonly _onDidChangeLanguage: Emitter = this._register(new Emitter()); public readonly onDidChangeLanguage: Event = this._onDidChangeLanguage.event; get handle() { @@ -106,8 +106,8 @@ export abstract class BaseCellViewModel extends Disposable { this._onDidChangeLanguage.fire(e); })); - this._register(cell.onDidChangeMetadata((e) => { - this._onDidChangeMetadata.fire(e); + this._register(cell.onDidChangeMetadata(() => { + this._onDidChangeMetadata.fire(); })); } diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts index 921bbfb0d8c..952f8b39388 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts @@ -8,7 +8,7 @@ import * as UUID from 'vs/base/common/uuid'; import * as model from 'vs/editor/common/model'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; -import { EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_PADDING, CELL_MARGIN, RUN_BUTTON_WIDTH } from 'vs/workbench/contrib/notebook/browser/constants'; +import { EDITOR_BOTTOM_PADDING, EDITOR_TOOLBAR_HEIGHT, EDITOR_TOP_PADDING, CELL_MARGIN, CELL_RUN_GUTTER } from 'vs/workbench/contrib/notebook/browser/constants'; import { CellEditState, ICellViewModel, CellFindMatch, CodeCellLayoutChangeEvent, CodeCellLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellKind, ICell, NotebookCellOutputsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { BaseCellViewModel } from './baseCellViewModel'; @@ -72,6 +72,10 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod })); } + this._register(this.cell.onDidChangeMetadata(() => { + this._onDidChangeMetadata.fire(); + })); + this._outputCollection = new Array(this.cell.outputs.length); this._buffer = null; @@ -105,7 +109,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod ? EDITOR_TOOLBAR_HEIGHT + this.editorHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING + 16 + outputTotalHeight : EDITOR_TOOLBAR_HEIGHT + this.editorHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING + outputTotalHeight; const indicatorHeight = totalHeight - EDITOR_TOOLBAR_HEIGHT - 16; - const editorWidth = state.outerWidth !== undefined ? state.outerWidth - CELL_MARGIN * 2 - RUN_BUTTON_WIDTH : 0; + const editorWidth = state.outerWidth !== undefined ? state.outerWidth - CELL_MARGIN * 2 - CELL_RUN_GUTTER : 0; this._layoutInfo = { fontInfo: state.font || null, editorHeight: this._editorHeight, diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts index f9f7f15c403..9e80924fae3 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookCellTextModel.ts @@ -15,8 +15,8 @@ export class NotebookCellTextModel implements ICell { private _onDidChangeContent = new Emitter(); onDidChangeContent: Event = this._onDidChangeContent.event; - private _onDidChangeMetadata = new Emitter(); - onDidChangeMetadata: Event = this._onDidChangeMetadata.event; + private _onDidChangeMetadata = new Emitter(); + onDidChangeMetadata: Event = this._onDidChangeMetadata.event; private _onDidChangeLanguage = new Emitter(); onDidChangeLanguage: Event = this._onDidChangeLanguage.event; @@ -44,7 +44,7 @@ export class NotebookCellTextModel implements ICell { set metadata(newMetadata: NotebookCellMetadata | undefined) { this._metadata = newMetadata; - this._onDidChangeMetadata.fire(this._metadata); + this._onDidChangeMetadata.fire(); } get language() { diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 019f6666458..83d52da64d9 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -45,6 +45,7 @@ export interface NotebookDocumentMetadata { export interface NotebookCellMetadata { editable?: boolean; runnable?: boolean; + executionOrder?: number; } export interface INotebookDisplayOrder { @@ -135,8 +136,8 @@ export interface ICell { outputs: IOutput[]; metadata?: NotebookCellMetadata; onDidChangeOutputs?: Event; - onDidChangeMetadata: Event; onDidChangeLanguage: Event; + onDidChangeMetadata: Event; resolveTextBufferFactory(): PieceTreeTextBufferFactory; // TODO@rebornix it should be later on replaced by moving textmodel resolution into CellTextModel contentChange(): void; diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index c551b8aff40..55168a9d900 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -25,11 +25,10 @@ export class TestCell implements ICell { uri: URI; private _onDidChangeOutputs = new Emitter(); onDidChangeOutputs: Event = this._onDidChangeOutputs.event; - private _onDidChangeMetadata = new Emitter(); - onDidChangeMetadata: Event = this._onDidChangeMetadata.event; private _onDidChangeLanguage = new Emitter(); onDidChangeLanguage: Event = this._onDidChangeLanguage.event; - + private _onDidChangeMetadata = new Emitter(); + onDidChangeMetadata: Event = this._onDidChangeMetadata.event; private _isDirty: boolean = false; private _outputs: IOutput[]; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index 42017a6c213..bf16000107e 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -47,6 +47,7 @@ import { IPreferencesService, ISearchResult, ISettingsEditorModel, ISettingsEdit import { SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput'; import { Settings2EditorModel } from 'vs/workbench/services/preferences/common/preferencesModels'; import { IEditorModel } from 'vs/platform/editor/common/editor'; +import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys'; function createGroupIterator(group: SettingsTreeGroupElement): Iterator> { const groupsIt = Iterator.fromArray(group.children); @@ -67,6 +68,7 @@ interface IFocusEventFromScroll extends KeyboardEvent { fromScroll: true; } +const SETTINGS_AUTOSAVE_NOTIFIED_KEY = 'hasNotifiedOfSettingsAutosave'; const SETTINGS_EDITOR_STATE_KEY = 'settingsEditorState'; export class SettingsEditor2 extends BaseEditor { @@ -157,7 +159,8 @@ export class SettingsEditor2 extends BaseEditor { @IStorageService private readonly storageService: IStorageService, @INotificationService private readonly notificationService: INotificationService, @IEditorGroupsService protected editorGroupService: IEditorGroupsService, - @IKeybindingService private readonly keybindingService: IKeybindingService + @IKeybindingService private readonly keybindingService: IKeybindingService, + @IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService, ) { super(SettingsEditor2.ID, telemetryService, themeService, storageService); this.delayedFilterLogging = new Delayer(1000); @@ -183,6 +186,8 @@ export class SettingsEditor2 extends BaseEditor { this.onConfigUpdate(e.affectedKeys); } })); + + storageKeysSyncRegistryService.registerStorageKey({ key: SETTINGS_AUTOSAVE_NOTIFIED_KEY, version: 1 }); } get minimumWidth(): number { return 375; } @@ -704,8 +709,8 @@ export class SettingsEditor2 extends BaseEditor { } private notifyNoSaveNeeded() { - if (!this.storageService.getBoolean('hasNotifiedOfSettingsAutosave', StorageScope.GLOBAL, false)) { - this.storageService.store('hasNotifiedOfSettingsAutosave', true, StorageScope.GLOBAL); + if (!this.storageService.getBoolean(SETTINGS_AUTOSAVE_NOTIFIED_KEY, StorageScope.GLOBAL, false)) { + this.storageService.store(SETTINGS_AUTOSAVE_NOTIFIED_KEY, true, StorageScope.GLOBAL); this.notificationService.info(localize('settingsNoSaveNeeded', "Your changes are automatically saved as you edit.")); } } diff --git a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts index dd95ebd9a09..a34cc345272 100644 --- a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts +++ b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts @@ -776,12 +776,14 @@ export class TimelinePane extends ViewPane { // Refresh the view on focus to update the relative timestamps this.onDidFocus(() => this.refreshDebounced(), this, this.visibilityDisposables); + super.setVisible(visible); + this.onActiveEditorChanged(); } else { this.visibilityDisposables?.dispose(); - } - super.setVisible(visible); + super.setVisible(visible); + } } protected layoutBody(height: number, width: number): void { diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 1236270e91d..065099a486f 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -98,19 +98,19 @@ const getActivityTitle = (label: string, userDataSyncService: IUserDataSyncServi const getIdentityTitle = (label: string, authenticationProviderId: string, account: AuthenticationSession | undefined, authenticationService: IAuthenticationService): string => { return account ? `${label} (${authenticationService.getDisplayName(authenticationProviderId)}:${account.accountName})` : label; }; -const turnOnSyncCommand = { id: 'workbench.userData.actions.syncStart', title: localize('turn on sync with category', "Sync: Turn on Sync") }; -const signInCommand = { id: 'workbench.userData.actions.signin', title: localize('sign in', "Sync: Sign in to sync") }; -const stopSyncCommand = { id: 'workbench.userData.actions.stopSync', title(authenticationProviderId: string, account: AuthenticationSession | undefined, authenticationService: IAuthenticationService) { return getIdentityTitle(localize('stop sync', "Sync: Turn off Sync"), authenticationProviderId, account, authenticationService); } }; -const resolveSettingsConflictsCommand = { id: 'workbench.userData.actions.resolveSettingsConflicts', title: localize('showConflicts', "Sync: Show Settings Conflicts") }; -const resolveKeybindingsConflictsCommand = { id: 'workbench.userData.actions.resolveKeybindingsConflicts', title: localize('showKeybindingsConflicts', "Sync: Show Keybindings Conflicts") }; -const resolveSnippetsConflictsCommand = { id: 'workbench.userData.actions.resolveSnippetsConflicts', title: localize('showSnippetsConflicts', "Sync: Show User Snippets Conflicts") }; -const configureSyncCommand = { id: 'workbench.userData.actions.configureSync', title: localize('configure sync', "Sync: Configure") }; +const turnOnSyncCommand = { id: 'workbench.userData.actions.syncStart', title: localize('turn on sync with category', "Preferences Sync: Turn on...") }; +const signInCommand = { id: 'workbench.userData.actions.signin', title: localize('sign in', "Preferences Sync: Sign in to sync") }; +const stopSyncCommand = { id: 'workbench.userData.actions.stopSync', title(authenticationProviderId: string, account: AuthenticationSession | undefined, authenticationService: IAuthenticationService) { return getIdentityTitle(localize('stop sync', "Preferences Sync: Turn off"), authenticationProviderId, account, authenticationService); } }; +const resolveSettingsConflictsCommand = { id: 'workbench.userData.actions.resolveSettingsConflicts', title: localize('showConflicts', "Preferences Sync: Show Settings Conflicts") }; +const resolveKeybindingsConflictsCommand = { id: 'workbench.userData.actions.resolveKeybindingsConflicts', title: localize('showKeybindingsConflicts', "Preferences Sync: Show Keybindings Conflicts") }; +const resolveSnippetsConflictsCommand = { id: 'workbench.userData.actions.resolveSnippetsConflicts', title: localize('showSnippetsConflicts', "Preferences Sync: Show User Snippets Conflicts") }; +const configureSyncCommand = { id: 'workbench.userData.actions.configureSync', title: localize('configure sync', "Preferences Sync: Configure...") }; const showSyncActivityCommand = { id: 'workbench.userData.actions.showSyncActivity', title(userDataSyncService: IUserDataSyncService): string { - return getActivityTitle(localize('show sync log', "Sync: Show Log"), userDataSyncService); + return getActivityTitle(localize('show sync log', "Preferences Sync: Show Log"), userDataSyncService); } }; -const showSyncSettingsCommand = { id: 'workbench.userData.actions.syncSettings', title: localize('sync settings', "Sync: Settings"), }; +const showSyncSettingsCommand = { id: 'workbench.userData.actions.syncSettings', title: localize('sync settings', "Preferences Sync: Show Settings"), }; export class UserDataSyncWorkbenchContribution extends Disposable implements IWorkbenchContribution { @@ -249,7 +249,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo private async showSwitchAccountPicker(sessions: readonly AuthenticationSession[]): Promise { return new Promise((resolve, _) => { const quickPick = this.quickInputService.createQuickPick<{ label: string, session: AuthenticationSession }>(); - quickPick.title = localize('chooseAccountTitle', "Sync: Choose Account"); + quickPick.title = localize('chooseAccountTitle', "Preferences Sync: Choose Account"); quickPick.placeholder = localize('chooseAccount', "Choose an account you would like to use for settings sync"); quickPick.items = sessions.map(session => { return { @@ -577,7 +577,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo if (this.userDataSyncService.status !== SyncStatus.Uninitialized && this.userDataSyncEnablementService.isEnabled() && this.authenticationState.get() === AuthStatus.SignedOut) { badge = new NumberBadge(1, () => localize('sign in to sync', "Sign in to Sync")); } else if (this.userDataSyncService.conflicts.length) { - badge = new NumberBadge(this.userDataSyncService.conflicts.reduce((result, syncResourceConflict) => { return result + syncResourceConflict.conflicts.length; }, 0), () => localize('has conflicts', "Sync: Conflicts Detected")); + badge = new NumberBadge(this.userDataSyncService.conflicts.reduce((result, syncResourceConflict) => { return result + syncResourceConflict.conflicts.length; }, 0), () => localize('has conflicts', "Preferences Sync: Conflicts Detected")); } if (badge) { @@ -608,7 +608,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo const disposables: DisposableStore = new DisposableStore(); const quickPick = this.quickInputService.createQuickPick(); disposables.add(quickPick); - quickPick.title = localize('turn on title', "Sync: Turn On"); + quickPick.title = localize('turn on title', "Preferences Sync: Turn On"); quickPick.ok = false; quickPick.customButton = true; if (this.authenticationState.get() === AuthStatus.SignedIn) { @@ -713,7 +713,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo const disposables: DisposableStore = new DisposableStore(); const quickPick = this.quickInputService.createQuickPick(); disposables.add(quickPick); - quickPick.title = localize('turn on sync', "Turn on Sync"); + quickPick.title = localize('configure sync', "Preferences Sync: Configure..."); quickPick.placeholder = localize('configure sync placeholder', "Choose what to sync"); quickPick.canSelectMany = true; quickPick.ignoreFocusOut = true; @@ -888,7 +888,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo group: '5_sync', command: { id: turnOnSyncCommand.id, - title: localize('global activity turn on sync', "Turn on Sync...") + title: localize('global activity turn on sync', "Preferences Sync: Turn on...") }, when: turnOnSyncWhenContext, order: 1 @@ -901,7 +901,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo group: '5_sync', command: { id: turnOnSyncCommand.id, - title: localize('global activity turn on sync', "Turn on Sync...") + title: localize('global activity turn on sync', "Preferences Sync: Turn on...") }, when: turnOnSyncWhenContext, }); @@ -913,7 +913,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo constructor() { super({ id: signInCommand.id, - title: localize('sign in 2', "Sync: Sign in to sync (1)"), + title: localize('sign in 2', "Preferences Sync: Sign in to sync (1)"), menu: { group: '5_sync', id: MenuId.GlobalActivity, @@ -939,7 +939,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo group: '5_sync', command: { id: resolveSettingsConflictsCommand.id, - title: localize('resolveConflicts_global', "Sync: Show Settings Conflicts (1)"), + title: localize('resolveConflicts_global', "Preferences Sync: Show Settings Conflicts (1)"), }, when: resolveSettingsConflictsWhenContext, order: 2 @@ -948,7 +948,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo group: '5_sync', command: { id: resolveSettingsConflictsCommand.id, - title: localize('resolveConflicts_global', "Sync: Show Settings Conflicts (1)"), + title: localize('resolveConflicts_global', "Preferences Sync: Show Settings Conflicts (1)"), }, when: resolveSettingsConflictsWhenContext, order: 2 @@ -966,7 +966,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo group: '5_sync', command: { id: resolveKeybindingsConflictsCommand.id, - title: localize('resolveKeybindingsConflicts_global', "Sync: Show Keybindings Conflicts (1)"), + title: localize('resolveKeybindingsConflicts_global', "Preferences Sync: Show Keybindings Conflicts (1)"), }, when: resolveKeybindingsConflictsWhenContext, order: 2 @@ -975,7 +975,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo group: '5_sync', command: { id: resolveKeybindingsConflictsCommand.id, - title: localize('resolveKeybindingsConflicts_global', "Sync: Show Keybindings Conflicts (1)"), + title: localize('resolveKeybindingsConflicts_global', "Preferences Sync: Show Keybindings Conflicts (1)"), }, when: resolveKeybindingsConflictsWhenContext, order: 2 @@ -996,7 +996,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo group: '5_sync', command: { id: resolveSnippetsConflictsCommand.id, - title: localize('resolveSnippetsConflicts_global', "Sync: Show User Snippets Conflicts ({0})", conflicts?.length || 1), + title: localize('resolveSnippetsConflicts_global', "Preferences Sync: Show User Snippets Conflicts ({0})", conflicts?.length || 1), }, when: resolveSnippetsConflictsWhenContext, order: 2 @@ -1005,7 +1005,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo group: '5_sync', command: { id: resolveSnippetsConflictsCommand.id, - title: localize('resolveSnippetsConflicts_global', "Sync: Show User Snippets Conflicts ({0})", conflicts?.length || 1), + title: localize('resolveSnippetsConflicts_global', "Preferences Sync: Show User Snippets Conflicts ({0})", conflicts?.length || 1), }, when: resolveSnippetsConflictsWhenContext, order: 2 @@ -1023,7 +1023,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo constructor() { super({ id: 'workbench.userData.actions.syncStatus', - title: localize('sync is on', "Sync is on"), + title: localize('sync is on', "Preferences Sync: On"), menu: [ { id: MenuId.GlobalActivity, @@ -1262,8 +1262,8 @@ class AcceptChangesContribution extends Disposable implements IEditorContributio const result = await this.dialogService.confirm({ type: 'info', title: isRemote - ? localize('Sync accept remote', "Sync: {0}", acceptRemoteLabel) - : localize('Sync accept local', "Sync: {0}", acceptLocalLabel), + ? localize('Sync accept remote', "Preferences Sync: {0}", acceptRemoteLabel) + : localize('Sync accept local', "Preferences Sync: {0}", acceptLocalLabel), message: isRemote ? localize('confirm replace and overwrite local', "Would you like to accept remote {0} and replace local {1}?", syncAreaLabel.toLowerCase(), syncAreaLabel.toLowerCase()) : localize('confirm replace and overwrite remote', "Would you like to accept local {0} and replace remote {1}?", syncAreaLabel.toLowerCase(), syncAreaLabel.toLowerCase()), diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSyncView.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSyncView.ts index cd83abd8dda..3f4142ac469 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSyncView.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSyncView.ts @@ -36,7 +36,7 @@ export class UserDataSyncViewContribution implements IWorkbenchContribution { return Registry.as(Extensions.ViewContainersRegistry).registerViewContainer( { id: 'workbench.view.sync', - name: localize('sync', "Sync"), + name: localize('sync preferences', "Preferences Sync"), ctorDescriptor: new SyncDescriptor( ViewPaneContainer, ['workbench.view.sync', `workbench.view.sync.state`, { mergeViewWithContainerWhenSingleView: true }] @@ -80,7 +80,7 @@ export class UserDataSyncViewContribution implements IWorkbenchContribution { title: remote ? { value: localize('workbench.action.showSyncRemoteBackup', "Show Remote Backup"), original: `Show Remote Backup` } : { value: localize('workbench.action.showSyncLocalBackup', "Show Local Backup"), original: `Show Local Backup` }, - category: { value: localize('sync', "Sync"), original: `Sync` }, + category: { value: localize('sync preferences', "Preferences Sync"), original: `Preferences Sync` }, menu: { id: MenuId.CommandPalette, when: CONTEXT_SYNC_ENABLEMENT diff --git a/src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts b/src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts index 1a637d676cf..60d058a8fbd 100644 --- a/src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts +++ b/src/vs/workbench/contrib/userDataSync/electron-browser/userDataSync.contribution.ts @@ -33,7 +33,8 @@ registerAction2(class OpenSyncBackupsFolder extends Action2 { constructor() { super({ id: 'workbench.userData.actions.openSyncBackupsFolder', - title: localize('Open Backup folder', "Sync: Open Local Backups Folder"), + title: { value: localize('Open Backup folder', "Open Local Backups Folder"), original: 'Open Local Backups Folder' }, + category: { value: localize('sync preferences', "Preferences Sync"), original: `Preferences Sync` }, menu: { id: MenuId.CommandPalette, when: CONTEXT_SYNC_STATE.notEqualsTo(SyncStatus.Uninitialized), diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index c840aa894be..a07aaa8a2c3 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -233,11 +233,10 @@ export class ElectronWebviewBasedWebview extends BaseWebview impleme const webviewAndContents = this._register(new WebviewTagHandle(this.element!)); const session = this._register(new WebviewSession(webviewAndContents)); - this._protocolProvider = new WebviewProtocolProvider - (webviewAndContents, - () => this.extension ? this.extension.location : undefined, - () => (this.content.options.localResourceRoots || []), - fileService); + this._protocolProvider = new WebviewProtocolProvider(webviewAndContents, + () => this.extension?.location, + () => (this.content.options.localResourceRoots || []), + fileService); this._register(this._protocolProvider); this._register(new WebviewPortMappingProvider(