diff --git a/extensions/theme-abyss/themes/abyss-color-theme.json b/extensions/theme-abyss/themes/abyss-color-theme.json index 979b623698f63459be6fb806baedcab04f0a9c54..1f7d48782d21e419da9f64d012c9f09519fd59bb 100644 --- a/extensions/theme-abyss/themes/abyss-color-theme.json +++ b/extensions/theme-abyss/themes/abyss-color-theme.json @@ -400,7 +400,7 @@ "statusBar.noFolderBackground": "#10192c", "statusBar.debuggingBackground": "#10192c", // "statusBar.foreground": "", - "statusBarItem.hostBackground": "#0063a5", + "statusBarItem.remoteBackground": "#0063a5", "statusBarItem.prominentBackground": "#0063a5", "statusBarItem.prominentHoverBackground": "#0063a5dd", // "statusBarItem.activeBackground": "", diff --git a/extensions/theme-defaults/themes/hc_black.json b/extensions/theme-defaults/themes/hc_black.json index 0b20650d8db2c0e96ed2a856c8d2fddb7a6780d0..870681495dc50ebf6a3d0ba85085e98d3dd0eda3 100644 --- a/extensions/theme-defaults/themes/hc_black.json +++ b/extensions/theme-defaults/themes/hc_black.json @@ -5,7 +5,7 @@ "colors": { "selection.background": "#008000", "editor.selectionBackground": "#FFFFFF", - "statusBarItem.hostBackground": "#00000000" + "statusBarItem.remoteBackground": "#00000000" }, "tokenColors": [ { diff --git a/extensions/theme-defaults/themes/hc_black_defaults.json b/extensions/theme-defaults/themes/hc_black_defaults.json index 54211a5b80108e0a6974225b1b77e2e184e0ca0e..9d11138a99b7bd8c9ccfda45580e8a4f3a694570 100644 --- a/extensions/theme-defaults/themes/hc_black_defaults.json +++ b/extensions/theme-defaults/themes/hc_black_defaults.json @@ -6,7 +6,7 @@ "editor.foreground": "#FFFFFF", "editorIndentGuide.background": "#FFFFFF", "editorIndentGuide.activeBackground": "#FFFFFF", - "statusBarItem.hostBackground": "#00000000", + "statusBarItem.remoteBackground": "#00000000", "sideBarTitle.foreground": "#FFFFFF" }, "settings": [ diff --git a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json index 0d7753ae462eac6ebaddf8fdf03a0af78275a78f..fac06fd00d4d6e64d70f79baa6ade50fee5f1d39 100644 --- a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json +++ b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json @@ -27,7 +27,7 @@ "statusBar.background": "#423523", "statusBar.debuggingBackground": "#423523", "statusBar.noFolderBackground": "#423523", - "statusBarItem.hostBackground": "#6e583b", + "statusBarItem.remoteBackground": "#6e583b", "activityBar.background": "#221a0f", "activityBar.foreground": "#d3af86", "sideBar.background": "#362712", diff --git a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json index 1aad04028e461533c55e41c9edf15c986086a81a..ed325071b64e53acb804cab16ae0c8f0c9c48290 100644 --- a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json +++ b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json @@ -31,7 +31,7 @@ "statusBar.debuggingBackground": "#505050", "statusBar.noFolderBackground": "#505050", "titleBar.activeBackground": "#505050", - "statusBarItem.hostBackground": "#3655b5", + "statusBarItem.remoteBackground": "#3655b5", "activityBar.background": "#353535", "activityBar.foreground": "#ffffff", "activityBarBadge.background": "#3655b5", diff --git a/extensions/theme-monokai/themes/monokai-color-theme.json b/extensions/theme-monokai/themes/monokai-color-theme.json index a203ace74eeb714e445d16aaec5dba83cdfa0554..14d616f61532f22b7fb27325d10a1c0f465c422f 100644 --- a/extensions/theme-monokai/themes/monokai-color-theme.json +++ b/extensions/theme-monokai/themes/monokai-color-theme.json @@ -50,7 +50,7 @@ "statusBar.background": "#414339", "statusBar.noFolderBackground": "#414339", "statusBar.debuggingBackground": "#75715E", - "statusBarItem.hostBackground": "#AC6218", + "statusBarItem.remoteBackground": "#AC6218", "activityBar.background": "#272822", "activityBar.foreground": "#f8f8f2", "activityBar.dropBackground": "#414339", diff --git a/extensions/theme-quietlight/themes/quietlight-color-theme.json b/extensions/theme-quietlight/themes/quietlight-color-theme.json index 467c81df9dc965816ada4758e0b994baca80b30a..67f7caa4da5d5a4fcc375b5bab67edacf24edfba 100644 --- a/extensions/theme-quietlight/themes/quietlight-color-theme.json +++ b/extensions/theme-quietlight/themes/quietlight-color-theme.json @@ -516,7 +516,7 @@ "statusBar.background": "#705697", "statusBar.noFolderBackground": "#705697", "statusBar.debuggingBackground": "#705697", - "statusBarItem.hostBackground": "#4e3c69", + "statusBarItem.remoteBackground": "#4e3c69", "activityBar.background": "#EDEDF5", "activityBar.foreground": "#705697", "activityBarBadge.background": "#705697", diff --git a/extensions/theme-red/themes/Red-color-theme.json b/extensions/theme-red/themes/Red-color-theme.json index 31fa8a1b62052a3d323196345035dd3fb6a44b18..18e5786a8f3e049374889c5fff8614c0b11e7dd7 100644 --- a/extensions/theme-red/themes/Red-color-theme.json +++ b/extensions/theme-red/themes/Red-color-theme.json @@ -9,7 +9,7 @@ "sideBar.background": "#330000", "statusBar.background": "#700000", "statusBar.noFolderBackground": "#700000", - "statusBarItem.hostBackground": "#c33", + "statusBarItem.remoteBackground": "#c33", "editorGroupHeader.tabsBackground": "#330000", "titleBar.activeBackground": "#770000", "titleBar.inactiveBackground": "#772222", diff --git a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json index 9336e2ca21126b3056a248370895aff3d809ca76..5605aba721dda0442f79c3de51917a88cbeb34ab 100644 --- a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json +++ b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json @@ -448,7 +448,7 @@ "statusBar.background": "#00212B", "statusBar.debuggingBackground": "#00212B", "statusBar.noFolderBackground": "#00212B", - "statusBarItem.hostBackground": "#2AA19899", + "statusBarItem.remoteBackground": "#2AA19899", "statusBarItem.prominentBackground": "#003847", "statusBarItem.prominentHoverBackground": "#003847", // "statusBarItem.activeBackground": "", diff --git a/extensions/theme-solarized-light/themes/solarized-light-color-theme.json b/extensions/theme-solarized-light/themes/solarized-light-color-theme.json index 20e50ab36e8a6a5d3efefb565bfaf9b118892eb0..b94aeb71de8316fdade66cc3597f63d19b58bc4d 100644 --- a/extensions/theme-solarized-light/themes/solarized-light-color-theme.json +++ b/extensions/theme-solarized-light/themes/solarized-light-color-theme.json @@ -447,7 +447,7 @@ "statusBar.debuggingBackground": "#EEE8D5", "statusBar.noFolderBackground": "#EEE8D5", // "statusBar.foreground": "", - "statusBarItem.hostBackground": "#AC9D57", + "statusBarItem.remoteBackground": "#AC9D57", "statusBarItem.prominentBackground": "#DDD6C1", "statusBarItem.prominentHoverBackground": "#DDD6C199", // "statusBarItem.activeBackground": "", diff --git a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json index 5236bf4a911b4f40db1920b0a1027a76b332e71a..2ca39bf565d13ce1a63a4556a5047b8ba9a62099 100644 --- a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json +++ b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json @@ -30,7 +30,7 @@ "debugToolBar.background": "#001c40", "titleBar.activeBackground": "#001126", "statusBar.background": "#001126", - "statusBarItem.hostBackground": "#0e639c", + "statusBarItem.remoteBackground": "#0e639c", "statusBar.noFolderBackground": "#001126", "statusBar.debuggingBackground": "#001126", "activityBar.background": "#001733", diff --git a/package.json b/package.json index d9f316ee58a4ac30a9ae420daf3a40e399245dcb..b1c20cfec53080b352ee9ba924aeea087b2756eb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.34.0", - "distro": "7b2359d7f916e51e43161f06b62ae0b0c24045d7", + "distro": "9385c45c44e7ae495efe9564f253bd68cb5aedde", "author": { "name": "Microsoft Corporation" }, diff --git a/resources/win32/bin/code.sh b/resources/win32/bin/code.sh index 82f808a8650349807bb2e0cbfeec2f3fefa9f40d..23e8a522007b134b6bc922dcefba5f8ec14d6d22 100644 --- a/resources/win32/bin/code.sh +++ b/resources/win32/bin/code.sh @@ -25,7 +25,7 @@ if grep -qi Microsoft /proc/version; then WIN_CODE_CMD=$(wslpath -w "$(dirname "$(realpath "$0")")/$APP_NAME.cmd") # make sure the cwd is in the windows fs, otherwise there will be a warning from cmd pushd "$(dirname "$0")" > /dev/null - WSL_EXT_ID="ms-vscode.remote-wsl" + WSL_EXT_ID="ms-vscode-remote.remote-wsl" WSL_EXT_WLOC=$(cmd.exe /c "$WIN_CODE_CMD" --locate-extension $WSL_EXT_ID) popd > /dev/null if ! [ -z "$WSL_EXT_WLOC" ]; then diff --git a/scripts/code-cli.bat b/scripts/code-cli.bat index 927e3e00d22786eed1f5559763333a4a75358c34..6fbf5edd626f2307da205acf94a7b0abb865917d 100644 --- a/scripts/code-cli.bat +++ b/scripts/code-cli.bat @@ -17,7 +17,7 @@ set CODE=".build\electron\%NAMESHORT%" node build\lib\electron.js if %errorlevel% neq 0 node .\node_modules\gulp\bin\gulp.js electron -:: Manage build-in extensions +:: Manage built-in extensions if "%1"=="--builtin" goto builtin :: Sync built-in extensions diff --git a/scripts/code.sh b/scripts/code.sh index 8227916f953134fc3186a340945fd6fbcacfe73c..1f7cda590a1b2a40c0f88de2b96479016cfbda7e 100755 --- a/scripts/code.sh +++ b/scripts/code.sh @@ -60,7 +60,7 @@ function code-wsl() # in a wsl shell local WIN_CODE_CLI_CMD=$(wslpath -w "$ROOT/scripts/code-cli.bat") if ! [ -z "$WIN_CODE_CLI_CMD" ]; then - local WSL_EXT_ID="ms-vscode.remote-wsl" + local WSL_EXT_ID="ms-vscode-remote.remote-wsl" local WSL_EXT_WLOC=$(cmd.exe /c "$WIN_CODE_CLI_CMD" --locate-extension $WSL_EXT_ID) if ! [ -z "$WSL_EXT_WLOC" ]; then # replace \r\n with \n in WSL_EXT_WLOC diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 338645cd9886a7db8a937250567c15a4304cc86b..082dcf810f657cbd1f54da036f85c3a6b519220d 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -1215,6 +1215,7 @@ export interface Command { * @internal */ export interface CommentThreadTemplate { + controllerHandle: number; label: string; acceptInputCommand?: Command; additionalCommands?: Command[]; @@ -1281,6 +1282,7 @@ export interface CommentInput { */ export interface CommentThread2 { commentThreadHandle: number; + controllerHandle: number; extensionId?: string; threadId: string | null; resource: string | null; diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index ca44a26a1217b579c1cd6e5e5861d226c324908d..825cf3d08d3e90abcf42f87fd3cca6dafe10d791 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -8940,6 +8940,278 @@ declare module 'vscode' { */ export const onDidChange: Event; } + + //#region Comments + + /** + * Collapsible state of a [comment thread](#CommentThread) + */ + export enum CommentThreadCollapsibleState { + /** + * Determines an item is collapsed + */ + Collapsed = 0, + + /** + * Determines an item is expanded + */ + Expanded = 1 + } + + /** + * A collection of [comments](#Comment) representing a conversation at a particular range in a document. + */ + export interface CommentThread { + /** + * A unique identifier of the comment thread. + */ + readonly id: string; + + /** + * The uri of the document the thread has been created on. + */ + readonly resource: Uri; + + /** + * The range the comment thread is located within the document. The thread icon will be shown + * at the first line of the range. + */ + readonly range: Range; + + /** + * The ordered comments of the thread. + */ + comments: Comment[]; + + /** + * Whether the thread should be collapsed or expanded when opening the document. + * Defaults to Collapsed. + */ + collapsibleState: CommentThreadCollapsibleState; + + /** + * The optional human-readable label describing the [Comment Thread](#CommentThread) + */ + label?: string; + + /** + * Optional accept input command + * + * `acceptInputCommand` is the default action rendered on Comment Widget, which is always placed rightmost. + * This command will be invoked when users the user accepts the value in the comment editor. + * This command will disabled when the comment editor is empty. + */ + acceptInputCommand?: Command; + + /** + * Optional additonal commands. + * + * `additionalCommands` are the secondary actions rendered on Comment Widget. + */ + additionalCommands?: Command[]; + + /** + * The command to be executed when users try to delete the comment thread. Currently, this is only called + * when the user collapses a comment thread that has no comments in it. + */ + deleteCommand?: Command; + + /** + * Dispose this comment thread. + * + * Once disposed, this comment thread will be removed from visible editors and Comment Panel when approriate. + */ + dispose(): void; + } + + /** + * A comment is displayed within the editor or the Comments Panel, depending on how it is provided. + */ + export class Comment { + /** + * The id of the comment + */ + readonly id: string; + + /** + * The human-readable comment body + */ + readonly body: MarkdownString; + + /** + * The display name of the user who created the comment + */ + readonly userName: string; + + /** + * Optional label describing the [Comment](#Comment) + * Label will be rendered next to userName if exists. + */ + readonly label?: string; + + /** + * The icon path for the user who created the comment + */ + readonly userIconPath?: Uri; + + /** + * The command to be executed if the comment is selected in the Comments Panel + */ + readonly selectCommand?: Command; + + /** + * The command to be executed when users try to save the edits to the comment + */ + readonly editCommand?: Command; + + /** + * The command to be executed when users try to delete the comment + */ + readonly deleteCommand?: Command; + + /** + * @param id The id of the comment + * @param body The human-readable comment body + * @param userName The display name of the user who created the comment + */ + constructor(id: string, body: MarkdownString, userName: string); + } + + /** + * The comment input box in Comment Widget. + */ + export interface CommentInputBox { + /** + * Setter and getter for the contents of the comment input box + */ + value: string; + + /** + * The uri of the document comment input box has been created on + */ + resource: Uri; + + /** + * The range the comment input box is located within the document + */ + range: Range; + } + + /** + * Commenting range provider for a [comment controller](#CommentController). + */ + export interface CommentingRangeProvider { + /** + * Provide a list of ranges which allow new comment threads creation or null for a given document + */ + provideCommentingRanges(document: TextDocument, token: CancellationToken): ProviderResult; + } + + /** + * Comment thread template for new comment thread creation. + */ + export interface CommentThreadTemplate { + /** + * The human-readable label describing the [Comment Thread](#CommentThread) + */ + readonly label: string; + + /** + * Optional accept input command + * + * `acceptInputCommand` is the default action rendered on Comment Widget, which is always placed rightmost. + * This command will be invoked when users the user accepts the value in the comment editor. + * This command will disabled when the comment editor is empty. + */ + readonly acceptInputCommand?: Command; + + /** + * Optional additonal commands. + * + * `additionalCommands` are the secondary actions rendered on Comment Widget. + */ + readonly additionalCommands?: Command[]; + + /** + * The command to be executed when users try to delete the comment thread. Currently, this is only called + * when the user collapses a comment thread that has no comments in it. + */ + readonly deleteCommand?: Command; + } + + /** + * A comment controller is able to provide [comments](#CommentThread) support to the editor and + * provide users various ways to interact with comments. + */ + export interface CommentController { + /** + * The id of this comment controller. + */ + readonly id: string; + + /** + * The human-readable label of this comment controller. + */ + readonly label: string; + + /** + * The active [comment input box](#CommentInputBox) or `undefined`. The active `inputBox` is the input box of + * the comment thread widget that currently has focus. It's `undefined` when the focus is not in any CommentInputBox. + */ + readonly inputBox: CommentInputBox | undefined; + + /** + * Optional comment thread template information. + * + * The comment controller will use this information to create the comment widget when users attempt to create new comment thread + * from the gutter or command palette. + * + * When users run `CommentThreadTemplate.acceptInputCommand` or `CommentThreadTemplate.additionalCommands`, extensions should create + * the approriate [CommentThread](#CommentThread). + * + * If not provided, users won't be able to create new comment threads in the editor. + */ + template?: CommentThreadTemplate; + + /** + * Optional commenting range provider. Provide a list [ranges](#Range) which support commenting to any given resource uri. + * + * If not provided and `emptyCommentThreadFactory` exits, users can leave comments in any document opened in the editor. + */ + commentingRangeProvider?: CommentingRangeProvider; + + /** + * Create a [comment thread](#CommentThread). The comment thread will be displayed in visible text editors (if the resource matches) + * and Comments Panel once created. + * + * @param id An `id` for the comment thread. + * @param resource The uri of the document the thread has been created on. + * @param range The range the comment thread is located within the document. + * @param comments The ordered comments of the thread. + */ + createCommentThread(id: string, resource: Uri, range: Range, comments: Comment[]): CommentThread; + + /** + * Dispose this comment controller. + * + * Once disposed, all [comment threads](#CommentThread) created by this comment controller will also be removed from the editor + * and Comments Panel. + */ + dispose(): void; + } + + namespace comment { + /** + * Creates a new [comment controller](#CommentController) instance. + * + * @param id An `id` for the comment controller. + * @param label A human-readable string for the comment controller. + * @return An instance of [comment controller](#CommentController). + */ + export function createCommentController(id: string, label: string): CommentController; + } + + //#endregion } /** diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 33e70afbfe1105c24bd9cdd2469c03b37bfdb47d..b1c6b84bb3b6f3d3a1a0260e528e870337558793 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -735,91 +735,10 @@ declare module 'vscode' { inDraftMode?: boolean; } - export enum CommentThreadCollapsibleState { - /** - * Determines an item is collapsed - */ - Collapsed = 0, - /** - * Determines an item is expanded - */ - Expanded = 1 - } - - /** - * A collection of comments representing a conversation at a particular range in a document. - */ - export interface CommentThread { - /** - * A unique identifier of the comment thread. - */ - threadId: string; - - /** - * The uri of the document the thread has been created on. - */ - resource: Uri; - - /** - * The range the comment thread is located within the document. The thread icon will be shown - * at the first line of the range. - */ - range: Range; - - /** - * The human-readable label describing the [Comment Thread](#CommentThread) - */ - label?: string; - - /** - * The ordered comments of the thread. - */ - comments: Comment[]; - - /** - * Optional accept input command - * - * `acceptInputCommand` is the default action rendered on Comment Widget, which is always placed rightmost. - * This command will be invoked when users the user accepts the value in the comment editor. - * This command will disabled when the comment editor is empty. - */ - acceptInputCommand?: Command; - - /** - * Optional additonal commands. - * - * `additionalCommands` are the secondary actions rendered on Comment Widget. - */ - additionalCommands?: Command[]; - - /** - * Whether the thread should be collapsed or expanded when opening the document. - * Defaults to Collapsed. - */ - collapsibleState?: CommentThreadCollapsibleState; - - /** - * The command to be executed when users try to delete the comment thread. Currently, this is only called - * when the user collapses a comment thread that has no comments in it. - */ - deleteCommand?: Command; - - /** - * Dispose this comment thread. - * Once disposed, the comment thread will be removed from visible text editors and Comments Panel. - */ - dispose?(): void; - } - /** * A comment is displayed within the editor or the Comments Panel, depending on how it is provided. */ - export class Comment { - /** - * The id of the comment - */ - readonly id: string; - + export class CommentLegacy extends Comment { /** * The id of the comment * @@ -827,27 +746,6 @@ declare module 'vscode' { */ readonly commentId: string; - /** - * The human-readable comment body - */ - readonly body: MarkdownString; - - /** - * The display name of the user who created the comment - */ - readonly userName: string; - - /** - * Optional label describing the [Comment](#Comment) - * Label will be rendered next to userName if exists. - */ - readonly label?: string; - - /** - * The icon path for the user who created the comment - */ - readonly userIconPath?: Uri; - /** * @deprecated Use userIconPath instead. The avatar src of the user who created the comment */ @@ -879,21 +777,6 @@ declare module 'vscode' { */ command?: Command; - /** - * The command to be executed if the comment is selected in the Comments Panel - */ - readonly selectCommand?: Command; - - /** - * The command to be executed when users try to save the edits to the comment - */ - readonly editCommand?: Command; - - /** - * The command to be executed when users try to delete the comment - */ - readonly deleteCommand?: Command; - /** * Deprecated */ @@ -903,13 +786,6 @@ declare module 'vscode' { * Proposed Comment Reaction */ commentReactions?: CommentReaction[]; - - /** - * @param id The id of the comment - * @param body The human-readable comment body - * @param userName The display name of the user who created the comment - */ - constructor(id: string, body: MarkdownString, userName: string); } /** @@ -1011,16 +887,6 @@ declare module 'vscode' { onDidChangeCommentThreads: Event; } - /** - * The comment input box in Comment Widget. - */ - export interface CommentInputBox { - /** - * Setter and getter for the contents of the comment input box. - */ - value: string; - } - /** * Stay in proposed */ @@ -1029,118 +895,22 @@ declare module 'vscode' { toggleReaction?(document: TextDocument, comment: Comment, reaction: CommentReaction): Promise; } - export interface CommentingRangeProvider { - /** - * Provide a list of ranges which allow new comment threads creation or null for a given document - */ - provideCommentingRanges(document: TextDocument, token: CancellationToken): ProviderResult; - } - - export interface CommentThreadTemplate { - /** - * The human-readable label describing the [Comment Thread](#CommentThread) - */ - label: string; - - /** - * Optional accept input command - * - * `acceptInputCommand` is the default action rendered on Comment Widget, which is always placed rightmost. - * This command will be invoked when users the user accepts the value in the comment editor. - * This command will disabled when the comment editor is empty. - */ - acceptInputCommand?: Command; - - /** - * Optional additonal commands. - * - * `additionalCommands` are the secondary actions rendered on Comment Widget. - */ - additionalCommands?: Command[]; - - /** - * The command to be executed when users try to delete the comment thread. Currently, this is only called - * when the user collapses a comment thread that has no comments in it. - */ - deleteCommand?: Command; - } - - export interface EmptyCommentThreadFactory { - template: CommentThreadTemplate; - /** - * When users attempt to create new comment thread from the gutter or command palette, `template` will be used first to create the Comment Thread Widget in the editor for users to start comment drafting. - * Then `createEmptyCommentThread` is called after that. Extensions should still call [`createCommentThread`](CommentController.createCommentThread) to create a real [`CommentThread`](#CommentThread) - * Extensions still need to call `createCommentThread` inside this call when appropriate. - * - * @param document The document in which users attempt to create a new comment thread - * @param range The range the comment threadill located within the document. - * - * @returns commentThread The [`CommentThread`](#CommentThread) created by extensions - */ - createEmptyCommentThread(document: TextDocument, range: Range): ProviderResult; - } export interface CommentController { - /** - * The id of this comment controller. - */ - readonly id: string; - - /** - * The human-readable label of this comment controller. - */ - readonly label: string; - - /** - * The active [comment input box](#CommentInputBox) or `undefined`. The active `inputBox` is the input box of - * the comment thread widget that currently has focus. It's `undefined` when the focus is not in any CommentInputBox. - */ - readonly inputBox: CommentInputBox | undefined; - - /** - * The active [comment thread](#CommentThread) or `undefined`. The `activeCommentThread` is the comment thread of - * the comment thread widget that currently has focus. It's `undefined` when the focus is not in any comment thread widget. - */ - readonly activeCommentThread: CommentThread | undefined; - - /** - * Create a [CommentThread](#CommentThread). The comment thread will be displayed in visible text editors (if the resource matches) - * and Comments Panel. - * @param id An `id` for the comment thread. - * @param resource The uri of the document the thread has been created on. - * @param range The range the comment thread is located within the document. - * @param comments The ordered comments of the thread. - */ - createCommentThread(id: string, resource: Uri, range: Range, comments: Comment[]): CommentThread; - - /** - * Optional commenting range provider. Provide a list [ranges](#Range) which support commenting to any given resource uri. - * - * If not provided and `emptyCommentThreadFactory` exits, users can leave comments in any document opened in the editor. - */ - commentingRangeProvider?: CommentingRangeProvider; - - /** - * Optional empty comment thread factory. It's necessary for supporting users to trigger Comment Thread creation from the editor or command palette. - * - * If not provided, users won't be able to trigger new comment thread creation from the editor gutter area or command palette. - */ - emptyCommentThreadFactory?: EmptyCommentThreadFactory; - /** * Optional reaction provider * Stay in proposed. */ reactionProvider?: CommentReactionProvider; + } + export interface CommentController { /** - * Dispose this comment controller. + * The active [comment thread](#CommentThread) or `undefined`. The `activeCommentThread` is the comment thread of + * the comment widget that currently has focus. It's `undefined` when the focus is not in any comment thread widget, or + * the comment widget created from [comment thread template](#CommentThreadTemplate). */ - dispose(): void; - } - - namespace comment { - export function createCommentController(id: string, label: string): CommentController; + readonly activeCommentThread: CommentThread | undefined; } namespace workspace { diff --git a/src/vs/workbench/api/browser/mainThreadComments.ts b/src/vs/workbench/api/browser/mainThreadComments.ts index c70e82a6a57bf22746cf7cbe79a5867582376a70..4b4896e6ece94584fddfd75fce17d30ce2ef461c 100644 --- a/src/vs/workbench/api/browser/mainThreadComments.ts +++ b/src/vs/workbench/api/browser/mainThreadComments.ts @@ -192,7 +192,7 @@ export class MainThreadCommentThread implements modes.CommentThread2 { constructor( public commentThreadHandle: number, - public controller: MainThreadCommentController, + public controllerHandle: number, public extensionId: string, public threadId: string, public resource: string, @@ -232,7 +232,7 @@ export class MainThreadCommentThread implements modes.CommentThread2 { toJSON(): any { return { $mid: 7, - commentControlHandle: this.controller.handle, + commentControlHandle: this.controllerHandle, commentThreadHandle: this.commentThreadHandle, }; } @@ -290,7 +290,7 @@ export class MainThreadCommentController { ): modes.CommentThread2 { let thread = new MainThreadCommentThread( commentThreadHandle, - this, + this.handle, '', threadId, URI.revive(resource).toString(), @@ -395,7 +395,13 @@ export class MainThreadCommentController { } } : [], draftMode: modes.DraftMode.NotSupported, - template: this._features.commentThreadTemplate + template: this._features.commentThreadTemplate ? { + controllerHandle: this.handle, + label: this._features.commentThreadTemplate.label, + acceptInputCommand: this._features.commentThreadTemplate.acceptInputCommand, + additionalCommands: this._features.commentThreadTemplate.additionalCommands, + deleteCommand: this._features.commentThreadTemplate.deleteCommand + } : undefined }; } @@ -421,6 +427,28 @@ export class MainThreadCommentController { return ret; } + getCommentThreadFromTemplate(resource: UriComponents, range: IRange): MainThreadCommentThread { + let thread = new MainThreadCommentThread( + -1, + this.handle, + '', + '', + URI.revive(resource).toString(), + range + ); + + let template = this._features.commentThreadTemplate; + + if (template) { + thread.acceptInputCommand = template.acceptInputCommand; + thread.additionalCommands = template.additionalCommands; + thread.deleteCommand = template.deleteCommand; + thread.label = template.label; + } + + return thread; + } + toJSON(): any { return { $mid: 6, @@ -456,7 +484,8 @@ export class MainThreadComments extends Disposable implements MainThreadComments this._activeCommentThreadDisposables = []; this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostComments); this._disposables.push(this._commentService.onDidChangeActiveCommentThread(async thread => { - let controller = (thread as MainThreadCommentThread).controller; + let handle = (thread as MainThreadCommentThread).controllerHandle; + let controller = this._commentControllers.get(handle); if (!controller) { return; @@ -468,11 +497,11 @@ export class MainThreadComments extends Disposable implements MainThreadComments this._activeCommentThreadDisposables.push(this._activeCommentThread.onDidChangeInput(input => { // todo, dispose this._input = input; - this._proxy.$onCommentWidgetInputChange(controller.handle, this._input ? this._input.value : undefined); + this._proxy.$onCommentWidgetInputChange(handle, URI.parse(this._activeCommentThread!.resource), this._activeCommentThread!.range, this._input ? this._input.value : undefined); })); await this._proxy.$onActiveCommentThreadChange(controller.handle, controller.activeCommentThread.commentThreadHandle); - await this._proxy.$onCommentWidgetInputChange(controller.handle, this._input ? this._input.value : undefined); + await this._proxy.$onCommentWidgetInputChange(controller.handle, URI.parse(this._activeCommentThread!.resource), this._activeCommentThread.range, this._input ? this._input.value : undefined); })); } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 21443f8288b003373ed6d612a5788719965d0a26..cff14ddb273be507d006802fda9b0ae5026c4302 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1210,12 +1210,12 @@ export interface ExtHostProgressShape { export interface ExtHostCommentsShape { $provideDocumentComments(handle: number, document: UriComponents): Promise; $createNewCommentThread(handle: number, document: UriComponents, range: IRange, text: string): Promise; - $onCommentWidgetInputChange(commentControllerHandle: number, input: string | undefined): Promise; + $onCommentWidgetInputChange(commentControllerHandle: number, document: UriComponents, range: IRange, input: string | undefined): Promise; $onActiveCommentThreadChange(commentControllerHandle: number, threadHandle: number | undefined): Promise; $provideCommentingRanges(commentControllerHandle: number, uriComponents: UriComponents, token: CancellationToken): Promise; $provideReactionGroup(commentControllerHandle: number): Promise; $toggleReaction(commentControllerHandle: number, threadHandle: number, uri: UriComponents, comment: modes.Comment, reaction: modes.CommentReaction): Promise; - $createNewCommentWidgetCallback(commentControllerHandle: number, uriComponents: UriComponents, range: IRange, token: CancellationToken): Promise; + $createNewCommentWidgetCallback(commentControllerHandle: number, uriComponents: UriComponents, range: IRange, token: CancellationToken): Promise; $replyToCommentThread(handle: number, document: UriComponents, range: IRange, commentThread: modes.CommentThread, text: string): Promise; $editComment(handle: number, document: UriComponents, comment: modes.Comment, text: string): Promise; $deleteComment(handle: number, document: UriComponents, comment: modes.Comment): Promise; diff --git a/src/vs/workbench/api/common/extHostComments.ts b/src/vs/workbench/api/common/extHostComments.ts index 401f29b200f7a4090d017dcb308ca3c7c3764146..9b4fcc054999ea05b9246b2581f3decbae6596a7 100644 --- a/src/vs/workbench/api/common/extHostComments.ts +++ b/src/vs/workbench/api/common/extHostComments.ts @@ -88,14 +88,14 @@ export class ExtHostComments implements ExtHostCommentsShape { return commentController; } - $onCommentWidgetInputChange(commentControllerHandle: number, input: string): Promise { + $onCommentWidgetInputChange(commentControllerHandle: number, uriComponents: UriComponents, range: IRange, input: string): Promise { const commentController = this._commentControllers.get(commentControllerHandle); if (!commentController) { return Promise.resolve(undefined); } - commentController.$onCommentWidgetInputChange(input); + commentController.$onCommentWidgetInputChange(uriComponents, range, input); return Promise.resolve(commentControllerHandle); } @@ -157,34 +157,27 @@ export class ExtHostComments implements ExtHostCommentsShape { }); } - $createNewCommentWidgetCallback(commentControllerHandle: number, uriComponents: UriComponents, range: IRange, token: CancellationToken): Promise { + $createNewCommentWidgetCallback(commentControllerHandle: number, uriComponents: UriComponents, range: IRange, token: CancellationToken): Promise { const commentController = this._commentControllers.get(commentControllerHandle); if (!commentController) { - return Promise.resolve(undefined); + return Promise.resolve(); } - if (!(commentController as any).emptyCommentThreadFactory && !(commentController.commentingRangeProvider && commentController.commentingRangeProvider.createEmptyCommentThread) && !(commentController.emptyCommentThreadFactory && commentController.emptyCommentThreadFactory.createEmptyCommentThread)) { - return Promise.resolve(undefined); + if (!(commentController as any).emptyCommentThreadFactory && !(commentController.commentingRangeProvider && commentController.commentingRangeProvider.createEmptyCommentThread)) { + return Promise.resolve(); } const document = this._documents.getDocument(URI.revive(uriComponents)); return asPromise(() => { - if (commentController.emptyCommentThreadFactory) { - return commentController.emptyCommentThreadFactory!.createEmptyCommentThread(document, extHostTypeConverter.Range.to(range)); + if ((commentController as any).emptyCommentThreadFactory) { + return (commentController as any).emptyCommentThreadFactory!.createEmptyCommentThread(document, extHostTypeConverter.Range.to(range)); } if (commentController.commentingRangeProvider && commentController.commentingRangeProvider.createEmptyCommentThread) { return commentController.commentingRangeProvider.createEmptyCommentThread(document, extHostTypeConverter.Range.to(range)); } - - return; - }).then((commentThread: ExtHostCommentThread | undefined) => { - if (commentThread) { - return Promise.resolve(commentThread.handle); - } - return Promise.resolve(undefined); - }); + }).then(() => Promise.resolve()); } registerWorkspaceCommentProvider( @@ -384,7 +377,11 @@ export class ExtHostCommentThread implements vscode.CommentThread { private static _handlePool: number = 0; readonly handle = ExtHostCommentThread._handlePool++; get threadId(): string { - return this._threadId; + return this._id; + } + + get id(): string { + return this._id; } get resource(): vscode.Uri { @@ -416,11 +413,11 @@ export class ExtHostCommentThread implements vscode.CommentThread { this._onDidUpdateCommentThread.fire(); } - get comments(): vscode.Comment[] { + get comments(): (vscode.Comment & vscode.CommentLegacy)[] { return this._comments; } - set comments(newComments: vscode.Comment[]) { + set comments(newComments: (vscode.Comment & vscode.CommentLegacy)[]) { this._comments = newComments; this._onDidUpdateCommentThread.fire(); } @@ -478,15 +475,15 @@ export class ExtHostCommentThread implements vscode.CommentThread { private _proxy: MainThreadCommentsShape, private readonly _commandsConverter: CommandsConverter, private _commentController: ExtHostCommentController, - private _threadId: string, + private _id: string, private _resource: vscode.Uri, private _range: vscode.Range, - private _comments: vscode.Comment[] + private _comments: (vscode.Comment & vscode.CommentLegacy)[] ) { this._proxy.$createCommentThread( this._commentController.handle, this.handle, - this._threadId, + this._id, this._resource, extHostTypeConverter.Range.from(this._range) ); @@ -515,7 +512,7 @@ export class ExtHostCommentThread implements vscode.CommentThread { this._proxy.$updateCommentThread( this._commentController.handle, this.handle, - this._threadId, + this._id, this._resource, commentThreadRange, label, @@ -549,12 +546,14 @@ export class ExtHostCommentThread implements vscode.CommentThread { } export class ExtHostCommentInputBox implements vscode.CommentInputBox { - private _onDidChangeValue = new Emitter(); + get resource(): vscode.Uri { + return this._resource; + } - get onDidChangeValue(): Event { - return this._onDidChangeValue.event; + get range(): vscode.Range { + return this._range; } - private _value: string = ''; + get value(): string { return this._value; } @@ -565,16 +564,24 @@ export class ExtHostCommentInputBox implements vscode.CommentInputBox { this._proxy.$setInputValue(this.commentControllerHandle, newInput); } + private _onDidChangeValue = new Emitter(); + + get onDidChangeValue(): Event { + return this._onDidChangeValue.event; + } + constructor( private _proxy: MainThreadCommentsShape, - public commentControllerHandle: number, - input: string + private _resource: vscode.Uri, + private _range: vscode.Range, + private _value: string ) { - this._value = input; } - setInput(input: string) { + setInput(resource: vscode.Uri, range: vscode.Range, input: string) { + this._resource = resource; + this._range = range; this._value = input; } } @@ -607,22 +614,22 @@ class ExtHostCommentController implements vscode.CommentController { private _threads: Map = new Map(); commentingRangeProvider?: vscode.CommentingRangeProvider & { createEmptyCommentThread: (document: vscode.TextDocument, range: types.Range) => Promise; }; - private _emptyCommentThreadFactory: vscode.EmptyCommentThreadFactory | undefined; - get emptyCommentThreadFactory(): vscode.EmptyCommentThreadFactory | undefined { - return this._emptyCommentThreadFactory; + private _template: vscode.CommentThreadTemplate | undefined; + + get template(): vscode.CommentThreadTemplate | undefined { + return this._template; } - set emptyCommentThreadFactory(newEmptyCommentThreadFactory: vscode.EmptyCommentThreadFactory | undefined) { - this._emptyCommentThreadFactory = newEmptyCommentThreadFactory; + set template(newTemplate: vscode.CommentThreadTemplate | undefined) { + this._template = newTemplate; - if (this._emptyCommentThreadFactory && this._emptyCommentThreadFactory.template) { - let template = this._emptyCommentThreadFactory.template; - const acceptInputCommand = template.acceptInputCommand ? this._commandsConverter.toInternal(template.acceptInputCommand) : undefined; - const additionalCommands = template.additionalCommands ? template.additionalCommands.map(x => this._commandsConverter.toInternal(x)) : []; - const deleteCommand = template.deleteCommand ? this._commandsConverter.toInternal(template.deleteCommand) : undefined; + if (newTemplate) { + const acceptInputCommand = newTemplate.acceptInputCommand ? this._commandsConverter.toInternal(newTemplate.acceptInputCommand) : undefined; + const additionalCommands = newTemplate.additionalCommands ? newTemplate.additionalCommands.map(x => this._commandsConverter.toInternal(x)) : []; + const deleteCommand = newTemplate.deleteCommand ? this._commandsConverter.toInternal(newTemplate.deleteCommand) : undefined; this._proxy.$updateCommentControllerFeatures(this.handle, { commentThreadTemplate: { - label: template.label, + label: newTemplate.label, acceptInputCommand, additionalCommands, deleteCommand @@ -655,17 +662,17 @@ class ExtHostCommentController implements vscode.CommentController { this._proxy.$registerCommentController(this.handle, _id, _label); } - createCommentThread(id: string, resource: vscode.Uri, range: vscode.Range, comments: vscode.Comment[]): vscode.CommentThread { + createCommentThread(id: string, resource: vscode.Uri, range: vscode.Range, comments: (vscode.Comment & vscode.CommentLegacy)[]): vscode.CommentThread { const commentThread = new ExtHostCommentThread(this._proxy, this._commandsConverter, this, id, resource, range, comments); this._threads.set(commentThread.handle, commentThread); return commentThread; } - $onCommentWidgetInputChange(input: string) { + $onCommentWidgetInputChange(uriComponents: UriComponents, range: IRange, input: string) { if (!this.inputBox) { - this.inputBox = new ExtHostCommentInputBox(this._proxy, this.handle, input); + this.inputBox = new ExtHostCommentInputBox(this._proxy, this.handle, URI.revive(uriComponents), extHostTypeConverter.Range.to(range), input); } else { - this.inputBox.setInput(input); + this.inputBox.setInput(URI.revive(uriComponents), extHostTypeConverter.Range.to(range), input); } } @@ -698,25 +705,27 @@ function convertCommentInfo(owner: number, extensionId: ExtensionIdentifier, pro function convertToCommentThread(extensionId: ExtensionIdentifier, provider: vscode.DocumentCommentProvider | vscode.WorkspaceCommentProvider, vscodeCommentThread: vscode.CommentThread, commandsConverter: CommandsConverter): modes.CommentThread { return { extensionId: extensionId.value, - threadId: vscodeCommentThread.threadId, + threadId: vscodeCommentThread.id, resource: vscodeCommentThread.resource.toString(), range: extHostTypeConverter.Range.from(vscodeCommentThread.range), - comments: vscodeCommentThread.comments.map(comment => convertToComment(provider, comment, commandsConverter)), + comments: vscodeCommentThread.comments.map(comment => convertToComment(provider, comment as vscode.Comment & vscode.CommentLegacy, commandsConverter)), collapsibleState: vscodeCommentThread.collapsibleState }; } function convertFromCommentThread(commentThread: modes.CommentThread): vscode.CommentThread { return { + id: commentThread.threadId!, threadId: commentThread.threadId!, resource: URI.parse(commentThread.resource!), range: extHostTypeConverter.Range.to(commentThread.range), comments: commentThread.comments ? commentThread.comments.map(convertFromComment) : [], - collapsibleState: commentThread.collapsibleState - }; + collapsibleState: commentThread.collapsibleState, + dispose: () => { } + } as vscode.CommentThread; } -function convertFromComment(comment: modes.Comment): vscode.Comment { +function convertFromComment(comment: modes.Comment): vscode.Comment & vscode.CommentLegacy { let userIconPath: URI | undefined; if (comment.userIconPath) { try { @@ -745,7 +754,7 @@ function convertFromComment(comment: modes.Comment): vscode.Comment { }; } -function convertToModeComment(commentController: ExtHostCommentController, vscodeComment: vscode.Comment, commandsConverter: CommandsConverter): modes.Comment { +function convertToModeComment(commentController: ExtHostCommentController, vscodeComment: vscode.Comment & vscode.CommentLegacy, commandsConverter: CommandsConverter): modes.Comment { const iconPath = vscodeComment.userIconPath ? vscodeComment.userIconPath.toString() : vscodeComment.gravatar; return { @@ -762,7 +771,7 @@ function convertToModeComment(commentController: ExtHostCommentController, vscod }; } -function convertToComment(provider: vscode.DocumentCommentProvider | vscode.WorkspaceCommentProvider, vscodeComment: vscode.Comment, commandsConverter: CommandsConverter): modes.Comment { +function convertToComment(provider: vscode.DocumentCommentProvider | vscode.WorkspaceCommentProvider, vscodeComment: vscode.Comment & vscode.CommentLegacy, commandsConverter: CommandsConverter): modes.Comment { const canEdit = !!(provider as vscode.DocumentCommentProvider).editComment && vscodeComment.canEdit; const canDelete = !!(provider as vscode.DocumentCommentProvider).deleteComment && vscodeComment.canDelete; const iconPath = vscodeComment.userIconPath ? vscodeComment.userIconPath.toString() : vscodeComment.gravatar; diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 7ab3045022ea7e782aa0fe846b0cc4ce2948d041..ffe929454e31bcd155b4661f9feafab90aff8140 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -771,6 +771,7 @@ export function createApiFactory( ColorInformation: extHostTypes.ColorInformation, ColorPresentation: extHostTypes.ColorPresentation, Comment: extHostTypes.Comment, + CommentLegacy: extHostTypes.Comment, CommentThreadCollapsibleState: extHostTypes.CommentThreadCollapsibleState, CompletionItem: extHostTypes.CompletionItem, CompletionItemKind: extHostTypes.CompletionItemKind, diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index 3f47f28f7e2e34fdcd22d00eb448a7ba22c3a835..e93018b1378501861260721c8035cfb895994316 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -310,9 +310,9 @@ export const STATUS_BAR_PROMINENT_ITEM_HOVER_BACKGROUND = registerColor('statusB }, nls.localize('statusBarProminentItemHoverBackground', "Status bar prominent items background color when hovering. Prominent items stand out from other status bar entries to indicate importance. Change mode `Toggle Tab Key Moves Focus` from command palette to see an example. The status bar is shown in the bottom of the window.")); export const STATUS_BAR_HOST_NAME_BACKGROUND = registerColor('statusBarItem.remoteBackground', { - dark: '#C40057', - light: '#C40057', - hc: '#C40057' + dark: '#16825D', + light: '#16825D', + hc: '#FFFFFF00' }, nls.localize('statusBarItemHostBackground', "Background color for the remote indicator on the status bar.")); export const STATUS_BAR_HOST_NAME_FOREGROUND = registerColor('statusBarItem.remoteForeground', { diff --git a/src/vs/workbench/contrib/comments/browser/commentService.ts b/src/vs/workbench/contrib/comments/browser/commentService.ts index f4bb3e28d9e527e643332481403a6eddabf2b1a8..296267ceb605b70ec697a5001711b5ba88e87d83 100644 --- a/src/vs/workbench/contrib/comments/browser/commentService.ts +++ b/src/vs/workbench/contrib/comments/browser/commentService.ts @@ -66,6 +66,7 @@ export interface ICommentService { deleteReaction(owner: string, resource: URI, comment: Comment, reaction: CommentReaction): Promise; getReactionGroup(owner: string): CommentReaction[] | undefined; toggleReaction(owner: string, resource: URI, thread: CommentThread2, comment: Comment, reaction: CommentReaction): Promise; + getCommentThreadFromTemplate(owner: string, resource: URI, range: IRange, ): CommentThread2 | undefined; setActiveCommentThread(commentThread: CommentThread | null): void; setInput(input: string): void; } @@ -255,6 +256,16 @@ export class CommentService extends Disposable implements ICommentService { } } + getCommentThreadFromTemplate(owner: string, resource: URI, range: IRange, ): CommentThread2 | undefined { + const commentController = this._commentControls.get(owner); + + if (commentController) { + return commentController.getCommentThreadFromTemplate(resource, range); + } + + return undefined; + } + getReactionGroup(owner: string): CommentReaction[] | undefined { const commentProvider = this._commentControls.get(owner); diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts index c8102c7e739a9ff9b01be5acd1fb8c8815874d7e..db53215e8e62d0d40b169f0e57d508b9eba9b396 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts @@ -65,6 +65,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget private _commentGlyph?: CommentGlyphWidget; private _submitActionsDisposables: IDisposable[]; private _globalToDispose: IDisposable[]; + private _commentThreadDisposables: IDisposable[] = []; private _markdownRenderer: MarkdownRenderer; private _styleElement: HTMLStyleElement; private _formActions: HTMLElement | null; @@ -103,6 +104,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._resizeObserver = null; this._isExpanded = _commentThread.collapsibleState ? _commentThread.collapsibleState === modes.CommentThreadCollapsibleState.Expanded : undefined; this._globalToDispose = []; + this._commentThreadDisposables = []; this._submitActionsDisposables = []; this._formActions = null; this.create(); @@ -214,6 +216,9 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget if (deleteCommand) { this.commentService.setActiveCommentThread(this._commentThread); return this.commandService.executeCommand(deleteCommand.id, ...(deleteCommand.arguments || [])); + } else if (this._commentEditor.getValue() === '') { + this.dispose(); + return Promise.resolve(); } } } @@ -291,6 +296,12 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._commentElements = newCommentNodeList; this.createThreadLabel(replaceTemplate); + if (replaceTemplate) { + // since we are replacing the old comment thread, we need to rebind the listeners. + this._commentThreadDisposables.forEach(global => global.dispose()); + this._commentThreadDisposables = []; + } + if (replaceTemplate) { this.createTextModelListener(); } @@ -395,7 +406,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._commentEditor.setModel(model); this._disposables.push(this._commentEditor); this._disposables.push(this._commentEditor.getModel()!.onDidChangeContent(() => this.setCommentEditorDecorations())); - if ((this._commentThread as modes.CommentThread2).commentThreadHandle !== undefined && !fromTemplate) { + if ((this._commentThread as modes.CommentThread2).commentThreadHandle !== undefined) { this.createTextModelListener(); } @@ -445,7 +456,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget } private createTextModelListener() { - this._disposables.push(this._commentEditor.onDidFocusEditorWidget(() => { + this._commentThreadDisposables.push(this._commentEditor.onDidFocusEditorWidget(() => { let commentThread = this._commentThread as modes.CommentThread2; commentThread.input = { uri: this._commentEditor.getModel()!.uri, @@ -454,7 +465,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this.commentService.setActiveCommentThread(this._commentThread); })); - this._disposables.push(this._commentEditor.getModel()!.onDidChangeContent(() => { + this._commentThreadDisposables.push(this._commentEditor.getModel()!.onDidChangeContent(() => { let modelContent = this._commentEditor.getValue(); let thread = (this._commentThread as modes.CommentThread2); if (thread.input && thread.input.uri === this._commentEditor.getModel()!.uri && thread.input.value !== modelContent) { @@ -464,7 +475,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget } })); - this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeInput(input => { + this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeInput(input => { let thread = (this._commentThread as modes.CommentThread2); if (thread.input && thread.input.uri !== this._commentEditor.getModel()!.uri) { @@ -489,31 +500,31 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget } })); - this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeComments(async _ => { + this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeComments(async _ => { await this.update(this._commentThread); })); - this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeLabel(_ => { + this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeLabel(_ => { this.createThreadLabel(); })); } private createCommentWidgetActionsListener(container: HTMLElement, model: ITextModel) { - this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeAcceptInputCommand(_ => { + this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeAcceptInputCommand(_ => { if (container) { dom.clearNode(container); this.createCommentWidgetActions2(container, model); } })); - this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeAdditionalCommands(_ => { + this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeAdditionalCommands(_ => { if (container) { dom.clearNode(container); this.createCommentWidgetActions2(container, model); } })); - this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeRange(range => { + this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeRange(range => { // Move comment glyph widget and show position if the line has changed. const lineNumber = this._commentThread.range.startLineNumber; let shouldMoveWidget = false; @@ -529,7 +540,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget } })); - this._disposables.push((this._commentThread as modes.CommentThread2).onDidChangeCollasibleState(state => { + this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeCollasibleState(state => { if (state === modes.CommentThreadCollapsibleState.Expanded && !this._isExpanded) { const lineNumber = this._commentThread.range.startLineNumber; @@ -1062,6 +1073,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget } this._globalToDispose.forEach(global => global.dispose()); + this._commentThreadDisposables.forEach(global => global.dispose()); this._submitActionsDisposables.forEach(local => local.dispose()); this._onDidClose.fire(undefined); } diff --git a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts index f3e51559ddbc415067a7035d23582cd71311e34c..d91b88891df4934f6d22137cb6d00100f867204a 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsEditorContribution.ts @@ -446,6 +446,13 @@ export class ReviewController implements IEditorContribution { return; } + let matchedNewCommentThreadZones = this._commentWidgets.filter(zoneWidget => zoneWidget.owner === e.owner && (zoneWidget.commentThread as any).commentThreadHandle === -1 && Range.equalsRange(zoneWidget.commentThread.range, thread.range)); + + if (matchedNewCommentThreadZones.length) { + matchedNewCommentThreadZones[0].update(thread, true); + return; + } + const pendingCommentText = this._pendingCommentCache[e.owner] && this._pendingCommentCache[e.owner][thread.threadId]; this.displayCommentThread(e.owner, thread, pendingCommentText, draftMode); this._commentInfos.filter(info => info.owner === e.owner)[0].threads.push(thread); @@ -462,26 +469,18 @@ export class ReviewController implements IEditorContribution { this._commentWidgets.push(zoneWidget); } - private addCommentThreadFromTemplate(lineNumber: number, ownerId: string, extensionId: string | undefined, template: modes.CommentThreadTemplate): ReviewZoneWidget { - let templateReviewZoneWidget = this.instantiationService.createInstance(ReviewZoneWidget, this.editor, ownerId, { - commentThreadHandle: -1, - label: template!.label, - acceptInputCommand: template.acceptInputCommand, - additionalCommands: template.additionalCommands, - deleteCommand: template.deleteCommand, - extensionId: extensionId, - threadId: null, - resource: null, - comments: [], - range: { - startLineNumber: lineNumber, - startColumn: 0, - endLineNumber: lineNumber, - endColumn: 0 - }, - collapsibleState: modes.CommentThreadCollapsibleState.Expanded, - }, - '', modes.DraftMode.NotSupported); + private addCommentThreadFromTemplate(lineNumber: number, ownerId: string): ReviewZoneWidget { + let templateCommentThread = this.commentService.getCommentThreadFromTemplate(ownerId, this.editor.getModel()!.uri, { + startLineNumber: lineNumber, + startColumn: 1, + endLineNumber: lineNumber, + endColumn: 1 + })!; + + templateCommentThread.collapsibleState = modes.CommentThreadCollapsibleState.Expanded; + templateCommentThread.comments = []; + + let templateReviewZoneWidget = this.instantiationService.createInstance(ReviewZoneWidget, this.editor, ownerId, templateCommentThread, '', modes.DraftMode.NotSupported); return templateReviewZoneWidget; } @@ -692,22 +691,19 @@ export class ReviewController implements IEditorContribution { public addCommentAtLine2(lineNumber: number, replyCommand: modes.Command | undefined, ownerId: string, extensionId: string | undefined, commentingRangesInfo: modes.CommentingRanges | undefined, template: modes.CommentThreadTemplate | undefined) { if (commentingRangesInfo) { let range = new Range(lineNumber, 1, lineNumber, 1); - if (commentingRangesInfo.newCommentThreadCallback && template) { + if (template) { // create comment widget through template - let commentThreadWidget = this.addCommentThreadFromTemplate(lineNumber, ownerId, extensionId, template); + let commentThreadWidget = this.addCommentThreadFromTemplate(lineNumber, ownerId); commentThreadWidget.display(lineNumber, true); - - return commentingRangesInfo.newCommentThreadCallback(this.editor.getModel()!.uri, range) - .then(commentThread => { - commentThreadWidget.update(commentThread!, true); - this._commentWidgets.push(commentThreadWidget); - this.processNextThreadToAdd(); - }) - .catch(e => { - this.notificationService.error(nls.localize('commentThreadAddFailure', "Adding a new comment thread failed: {0}.", e.message)); - commentThreadWidget.dispose(); - this.processNextThreadToAdd(); - }); + this._commentWidgets.push(commentThreadWidget); + commentThreadWidget.onDidClose(() => { + this._commentWidgets = this._commentWidgets.filter(zoneWidget => !( + zoneWidget.owner === commentThreadWidget.owner && + (zoneWidget.commentThread as any).commentThreadHandle === -1 && + Range.equalsRange(zoneWidget.commentThread.range, commentThreadWidget.commentThread.range) + )); + }); + this.processNextThreadToAdd(); } else if (commentingRangesInfo.newCommentThreadCallback) { return commentingRangesInfo.newCommentThreadCallback(this.editor.getModel()!.uri, range) .then(_ => { diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts index 5ba5b7377fc72ec96e538a94460fbe51db0b5057..c34a342320fd2d9eb566cea979770e536635a379 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsWidgets.ts @@ -168,7 +168,7 @@ export class TooltipWidget extends ExtensionWidget { this.parent.removeAttribute('aria-label'); this.parent.title = this.getTooltip(); if (this.extension) { - this.parent.setAttribute('aria-label', localize('extension-arialabel', "{0}. {1} Press enter for extension details.", this.extension.displayName)); + this.parent.setAttribute('aria-label', localize('extension-arialabel', "{0}. Press enter for extension details.", this.extension.displayName)); } } diff --git a/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts b/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts index 5b7340c997d0d3dbe9716df58c4a63f9f808b02b..0e8c29a2706276a4674bc1f464babbbbcf0a7dc6 100644 --- a/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts +++ b/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts @@ -19,7 +19,7 @@ import { ResourceMap } from 'vs/base/common/map'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { FileOnDiskContentProvider } from 'vs/workbench/contrib/files/common/files'; +import { FileOnDiskContentProvider, resourceToFileOnDisk } from 'vs/workbench/contrib/files/common/files'; import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; import { IModelService } from 'vs/editor/common/services/modelService'; import { SAVE_FILE_COMMAND_ID, REVERT_FILE_COMMAND_ID, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL } from 'vs/workbench/contrib/files/browser/fileCommands'; @@ -248,7 +248,7 @@ class ResolveSaveConflictAction extends Action { return this.editorService.openEditor( { - leftResource: resource.with({ scheme: CONFLICT_RESOLUTION_SCHEME }), + leftResource: resourceToFileOnDisk(CONFLICT_RESOLUTION_SCHEME, resource), rightResource: resource, label: editorLabel, options: { pinned: true } diff --git a/src/vs/workbench/contrib/files/common/files.ts b/src/vs/workbench/contrib/files/common/files.ts index 56ce9d0b9898a0f59dc715ee8cb89e46be1bccf3..f0b2a14c926d791209b7116915f5fee07edef9ba 100644 --- a/src/vs/workbench/contrib/files/common/files.ts +++ b/src/vs/workbench/contrib/files/common/files.ts @@ -23,8 +23,6 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; import { once } from 'vs/base/common/functional'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { toLocalResource } from 'vs/base/common/resources'; /** * Explorer viewlet id. @@ -133,6 +131,14 @@ export const SortOrderConfiguration = { export type SortOrder = 'default' | 'mixed' | 'filesFirst' | 'type' | 'modified'; +export function resourceToFileOnDisk(scheme: string, resource: URI): URI { + return resource.with({ scheme, query: JSON.stringify({ scheme: resource.scheme }) }); +} + +export function fileOnDiskToResource(resource: URI): URI { + return resource.with({ scheme: JSON.parse(resource.query)['scheme'], query: null }); +} + export class FileOnDiskContentProvider implements ITextModelContentProvider { private fileWatcherDisposable: IDisposable | undefined; @@ -140,13 +146,12 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider { @ITextFileService private readonly textFileService: ITextFileService, @IFileService private readonly fileService: IFileService, @IModeService private readonly modeService: IModeService, - @IModelService private readonly modelService: IModelService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService + @IModelService private readonly modelService: IModelService ) { } provideTextContent(resource: URI): Promise { - const savedFileResource = toLocalResource(resource, this.environmentService.configuration.remoteAuthority); + const savedFileResource = fileOnDiskToResource(resource); // Make sure our file from disk is resolved up to date return this.resolveEditorModel(resource).then(codeEditorModel => { @@ -174,7 +179,7 @@ export class FileOnDiskContentProvider implements ITextModelContentProvider { private resolveEditorModel(resource: URI, createAsNeeded?: true): Promise; private resolveEditorModel(resource: URI, createAsNeeded?: boolean): Promise; private resolveEditorModel(resource: URI, createAsNeeded: boolean = true): Promise { - const savedFileResource = toLocalResource(resource, this.environmentService.configuration.remoteAuthority); + const savedFileResource = fileOnDiskToResource(resource); return this.textFileService.readStream(savedFileResource).then(content => { let codeEditorModel = this.modelService.getModel(resource); diff --git a/src/vs/workbench/contrib/files/test/common/fileOnDiskProvider.test.ts b/src/vs/workbench/contrib/files/test/common/fileOnDiskProvider.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..62fcf91ca425ec8b68876c9d82ce3228987b3e8d --- /dev/null +++ b/src/vs/workbench/contrib/files/test/common/fileOnDiskProvider.test.ts @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { URI } from 'vs/base/common/uri'; +import { workbenchInstantiationService, TestFileService } from 'vs/workbench/test/workbenchTestServices'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { FileOnDiskContentProvider, resourceToFileOnDisk } from 'vs/workbench/contrib/files/common/files'; +import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; +import { IFileService } from 'vs/platform/files/common/files'; + +class ServiceAccessor { + constructor( + @IFileService public fileService: TestFileService + ) { + } +} + +suite('Files - FileOnDiskContentProvider', () => { + + let instantiationService: IInstantiationService; + let accessor: ServiceAccessor; + + setup(() => { + instantiationService = workbenchInstantiationService(); + accessor = instantiationService.createInstance(ServiceAccessor); + }); + + test('provideTextContent', async () => { + const provider = instantiationService.createInstance(FileOnDiskContentProvider); + const uri = URI.parse('testFileOnDiskContentProvider://foo'); + + const content = await provider.provideTextContent(resourceToFileOnDisk('conflictResolution', uri)); + + assert.equal(snapshotToString(content.createSnapshot()), 'Hello Html'); + assert.equal(accessor.fileService.getLastReadFileUri().toString(), uri.toString()); + }); +}); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 411f524fd5e011b489b7ae933a6c7eec270f34fb..89df06ec1415b24e9c25612dff9e2de17d5c1379 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -899,6 +899,7 @@ export class TestFileService implements IFileService { readonly onError: Event = Event.None; private content = 'Hello Html'; + private lastReadFileUri: URI; constructor() { this._onFileChanges = new Emitter(); @@ -913,6 +914,10 @@ export class TestFileService implements IFileService { return this.content; } + public getLastReadFileUri(): URI { + return this.lastReadFileUri; + } + public get onFileChanges(): Event { return this._onFileChanges.event; } @@ -952,6 +957,8 @@ export class TestFileService implements IFileService { } readFile(resource: URI, options?: IReadFileOptions | undefined): Promise { + this.lastReadFileUri = resource; + return Promise.resolve({ resource: resource, value: VSBuffer.fromString(this.content), @@ -964,6 +971,8 @@ export class TestFileService implements IFileService { } readFileStream(resource: URI, options?: IReadFileOptions | undefined): Promise { + this.lastReadFileUri = resource; + return Promise.resolve({ resource: resource, value: { diff --git a/test/smoke/src/areas/extensions/extensions.test.ts b/test/smoke/src/areas/extensions/extensions.test.ts index d705254e193486bee808ff32f5b08ec593bb1f54..4215a7fe24741a0a6a9a2e01beb69c3174ee17d5 100644 --- a/test/smoke/src/areas/extensions/extensions.test.ts +++ b/test/smoke/src/areas/extensions/extensions.test.ts @@ -15,10 +15,9 @@ export function setup() { return; } - const extensionName = 'vscode-smoketest-check'; await app.workbench.extensions.openExtensionsViewlet(); - await app.workbench.extensions.installExtension(extensionName); + await app.workbench.extensions.installExtension('michelkaporin.vscode-smoketest-check', 'vscode-smoketest-check'); await app.workbench.extensions.waitForExtensionsViewlet(); await app.workbench.quickopen.runCommand('Smoke Test Check'); diff --git a/test/smoke/src/areas/extensions/extensions.ts b/test/smoke/src/areas/extensions/extensions.ts index bf9748c466e2d0bab81211ce001eef16b5cb084e..899783e4f64b8a42dcb85fa051f755fcaa22b7d7 100644 --- a/test/smoke/src/areas/extensions/extensions.ts +++ b/test/smoke/src/areas/extensions/extensions.ts @@ -28,14 +28,14 @@ export class Extensions extends Viewlet { await this.code.waitForElement(SEARCH_BOX); } - async searchForExtension(name: string): Promise { + async searchForExtension(id: string): Promise { await this.code.waitAndClick(SEARCH_BOX); await this.code.waitForActiveElement(SEARCH_BOX); - await this.code.waitForTypeInEditor(SEARCH_BOX, `name:"${name}"`); + await this.code.waitForTypeInEditor(SEARCH_BOX, `@id:${id}`); } - async installExtension(name: string): Promise { - await this.searchForExtension(name); + async installExtension(id: string, name: string): Promise { + await this.searchForExtension(id); const ariaLabel = `${name}. Press enter for extension details.`; await this.code.waitAndClick(`div.extensions-viewlet[id="workbench.view.extensions"] .monaco-list-row[aria-label="${ariaLabel}"] .extension li[class='action-item'] .extension-action.install`); await this.code.waitForElement(`.extension-editor .monaco-action-bar .action-item:not(.disabled) .extension-action.uninstall`); diff --git a/test/smoke/src/areas/workbench/localization.test.ts b/test/smoke/src/areas/workbench/localization.test.ts index dace3cc683e3b7aeb6fc4b847cc6e2292cdc93df..c0844c2c6bfd44d6b7fa1ce0086057a6f5b26c5e 100644 --- a/test/smoke/src/areas/workbench/localization.test.ts +++ b/test/smoke/src/areas/workbench/localization.test.ts @@ -14,9 +14,8 @@ export function setup() { return; } - const extensionName = 'German Language Pack for Visual Studio Code'; await app.workbench.extensions.openExtensionsViewlet(); - await app.workbench.extensions.installExtension(extensionName); + await app.workbench.extensions.installExtension('ms-ceintl.vscode-language-pack-de', 'German Language Pack for Visual Studio Code'); await app.restart({ extraArgs: ['--locale=DE'] }); });