@opensumi/ide-comments 3.0.5-next-1717640023.0 → 3.0.5-next-1717640331.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/comments-item.view.d.ts.map +1 -1
- package/lib/browser/comments-item.view.js +6 -2
- package/lib/browser/comments-item.view.js.map +1 -1
- package/lib/browser/comments-thread.d.ts +3 -1
- package/lib/browser/comments-thread.d.ts.map +1 -1
- package/lib/browser/comments-thread.js +36 -2
- package/lib/browser/comments-thread.js.map +1 -1
- package/lib/browser/comments-zone.service.d.ts +2 -0
- package/lib/browser/comments-zone.service.d.ts.map +1 -1
- package/lib/browser/comments-zone.service.js +8 -0
- package/lib/browser/comments-zone.service.js.map +1 -1
- package/lib/browser/comments-zone.view.d.ts.map +1 -1
- package/lib/browser/comments-zone.view.js +15 -3
- package/lib/browser/comments-zone.view.js.map +1 -1
- package/lib/browser/comments.module.less +81 -16
- package/lib/browser/comments.service.d.ts +29 -0
- package/lib/browser/comments.service.d.ts.map +1 -1
- package/lib/browser/comments.service.js +508 -44
- package/lib/browser/comments.service.js.map +1 -1
- package/lib/common/index.d.ts +9 -0
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js.map +1 -1
- package/package.json +10 -10
- package/src/browser/comments-item.view.tsx +6 -1
- package/src/browser/comments-thread.ts +22 -3
- package/src/browser/comments-zone.service.ts +9 -0
- package/src/browser/comments-zone.view.tsx +29 -3
- package/src/browser/comments.module.less +81 -16
- package/src/browser/comments.service.ts +593 -58
- package/src/common/index.ts +9 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import debounce from 'lodash/debounce';
|
|
2
1
|
import flattenDeep from 'lodash/flattenDeep';
|
|
3
2
|
import groupBy from 'lodash/groupBy';
|
|
4
3
|
|
|
@@ -36,6 +35,7 @@ import * as textModel from '@opensumi/monaco-editor-core/esm/vs/editor/common/mo
|
|
|
36
35
|
|
|
37
36
|
import {
|
|
38
37
|
CommentPanelId,
|
|
38
|
+
CommentThreadCollapsibleState,
|
|
39
39
|
ICommentRangeProvider,
|
|
40
40
|
ICommentsFeatureRegistry,
|
|
41
41
|
ICommentsService,
|
|
@@ -88,6 +88,9 @@ export class CommentsService extends Disposable implements ICommentsService {
|
|
|
88
88
|
|
|
89
89
|
private threadsCommentChangeEmitter = new Emitter<ICommentsThread>();
|
|
90
90
|
|
|
91
|
+
private commentRangeProviderChangeEmitter = new Emitter<void>();
|
|
92
|
+
private onDidChangeCurrentCommentThreadEmitter = new Emitter<ICommentsThread | undefined>();
|
|
93
|
+
|
|
91
94
|
private threadsCreatedEmitter = new Emitter<ICommentsThread>();
|
|
92
95
|
|
|
93
96
|
private rangeProviderMap = new Map<string, ICommentRangeProvider>();
|
|
@@ -96,8 +99,10 @@ export class CommentsService extends Disposable implements ICommentsService {
|
|
|
96
99
|
|
|
97
100
|
private providerDecorationCache = new LRUCache<string, Deferred<IRange[]>>(10000);
|
|
98
101
|
|
|
102
|
+
private commentRangeDecorationMap: Map<string, string[]> = new Map();
|
|
103
|
+
|
|
99
104
|
// 默认在 file 协议和 git 协议中显示评论数据
|
|
100
|
-
private shouldShowCommentsSchemes = new Set(['file', 'git']);
|
|
105
|
+
private shouldShowCommentsSchemes = new Set(['file', 'git', 'diff']);
|
|
101
106
|
|
|
102
107
|
private decorationProviderDisposer = Disposable.NULL;
|
|
103
108
|
|
|
@@ -132,6 +137,18 @@ export class CommentsService extends Disposable implements ICommentsService {
|
|
|
132
137
|
return this.threadsCreatedEmitter.event;
|
|
133
138
|
}
|
|
134
139
|
|
|
140
|
+
get onCommentRangeProviderChange() {
|
|
141
|
+
return this.commentRangeProviderChangeEmitter.event;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
get onDidChangeCurrentCommentThread() {
|
|
145
|
+
return this.onDidChangeCurrentCommentThreadEmitter.event;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public setCurrentCommentThread(thread: ICommentsThread) {
|
|
149
|
+
this.onDidChangeCurrentCommentThreadEmitter.fire(thread);
|
|
150
|
+
}
|
|
151
|
+
|
|
135
152
|
/**
|
|
136
153
|
* -------------------------------- IMPORTANT --------------------------------
|
|
137
154
|
* 需要注意区分 model.IModelDecorationOptions 与 monaco.editor.IModelDecorationOptions 两个类型
|
|
@@ -146,12 +163,55 @@ export class CommentsService extends Disposable implements ICommentsService {
|
|
|
146
163
|
const avatar =
|
|
147
164
|
thread.comments.length === 0 ? this.currentAuthorAvatar : thread.comments[0].author.iconPath?.toString();
|
|
148
165
|
const icon = avatar
|
|
149
|
-
? this.iconService.fromIcon('', avatar, IconType.Background)
|
|
150
|
-
: this.iconService.fromString('$(comment
|
|
166
|
+
? `${this.iconService.fromIcon('', avatar, IconType.Background)} avatar-icon`
|
|
167
|
+
: this.iconService.fromString('$(comment)');
|
|
151
168
|
const decorationOptions: model.IModelDecorationOptions = {
|
|
152
169
|
description: 'comments-thread-decoration',
|
|
153
|
-
|
|
154
|
-
|
|
170
|
+
glyphMarginClassName: avatar
|
|
171
|
+
? ['comment-thread', icon].join(' ')
|
|
172
|
+
: ['comment-range', 'comment-thread', icon].join(' '),
|
|
173
|
+
};
|
|
174
|
+
return textModel.ModelDecorationOptions.createDynamic(decorationOptions);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private currentThreadCollapseStateListener: IDisposable | undefined;
|
|
178
|
+
private activeThreadDecorationIds: string[] = [];
|
|
179
|
+
|
|
180
|
+
private updateActiveThreadDecoration(thread?: ICommentsThread) {
|
|
181
|
+
const editor = this.getCurrentEditor(thread?.uri);
|
|
182
|
+
if (!editor) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
this.currentThreadCollapseStateListener?.dispose();
|
|
186
|
+
const newDecoration: {
|
|
187
|
+
range: IRange;
|
|
188
|
+
options: model.IModelDecorationOptions;
|
|
189
|
+
}[] = [];
|
|
190
|
+
|
|
191
|
+
if (thread) {
|
|
192
|
+
const range = thread.range;
|
|
193
|
+
if (!thread.isCollapsed) {
|
|
194
|
+
this.currentThreadCollapseStateListener = thread.onDidChangeCollapsibleState((state) => {
|
|
195
|
+
if (state === CommentThreadCollapsibleState.Collapsed) {
|
|
196
|
+
this.updateActiveThreadDecoration(undefined);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
newDecoration.push({
|
|
200
|
+
range,
|
|
201
|
+
options: this.createThreadRangeActiveDecoration(),
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
this.activeThreadDecorationIds = editor.monacoEditor.deltaDecorations(
|
|
206
|
+
this.activeThreadDecorationIds,
|
|
207
|
+
newDecoration,
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private createDottedRangeDecoration(): model.IModelDecorationOptions {
|
|
212
|
+
const decorationOptions: model.IModelDecorationOptions = {
|
|
213
|
+
description: 'comments-multiline-hover-decoration',
|
|
214
|
+
linesDecorationsClassName: ['comment-range', 'multiline-add'].join(' '),
|
|
155
215
|
};
|
|
156
216
|
return textModel.ModelDecorationOptions.createDynamic(decorationOptions);
|
|
157
217
|
}
|
|
@@ -159,7 +219,39 @@ export class CommentsService extends Disposable implements ICommentsService {
|
|
|
159
219
|
private createHoverDecoration(): model.IModelDecorationOptions {
|
|
160
220
|
const decorationOptions: model.IModelDecorationOptions = {
|
|
161
221
|
description: 'comments-hover-decoration',
|
|
162
|
-
linesDecorationsClassName: ['
|
|
222
|
+
linesDecorationsClassName: ['comment-range', 'line-hover', 'comment-add'].join(' '),
|
|
223
|
+
};
|
|
224
|
+
return textModel.ModelDecorationOptions.createDynamic(decorationOptions);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
private createThreadRangeActiveDecoration(): model.IModelDecorationOptions {
|
|
228
|
+
const activeDecorationOptions: model.IModelDecorationOptions = {
|
|
229
|
+
description: 'comments-thread-range-active-decoration',
|
|
230
|
+
isWholeLine: false,
|
|
231
|
+
zIndex: 20,
|
|
232
|
+
className: 'comment-thread-range-current',
|
|
233
|
+
shouldFillLineOnLineBreak: true,
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
return textModel.ModelDecorationOptions.createDynamic(activeDecorationOptions);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
private createThreadRangeDecoration(): model.IModelDecorationOptions {
|
|
240
|
+
const activeDecorationOptions: model.IModelDecorationOptions = {
|
|
241
|
+
description: 'comments-thread-range-decoration',
|
|
242
|
+
isWholeLine: false,
|
|
243
|
+
zIndex: 20,
|
|
244
|
+
className: 'comment-thread-range',
|
|
245
|
+
shouldFillLineOnLineBreak: true,
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
return textModel.ModelDecorationOptions.createDynamic(activeDecorationOptions);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
private createCommentRangeDecoration(): model.IModelDecorationOptions {
|
|
252
|
+
const decorationOptions: model.IModelDecorationOptions = {
|
|
253
|
+
description: 'comments-range-decoration',
|
|
254
|
+
linesDecorationsClassName: ['comment-range', 'comment-diff-added'].join(' '),
|
|
163
255
|
};
|
|
164
256
|
return textModel.ModelDecorationOptions.createDynamic(decorationOptions);
|
|
165
257
|
}
|
|
@@ -191,49 +283,56 @@ export class CommentsService extends Disposable implements ICommentsService {
|
|
|
191
283
|
this.registerDecorationProvider();
|
|
192
284
|
}
|
|
193
285
|
|
|
286
|
+
private startCommentRange: IRange | null;
|
|
287
|
+
private endCommentRange: IRange | null;
|
|
288
|
+
private editor: IEditor | null;
|
|
289
|
+
private allEditors: IEditor[] = [];
|
|
290
|
+
|
|
291
|
+
getCurrentEditor(uri?: URI) {
|
|
292
|
+
if (uri) {
|
|
293
|
+
for (const editor of this.allEditors) {
|
|
294
|
+
if (editor.currentUri?.isEqual(uri)) {
|
|
295
|
+
this.editor = editor;
|
|
296
|
+
return editor;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return this.editor;
|
|
301
|
+
}
|
|
302
|
+
|
|
194
303
|
public handleOnCreateEditor(editor: IEditor) {
|
|
304
|
+
this.allEditors.push(editor);
|
|
305
|
+
this.editor = editor;
|
|
195
306
|
const disposer = new Disposable();
|
|
307
|
+
let commentRangeDecorationIds: string[] = [];
|
|
308
|
+
let hasHiddenArea = false;
|
|
196
309
|
|
|
197
310
|
disposer.addDispose(
|
|
198
311
|
editor.monacoEditor.onMouseDown((event) => {
|
|
199
312
|
if (
|
|
200
313
|
event.target.type === monacoBrowser.editor.MouseTargetType.GUTTER_LINE_DECORATIONS &&
|
|
201
314
|
event.target.element &&
|
|
202
|
-
event.target.element.className.indexOf('
|
|
315
|
+
event.target.element.className.indexOf('comment-add') > -1
|
|
203
316
|
) {
|
|
204
317
|
const { target } = event;
|
|
205
318
|
if (target && target.range) {
|
|
206
319
|
const { range } = target;
|
|
207
|
-
|
|
208
|
-
if (
|
|
209
|
-
!this.commentsThreads.some(
|
|
210
|
-
(thread) =>
|
|
211
|
-
thread.comments.length === 0 &&
|
|
212
|
-
thread.uri.isEqual(editor.currentUri!) &&
|
|
213
|
-
thread.range.startLineNumber === range.startLineNumber,
|
|
214
|
-
)
|
|
215
|
-
) {
|
|
216
|
-
const thread = this.createThread(editor.currentUri!, range);
|
|
217
|
-
thread.show(editor);
|
|
218
|
-
}
|
|
320
|
+
this.startCommentRange = range;
|
|
219
321
|
event.event.stopPropagation();
|
|
220
322
|
}
|
|
221
323
|
} else if (
|
|
222
324
|
event.target.type === monacoBrowser.editor.MouseTargetType.GUTTER_GLYPH_MARGIN &&
|
|
223
325
|
event.target.element &&
|
|
224
|
-
event.target.element.className.indexOf('
|
|
326
|
+
event.target.element.className.indexOf('comment-thread') > -1
|
|
225
327
|
) {
|
|
226
328
|
const { target } = event;
|
|
227
329
|
if (target && target.range) {
|
|
228
330
|
const { range } = target;
|
|
229
331
|
const threads = this.commentsThreads.filter(
|
|
230
|
-
(thread) =>
|
|
231
|
-
thread.uri.isEqual(editor.currentUri!) && thread.range.startLineNumber === range.startLineNumber,
|
|
332
|
+
(thread) => thread.uri.isEqual(editor.currentUri!) && thread.range.endLineNumber === range.endLineNumber,
|
|
232
333
|
);
|
|
233
334
|
if (threads.length) {
|
|
234
|
-
// 判断当前 widget 是否是显示的
|
|
235
335
|
const isShowWidget = threads.some((thread) => thread.isShowWidget(editor));
|
|
236
|
-
|
|
237
336
|
if (isShowWidget) {
|
|
238
337
|
threads.forEach((thread) => thread.hide(editor));
|
|
239
338
|
} else {
|
|
@@ -245,55 +344,479 @@ export class CommentsService extends Disposable implements ICommentsService {
|
|
|
245
344
|
}
|
|
246
345
|
}),
|
|
247
346
|
);
|
|
248
|
-
|
|
347
|
+
|
|
249
348
|
disposer.addDispose(
|
|
250
|
-
editor.monacoEditor.
|
|
251
|
-
|
|
252
|
-
|
|
349
|
+
editor.monacoEditor.onMouseUp(async (event) => {
|
|
350
|
+
if (this.startCommentRange) {
|
|
351
|
+
if (hasHiddenArea) {
|
|
352
|
+
this.renderCommentRange(editor);
|
|
353
|
+
hasHiddenArea = false;
|
|
354
|
+
this.startCommentRange = null;
|
|
355
|
+
this.endCommentRange = null;
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
let range = this.startCommentRange;
|
|
359
|
+
if (this.endCommentRange) {
|
|
360
|
+
if (this.endCommentRange.startLineNumber < this.startCommentRange.startLineNumber) {
|
|
361
|
+
range.startColumn = this.endCommentRange.startColumn;
|
|
362
|
+
range.startLineNumber = this.endCommentRange.startLineNumber;
|
|
363
|
+
} else {
|
|
364
|
+
range.endColumn = this.endCommentRange.endColumn;
|
|
365
|
+
range.endLineNumber = this.endCommentRange.endLineNumber;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (editor.currentUri) {
|
|
369
|
+
range = await this.getValidRange(range, editor.currentUri);
|
|
370
|
+
}
|
|
371
|
+
if (range) {
|
|
372
|
+
if (
|
|
373
|
+
!this.commentsThreads.some(
|
|
374
|
+
(thread) =>
|
|
375
|
+
thread.comments.length === 0 &&
|
|
376
|
+
thread.uri.isEqual(editor.currentUri!) &&
|
|
377
|
+
thread.range.startLineNumber === range.startLineNumber &&
|
|
378
|
+
thread.range.endLineNumber === range.endLineNumber,
|
|
379
|
+
)
|
|
380
|
+
) {
|
|
381
|
+
const thread = this.createThread(editor.currentUri!, range);
|
|
382
|
+
thread.show(editor);
|
|
383
|
+
}
|
|
384
|
+
event.event.stopPropagation();
|
|
385
|
+
}
|
|
386
|
+
} else if (
|
|
387
|
+
event.target.type === monacoBrowser.editor.MouseTargetType.GUTTER_LINE_DECORATIONS &&
|
|
388
|
+
event.target.element &&
|
|
389
|
+
event.target.element.className.indexOf('comment-range') > -1 &&
|
|
390
|
+
event.target.element.className.indexOf('comment-thread') < 0
|
|
391
|
+
) {
|
|
392
|
+
const { target } = event;
|
|
393
|
+
const range: IRange | undefined = target.range;
|
|
394
|
+
if (range) {
|
|
395
|
+
if (
|
|
396
|
+
!this.commentsThreads.some(
|
|
397
|
+
(thread) =>
|
|
398
|
+
thread.comments.length === 0 &&
|
|
399
|
+
thread.uri.isEqual(editor.currentUri!) &&
|
|
400
|
+
thread.range.startLineNumber === range.startLineNumber &&
|
|
401
|
+
thread.range.endLineNumber === range.endLineNumber,
|
|
402
|
+
)
|
|
403
|
+
) {
|
|
404
|
+
const thread = this.createThread(editor.currentUri!, range);
|
|
405
|
+
thread.show(editor);
|
|
406
|
+
}
|
|
407
|
+
event.event.stopPropagation();
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
this.startCommentRange = null;
|
|
411
|
+
this.endCommentRange = null;
|
|
412
|
+
}),
|
|
413
|
+
);
|
|
253
414
|
|
|
254
|
-
|
|
415
|
+
disposer.addDispose(
|
|
416
|
+
editor.monacoEditor.onMouseMove(async (event) => {
|
|
417
|
+
const uri = editor.currentUri;
|
|
418
|
+
const range = event.target.range;
|
|
419
|
+
// 多行评论
|
|
420
|
+
if (this.startCommentRange) {
|
|
421
|
+
if (!event.target.element?.className) {
|
|
422
|
+
if (event.target.element?.offsetParent?.className.includes('diff-hidden-lines')) {
|
|
423
|
+
// 当多行评论跨过折叠代码时,不创建评论
|
|
424
|
+
hasHiddenArea = true;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
if (uri && range) {
|
|
428
|
+
let selection = {
|
|
429
|
+
startLineNumber: this.startCommentRange.startLineNumber,
|
|
430
|
+
endLineNumber: range.endLineNumber,
|
|
431
|
+
startColumn: this.startCommentRange.startColumn,
|
|
432
|
+
endColumn: range.endColumn,
|
|
433
|
+
};
|
|
434
|
+
if (this.startCommentRange.startLineNumber > range.startLineNumber) {
|
|
435
|
+
selection = {
|
|
436
|
+
startLineNumber: range.startLineNumber,
|
|
437
|
+
endLineNumber: this.startCommentRange.endLineNumber,
|
|
438
|
+
startColumn: range.startColumn,
|
|
439
|
+
endColumn: this.startCommentRange.endColumn,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
this.renderCommentRange(editor, selection);
|
|
443
|
+
this.endCommentRange = range;
|
|
444
|
+
}
|
|
445
|
+
} else {
|
|
255
446
|
if (uri && range && (await this.shouldShowHoverDecoration(uri, range))) {
|
|
256
|
-
|
|
447
|
+
const newDecorations = [
|
|
257
448
|
{
|
|
258
449
|
range: positionToRange(range.startLineNumber),
|
|
259
450
|
options: this.createHoverDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
260
451
|
},
|
|
261
|
-
]
|
|
262
|
-
|
|
263
|
-
oldDecorations = editor.monacoEditor.deltaDecorations(oldDecorations, []);
|
|
452
|
+
];
|
|
453
|
+
commentRangeDecorationIds = editor.monacoEditor.deltaDecorations(commentRangeDecorationIds, newDecorations);
|
|
264
454
|
}
|
|
265
|
-
}
|
|
266
|
-
),
|
|
455
|
+
}
|
|
456
|
+
}),
|
|
267
457
|
);
|
|
268
458
|
|
|
269
459
|
disposer.addDispose(
|
|
270
|
-
editor.monacoEditor.onMouseLeave(
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
460
|
+
editor.monacoEditor.onMouseLeave(async (event) => {
|
|
461
|
+
const range = event.target?.range;
|
|
462
|
+
const newDecorations: {
|
|
463
|
+
range: IRange;
|
|
464
|
+
options: monaco.editor.IModelDecorationOptions;
|
|
465
|
+
}[] = [];
|
|
466
|
+
if (!this.startCommentRange && range) {
|
|
467
|
+
newDecorations.push({
|
|
468
|
+
range: positionToRange(range.startLineNumber),
|
|
469
|
+
options: this.createCommentRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
commentRangeDecorationIds = editor.monacoEditor.deltaDecorations(commentRangeDecorationIds, newDecorations);
|
|
473
|
+
}),
|
|
474
|
+
);
|
|
475
|
+
|
|
476
|
+
disposer.addDispose(
|
|
477
|
+
this.onCommentRangeProviderChange(() => {
|
|
478
|
+
this.renderCommentRange(editor);
|
|
479
|
+
}),
|
|
480
|
+
);
|
|
481
|
+
|
|
482
|
+
disposer.addDispose(
|
|
483
|
+
Event.any(
|
|
484
|
+
this.onThreadsChanged,
|
|
485
|
+
this.onThreadsCommentChange,
|
|
486
|
+
this.onThreadsCreated,
|
|
487
|
+
)((thread) => {
|
|
488
|
+
const editor = this.getCurrentEditor(thread.uri);
|
|
489
|
+
if (editor) {
|
|
490
|
+
this.renderCommentRange(editor);
|
|
491
|
+
}
|
|
492
|
+
this.updateActiveThreadDecoration(undefined);
|
|
493
|
+
}),
|
|
494
|
+
);
|
|
495
|
+
|
|
496
|
+
disposer.addDispose(
|
|
497
|
+
this.onDidChangeCurrentCommentThread((thread) => {
|
|
498
|
+
this.updateActiveThreadDecoration(thread);
|
|
499
|
+
}),
|
|
275
500
|
);
|
|
276
501
|
|
|
502
|
+
this.tryUpdateReservedSpace(editor);
|
|
503
|
+
|
|
504
|
+
disposer.addDispose(
|
|
505
|
+
editor.monacoEditor.onDidChangeModel(() => {
|
|
506
|
+
this.renderCommentRange(editor);
|
|
507
|
+
this.tryUpdateReservedSpace(editor);
|
|
508
|
+
}),
|
|
509
|
+
);
|
|
277
510
|
return disposer;
|
|
278
511
|
}
|
|
279
512
|
|
|
513
|
+
private editorCommentingRangeSpaceReservedMap: Map<string, boolean> = new Map();
|
|
514
|
+
private editorLineDecorationsWidthMap: Map<string, number> = new Map();
|
|
515
|
+
|
|
516
|
+
private async getValidRange(range: IRange, uri?: URI) {
|
|
517
|
+
if (!uri) {
|
|
518
|
+
return range;
|
|
519
|
+
}
|
|
520
|
+
const contributionRanges = await this.getContributionRanges(uri);
|
|
521
|
+
if (contributionRanges.length === 0) {
|
|
522
|
+
return range;
|
|
523
|
+
}
|
|
524
|
+
const validRange = contributionRanges.find((contributionRange) => {
|
|
525
|
+
if (
|
|
526
|
+
range.startLineNumber >= contributionRange.startLineNumber &&
|
|
527
|
+
range.startLineNumber <= contributionRange.endLineNumber
|
|
528
|
+
) {
|
|
529
|
+
return true;
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
if (validRange) {
|
|
533
|
+
if (validRange.endLineNumber < range.endLineNumber) {
|
|
534
|
+
return {
|
|
535
|
+
startLineNumber: range.startLineNumber,
|
|
536
|
+
startColumn: range.startColumn,
|
|
537
|
+
endLineNumber: validRange.endLineNumber,
|
|
538
|
+
endColumn: validRange.endColumn,
|
|
539
|
+
};
|
|
540
|
+
} else {
|
|
541
|
+
return range;
|
|
542
|
+
}
|
|
543
|
+
} else {
|
|
544
|
+
return range;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
private ensureCommentingRangeReservedAmount(editor: IEditor) {
|
|
549
|
+
const existing = this.getExistingCommentEditorOptions(editor);
|
|
550
|
+
const lineDecorationsWidth = this.editorLineDecorationsWidthMap.get(editor.getId());
|
|
551
|
+
if (existing.lineDecorationsWidth !== lineDecorationsWidth) {
|
|
552
|
+
editor.updateOptions({
|
|
553
|
+
lineDecorationsWidth: this.getWithCommentsLineDecorationWidth(editor, existing.lineDecorationsWidth),
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
private async tryUpdateReservedSpace(editor: IEditor) {
|
|
559
|
+
if (!editor) {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
let commentingRangeSpaceReserved = this.editorCommentingRangeSpaceReservedMap.get(editor.getId()) || false;
|
|
563
|
+
const shouldShowComments = editor.currentUri ? this.shouldShowCommentsSchemes.has(editor.currentUri.scheme) : false;
|
|
564
|
+
|
|
565
|
+
const hasComments = this.commentsThreads.some(
|
|
566
|
+
(thread) => thread.uri.isEqual(editor.currentUri!) && thread.comments.length > 0,
|
|
567
|
+
);
|
|
568
|
+
|
|
569
|
+
const hasCommentsOrRanges = shouldShowComments || hasComments;
|
|
570
|
+
if (hasCommentsOrRanges) {
|
|
571
|
+
if (!commentingRangeSpaceReserved) {
|
|
572
|
+
commentingRangeSpaceReserved = true;
|
|
573
|
+
const { lineDecorationsWidth, extraEditorClassName } = this.getExistingCommentEditorOptions(editor);
|
|
574
|
+
const newOptions = this.getWithCommentsEditorOptions(editor, extraEditorClassName, lineDecorationsWidth);
|
|
575
|
+
this.updateEditorLayoutOptions(editor, newOptions.extraEditorClassName, newOptions.lineDecorationsWidth);
|
|
576
|
+
} else {
|
|
577
|
+
this.ensureCommentingRangeReservedAmount(editor);
|
|
578
|
+
}
|
|
579
|
+
} else if (!hasCommentsOrRanges && commentingRangeSpaceReserved) {
|
|
580
|
+
commentingRangeSpaceReserved = false;
|
|
581
|
+
const { lineDecorationsWidth, extraEditorClassName } = this.getExistingCommentEditorOptions(editor);
|
|
582
|
+
const newOptions = this.getWithoutCommentsEditorOptions(editor, extraEditorClassName, lineDecorationsWidth);
|
|
583
|
+
this.updateEditorLayoutOptions(editor, newOptions.extraEditorClassName, newOptions.lineDecorationsWidth);
|
|
584
|
+
}
|
|
585
|
+
this.editorCommentingRangeSpaceReservedMap.set(editor.getId(), commentingRangeSpaceReserved);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
private getExistingCommentEditorOptions(editor: IEditor) {
|
|
589
|
+
const lineDecorationsWidth: number = editor.monacoEditor.getOption(monaco.EditorOption.lineDecorationsWidth);
|
|
590
|
+
let extraEditorClassName: string[] = [];
|
|
591
|
+
const configuredExtraClassName = editor.monacoEditor.getRawOptions().extraEditorClassName;
|
|
592
|
+
if (configuredExtraClassName) {
|
|
593
|
+
extraEditorClassName = configuredExtraClassName.split(' ');
|
|
594
|
+
}
|
|
595
|
+
return { lineDecorationsWidth, extraEditorClassName };
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
private getWithoutCommentsEditorOptions(
|
|
599
|
+
editor: IEditor,
|
|
600
|
+
extraEditorClassName: string[],
|
|
601
|
+
startingLineDecorationsWidth: number,
|
|
602
|
+
) {
|
|
603
|
+
let lineDecorationsWidth = startingLineDecorationsWidth;
|
|
604
|
+
const inlineCommentPos = extraEditorClassName.findIndex((name) => name === 'inline-comment');
|
|
605
|
+
if (inlineCommentPos >= 0) {
|
|
606
|
+
extraEditorClassName.splice(inlineCommentPos, 1);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const options = editor.monacoEditor.getOptions();
|
|
610
|
+
if (options.get(monaco.EditorOption.folding) && options.get(monaco.EditorOption.showFoldingControls) !== 'never') {
|
|
611
|
+
lineDecorationsWidth += 11; // 11 comes from https://github.com/microsoft/vscode/blob/94ee5f58619d59170983f453fe78f156c0cc73a3/src/vs/workbench/contrib/comments/browser/media/review.css#L485
|
|
612
|
+
}
|
|
613
|
+
lineDecorationsWidth -= 24;
|
|
614
|
+
return { extraEditorClassName, lineDecorationsWidth };
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
private updateEditorLayoutOptions(editor: IEditor, extraEditorClassName: string[], lineDecorationsWidth: number) {
|
|
618
|
+
editor.updateOptions({
|
|
619
|
+
extraEditorClassName: extraEditorClassName.join(' '),
|
|
620
|
+
lineDecorationsWidth,
|
|
621
|
+
});
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
private getWithCommentsEditorOptions(
|
|
625
|
+
editor: IEditor,
|
|
626
|
+
extraEditorClassName: string[],
|
|
627
|
+
startingLineDecorationsWidth: number,
|
|
628
|
+
) {
|
|
629
|
+
extraEditorClassName.push('inline-comment');
|
|
630
|
+
return {
|
|
631
|
+
lineDecorationsWidth: this.getWithCommentsLineDecorationWidth(editor, startingLineDecorationsWidth),
|
|
632
|
+
extraEditorClassName,
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
private getWithCommentsLineDecorationWidth(editor: IEditor, startingLineDecorationsWidth: number) {
|
|
637
|
+
let lineDecorationsWidth = startingLineDecorationsWidth;
|
|
638
|
+
const options = editor.monacoEditor.getOptions();
|
|
639
|
+
if (options.get(monaco.EditorOption.folding) && options.get(monaco.EditorOption.showFoldingControls) !== 'never') {
|
|
640
|
+
lineDecorationsWidth -= 11;
|
|
641
|
+
}
|
|
642
|
+
lineDecorationsWidth += 24;
|
|
643
|
+
this.editorLineDecorationsWidthMap.set(editor.getId(), lineDecorationsWidth);
|
|
644
|
+
return lineDecorationsWidth;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
private async renderCommentRange(
|
|
648
|
+
editor: IEditor,
|
|
649
|
+
selection: IRange = {
|
|
650
|
+
startLineNumber: 0,
|
|
651
|
+
endLineNumber: 0,
|
|
652
|
+
startColumn: 0,
|
|
653
|
+
endColumn: 0,
|
|
654
|
+
},
|
|
655
|
+
) {
|
|
656
|
+
if (!editor.currentUri) {
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
const contributionRanges = await this.getContributionRanges(editor.currentUri);
|
|
660
|
+
if (contributionRanges.length > 0) {
|
|
661
|
+
const newDecorations: {
|
|
662
|
+
range: IRange;
|
|
663
|
+
options: monaco.editor.IModelDecorationOptions;
|
|
664
|
+
}[] = [];
|
|
665
|
+
contributionRanges.map((contributionRange) => {
|
|
666
|
+
if (selection.startLineNumber === 0 && selection.endLineNumber === 0) {
|
|
667
|
+
newDecorations.push({
|
|
668
|
+
range: contributionRange,
|
|
669
|
+
options: this.createCommentRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
670
|
+
});
|
|
671
|
+
} else if (
|
|
672
|
+
selection.startLineNumber <= contributionRange.startLineNumber &&
|
|
673
|
+
selection.endLineNumber >= contributionRange.endLineNumber
|
|
674
|
+
) {
|
|
675
|
+
newDecorations.push(
|
|
676
|
+
...[
|
|
677
|
+
{
|
|
678
|
+
range: contributionRange,
|
|
679
|
+
options: this.createDottedRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
range: contributionRange,
|
|
683
|
+
options: this.createThreadRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
684
|
+
},
|
|
685
|
+
],
|
|
686
|
+
);
|
|
687
|
+
} else if (selection.endLineNumber >= contributionRange.endLineNumber) {
|
|
688
|
+
if (selection.startLineNumber <= contributionRange.endLineNumber) {
|
|
689
|
+
// 存在交集
|
|
690
|
+
const selectionRange = {
|
|
691
|
+
startLineNumber: selection.startLineNumber,
|
|
692
|
+
endLineNumber: contributionRange.endLineNumber,
|
|
693
|
+
startColumn: selection.startColumn,
|
|
694
|
+
endColumn: contributionRange.endColumn,
|
|
695
|
+
};
|
|
696
|
+
const topCommentRange = {
|
|
697
|
+
startLineNumber: contributionRange.startLineNumber,
|
|
698
|
+
endLineNumber: selectionRange.startLineNumber - 1,
|
|
699
|
+
startColumn: contributionRange.startColumn,
|
|
700
|
+
endColumn: selectionRange.endColumn,
|
|
701
|
+
};
|
|
702
|
+
newDecorations.push(
|
|
703
|
+
...[
|
|
704
|
+
{
|
|
705
|
+
range: topCommentRange,
|
|
706
|
+
options: this.createCommentRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
707
|
+
},
|
|
708
|
+
{
|
|
709
|
+
range: selectionRange,
|
|
710
|
+
options: this.createDottedRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
711
|
+
},
|
|
712
|
+
{
|
|
713
|
+
range: selectionRange,
|
|
714
|
+
options: this.createThreadRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
715
|
+
},
|
|
716
|
+
],
|
|
717
|
+
);
|
|
718
|
+
} else {
|
|
719
|
+
newDecorations.push({
|
|
720
|
+
range: contributionRange,
|
|
721
|
+
options: this.createCommentRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
} else if (selection.endLineNumber < contributionRange.endLineNumber) {
|
|
725
|
+
if (selection.endLineNumber >= contributionRange.startLineNumber) {
|
|
726
|
+
// 存在交集
|
|
727
|
+
if (selection.startLineNumber >= contributionRange.startLineNumber) {
|
|
728
|
+
const topCommentRange = {
|
|
729
|
+
startLineNumber: contributionRange.startLineNumber,
|
|
730
|
+
startColumn: contributionRange.startColumn,
|
|
731
|
+
endLineNumber: selection.startLineNumber - 1,
|
|
732
|
+
endColumn: selection.startColumn,
|
|
733
|
+
};
|
|
734
|
+
const bottomCommentRange = {
|
|
735
|
+
startLineNumber: selection.endLineNumber + 1,
|
|
736
|
+
startColumn: selection.endColumn,
|
|
737
|
+
endLineNumber: contributionRange.endLineNumber,
|
|
738
|
+
endColumn: contributionRange.endColumn,
|
|
739
|
+
};
|
|
740
|
+
const decorations =
|
|
741
|
+
selection.startLineNumber !== contributionRange.startLineNumber
|
|
742
|
+
? [
|
|
743
|
+
{
|
|
744
|
+
range: topCommentRange,
|
|
745
|
+
options:
|
|
746
|
+
this.createCommentRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
747
|
+
},
|
|
748
|
+
]
|
|
749
|
+
: [];
|
|
750
|
+
decorations.push({
|
|
751
|
+
range: selection,
|
|
752
|
+
options: this.createDottedRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
753
|
+
});
|
|
754
|
+
decorations.push({
|
|
755
|
+
range: selection,
|
|
756
|
+
options: this.createThreadRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
757
|
+
});
|
|
758
|
+
decorations.push({
|
|
759
|
+
range: bottomCommentRange,
|
|
760
|
+
options: this.createCommentRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
761
|
+
});
|
|
762
|
+
newDecorations.push(...decorations);
|
|
763
|
+
} else {
|
|
764
|
+
const selectionRange = {
|
|
765
|
+
startLineNumber: contributionRange.startLineNumber,
|
|
766
|
+
startColumn: contributionRange.startColumn,
|
|
767
|
+
endLineNumber: selection.endLineNumber,
|
|
768
|
+
endColumn: selection.endColumn,
|
|
769
|
+
};
|
|
770
|
+
const bottomCommentRange = {
|
|
771
|
+
startLineNumber: selectionRange.endLineNumber + 1,
|
|
772
|
+
startColumn: selectionRange.endColumn,
|
|
773
|
+
endLineNumber: contributionRange.endLineNumber,
|
|
774
|
+
endColumn: contributionRange.endColumn,
|
|
775
|
+
};
|
|
776
|
+
newDecorations.push(
|
|
777
|
+
...[
|
|
778
|
+
{
|
|
779
|
+
range: selectionRange,
|
|
780
|
+
options: this.createDottedRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
781
|
+
},
|
|
782
|
+
{
|
|
783
|
+
range: selectionRange,
|
|
784
|
+
options: this.createThreadRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
785
|
+
},
|
|
786
|
+
{
|
|
787
|
+
range: bottomCommentRange,
|
|
788
|
+
options: this.createCommentRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
789
|
+
},
|
|
790
|
+
],
|
|
791
|
+
);
|
|
792
|
+
}
|
|
793
|
+
} else {
|
|
794
|
+
newDecorations.push({
|
|
795
|
+
range: contributionRange,
|
|
796
|
+
options: this.createCommentRangeDecoration() as unknown as monaco.editor.IModelDecorationOptions,
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
});
|
|
801
|
+
const commentRangeDecorationIds = this.commentRangeDecorationMap.get(editor.currentUri.toString()) || [];
|
|
802
|
+
this.commentRangeDecorationMap.set(
|
|
803
|
+
editor.currentUri.toString(),
|
|
804
|
+
editor.monacoEditor.deltaDecorations(commentRangeDecorationIds, newDecorations),
|
|
805
|
+
);
|
|
806
|
+
} else {
|
|
807
|
+
this.commentRangeDecorationMap.set(editor.currentUri.toString(), []);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
280
811
|
private async shouldShowHoverDecoration(uri: URI, range: IRange) {
|
|
281
812
|
if (!this.shouldShowCommentsSchemes.has(uri.scheme)) {
|
|
282
813
|
return false;
|
|
283
814
|
}
|
|
284
815
|
const contributionRanges = await this.getContributionRanges(uri);
|
|
285
816
|
const isProviderRanges = contributionRanges.some(
|
|
286
|
-
(contributionRange) =>
|
|
287
|
-
range.startLineNumber >= contributionRange.startLineNumber &&
|
|
288
|
-
range.startLineNumber <= contributionRange.endLineNumber,
|
|
817
|
+
(contributionRange) => range.startLineNumber <= contributionRange.endLineNumber,
|
|
289
818
|
);
|
|
290
|
-
|
|
291
|
-
const isShowHoverToSingleLine =
|
|
292
|
-
this.isMultiCommentsForSingleLine ||
|
|
293
|
-
!this.commentsThreads.some(
|
|
294
|
-
(thread) => thread.uri.isEqual(uri) && thread.range.startLineNumber === range.startLineNumber,
|
|
295
|
-
);
|
|
296
|
-
return isProviderRanges && isShowHoverToSingleLine;
|
|
819
|
+
return isProviderRanges;
|
|
297
820
|
}
|
|
298
821
|
|
|
299
822
|
public createThread(
|
|
@@ -305,7 +828,7 @@ export class CommentsService extends Disposable implements ICommentsService {
|
|
|
305
828
|
},
|
|
306
829
|
) {
|
|
307
830
|
// 获取当前 range 的 providerId,用于 commentController contextKey 的生成
|
|
308
|
-
const providerId = this.getProviderIdsByLine(range.
|
|
831
|
+
const providerId = this.getProviderIdsByLine(range.endLineNumber)[0];
|
|
309
832
|
const thread = this.injector.get(CommentsThread, [uri, range, providerId, options]);
|
|
310
833
|
thread.onDispose(() => {
|
|
311
834
|
this.threads.delete(thread.id);
|
|
@@ -367,13 +890,17 @@ export class CommentsService extends Disposable implements ICommentsService {
|
|
|
367
890
|
for (const thread of (parent as CommentFileNode).threads) {
|
|
368
891
|
const [first] = thread.comments;
|
|
369
892
|
const comment = typeof first.body === 'string' ? first.body : first.body.value;
|
|
893
|
+
let description = `[Ln ${thread.range.startLineNumber}]`;
|
|
894
|
+
if (thread.range.startLineNumber !== thread.range.endLineNumber) {
|
|
895
|
+
description = `[Ln ${thread.range.startLineNumber}-${thread.range.endLineNumber}]`;
|
|
896
|
+
}
|
|
370
897
|
childs.push(
|
|
371
898
|
new CommentContentNode(
|
|
372
899
|
this,
|
|
373
900
|
thread,
|
|
374
901
|
comment,
|
|
375
|
-
|
|
376
|
-
first.author.iconPath
|
|
902
|
+
description,
|
|
903
|
+
first.author.iconPath && (first.author.iconPath as URI)?.authority
|
|
377
904
|
? (this.iconService.fromIcon('', first.author.iconPath.toString(), IconType.Background) as string)
|
|
378
905
|
: getIcon('message'),
|
|
379
906
|
first.author,
|
|
@@ -444,13 +971,16 @@ export class CommentsService extends Disposable implements ICommentsService {
|
|
|
444
971
|
return await cache.promise;
|
|
445
972
|
}
|
|
446
973
|
|
|
447
|
-
const model = this.documentService.getModelReference(uri, '
|
|
974
|
+
const model = this.documentService.getModelReference(uri, 'Get Comment Range');
|
|
448
975
|
const rangePromise: Promise<IRange[] | undefined>[] = [];
|
|
449
976
|
for (const rangeProvider of this.rangeProviderMap) {
|
|
450
977
|
const [id, provider] = rangeProvider;
|
|
451
978
|
rangePromise.push(
|
|
452
979
|
(async () => {
|
|
453
|
-
|
|
980
|
+
if (!model?.instance) {
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
const ranges = await provider.getCommentingRanges(model.instance);
|
|
454
984
|
if (ranges && ranges.length) {
|
|
455
985
|
// FIXME: ranges 会被 Diff uri 的两个 range 互相覆盖,导致可能根据行查不到 provider
|
|
456
986
|
this.rangeOwner.set(id, ranges);
|
|
@@ -503,7 +1033,12 @@ export class CommentsService extends Disposable implements ICommentsService {
|
|
|
503
1033
|
return isCurrentThread;
|
|
504
1034
|
})
|
|
505
1035
|
.map((thread) => ({
|
|
506
|
-
range:
|
|
1036
|
+
range: {
|
|
1037
|
+
startLineNumber: thread.range.endLineNumber,
|
|
1038
|
+
endLineNumber: thread.range.endLineNumber,
|
|
1039
|
+
startColumn: thread.range.endColumn,
|
|
1040
|
+
endColumn: thread.range.endColumn,
|
|
1041
|
+
},
|
|
507
1042
|
options: this.createThreadDecoration(thread) as unknown as monaco.editor.IModelDecorationOptions,
|
|
508
1043
|
})),
|
|
509
1044
|
});
|
|
@@ -543,6 +1078,7 @@ export class CommentsService extends Disposable implements ICommentsService {
|
|
|
543
1078
|
this.rangeProviderMap.set(id, provider);
|
|
544
1079
|
// 注册一个新的 range provider 后清理掉之前的缓存
|
|
545
1080
|
this.providerDecorationCache.clear();
|
|
1081
|
+
this.commentRangeProviderChangeEmitter.fire();
|
|
546
1082
|
return Disposable.create(() => {
|
|
547
1083
|
this.rangeProviderMap.delete(id);
|
|
548
1084
|
this.rangeOwner.delete(id);
|
|
@@ -563,7 +1099,6 @@ export class CommentsService extends Disposable implements ICommentsService {
|
|
|
563
1099
|
public getProviderIdsByLine(line: number): string[] {
|
|
564
1100
|
const result: string[] = [];
|
|
565
1101
|
if (this.rangeOwner.size === 1) {
|
|
566
|
-
// 只有一个provider,直接返回
|
|
567
1102
|
return [this.rangeOwner.keys().next().value];
|
|
568
1103
|
}
|
|
569
1104
|
for (const rangeOwner of this.rangeOwner) {
|