From ad8e77725b384870bfdd29fca4599d34ce3821c1 Mon Sep 17 00:00:00 2001 From: Peng Lyu Date: Tue, 30 Apr 2019 15:08:11 -0700 Subject: [PATCH] Update comments api. --- comment-sample/src/extension.ts | 119 +++++++------ .../src/typings/vscode.proposed.d.ts | 167 ++++++++++++++---- 2 files changed, 197 insertions(+), 89 deletions(-) diff --git a/comment-sample/src/extension.ts b/comment-sample/src/extension.ts index 094c4626..e57d6c3f 100644 --- a/comment-sample/src/extension.ts +++ b/comment-sample/src/extension.ts @@ -15,61 +15,80 @@ export function activate(context: vscode.ExtensionContext) { provideCommentingRanges: (document: vscode.TextDocument, token: vscode.CancellationToken) => { let lineCount = document.lineCount; return [new vscode.Range(0, 0, lineCount - 1, 0)]; - }, - // callback when users click `+` button on Gutter or run Create Comment command from Command Palette - createEmptyCommentThread: (document: vscode.TextDocument, range: vscode.Range) => { - // create a empty thread - let thread = commentController.createCommentThread(`${++threadId}`, document.uri, range, []); - // by default, a comment thread is collapsed, for newly created empty comment thread, we want to expand it and users can start commenting immediately - thread.collapsibleState = vscode.CommentThreadCollapsibleState.Expanded; - - // In this example, we call it `Create New Note` while for GH PR case, we can call it `Start Review` or `Start New Converstation` - thread.label = 'Create New Note'; - - // We will render all `acceptInputCommands` as Actions on the bottom of Comment Widget in the editor. - thread.acceptInputCommand = { - title: 'Create Note', - command: 'mywiki.createNote', - // Command is responsible for arguments - arguments: [ - commentController, - thread - ] - }; - - thread.deleteCommand = { - title: 'Delete Note', - command: 'mywiki.deleteNote', - arguments: [ - thread - ] - }; + } + }; + + commentController.template = { + label: 'Create New Note:', + acceptInputCommand: { + title: 'Create Note', + command: 'mywiki.createNote', + // Command is responsible for arguments + arguments: [ + commentController + ] } }; // register `mywiki.createNote` command - context.subscriptions.push(vscode.commands.registerCommand('mywiki.createNote', (commentController: vscode.CommentController, thread: vscode.CommentThread) => { + context.subscriptions.push(vscode.commands.registerCommand('mywiki.createNote', (commentController: vscode.CommentController, thread: vscode.CommentThread | undefined) => { if (commentController.inputBox) { - // Read text from the focused textarea in the Comment Widget. - let text = commentController.inputBox.value; - let markedString = new vscode.MarkdownString(text); - let newComment: vscode.Comment = { commentId: `${++commentId}`, body: markedString, userName: 'vscode' }; + if (!thread) { + // the comment thread is created from comment thread template + let thread = commentController.createCommentThread(`${++threadId}`, commentController.inputBox.resource, commentController.inputBox.range, []); + // by default, a comment thread is collapsed, for newly created empty comment thread, we want to expand it and users can start commenting immediately + thread.collapsibleState = vscode.CommentThreadCollapsibleState.Expanded; - thread.comments = [newComment]; - thread.label = 'Participants: vscode'; - - // After we create the new comment thread, we may want to update the actions on the Comment Widget. - thread.acceptInputCommand = { - title: 'Create Comment', - command: 'mywiki.createComment', - arguments: [ - commentController, - thread - ] - }; - - // Lastly, we want to clear the textarea in Comment Widget. - commentController.inputBox.value = ''; + // In this example, we call it `Create New Note` while for GH PR case, we can call it `Start Review` or `Start New Converstation` + let text = commentController.inputBox.value; + let markedString = new vscode.MarkdownString(text); + let newComment = new vscode.Comment(`${++commentId}`, markedString, 'vscode'); + + thread.comments = [newComment]; + thread.label = 'Participants: vscode'; + + // We will render all `acceptInputCommands` as Actions on the bottom of Comment Widget in the editor. + thread.acceptInputCommand = { + title: 'Create Comment', + command: 'mywiki.createComment', + arguments: [ + commentController, + thread + ] + }; + + thread.deleteCommand = { + title: 'Delete Note', + command: 'mywiki.deleteNote', + arguments: [ + thread + ] + }; + + // Lastly, we want to clear the textarea in Comment Widget. + commentController.inputBox.value = ''; + } else { + // Read text from the focused textarea in the Comment Widget. + let text = commentController.inputBox.value; + let markedString = new vscode.MarkdownString(text); + let newComment = new vscode.Comment(`${++commentId}`, markedString, 'vscode'); + + thread.comments = [newComment]; + thread.label = 'Participants: vscode'; + + // After we create the new comment thread, we may want to update the actions on the Comment Widget. + thread.acceptInputCommand = { + title: 'Create Comment', + command: 'mywiki.createComment', + arguments: [ + commentController, + thread + ] + }; + + // Lastly, we want to clear the textarea in Comment Widget. + commentController.inputBox.value = ''; + } } })); @@ -77,7 +96,7 @@ export function activate(context: vscode.ExtensionContext) { if (commentController.inputBox) { let text = commentController.inputBox.value; let markedString = new vscode.MarkdownString(text); - let newComment: vscode.Comment = { commentId: `${++commentId}`, body: markedString, userName: 'vscode' }; + let newComment = new vscode.Comment(`${++commentId}`, markedString, 'vscode'); thread.comments = [...thread.comments, newComment]; commentController.inputBox.value = ''; diff --git a/comment-sample/src/typings/vscode.proposed.d.ts b/comment-sample/src/typings/vscode.proposed.d.ts index e5b5e7d4..ef1b2c19 100644 --- a/comment-sample/src/typings/vscode.proposed.d.ts +++ b/comment-sample/src/typings/vscode.proposed.d.ts @@ -17,11 +17,18 @@ import { Range } from "vscode"; */ declare module 'vscode' { + + //#region Comments + + /** + * Collapsible state of a [comment thread](#CommentThread) + */ export enum CommentThreadCollapsibleState { /** * Determines an item is collapsed */ Collapsed = 0, + /** * Determines an item is expanded */ @@ -29,35 +36,41 @@ declare module 'vscode' { } /** - * A collection of comments representing a conversation at a particular range in a document. + * 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. */ - threadId: string; + readonly id: string; /** * The uri of the document the thread has been created on. */ - resource: Uri; + 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. */ - range: Range; - - /** - * The human-readable label describing the [Comment Thread](#CommentThread) - */ - label?: string; + 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 * @@ -74,12 +87,6 @@ declare module 'vscode' { */ 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. @@ -88,36 +95,37 @@ declare module 'vscode' { /** * Dispose this comment thread. - * Once disposed, the comment thread will be removed from visible text editors and Comments Panel. + * + * Once disposed, this comment thread will be removed from visible editors and Comment Panel when approriate. */ - dispose?(): void; + dispose(): void; } /** * A comment is displayed within the editor or the Comments Panel, depending on how it is provided. */ - export interface Comment { + export class Comment { /** * The id of the comment */ - readonly commentId: string; + readonly id: string; /** - * The text of the comment + * 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 display name of the user who created the comment - */ - readonly userName: string; - /** * The icon path for the user who created the comment */ @@ -137,32 +145,81 @@ declare module 'vscode' { * 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. + * 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; - - /** - * The method `createEmptyCommentThread` is called when users attempt to create new comment thread from the gutter or command palette. - * Extensions still need to call `createCommentThread` inside this call when appropriate. - */ - createEmptyCommentThread(document: TextDocument, range: Range): 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. @@ -175,30 +232,62 @@ declare module 'vscode' { readonly label: string; /** - * The active (focused) [comment input box](#CommentInputBox). + * 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; + readonly inputBox: CommentInputBox | undefined; /** - * Create a [CommentThread](#CommentThread) + * 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. */ - createCommentThread(id: string, resource: Uri, range: Range, comments: Comment[]): CommentThread; + template?: CommentThreadTemplate; /** - * Optional commenting range provider. - * Provide a list [ranges](#Range) which support commenting to any given resource uri. + * 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 + }