Skip to content

Commit 8cae0f0

Browse files
mjbvzalexr00
andauthored
Expose comments input as text document (microsoft#209512)
* Expose comments input as text document Fixes https://github.com/microsoft/vscode-pull-request-github/issues/5875 For microsoft#209508 Exposes comment input editors as text documents that extensions can see. Enables a few features in them too such as 'paste as' and 'drop into' * Small fixes * Enable markers in comments * Fix async * Fix comment buttons on the top --------- Co-authored-by: Alex Ross <[email protected]>
1 parent 2fa8d0c commit 8cae0f0

File tree

13 files changed

+143
-69
lines changed

13 files changed

+143
-69
lines changed

src/vs/base/common/network.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ export namespace Schemas {
113113
*/
114114
export const vscodeSourceControl = 'vscode-scm';
115115

116+
/**
117+
* Scheme used for input box for creating comments.
118+
*/
119+
export const commentsInput = 'comment';
120+
116121
/**
117122
* Scheme used for special rendering of settings in the release notes
118123
*/

src/vs/platform/markers/common/markerService.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@ import { Schemas } from 'vs/base/common/network';
1212
import { URI } from 'vs/base/common/uri';
1313
import { IMarker, IMarkerData, IMarkerService, IResourceMarker, MarkerSeverity, MarkerStatistics } from './markers';
1414

15-
export const unsupportedSchemas = new Set([Schemas.inMemory, Schemas.vscodeSourceControl, Schemas.walkThrough, Schemas.walkThroughSnippet, Schemas.vscodeChatCodeBlock]);
15+
export const unsupportedSchemas = new Set([
16+
Schemas.inMemory,
17+
Schemas.vscodeSourceControl,
18+
Schemas.walkThrough,
19+
Schemas.walkThroughSnippet,
20+
Schemas.vscodeChatCodeBlock,
21+
]);
1622

1723
class DoubleResourceMap<V> {
1824

src/vs/workbench/contrib/comments/browser/commentNode.ts

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,8 @@ import * as dom from 'vs/base/browser/dom';
88
import * as languages from 'vs/editor/common/languages';
99
import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
1010
import { Action, IActionRunner, IAction, Separator, ActionRunner } from 'vs/base/common/actions';
11-
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
11+
import { Disposable, IDisposable, IReference, dispose } from 'vs/base/common/lifecycle';
1212
import { URI, UriComponents } from 'vs/base/common/uri';
13-
import { ITextModel } from 'vs/editor/common/model';
14-
import { IModelService } from 'vs/editor/common/services/model';
15-
import { ILanguageService } from 'vs/editor/common/languages/language';
1613
import { MarkdownRenderer } from 'vs/editor/browser/widget/markdownRenderer/browser/markdownRenderer';
1714
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
1815
import { ICommentService } from 'vs/workbench/contrib/comments/browser/commentService';
@@ -45,13 +42,14 @@ import { Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';
4542
import { SmoothScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
4643
import { DomEmitter } from 'vs/base/browser/event';
4744
import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/commentContextKeys';
48-
import { FileAccess } from 'vs/base/common/network';
45+
import { FileAccess, Schemas } from 'vs/base/common/network';
4946
import { COMMENTS_SECTION, ICommentsConfiguration } from 'vs/workbench/contrib/comments/common/commentsConfiguration';
5047
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
5148
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
5249
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
5350
import { MarshalledCommentThread } from 'vs/workbench/common/comments';
5451
import { IHoverService } from 'vs/platform/hover/browser/hover';
52+
import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService';
5553

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

8179
private _isPendingLabel!: HTMLElement;
@@ -112,15 +110,14 @@ export class CommentNode<T extends IRange | ICellRange> extends Disposable {
112110
private markdownRenderer: MarkdownRenderer,
113111
@IInstantiationService private instantiationService: IInstantiationService,
114112
@ICommentService private commentService: ICommentService,
115-
@IModelService private modelService: IModelService,
116-
@ILanguageService private languageService: ILanguageService,
117113
@INotificationService private notificationService: INotificationService,
118114
@IContextMenuService private contextMenuService: IContextMenuService,
119115
@IContextKeyService contextKeyService: IContextKeyService,
120116
@IConfigurationService private configurationService: IConfigurationService,
121117
@IHoverService private hoverService: IHoverService,
122118
@IAccessibilityService private accessibilityService: IAccessibilityService,
123-
@IKeybindingService private keybindingService: IKeybindingService
119+
@IKeybindingService private keybindingService: IKeybindingService,
120+
@ITextModelService private readonly textModelService: ITextModelService,
124121
) {
125122
super();
126123

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

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

503-
this._commentEditor.setModel(this._commentEditorModel);
498+
const resource = URI.from({
499+
scheme: Schemas.commentsInput,
500+
path: `/commentinput-${this.comment.uniqueIdInThread}-${Date.now()}.md`
501+
});
502+
const modelRef = await this.textModelService.createModelReference(resource);
503+
this._commentEditorModel = modelRef;
504+
505+
this._commentEditor.setModel(this._commentEditorModel.object.textEditorModel);
504506
this._commentEditor.setValue(this.pendingEdit ?? this.commentBodyValue);
505507
this.pendingEdit = undefined;
506508
this._commentEditor.layout({ width: container.clientWidth - 14, height: this._editorHeight });
@@ -511,8 +513,8 @@ export class CommentNode<T extends IRange | ICellRange> extends Disposable {
511513
this._commentEditor!.focus();
512514
});
513515

514-
const lastLine = this._commentEditorModel.getLineCount();
515-
const lastColumn = this._commentEditorModel.getLineLength(lastLine) + 1;
516+
const lastLine = this._commentEditorModel.object.textEditorModel.getLineCount();
517+
const lastColumn = this._commentEditorModel.object.textEditorModel.getLineLength(lastLine) + 1;
516518
this._commentEditor.setSelection(new Selection(lastLine, lastColumn, lastLine, lastColumn));
517519

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

548550
this.calculateEditorHeight();
549551

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

607-
public switchToEditMode() {
609+
public async switchToEditMode() {
608610
if (this.isEditing) {
609611
return;
610612
}
611613

612614
this.isEditing = true;
613615
this._body.classList.add('hidden');
614616
this._commentEditContainer = dom.append(this._commentDetailsContainer, dom.$('.edit-container'));
615-
this.createCommentEditor(this._commentEditContainer);
617+
await this.createCommentEditor(this._commentEditContainer);
616618

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

708-
update(newComment: languages.Comment) {
710+
async update(newComment: languages.Comment) {
709711

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

722724
if (isChangingMode) {
723725
if (newComment.mode === languages.CommentMode.Editing) {
724-
this.switchToEditMode();
726+
await this.switchToEditMode();
725727
} else {
726728
this.removeCommentEditor();
727729
}

src/vs/workbench/contrib/comments/browser/commentReply.ts

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,24 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import * as dom from 'vs/base/browser/dom';
7+
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';
78
import { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';
89
import { IAction } from 'vs/base/common/actions';
910
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
1011
import { MarshalledId } from 'vs/base/common/marshallingIds';
12+
import { Schemas } from 'vs/base/common/network';
1113
import { URI } from 'vs/base/common/uri';
1214
import { generateUuid } from 'vs/base/common/uuid';
1315
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
1416
import { IRange } from 'vs/editor/common/core/range';
1517
import * as languages from 'vs/editor/common/languages';
16-
import { ILanguageService } from 'vs/editor/common/languages/language';
1718
import { ITextModel } from 'vs/editor/common/model';
18-
import { IModelService } from 'vs/editor/common/services/model';
19+
import { ITextModelService } from 'vs/editor/common/services/resolverService';
1920
import * as nls from 'vs/nls';
2021
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
2122
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
2223
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
24+
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
2325
import { editorForeground, resolveColorValue } from 'vs/platform/theme/common/colorRegistry';
2426
import { IThemeService } from 'vs/platform/theme/common/themeService';
2527
import { CommentFormActions } from 'vs/workbench/contrib/comments/browser/commentFormActions';
@@ -29,11 +31,8 @@ import { CommentContextKeys } from 'vs/workbench/contrib/comments/common/comment
2931
import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget';
3032
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
3133
import { LayoutableEditor, MIN_EDITOR_HEIGHT, SimpleCommentEditor, calculateEditorHeight } from './simpleCommentEditor';
32-
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
33-
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';
3434
import { IHoverService } from 'vs/platform/hover/browser/hover';
3535

36-
const COMMENT_SCHEME = 'comment';
3736
let INMEM_MODEL_ID = 0;
3837
export const COMMENTEDITOR_DECORATION_KEY = 'commenteditordecoration';
3938

@@ -42,8 +41,8 @@ export class CommentReply<T extends IRange | ICellRange> extends Disposable {
4241
form: HTMLElement;
4342
commentEditorIsEmpty: IContextKey<boolean>;
4443
private _error!: HTMLElement;
45-
private _formActions: HTMLElement | null;
46-
private _editorActions: HTMLElement | null;
44+
private _formActions!: HTMLElement;
45+
private _editorActions!: HTMLElement;
4746
private _commentThreadDisposables: IDisposable[] = [];
4847
private _commentFormActions!: CommentFormActions;
4948
private _commentEditorActions!: CommentFormActions;
@@ -63,12 +62,11 @@ export class CommentReply<T extends IRange | ICellRange> extends Disposable {
6362
private _parentThread: ICommentThreadWidget,
6463
private _actionRunDelegate: (() => void) | null,
6564
@ICommentService private commentService: ICommentService,
66-
@ILanguageService private languageService: ILanguageService,
67-
@IModelService private modelService: IModelService,
6865
@IThemeService private themeService: IThemeService,
6966
@IConfigurationService configurationService: IConfigurationService,
7067
@IKeybindingService private keybindingService: IKeybindingService,
7168
@IHoverService private hoverService: IHoverService,
69+
@ITextModelService private readonly textModelService: ITextModelService
7270
) {
7371
super();
7472

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

78+
this.initialize();
79+
}
80+
81+
async initialize() {
8082
const hasExistingComments = this._commentThread.comments && this._commentThread.comments.length > 0;
8183
const modeId = generateUuid() + '-' + (hasExistingComments ? this._commentThread.threadId : ++INMEM_MODEL_ID);
8284
const params = JSON.stringify({
8385
extensionId: this._commentThread.extensionId,
8486
commentThreadId: this._commentThread.threadId
8587
});
8688

87-
let resource = URI.parse(`${COMMENT_SCHEME}://${this._commentThread.extensionId}/commentinput-${modeId}.md?${params}`); // TODO. Remove params once extensions adopt authority.
88-
const commentController = this.commentService.getCommentController(owner);
89+
let resource = URI.from({
90+
scheme: Schemas.commentsInput,
91+
path: `/${this._commentThread.extensionId}/commentinput-${modeId}.md?${params}` // TODO. Remove params once extensions adopt authority.
92+
});
93+
const commentController = this.commentService.getCommentController(this.owner);
8994
if (commentController) {
9095
resource = resource.with({ authority: commentController.id });
9196
}
9297

93-
const model = this.modelService.createModel(this._pendingComment || '', this.languageService.createByFilepathOrFirstLine(resource), resource, false);
98+
const model = await this.textModelService.createModelReference(resource);
99+
model.object.textEditorModel.setValue(this._pendingComment || '');
100+
94101
this._register(model);
95-
this.commentEditor.setModel(model);
102+
this.commentEditor.setModel(model.object.textEditorModel);
96103
this.calculateEditorHeight();
97104

98-
this._register((model.onDidChangeContent(() => {
105+
this._register(model.object.textEditorModel.onDidChangeContent(() => {
99106
this.setCommentEditorDecorations();
100107
this.commentEditorIsEmpty?.set(!this.commentEditor.getValue());
101108
if (this.calculateEditorHeight()) {
102109
this.commentEditor.layout({ height: this._editorHeight, width: this.commentEditor.getLayoutInfo().width });
103110
this.commentEditor.render(true);
104111
}
105-
})));
112+
}));
106113

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

@@ -117,9 +124,9 @@ export class CommentReply<T extends IRange | ICellRange> extends Disposable {
117124
this._error = dom.append(this.form, dom.$('.validation-error.hidden'));
118125
const formActions = dom.append(this.form, dom.$('.form-actions'));
119126
this._formActions = dom.append(formActions, dom.$('.other-actions'));
120-
this.createCommentWidgetFormActions(this._formActions, model);
127+
this.createCommentWidgetFormActions(this._formActions, model.object.textEditorModel);
121128
this._editorActions = dom.append(formActions, dom.$('.editor-actions'));
122-
this.createCommentWidgetEditorActions(this._editorActions, model);
129+
this.createCommentWidgetEditorActions(this._editorActions, model.object.textEditorModel);
123130
}
124131

125132
private calculateEditorHeight(): boolean {

src/vs/workbench/contrib/comments/browser/commentThreadBody.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export class CommentThreadBody<T extends IRange | ICellRange = IRange> extends D
7070
this._commentsElement.focus();
7171
}
7272

73-
display() {
73+
async display() {
7474
this._commentsElement = dom.append(this.container, dom.$('div.comments-container'));
7575
this._commentsElement.setAttribute('role', 'presentation');
7676
this._commentsElement.tabIndex = 0;
@@ -98,7 +98,7 @@ export class CommentThreadBody<T extends IRange | ICellRange = IRange> extends D
9898
this._commentElements.push(newCommentNode);
9999
this._commentsElement.appendChild(newCommentNode.domNode);
100100
if (comment.mode === languages.CommentMode.Editing) {
101-
newCommentNode.switchToEditMode();
101+
await newCommentNode.switchToEditMode();
102102
}
103103
}
104104
}
@@ -156,7 +156,7 @@ export class CommentThreadBody<T extends IRange | ICellRange = IRange> extends D
156156
return;
157157
}
158158

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

@@ -207,7 +207,7 @@ export class CommentThreadBody<T extends IRange | ICellRange = IRange> extends D
207207
}
208208

209209
if (currentComment.mode === languages.CommentMode.Editing) {
210-
newElement.switchToEditMode();
210+
await newElement.switchToEditMode();
211211
newCommentsInEditMode.push(newElement);
212212
}
213213
}

src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ export class CommentThreadWidget<T extends IRange | ICellRange = IRange> extends
205205
}, true));
206206
}
207207

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

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

233-
display(lineHeight: number) {
233+
async display(lineHeight: number) {
234234
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
235235
this._header.updateHeight(headHeight);
236236

237-
this._body.display();
237+
await this._body.display();
238238

239239
// create comment thread only when it supports reply
240240
if (this._commentThread.canReply) {

src/vs/workbench/contrib/comments/browser/commentThreadZoneWidget.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget
328328
this.bindCommentThreadListeners();
329329
}
330330

331-
this._commentThreadWidget.updateCommentThread(commentThread);
331+
await this._commentThreadWidget.updateCommentThread(commentThread);
332332

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

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

365-
this._commentThreadWidget.display(this.editor.getOption(EditorOption.lineHeight));
365+
await this._commentThreadWidget.display(this.editor.getOption(EditorOption.lineHeight));
366366
this._disposables.add(this._commentThreadWidget.onDidResize(dimension => {
367367
this._refresh(dimension);
368368
}));

0 commit comments

Comments
 (0)