Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose comments input as text document #209512

Merged
merged 5 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/vs/base/common/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ export namespace Schemas {
*/
export const vscodeSourceControl = 'vscode-scm';

/**
* Scheme used for input box for creating comments.
*/
export const commentsInput = 'comment';

/**
* Scheme used for special rendering of settings in the release notes
*/
Expand Down
8 changes: 7 additions & 1 deletion src/vs/platform/markers/common/markerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { IMarker, IMarkerData, IMarkerService, IResourceMarker, MarkerSeverity, MarkerStatistics } from './markers';

export const unsupportedSchemas = new Set([Schemas.inMemory, Schemas.vscodeSourceControl, Schemas.walkThrough, Schemas.walkThroughSnippet, Schemas.vscodeChatCodeBlock]);
export const unsupportedSchemas = new Set([
Schemas.inMemory,
Schemas.vscodeSourceControl,
Schemas.walkThrough,
Schemas.walkThroughSnippet,
Schemas.vscodeChatCodeBlock,
]);

class DoubleResourceMap<V> {

Expand Down
42 changes: 22 additions & 20 deletions src/vs/workbench/contrib/comments/browser/commentNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,8 @@ import * as dom from 'vs/base/browser/dom';
import * as languages from 'vs/editor/common/languages';
import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action, IActionRunner, IAction, Separator, ActionRunner } from 'vs/base/common/actions';
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Disposable, IDisposable, IReference, dispose } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ITextModel } from 'vs/editor/common/model';
import { IModelService } from 'vs/editor/common/services/model';
import { ILanguageService } from 'vs/editor/common/languages/language';
import { MarkdownRenderer } from 'vs/editor/browser/widget/markdownRenderer/browser/markdownRenderer';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ICommentService } from 'vs/workbench/contrib/comments/browser/commentService';
Expand Down Expand Up @@ -45,13 +42,14 @@ import { Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';
import { SmoothScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { DomEmitter } from 'vs/base/browser/event';
import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/commentContextKeys';
import { FileAccess } from 'vs/base/common/network';
import { FileAccess, Schemas } from 'vs/base/common/network';
import { COMMENTS_SECTION, ICommentsConfiguration } from 'vs/workbench/contrib/comments/common/commentsConfiguration';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { MarshalledCommentThread } from 'vs/workbench/common/comments';
import { IHoverService } from 'vs/platform/hover/browser/hover';
import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService';

class CommentsActionRunner extends ActionRunner {
protected override async runAction(action: IAction, context: any[]): Promise<void> {
Expand All @@ -75,7 +73,7 @@ export class CommentNode<T extends IRange | ICellRange> extends Disposable {
private _reactionActionsContainer?: HTMLElement;
private _commentEditor: SimpleCommentEditor | null = null;
private _commentEditorDisposables: IDisposable[] = [];
private _commentEditorModel: ITextModel | null = null;
private _commentEditorModel: IReference<IResolvedTextEditorModel> | null = null;
private _editorHeight = MIN_EDITOR_HEIGHT;

private _isPendingLabel!: HTMLElement;
Expand Down Expand Up @@ -112,15 +110,14 @@ export class CommentNode<T extends IRange | ICellRange> extends Disposable {
private markdownRenderer: MarkdownRenderer,
@IInstantiationService private instantiationService: IInstantiationService,
@ICommentService private commentService: ICommentService,
@IModelService private modelService: IModelService,
@ILanguageService private languageService: ILanguageService,
@INotificationService private notificationService: INotificationService,
@IContextMenuService private contextMenuService: IContextMenuService,
@IContextKeyService contextKeyService: IContextKeyService,
@IConfigurationService private configurationService: IConfigurationService,
@IHoverService private hoverService: IHoverService,
@IAccessibilityService private accessibilityService: IAccessibilityService,
@IKeybindingService private keybindingService: IKeybindingService
@IKeybindingService private keybindingService: IKeybindingService,
@ITextModelService private readonly textModelService: ITextModelService,
) {
super();

Expand Down Expand Up @@ -494,13 +491,18 @@ export class CommentNode<T extends IRange | ICellRange> extends Disposable {
return (typeof this.comment.body === 'string') ? this.comment.body : this.comment.body.value;
}

private createCommentEditor(editContainer: HTMLElement): void {
private async createCommentEditor(editContainer: HTMLElement): Promise<void> {
const container = dom.append(editContainer, dom.$('.edit-textarea'));
this._commentEditor = this.instantiationService.createInstance(SimpleCommentEditor, container, SimpleCommentEditor.getEditorOptions(this.configurationService), this._contextKeyService, this.parentThread);
const resource = URI.parse(`comment:commentinput-${this.comment.uniqueIdInThread}-${Date.now()}.md`);
this._commentEditorModel = this.modelService.createModel('', this.languageService.createByFilepathOrFirstLine(resource), resource, false);

this._commentEditor.setModel(this._commentEditorModel);
const resource = URI.from({
scheme: Schemas.commentsInput,
path: `/commentinput-${this.comment.uniqueIdInThread}-${Date.now()}.md`
});
const modelRef = await this.textModelService.createModelReference(resource);
this._commentEditorModel = modelRef;

this._commentEditor.setModel(this._commentEditorModel.object.textEditorModel);
this._commentEditor.setValue(this.pendingEdit ?? this.commentBodyValue);
this.pendingEdit = undefined;
this._commentEditor.layout({ width: container.clientWidth - 14, height: this._editorHeight });
Expand All @@ -511,8 +513,8 @@ export class CommentNode<T extends IRange | ICellRange> extends Disposable {
this._commentEditor!.focus();
});

const lastLine = this._commentEditorModel.getLineCount();
const lastColumn = this._commentEditorModel.getLineLength(lastLine) + 1;
const lastLine = this._commentEditorModel.object.textEditorModel.getLineCount();
const lastColumn = this._commentEditorModel.object.textEditorModel.getLineLength(lastLine) + 1;
this._commentEditor.setSelection(new Selection(lastLine, lastColumn, lastLine, lastColumn));

const commentThread = this.commentThread;
Expand Down Expand Up @@ -547,7 +549,7 @@ export class CommentNode<T extends IRange | ICellRange> extends Disposable {

this.calculateEditorHeight();

this._register((this._commentEditorModel.onDidChangeContent(() => {
this._register((this._commentEditorModel.object.textEditorModel.onDidChangeContent(() => {
if (this._commentEditor && this.calculateEditorHeight()) {
this._commentEditor.layout({ height: this._editorHeight, width: this._commentEditor.getLayoutInfo().width });
this._commentEditor.render(true);
Expand Down Expand Up @@ -604,15 +606,15 @@ export class CommentNode<T extends IRange | ICellRange> extends Disposable {
this._scrollableElement.setScrollDimensions({ width, scrollWidth, height, scrollHeight });
}

public switchToEditMode() {
public async switchToEditMode() {
alexr00 marked this conversation as resolved.
Show resolved Hide resolved
if (this.isEditing) {
return;
}

this.isEditing = true;
this._body.classList.add('hidden');
this._commentEditContainer = dom.append(this._commentDetailsContainer, dom.$('.edit-container'));
this.createCommentEditor(this._commentEditContainer);
await this.createCommentEditor(this._commentEditContainer);

const formActions = dom.append(this._commentEditContainer, dom.$('.form-actions'));
const otherActions = dom.append(formActions, dom.$('.other-actions'));
Expand Down Expand Up @@ -705,7 +707,7 @@ export class CommentNode<T extends IRange | ICellRange> extends Disposable {
}));
}

update(newComment: languages.Comment) {
async update(newComment: languages.Comment) {

if (newComment.body !== this.comment.body) {
this.updateCommentBody(newComment.body);
Expand All @@ -721,7 +723,7 @@ export class CommentNode<T extends IRange | ICellRange> extends Disposable {

if (isChangingMode) {
if (newComment.mode === languages.CommentMode.Editing) {
this.switchToEditMode();
await this.switchToEditMode();
} else {
this.removeCommentEditor();
}
Expand Down
41 changes: 24 additions & 17 deletions src/vs/workbench/contrib/comments/browser/commentReply.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@
*--------------------------------------------------------------------------------------------*/

import * as dom from 'vs/base/browser/dom';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';
import { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';
import { IAction } from 'vs/base/common/actions';
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { MarshalledId } from 'vs/base/common/marshallingIds';
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { generateUuid } from 'vs/base/common/uuid';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { IRange } from 'vs/editor/common/core/range';
import * as languages from 'vs/editor/common/languages';
import { ILanguageService } from 'vs/editor/common/languages/language';
import { ITextModel } from 'vs/editor/common/model';
import { IModelService } from 'vs/editor/common/services/model';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import * as nls from 'vs/nls';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { editorForeground, resolveColorValue } from 'vs/platform/theme/common/colorRegistry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { CommentFormActions } from 'vs/workbench/contrib/comments/browser/commentFormActions';
Expand All @@ -29,11 +31,8 @@ import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/comment
import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget';
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
import { LayoutableEditor, MIN_EDITOR_HEIGHT, SimpleCommentEditor, calculateEditorHeight } from './simpleCommentEditor';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';
import { IHoverService } from 'vs/platform/hover/browser/hover';

const COMMENT_SCHEME = 'comment';
let INMEM_MODEL_ID = 0;
export const COMMENTEDITOR_DECORATION_KEY = 'commenteditordecoration';

Expand All @@ -42,8 +41,8 @@ export class CommentReply<T extends IRange | ICellRange> extends Disposable {
form: HTMLElement;
commentEditorIsEmpty: IContextKey<boolean>;
private _error!: HTMLElement;
private _formActions: HTMLElement | null;
private _editorActions: HTMLElement | null;
private _formActions!: HTMLElement;
private _editorActions!: HTMLElement;
private _commentThreadDisposables: IDisposable[] = [];
private _commentFormActions!: CommentFormActions;
private _commentEditorActions!: CommentFormActions;
Expand All @@ -63,12 +62,11 @@ export class CommentReply<T extends IRange | ICellRange> extends Disposable {
private _parentThread: ICommentThreadWidget,
private _actionRunDelegate: (() => void) | null,
@ICommentService private commentService: ICommentService,
@ILanguageService private languageService: ILanguageService,
@IModelService private modelService: IModelService,
@IThemeService private themeService: IThemeService,
@IConfigurationService configurationService: IConfigurationService,
@IKeybindingService private keybindingService: IKeybindingService,
@IHoverService private hoverService: IHoverService,
@ITextModelService private readonly textModelService: ITextModelService
) {
super();

Expand All @@ -77,32 +75,41 @@ export class CommentReply<T extends IRange | ICellRange> extends Disposable {
this.commentEditorIsEmpty = CommentContextKeys.commentIsEmpty.bindTo(this._contextKeyService);
this.commentEditorIsEmpty.set(!this._pendingComment);

this.initialize();
}

async initialize() {
const hasExistingComments = this._commentThread.comments && this._commentThread.comments.length > 0;
const modeId = generateUuid() + '-' + (hasExistingComments ? this._commentThread.threadId : ++INMEM_MODEL_ID);
const params = JSON.stringify({
extensionId: this._commentThread.extensionId,
commentThreadId: this._commentThread.threadId
});

let resource = URI.parse(`${COMMENT_SCHEME}://${this._commentThread.extensionId}/commentinput-${modeId}.md?${params}`); // TODO. Remove params once extensions adopt authority.
const commentController = this.commentService.getCommentController(owner);
let resource = URI.from({
scheme: Schemas.commentsInput,
path: `/${this._commentThread.extensionId}/commentinput-${modeId}.md?${params}` // TODO. Remove params once extensions adopt authority.
});
const commentController = this.commentService.getCommentController(this.owner);
if (commentController) {
resource = resource.with({ authority: commentController.id });
}

const model = this.modelService.createModel(this._pendingComment || '', this.languageService.createByFilepathOrFirstLine(resource), resource, false);
const model = await this.textModelService.createModelReference(resource);
alexr00 marked this conversation as resolved.
Show resolved Hide resolved
model.object.textEditorModel.setValue(this._pendingComment || '');

this._register(model);
this.commentEditor.setModel(model);
this.commentEditor.setModel(model.object.textEditorModel);
this.calculateEditorHeight();

this._register((model.onDidChangeContent(() => {
this._register(model.object.textEditorModel.onDidChangeContent(() => {
this.setCommentEditorDecorations();
this.commentEditorIsEmpty?.set(!this.commentEditor.getValue());
if (this.calculateEditorHeight()) {
this.commentEditor.layout({ height: this._editorHeight, width: this.commentEditor.getLayoutInfo().width });
this.commentEditor.render(true);
}
})));
}));

this.createTextModelListener(this.commentEditor, this.form);

Expand All @@ -117,9 +124,9 @@ export class CommentReply<T extends IRange | ICellRange> extends Disposable {
this._error = dom.append(this.form, dom.$('.validation-error.hidden'));
const formActions = dom.append(this.form, dom.$('.form-actions'));
this._formActions = dom.append(formActions, dom.$('.other-actions'));
this.createCommentWidgetFormActions(this._formActions, model);
this.createCommentWidgetFormActions(this._formActions, model.object.textEditorModel);
this._editorActions = dom.append(formActions, dom.$('.editor-actions'));
this.createCommentWidgetEditorActions(this._editorActions, model);
this.createCommentWidgetEditorActions(this._editorActions, model.object.textEditorModel);
}

private calculateEditorHeight(): boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class CommentThreadBody<T extends IRange | ICellRange = IRange> extends D
this._commentsElement.focus();
}

display() {
async display() {
this._commentsElement = dom.append(this.container, dom.$('div.comments-container'));
this._commentsElement.setAttribute('role', 'presentation');
this._commentsElement.tabIndex = 0;
Expand Down Expand Up @@ -98,7 +98,7 @@ export class CommentThreadBody<T extends IRange | ICellRange = IRange> extends D
this._commentElements.push(newCommentNode);
this._commentsElement.appendChild(newCommentNode.domNode);
if (comment.mode === languages.CommentMode.Editing) {
newCommentNode.switchToEditMode();
await newCommentNode.switchToEditMode();
}
}
}
Expand Down Expand Up @@ -156,7 +156,7 @@ export class CommentThreadBody<T extends IRange | ICellRange = IRange> extends D
return;
}

updateCommentThread(commentThread: languages.CommentThread<T>, preserveFocus: boolean) {
async updateCommentThread(commentThread: languages.CommentThread<T>, preserveFocus: boolean) {
const oldCommentsLen = this._commentElements.length;
const newCommentsLen = commentThread.comments ? commentThread.comments.length : 0;

Expand Down Expand Up @@ -207,7 +207,7 @@ export class CommentThreadBody<T extends IRange | ICellRange = IRange> extends D
}

if (currentComment.mode === languages.CommentMode.Editing) {
newElement.switchToEditMode();
await newElement.switchToEditMode();
newCommentsInEditMode.push(newElement);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export class CommentThreadWidget<T extends IRange | ICellRange = IRange> extends
}, true));
}

updateCommentThread(commentThread: languages.CommentThread<T>) {
async updateCommentThread(commentThread: languages.CommentThread<T>) {
const shouldCollapse = (this._commentThread.collapsibleState === languages.CommentThreadCollapsibleState.Expanded) && (this._commentThreadState === languages.CommentThreadState.Unresolved)
&& (commentThread.state === languages.CommentThreadState.Resolved);
this._commentThreadState = commentThread.state;
Expand All @@ -214,7 +214,7 @@ export class CommentThreadWidget<T extends IRange | ICellRange = IRange> extends
this._commentThreadDisposables = [];
this._bindCommentThreadListeners();

this._body.updateCommentThread(commentThread, this._commentReply?.isCommentEditorFocused() ?? false);
await this._body.updateCommentThread(commentThread, this._commentReply?.isCommentEditorFocused() ?? false);
this._threadIsEmpty.set(!this._body.length);
this._header.updateCommentThread(commentThread);
this._commentReply?.updateCommentThread(commentThread);
Expand All @@ -230,11 +230,11 @@ export class CommentThreadWidget<T extends IRange | ICellRange = IRange> extends
}
}

display(lineHeight: number) {
async display(lineHeight: number) {
const headHeight = Math.max(23, Math.ceil(lineHeight * 1.2)); // 23 is the value of `Math.ceil(lineHeight * 1.2)` with the default editor font size
this._header.updateHeight(headHeight);

this._body.display();
await this._body.display();

// create comment thread only when it supports reply
if (this._commentThread.canReply) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this.bindCommentThreadListeners();
}

this._commentThreadWidget.updateCommentThread(commentThread);
await this._commentThreadWidget.updateCommentThread(commentThread);

// Move comment glyph widget and show position if the line has changed.
const lineNumber = this._commentThread.range?.endLineNumber ?? 1;
Expand Down Expand Up @@ -356,13 +356,13 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
this._commentThreadWidget.layout(widthInPixel);
}

display(range: IRange | undefined) {
async display(range: IRange | undefined) {
if (range) {
this._commentGlyph = new CommentGlyphWidget(this.editor, range?.endLineNumber ?? -1);
this._commentGlyph.setThreadState(this._commentThread.state);
}

this._commentThreadWidget.display(this.editor.getOption(EditorOption.lineHeight));
await this._commentThreadWidget.display(this.editor.getOption(EditorOption.lineHeight));
this._disposables.add(this._commentThreadWidget.onDidResize(dimension => {
this._refresh(dimension);
}));
Expand Down
Loading
Loading