@opensumi/ide-comments 3.0.5-next-1717473339.0 → 3.0.5-next-1717490251.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.
@@ -1,3 +1,4 @@
1
+ import debounce from 'lodash/debounce';
1
2
  import flattenDeep from 'lodash/flattenDeep';
2
3
  import groupBy from 'lodash/groupBy';
3
4
 
@@ -35,7 +36,6 @@ import * as textModel from '@opensumi/monaco-editor-core/esm/vs/editor/common/mo
35
36
 
36
37
  import {
37
38
  CommentPanelId,
38
- CommentThreadCollapsibleState,
39
39
  ICommentRangeProvider,
40
40
  ICommentsFeatureRegistry,
41
41
  ICommentsService,
@@ -88,9 +88,6 @@ 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
-
94
91
  private threadsCreatedEmitter = new Emitter<ICommentsThread>();
95
92
 
96
93
  private rangeProviderMap = new Map<string, ICommentRangeProvider>();
@@ -99,10 +96,8 @@ export class CommentsService extends Disposable implements ICommentsService {
99
96
 
100
97
  private providerDecorationCache = new LRUCache<string, Deferred<IRange[]>>(10000);
101
98
 
102
- private commentRangeDecorationMap: Map<string, string[]> = new Map();
103
-
104
99
  // 默认在 file 协议和 git 协议中显示评论数据
105
- private shouldShowCommentsSchemes = new Set(['file', 'git', 'diff']);
100
+ private shouldShowCommentsSchemes = new Set(['file', 'git']);
106
101
 
107
102
  private decorationProviderDisposer = Disposable.NULL;
108
103
 
@@ -137,18 +132,6 @@ export class CommentsService extends Disposable implements ICommentsService {
137
132
  return this.threadsCreatedEmitter.event;
138
133
  }
139
134
 
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
-
152
135
  /**
153
136
  * -------------------------------- IMPORTANT --------------------------------
154
137
  * 需要注意区分 model.IModelDecorationOptions 与 monaco.editor.IModelDecorationOptions 两个类型
@@ -163,55 +146,12 @@ export class CommentsService extends Disposable implements ICommentsService {
163
146
  const avatar =
164
147
  thread.comments.length === 0 ? this.currentAuthorAvatar : thread.comments[0].author.iconPath?.toString();
165
148
  const icon = avatar
166
- ? `${this.iconService.fromIcon('', avatar, IconType.Background)} avatar-icon`
167
- : this.iconService.fromString('$(comment)');
149
+ ? this.iconService.fromIcon('', avatar, IconType.Background)
150
+ : this.iconService.fromString('$(comment-unresolved)');
168
151
  const decorationOptions: model.IModelDecorationOptions = {
169
152
  description: 'comments-thread-decoration',
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(' '),
153
+ // 创建评论显示在 glyph margin 处
154
+ glyphMarginClassName: ['comments-decoration', 'comments-thread', icon].join(' '),
215
155
  };
216
156
  return textModel.ModelDecorationOptions.createDynamic(decorationOptions);
217
157
  }
@@ -219,39 +159,7 @@ export class CommentsService extends Disposable implements ICommentsService {
219
159
  private createHoverDecoration(): model.IModelDecorationOptions {
220
160
  const decorationOptions: model.IModelDecorationOptions = {
221
161
  description: 'comments-hover-decoration',
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(' '),
162
+ linesDecorationsClassName: ['comments-decoration', 'comments-add', getIcon('add-comments')].join(' '),
255
163
  };
256
164
  return textModel.ModelDecorationOptions.createDynamic(decorationOptions);
257
165
  }
@@ -283,56 +191,49 @@ export class CommentsService extends Disposable implements ICommentsService {
283
191
  this.registerDecorationProvider();
284
192
  }
285
193
 
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
-
303
194
  public handleOnCreateEditor(editor: IEditor) {
304
- this.allEditors.push(editor);
305
- this.editor = editor;
306
195
  const disposer = new Disposable();
307
- let commentRangeDecorationIds: string[] = [];
308
- let hasHiddenArea = false;
309
196
 
310
197
  disposer.addDispose(
311
198
  editor.monacoEditor.onMouseDown((event) => {
312
199
  if (
313
200
  event.target.type === monacoBrowser.editor.MouseTargetType.GUTTER_LINE_DECORATIONS &&
314
201
  event.target.element &&
315
- event.target.element.className.indexOf('comment-add') > -1
202
+ event.target.element.className.indexOf('comments-add') > -1
316
203
  ) {
317
204
  const { target } = event;
318
205
  if (target && target.range) {
319
206
  const { range } = target;
320
- this.startCommentRange = range;
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
+ }
321
219
  event.event.stopPropagation();
322
220
  }
323
221
  } else if (
324
222
  event.target.type === monacoBrowser.editor.MouseTargetType.GUTTER_GLYPH_MARGIN &&
325
223
  event.target.element &&
326
- event.target.element.className.indexOf('comment-thread') > -1
224
+ event.target.element.className.indexOf('comments-thread') > -1
327
225
  ) {
328
226
  const { target } = event;
329
227
  if (target && target.range) {
330
228
  const { range } = target;
331
229
  const threads = this.commentsThreads.filter(
332
- (thread) => thread.uri.isEqual(editor.currentUri!) && thread.range.endLineNumber === range.endLineNumber,
230
+ (thread) =>
231
+ thread.uri.isEqual(editor.currentUri!) && thread.range.startLineNumber === range.startLineNumber,
333
232
  );
334
233
  if (threads.length) {
234
+ // 判断当前 widget 是否是显示的
335
235
  const isShowWidget = threads.some((thread) => thread.isShowWidget(editor));
236
+
336
237
  if (isShowWidget) {
337
238
  threads.forEach((thread) => thread.hide(editor));
338
239
  } else {
@@ -344,479 +245,55 @@ export class CommentsService extends Disposable implements ICommentsService {
344
245
  }
345
246
  }),
346
247
  );
347
-
248
+ let oldDecorations: string[] = [];
348
249
  disposer.addDispose(
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
- );
250
+ editor.monacoEditor.onMouseMove(
251
+ debounce(async (event) => {
252
+ const uri = editor.currentUri;
414
253
 
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 {
254
+ const range = event.target.range;
446
255
  if (uri && range && (await this.shouldShowHoverDecoration(uri, range))) {
447
- const newDecorations = [
256
+ oldDecorations = editor.monacoEditor.deltaDecorations(oldDecorations, [
448
257
  {
449
258
  range: positionToRange(range.startLineNumber),
450
259
  options: this.createHoverDecoration() as unknown as monaco.editor.IModelDecorationOptions,
451
260
  },
452
- ];
453
- commentRangeDecorationIds = editor.monacoEditor.deltaDecorations(commentRangeDecorationIds, newDecorations);
261
+ ]);
262
+ } else {
263
+ oldDecorations = editor.monacoEditor.deltaDecorations(oldDecorations, []);
454
264
  }
455
- }
456
- }),
457
- );
458
-
459
- disposer.addDispose(
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
- }),
265
+ }, 10),
266
+ ),
494
267
  );
495
268
 
496
269
  disposer.addDispose(
497
- this.onDidChangeCurrentCommentThread((thread) => {
498
- this.updateActiveThreadDecoration(thread);
499
- }),
270
+ editor.monacoEditor.onMouseLeave(
271
+ debounce(() => {
272
+ oldDecorations = editor.monacoEditor.deltaDecorations(oldDecorations, []);
273
+ }, 10),
274
+ ),
500
275
  );
501
276
 
502
- this.tryUpdateReservedSpace(editor);
503
-
504
- disposer.addDispose(
505
- editor.monacoEditor.onDidChangeModel(() => {
506
- this.renderCommentRange(editor);
507
- this.tryUpdateReservedSpace(editor);
508
- }),
509
- );
510
277
  return disposer;
511
278
  }
512
279
 
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
-
811
280
  private async shouldShowHoverDecoration(uri: URI, range: IRange) {
812
281
  if (!this.shouldShowCommentsSchemes.has(uri.scheme)) {
813
282
  return false;
814
283
  }
815
284
  const contributionRanges = await this.getContributionRanges(uri);
816
285
  const isProviderRanges = contributionRanges.some(
817
- (contributionRange) => range.startLineNumber <= contributionRange.endLineNumber,
286
+ (contributionRange) =>
287
+ range.startLineNumber >= contributionRange.startLineNumber &&
288
+ range.startLineNumber <= contributionRange.endLineNumber,
818
289
  );
819
- return isProviderRanges;
290
+ // 如果不支持对同一行进行多个评论,那么过滤掉当前有 thread 行号的 decoration
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;
820
297
  }
821
298
 
822
299
  public createThread(
@@ -828,7 +305,7 @@ export class CommentsService extends Disposable implements ICommentsService {
828
305
  },
829
306
  ) {
830
307
  // 获取当前 range 的 providerId,用于 commentController contextKey 的生成
831
- const providerId = this.getProviderIdsByLine(range.endLineNumber)[0];
308
+ const providerId = this.getProviderIdsByLine(range.startLineNumber)[0];
832
309
  const thread = this.injector.get(CommentsThread, [uri, range, providerId, options]);
833
310
  thread.onDispose(() => {
834
311
  this.threads.delete(thread.id);
@@ -890,17 +367,13 @@ export class CommentsService extends Disposable implements ICommentsService {
890
367
  for (const thread of (parent as CommentFileNode).threads) {
891
368
  const [first] = thread.comments;
892
369
  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
- }
897
370
  childs.push(
898
371
  new CommentContentNode(
899
372
  this,
900
373
  thread,
901
374
  comment,
902
- description,
903
- first.author.iconPath && (first.author.iconPath as URI)?.authority
375
+ `[Ln ${thread.range.startLineNumber}]`,
376
+ first.author.iconPath
904
377
  ? (this.iconService.fromIcon('', first.author.iconPath.toString(), IconType.Background) as string)
905
378
  : getIcon('message'),
906
379
  first.author,
@@ -971,16 +444,13 @@ export class CommentsService extends Disposable implements ICommentsService {
971
444
  return await cache.promise;
972
445
  }
973
446
 
974
- const model = this.documentService.getModelReference(uri, 'Get Comment Range');
447
+ const model = this.documentService.getModelReference(uri, 'get-contribution-rages');
975
448
  const rangePromise: Promise<IRange[] | undefined>[] = [];
976
449
  for (const rangeProvider of this.rangeProviderMap) {
977
450
  const [id, provider] = rangeProvider;
978
451
  rangePromise.push(
979
452
  (async () => {
980
- if (!model?.instance) {
981
- return;
982
- }
983
- const ranges = await provider.getCommentingRanges(model.instance);
453
+ const ranges = await provider.getCommentingRanges(model?.instance!);
984
454
  if (ranges && ranges.length) {
985
455
  // FIXME: ranges 会被 Diff uri 的两个 range 互相覆盖,导致可能根据行查不到 provider
986
456
  this.rangeOwner.set(id, ranges);
@@ -1033,12 +503,7 @@ export class CommentsService extends Disposable implements ICommentsService {
1033
503
  return isCurrentThread;
1034
504
  })
1035
505
  .map((thread) => ({
1036
- range: {
1037
- startLineNumber: thread.range.endLineNumber,
1038
- endLineNumber: thread.range.endLineNumber,
1039
- startColumn: thread.range.endColumn,
1040
- endColumn: thread.range.endColumn,
1041
- },
506
+ range: thread.range,
1042
507
  options: this.createThreadDecoration(thread) as unknown as monaco.editor.IModelDecorationOptions,
1043
508
  })),
1044
509
  });
@@ -1078,7 +543,6 @@ export class CommentsService extends Disposable implements ICommentsService {
1078
543
  this.rangeProviderMap.set(id, provider);
1079
544
  // 注册一个新的 range provider 后清理掉之前的缓存
1080
545
  this.providerDecorationCache.clear();
1081
- this.commentRangeProviderChangeEmitter.fire();
1082
546
  return Disposable.create(() => {
1083
547
  this.rangeProviderMap.delete(id);
1084
548
  this.rangeOwner.delete(id);
@@ -1099,6 +563,7 @@ export class CommentsService extends Disposable implements ICommentsService {
1099
563
  public getProviderIdsByLine(line: number): string[] {
1100
564
  const result: string[] = [];
1101
565
  if (this.rangeOwner.size === 1) {
566
+ // 只有一个provider,直接返回
1102
567
  return [this.rangeOwner.keys().next().value];
1103
568
  }
1104
569
  for (const rangeOwner of this.rangeOwner) {