@opensumi/ide-ai-native 3.2.5 → 3.2.6-next-1724809247.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.
Files changed (178) hide show
  1. package/lib/browser/ai-core.contribution.d.ts +1 -0
  2. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  3. package/lib/browser/ai-core.contribution.js +12 -23
  4. package/lib/browser/ai-core.contribution.js.map +1 -1
  5. package/lib/browser/ai-editor.contribution.d.ts +1 -0
  6. package/lib/browser/ai-editor.contribution.d.ts.map +1 -1
  7. package/lib/browser/ai-editor.contribution.js +8 -0
  8. package/lib/browser/ai-editor.contribution.js.map +1 -1
  9. package/lib/browser/chat/chat-agent.service.d.ts +1 -0
  10. package/lib/browser/chat/chat-agent.service.d.ts.map +1 -1
  11. package/lib/browser/chat/chat-agent.service.js +1 -3
  12. package/lib/browser/chat/chat-agent.service.js.map +1 -1
  13. package/lib/browser/chat/chat.module.less +1 -0
  14. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  15. package/lib/browser/chat/chat.view.js +21 -3
  16. package/lib/browser/chat/chat.view.js.map +1 -1
  17. package/lib/browser/components/ChatEditor.d.ts.map +1 -1
  18. package/lib/browser/components/ChatEditor.js +2 -2
  19. package/lib/browser/components/ChatEditor.js.map +1 -1
  20. package/lib/browser/components/ChatMarkdown.js +1 -1
  21. package/lib/browser/components/ChatMarkdown.js.map +1 -1
  22. package/lib/browser/components/ChatThinking.d.ts.map +1 -1
  23. package/lib/browser/components/ChatThinking.js +2 -2
  24. package/lib/browser/components/ChatThinking.js.map +1 -1
  25. package/lib/browser/contextkey/ai-native.contextkey.service.d.ts +1 -0
  26. package/lib/browser/contextkey/ai-native.contextkey.service.d.ts.map +1 -1
  27. package/lib/browser/contextkey/ai-native.contextkey.service.js +1 -0
  28. package/lib/browser/contextkey/ai-native.contextkey.service.js.map +1 -1
  29. package/lib/browser/contrib/inline-completions/completeProvider.d.ts +4 -31
  30. package/lib/browser/contrib/inline-completions/completeProvider.d.ts.map +1 -1
  31. package/lib/browser/contrib/inline-completions/completeProvider.js +3 -224
  32. package/lib/browser/contrib/inline-completions/completeProvider.js.map +1 -1
  33. package/lib/browser/contrib/inline-completions/inline-completions.handler.d.ts +1 -3
  34. package/lib/browser/contrib/inline-completions/inline-completions.handler.d.ts.map +1 -1
  35. package/lib/browser/contrib/inline-completions/inline-completions.handler.js +8 -20
  36. package/lib/browser/contrib/inline-completions/inline-completions.handler.js.map +1 -1
  37. package/lib/browser/contrib/inline-completions/model/competionModel.d.ts +2 -2
  38. package/lib/browser/contrib/inline-completions/model/competionModel.d.ts.map +1 -1
  39. package/lib/browser/contrib/inline-completions/model/inlineCompletionRequestTask.d.ts +28 -0
  40. package/lib/browser/contrib/inline-completions/model/inlineCompletionRequestTask.d.ts.map +1 -0
  41. package/lib/browser/contrib/inline-completions/model/inlineCompletionRequestTask.js +209 -0
  42. package/lib/browser/contrib/inline-completions/model/inlineCompletionRequestTask.js.map +1 -0
  43. package/lib/browser/contrib/inline-completions/promptCache.d.ts +3 -2
  44. package/lib/browser/contrib/inline-completions/promptCache.d.ts.map +1 -1
  45. package/lib/browser/contrib/inline-completions/promptCache.js.map +1 -1
  46. package/lib/browser/contrib/inline-completions/service/ai-completions.service.d.ts +5 -6
  47. package/lib/browser/contrib/inline-completions/service/ai-completions.service.d.ts.map +1 -1
  48. package/lib/browser/contrib/inline-completions/service/ai-completions.service.js +33 -23
  49. package/lib/browser/contrib/inline-completions/service/ai-completions.service.js.map +1 -1
  50. package/lib/browser/contrib/intelligent-completions/diff-computer.d.ts +18 -0
  51. package/lib/browser/contrib/intelligent-completions/diff-computer.d.ts.map +1 -0
  52. package/lib/browser/contrib/intelligent-completions/diff-computer.js +144 -0
  53. package/lib/browser/contrib/intelligent-completions/diff-computer.js.map +1 -0
  54. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.d.ts +8 -0
  55. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.d.ts.map +1 -0
  56. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js +47 -0
  57. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js.map +1 -0
  58. package/lib/browser/contrib/intelligent-completions/intelligent-completions.d.ts +15 -0
  59. package/lib/browser/contrib/intelligent-completions/intelligent-completions.d.ts.map +1 -0
  60. package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.d.ts +8 -0
  61. package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.d.ts.map +1 -0
  62. package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.js +19 -0
  63. package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.js.map +1 -0
  64. package/lib/browser/contrib/intelligent-completions/intelligent-completions.handler.d.ts +20 -0
  65. package/lib/browser/contrib/intelligent-completions/intelligent-completions.handler.d.ts.map +1 -0
  66. package/lib/browser/contrib/intelligent-completions/intelligent-completions.handler.js +94 -0
  67. package/lib/browser/contrib/intelligent-completions/intelligent-completions.handler.js.map +1 -0
  68. package/lib/browser/contrib/intelligent-completions/intelligent-completions.js +3 -0
  69. package/lib/browser/contrib/intelligent-completions/intelligent-completions.js.map +1 -0
  70. package/lib/browser/contrib/intelligent-completions/multi-line.decoration.d.ts +33 -0
  71. package/lib/browser/contrib/intelligent-completions/multi-line.decoration.d.ts.map +1 -0
  72. package/lib/browser/contrib/intelligent-completions/multi-line.decoration.js +258 -0
  73. package/lib/browser/contrib/intelligent-completions/multi-line.decoration.js.map +1 -0
  74. package/lib/browser/contrib/merge-conflict/merge-conflict.feature.registry.d.ts +0 -1
  75. package/lib/browser/contrib/merge-conflict/merge-conflict.feature.registry.d.ts.map +1 -1
  76. package/lib/browser/contrib/merge-conflict/merge-conflict.feature.registry.js +0 -3
  77. package/lib/browser/contrib/merge-conflict/merge-conflict.feature.registry.js.map +1 -1
  78. package/lib/browser/index.d.ts.map +1 -1
  79. package/lib/browser/index.js +7 -0
  80. package/lib/browser/index.js.map +1 -1
  81. package/lib/browser/layout/ai-layout.d.ts.map +1 -1
  82. package/lib/browser/layout/ai-layout.js +4 -4
  83. package/lib/browser/layout/ai-layout.js.map +1 -1
  84. package/lib/browser/layout/layout.module.less +0 -9
  85. package/lib/browser/model/enhanceDecorationsCollection.d.ts +38 -4
  86. package/lib/browser/model/enhanceDecorationsCollection.d.ts.map +1 -1
  87. package/lib/browser/model/enhanceDecorationsCollection.js +44 -23
  88. package/lib/browser/model/enhanceDecorationsCollection.js.map +1 -1
  89. package/lib/browser/types.d.ts +20 -13
  90. package/lib/browser/types.d.ts.map +1 -1
  91. package/lib/browser/types.js +0 -4
  92. package/lib/browser/types.js.map +1 -1
  93. package/lib/browser/widget/inline-chat/inline-chat.handler.d.ts.map +1 -1
  94. package/lib/browser/widget/inline-chat/inline-chat.handler.js +18 -10
  95. package/lib/browser/widget/inline-chat/inline-chat.handler.js.map +1 -1
  96. package/lib/browser/widget/inline-chat/inline-content-widget.d.ts +5 -2
  97. package/lib/browser/widget/inline-chat/inline-content-widget.d.ts.map +1 -1
  98. package/lib/browser/widget/inline-chat/inline-content-widget.js +45 -53
  99. package/lib/browser/widget/inline-chat/inline-content-widget.js.map +1 -1
  100. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts +16 -14
  101. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts.map +1 -1
  102. package/lib/browser/widget/inline-diff/inline-diff-previewer.js +98 -46
  103. package/lib/browser/widget/inline-diff/inline-diff-previewer.js.map +1 -1
  104. package/lib/browser/widget/inline-diff/inline-diff-widget.d.ts +5 -2
  105. package/lib/browser/widget/inline-diff/inline-diff-widget.d.ts.map +1 -1
  106. package/lib/browser/widget/inline-diff/inline-diff-widget.js +11 -2
  107. package/lib/browser/widget/inline-diff/inline-diff-widget.js.map +1 -1
  108. package/lib/browser/widget/inline-diff/inline-diff.handler.d.ts +12 -13
  109. package/lib/browser/widget/inline-diff/inline-diff.handler.d.ts.map +1 -1
  110. package/lib/browser/widget/inline-diff/inline-diff.handler.js +69 -77
  111. package/lib/browser/widget/inline-diff/inline-diff.handler.js.map +1 -1
  112. package/lib/browser/widget/inline-input/inline-input-widget.d.ts +1 -0
  113. package/lib/browser/widget/inline-input/inline-input-widget.d.ts.map +1 -1
  114. package/lib/browser/widget/inline-input/inline-input-widget.js +1 -0
  115. package/lib/browser/widget/inline-input/inline-input-widget.js.map +1 -1
  116. package/lib/browser/widget/inline-input/inline-input.handler.js +2 -2
  117. package/lib/browser/widget/inline-input/inline-input.handler.js.map +1 -1
  118. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +28 -15
  119. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  120. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +56 -31
  121. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  122. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.module.less +9 -6
  123. package/lib/browser/widget/inline-stream-diff/live-preview-stack.d.ts +21 -0
  124. package/lib/browser/widget/inline-stream-diff/live-preview-stack.d.ts.map +1 -0
  125. package/lib/browser/widget/inline-stream-diff/live-preview-stack.js +41 -0
  126. package/lib/browser/widget/inline-stream-diff/live-preview-stack.js.map +1 -0
  127. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts +105 -0
  128. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts.map +1 -0
  129. package/lib/browser/widget/inline-stream-diff/live-preview.component.js +237 -0
  130. package/lib/browser/widget/inline-stream-diff/live-preview.component.js.map +1 -0
  131. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts +27 -103
  132. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts.map +1 -1
  133. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js +186 -370
  134. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js.map +1 -1
  135. package/lib/common/index.d.ts +1 -0
  136. package/lib/common/index.d.ts.map +1 -1
  137. package/lib/common/index.js.map +1 -1
  138. package/package.json +19 -19
  139. package/src/browser/ai-core.contribution.ts +12 -26
  140. package/src/browser/ai-editor.contribution.ts +9 -0
  141. package/src/browser/chat/chat-agent.service.ts +1 -3
  142. package/src/browser/chat/chat.module.less +1 -0
  143. package/src/browser/chat/chat.view.tsx +48 -3
  144. package/src/browser/components/ChatEditor.tsx +14 -2
  145. package/src/browser/components/ChatMarkdown.tsx +1 -1
  146. package/src/browser/components/ChatThinking.tsx +3 -1
  147. package/src/browser/contextkey/ai-native.contextkey.service.ts +3 -0
  148. package/src/browser/contrib/inline-completions/completeProvider.ts +7 -289
  149. package/src/browser/contrib/inline-completions/inline-completions.handler.ts +15 -22
  150. package/src/browser/contrib/inline-completions/model/competionModel.ts +3 -2
  151. package/src/browser/contrib/inline-completions/model/inlineCompletionRequestTask.ts +270 -0
  152. package/src/browser/contrib/inline-completions/promptCache.ts +3 -2
  153. package/src/browser/contrib/inline-completions/service/ai-completions.service.ts +37 -36
  154. package/src/browser/contrib/intelligent-completions/diff-computer.ts +185 -0
  155. package/src/browser/contrib/intelligent-completions/intelligent-completions.contribution.ts +54 -0
  156. package/src/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.ts +17 -0
  157. package/src/browser/contrib/intelligent-completions/intelligent-completions.handler.ts +130 -0
  158. package/src/browser/contrib/intelligent-completions/intelligent-completions.ts +15 -0
  159. package/src/browser/contrib/intelligent-completions/multi-line.decoration.ts +325 -0
  160. package/src/browser/contrib/merge-conflict/merge-conflict.feature.registry.ts +0 -4
  161. package/src/browser/index.ts +8 -1
  162. package/src/browser/layout/ai-layout.tsx +7 -1
  163. package/src/browser/layout/layout.module.less +0 -9
  164. package/src/browser/model/enhanceDecorationsCollection.ts +71 -34
  165. package/src/browser/types.ts +27 -14
  166. package/src/browser/widget/inline-chat/inline-chat.handler.ts +20 -16
  167. package/src/browser/widget/inline-chat/inline-content-widget.tsx +58 -61
  168. package/src/browser/widget/inline-diff/inline-diff-previewer.ts +102 -62
  169. package/src/browser/widget/inline-diff/inline-diff-widget.tsx +36 -5
  170. package/src/browser/widget/inline-diff/inline-diff.handler.ts +82 -94
  171. package/src/browser/widget/inline-input/inline-input-widget.tsx +1 -0
  172. package/src/browser/widget/inline-input/inline-input.handler.ts +2 -2
  173. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +108 -45
  174. package/src/browser/widget/inline-stream-diff/inline-stream-diff.module.less +9 -6
  175. package/src/browser/widget/inline-stream-diff/live-preview-stack.ts +52 -0
  176. package/src/browser/widget/inline-stream-diff/live-preview.component.tsx +388 -0
  177. package/src/browser/widget/inline-stream-diff/live-preview.decoration.tsx +244 -544
  178. package/src/common/index.ts +2 -0
@@ -226,6 +226,18 @@ export class InlineChatHandler extends Disposable {
226
226
  return;
227
227
  }
228
228
 
229
+ const previewer = () => {
230
+ // 兼容 providerDiffPreviewStrategy api
231
+ const strategy = handler.providerDiffPreviewStrategy
232
+ ? handler.providerDiffPreviewStrategy
233
+ : handler.providePreviewStrategy;
234
+ if (!strategy) {
235
+ return undefined;
236
+ }
237
+
238
+ return strategy.bind(this, monacoEditor, this.cancelIndicator.token);
239
+ };
240
+
229
241
  this.runInlineChatAction(
230
242
  monacoEditor,
231
243
  () => {
@@ -238,9 +250,7 @@ export class InlineChatHandler extends Disposable {
238
250
  return relationId;
239
251
  },
240
252
  handler.execute ? handler.execute!.bind(this, monacoEditor, this.cancelIndicator.token) : undefined,
241
- handler.providerDiffPreviewStrategy
242
- ? handler.providerDiffPreviewStrategy.bind(this, monacoEditor, this.cancelIndicator.token)
243
- : undefined,
253
+ previewer(),
244
254
  );
245
255
  }),
246
256
  );
@@ -268,8 +278,8 @@ export class InlineChatHandler extends Disposable {
268
278
  handler.execute && strategy === ERunStrategy.EXECUTE
269
279
  ? handler.execute!.bind(this, monacoEditor, value, this.cancelIndicator.token)
270
280
  : undefined,
271
- handler.providerDiffPreviewStrategy && strategy === ERunStrategy.DIFF_PREVIEW
272
- ? handler.providerDiffPreviewStrategy.bind(this, monacoEditor, value, this.cancelIndicator.token)
281
+ handler.providePreviewStrategy && strategy === ERunStrategy.PREVIEW
282
+ ? handler.providePreviewStrategy.bind(this, monacoEditor, value, this.cancelIndicator.token)
273
283
  : undefined,
274
284
  );
275
285
  }),
@@ -400,7 +410,7 @@ export class InlineChatHandler extends Disposable {
400
410
 
401
411
  const model = monacoEditor.getModel();
402
412
 
403
- this.inlineDiffHandler.hidePreviewer(monacoEditor);
413
+ this.inlineDiffHandler.destroyPreviewer(model!.uri.toString());
404
414
  this.aiInlineChatOperationDisposable.dispose();
405
415
 
406
416
  this.ensureInlineChatVisible(monacoEditor, crossSelection);
@@ -442,7 +452,7 @@ export class InlineChatHandler extends Disposable {
442
452
 
443
453
  this.aiInlineChatOperationDisposable.addDispose([
444
454
  this.aiInlineContentWidget.onResultClick((kind: EResultKind) => {
445
- this.inlineDiffHandler.handleAction(monacoEditor, kind);
455
+ this.inlineDiffHandler.handleAction(kind);
446
456
 
447
457
  if (kind === EResultKind.ACCEPT) {
448
458
  this.aiReporter.end(relationId, { message: 'accept', success: true, isReceive: true });
@@ -477,7 +487,7 @@ export class InlineChatHandler extends Disposable {
477
487
  monacoEditor: monaco.ICodeEditor,
478
488
  reporterFn: () => string,
479
489
  execute?: () => MaybePromise<void>,
480
- providerDiffPreviewStrategy?: () => MaybePromise<ChatResponse | InlineChatController>,
490
+ providerPreview?: () => MaybePromise<ChatResponse | InlineChatController>,
481
491
  ) {
482
492
  const selection = monacoEditor.getSelection();
483
493
  if (!selection) {
@@ -490,20 +500,14 @@ export class InlineChatHandler extends Disposable {
490
500
  this.disposeAllWidget();
491
501
  }
492
502
 
493
- if (providerDiffPreviewStrategy) {
503
+ if (providerPreview) {
494
504
  const crossSelection = selection
495
505
  .setStartPosition(selection.startLineNumber, 1)
496
506
  .setEndPosition(selection.endLineNumber, Number.MAX_SAFE_INTEGER);
497
507
 
498
508
  const relationId = reporterFn();
499
509
 
500
- await this.handleDiffPreviewStrategy(
501
- monacoEditor,
502
- providerDiffPreviewStrategy,
503
- crossSelection,
504
- relationId,
505
- false,
506
- );
510
+ await this.handleDiffPreviewStrategy(monacoEditor, providerPreview, crossSelection, relationId, false);
507
511
  }
508
512
  }
509
513
  }
@@ -351,39 +351,42 @@ export class AIInlineContentWidget extends ReactInlineContentWidget {
351
351
  };
352
352
  }
353
353
 
354
- private recheckPosition(lineNumber: number, column: number): monaco.editor.IContentWidgetPosition {
355
- const preNonWhitespaceColumn = this.safeGetLineLastNonWhitespaceColumn(lineNumber - 1);
356
- const curNonWhitespaceColumn = this.safeGetLineLastNonWhitespaceColumn(lineNumber);
357
- const nextNonWhitespaceColumn = this.safeGetLineLastNonWhitespaceColumn(lineNumber + 1);
358
-
359
- let newPreference = [monacoBrowser.editor.ContentWidgetPositionPreference.ABOVE];
360
- let newLineNumber = lineNumber;
361
- let newColumn = column;
362
-
363
- if (curNonWhitespaceColumn >= nextNonWhitespaceColumn) {
364
- newPreference = [monacoBrowser.editor.ContentWidgetPositionPreference.BELOW];
365
- } else if (curNonWhitespaceColumn >= preNonWhitespaceColumn) {
366
- newPreference = [monacoBrowser.editor.ContentWidgetPositionPreference.ABOVE];
367
- } else {
368
- newColumn = Math.min(preNonWhitespaceColumn, nextNonWhitespaceColumn);
369
-
370
- if (preNonWhitespaceColumn >= nextNonWhitespaceColumn) {
371
- newPreference = [monacoBrowser.editor.ContentWidgetPositionPreference.BELOW];
372
- newLineNumber = lineNumber - 1;
373
- } else {
374
- newPreference = [monacoBrowser.editor.ContentWidgetPositionPreference.ABOVE];
375
- newLineNumber = lineNumber + 1;
376
- }
354
+ /**
355
+ * 以当前 selection 为中心取上下各 1 行重新计算
356
+ */
357
+ private recheckSelection(selection: monaco.Selection): monaco.editor.IContentWidgetPosition {
358
+ const preStartPosition = selection.getStartPosition();
359
+ const preEndPosition = selection.getEndPosition();
360
+
361
+ const model = this.editor.getModel()!;
362
+ const maxCount = model.getLineCount();
363
+
364
+ const safeAboveStartLine = Math.max(1, preEndPosition.lineNumber - 1);
365
+ const safeBelowEndLine = Math.min(maxCount, preEndPosition.lineNumber + 1);
366
+
367
+ const newStartPosition = preStartPosition.with(safeAboveStartLine, 1);
368
+ const newEndPosition = preEndPosition.with(
369
+ safeBelowEndLine,
370
+ this.safeGetLineLastNonWhitespaceColumn(safeBelowEndLine),
371
+ );
372
+
373
+ // 如果整个文档只有 1 行,则直接显示在右下角
374
+ if (maxCount === 1) {
375
+ return this.toBelowPosition(safeBelowEndLine, this.safeGetLineLastNonWhitespaceColumn(safeBelowEndLine));
377
376
  }
378
377
 
379
- if (lineNumber === 1 || lineNumber === 2) {
380
- newPreference = [monacoBrowser.editor.ContentWidgetPositionPreference.BELOW];
378
+ if (newEndPosition.lineNumber === 1 && preEndPosition.lineNumber !== preStartPosition.lineNumber) {
379
+ return this.computePosition(monaco.Selection.fromPositions(newStartPosition, newEndPosition));
381
380
  }
382
381
 
383
- return {
384
- position: new monaco.Position(newLineNumber, newColumn),
385
- preference: newPreference,
386
- };
382
+ const aboveMaxColumn = this.safeGetLineLastNonWhitespaceColumn(safeAboveStartLine);
383
+ const belowMaxColumn = this.safeGetLineLastNonWhitespaceColumn(safeBelowEndLine);
384
+ const currentMaxColumn = this.safeGetLineLastNonWhitespaceColumn(preEndPosition.lineNumber);
385
+ if (belowMaxColumn > currentMaxColumn && belowMaxColumn > aboveMaxColumn) {
386
+ return this.computePosition(monaco.Selection.fromPositions(newEndPosition, newStartPosition));
387
+ }
388
+
389
+ return this.computePosition(monaco.Selection.fromPositions(newStartPosition, newEndPosition));
387
390
  }
388
391
 
389
392
  private isProtrudeAbove(line: number) {
@@ -408,25 +411,27 @@ export class AIInlineContentWidget extends ReactInlineContentWidget {
408
411
  * 2. 靠近光标处周围没有字符的空白区域作为要显示的区域
409
412
  * 3. 显示的区域方向在右侧,左侧不考虑
410
413
  */
411
- protected computePosition(selection: monaco.Selection): monaco.editor.IContentWidgetPosition | null {
412
- const startPosition = selection.getStartPosition();
413
- const endPosition = selection.getEndPosition();
414
- const model = this.editor.getModel();
414
+ protected computePosition(selection: monaco.Selection): monaco.editor.IContentWidgetPosition {
415
+ let startPosition = selection.getStartPosition();
416
+ let endPosition = selection.getEndPosition();
417
+ let cursorPosition = selection.getPosition();
415
418
 
416
- if (!model) {
417
- return null;
419
+ const model = this.editor.getModel()!;
420
+ const maxCount = model.getLineCount();
421
+
422
+ // 只选中了一行
423
+ if (startPosition.lineNumber === endPosition.lineNumber) {
424
+ return this.recheckSelection(selection);
418
425
  }
419
426
 
420
- const cursorPosition = selection.getPosition();
421
- const getCursorLastNonWhitespaceColumn = this.safeGetLineLastNonWhitespaceColumn(cursorPosition.lineNumber);
427
+ if (endPosition.lineNumber - startPosition.lineNumber === 1) {
428
+ cursorPosition = endPosition;
429
+ }
422
430
 
423
- let targetLine: number | null = null;
424
- let direction: 'above' | 'below' | null = null;
431
+ const getCursorLastNonWhitespaceColumn = this.safeGetLineLastNonWhitespaceColumn(cursorPosition.lineNumber);
425
432
 
426
- // 用户只选中了一行
427
- if (startPosition.lineNumber === endPosition.lineNumber) {
428
- return this.recheckPosition(cursorPosition.lineNumber, cursorPosition.column);
429
- }
433
+ let targetLine: number = cursorPosition.lineNumber;
434
+ let direction: 'above' | 'below' = 'below';
430
435
 
431
436
  // 用户选中了多行,光标在选中的开始位置
432
437
  if (cursorPosition.equals(startPosition)) {
@@ -435,10 +440,9 @@ export class AIInlineContentWidget extends ReactInlineContentWidget {
435
440
  this.safeGetLineLastNonWhitespaceColumn(cursorPosition.lineNumber - 2),
436
441
  );
437
442
 
438
- // 如果上面两行的最后一个非空白字符的列数小于当前行的最后一个非空白字符的列数 + 10
439
- // 则直接显示在上面
440
- if (getMaxLastWhitespaceColumn < getCursorLastNonWhitespaceColumn + 10) {
441
- return this.toAbovePosition(cursorPosition.lineNumber, getMaxLastWhitespaceColumn + 1);
443
+ // 如果上面两行的最后一个非空白字符的列数小于当前行的最后一个非空白字符的列数, 则直接显示在上面
444
+ if (getMaxLastWhitespaceColumn <= getCursorLastNonWhitespaceColumn) {
445
+ return this.toAbovePosition(cursorPosition.lineNumber, getCursorLastNonWhitespaceColumn);
442
446
  }
443
447
 
444
448
  for (let i = startPosition.lineNumber; i <= endPosition.lineNumber; i++) {
@@ -459,11 +463,11 @@ export class AIInlineContentWidget extends ReactInlineContentWidget {
459
463
  this.safeGetLineLastNonWhitespaceColumn(cursorPosition.lineNumber + 2),
460
464
  );
461
465
 
462
- if (getMaxLastWhitespaceColumn < getCursorLastNonWhitespaceColumn + 10) {
463
- return this.toBelowPosition(cursorPosition.lineNumber, getMaxLastWhitespaceColumn + 1);
466
+ if (getMaxLastWhitespaceColumn <= getCursorLastNonWhitespaceColumn) {
467
+ return this.toBelowPosition(cursorPosition.lineNumber, getCursorLastNonWhitespaceColumn);
464
468
  }
465
469
 
466
- for (let i = endPosition.lineNumber; i >= startPosition.lineNumber; i--) {
470
+ for (let i = Math.min(maxCount, endPosition.lineNumber + 1); i >= startPosition.lineNumber; i--) {
467
471
  if (this.isProtrudeBelow(i)) {
468
472
  targetLine = i;
469
473
  direction = 'below';
@@ -477,18 +481,11 @@ export class AIInlineContentWidget extends ReactInlineContentWidget {
477
481
  }
478
482
  }
479
483
 
480
- if (targetLine && direction) {
481
- const column = this.safeGetLineLastNonWhitespaceColumn(targetLine) + 1;
484
+ const column = this.safeGetLineLastNonWhitespaceColumn(targetLine) + 1;
482
485
 
483
- if (direction === 'below') {
484
- return this.toBelowPosition(targetLine, column);
485
- }
486
- return this.toAbovePosition(targetLine, column);
486
+ if (direction === 'below') {
487
+ return this.toBelowPosition(targetLine, column);
487
488
  }
488
-
489
- return this.recheckPosition(
490
- cursorPosition.lineNumber,
491
- this.safeGetLineLastNonWhitespaceColumn(cursorPosition.lineNumber),
492
- );
489
+ return this.toAbovePosition(targetLine, column);
493
490
  }
494
491
  }
@@ -14,7 +14,6 @@ import {
14
14
  import { EResultKind } from '../inline-chat/inline-chat.service';
15
15
  import { AIInlineContentWidget } from '../inline-chat/inline-content-widget';
16
16
  import { EComputerMode, InlineStreamDiffHandler } from '../inline-stream-diff/inline-stream-diff.handler';
17
- import { SerializableState } from '../inline-stream-diff/live-preview.decoration';
18
17
 
19
18
  import { InlineDiffWidget } from './inline-diff-widget';
20
19
 
@@ -22,41 +21,30 @@ export interface IDiffPreviewerOptions {
22
21
  disposeWhenEditorClosed: boolean;
23
22
  }
24
23
 
25
- export interface IExtendedSerializedState extends SerializableState {
26
- readonly options: IDiffPreviewerOptions;
24
+ export interface IInlineDiffPreviewerNode extends IDisposable {
25
+ previewerOptions: IDiffPreviewerOptions;
26
+ setPreviewerOptions(options: IDiffPreviewerOptions): void;
27
27
  }
28
28
 
29
29
  @Injectable({ multiple: true })
30
- export abstract class BaseInlineDiffPreviewer<N extends IDisposable> extends Disposable {
30
+ export abstract class BaseInlineDiffPreviewer<N extends IInlineDiffPreviewerNode> extends Disposable {
31
31
  @Autowired(INJECTOR_TOKEN)
32
32
  protected readonly injector: Injector;
33
33
 
34
34
  protected inlineContentWidget: AIInlineContentWidget | null = null;
35
-
35
+ protected selection: Selection;
36
36
  protected model: ITextModel;
37
37
 
38
- get disposeWhenEditorClosed() {
39
- return this.options.disposeWhenEditorClosed;
40
- }
41
-
42
- constructor(
43
- protected readonly monacoEditor: ICodeEditor,
44
- protected readonly selection: Selection,
45
- public options: IDiffPreviewerOptions = {
46
- disposeWhenEditorClosed: true,
47
- },
48
- ) {
38
+ constructor(protected readonly monacoEditor: ICodeEditor) {
49
39
  super();
50
- this.node = this.createNode();
51
40
  this.model = this.monacoEditor.getModel()!;
52
41
  this.addDispose(
53
42
  Disposable.create(() => {
54
43
  if (this.inlineContentWidget) {
55
44
  this.inlineContentWidget.dispose();
56
45
  }
57
- if (this.node) {
58
- this.node.dispose();
59
- }
46
+
47
+ this.attachNode(undefined);
60
48
  }),
61
49
  );
62
50
  }
@@ -104,8 +92,12 @@ export abstract class BaseInlineDiffPreviewer<N extends IDisposable> extends Dis
104
92
  return newTextLines.join(eol);
105
93
  }
106
94
 
107
- protected node: N;
108
- public getNode(): N {
95
+ protected node: N | undefined;
96
+ public getNode(): N | undefined {
97
+ return this.node;
98
+ }
99
+
100
+ public createNodeSnapshot(): N | undefined {
109
101
  return this.node;
110
102
  }
111
103
 
@@ -123,11 +115,26 @@ export abstract class BaseInlineDiffPreviewer<N extends IDisposable> extends Dis
123
115
  return Disposable.NULL;
124
116
  }
125
117
 
126
- abstract createNode(): N;
118
+ protected abstract createNode(): N;
127
119
  abstract onData(data: ReplyResponse): void;
128
120
  abstract handleAction(action: EResultKind): void;
129
121
  abstract getPosition(): IPosition;
130
122
 
123
+ create(
124
+ selection: Selection,
125
+ options: IDiffPreviewerOptions = {
126
+ disposeWhenEditorClosed: true,
127
+ },
128
+ ): void {
129
+ this.selection = selection;
130
+ this.node = this.createNode();
131
+ this.node.setPreviewerOptions(options);
132
+ }
133
+
134
+ attachNode(node: N | undefined): void {
135
+ this.node = node;
136
+ }
137
+
131
138
  show(line: number, heightInLines: number): void {
132
139
  // do nothing
133
140
  }
@@ -191,17 +198,20 @@ export class SideBySideInlineDiffWidget extends BaseInlineDiffPreviewer<InlineDi
191
198
  super.layout();
192
199
  }
193
200
  onReady(exec: () => void): IDisposable {
194
- return this.node.onReady(exec.bind(this));
201
+ if (this.node) {
202
+ return this.node!.onReady(exec.bind(this));
203
+ }
204
+ return Disposable.NULL;
195
205
  }
196
206
  show(line: number, heightInLines: number): void {
197
- this.node.showByLine(line, heightInLines);
207
+ this.node?.showByLine(line, heightInLines);
198
208
  }
199
209
  setValue(content: string): void {
200
- const modifiedModel = this.node.getModifiedModel();
210
+ const modifiedModel = this.node?.getModifiedModel();
201
211
  modifiedModel?.setValue(this.formatIndentation(content));
202
212
  }
203
213
  getValue(): string {
204
- const model = this.node.getModifiedModel();
214
+ const model = this.node?.getModifiedModel();
205
215
  return model!.getValue();
206
216
  }
207
217
  handleAction(action: EResultKind): void {
@@ -212,14 +222,14 @@ export class SideBySideInlineDiffWidget extends BaseInlineDiffPreviewer<InlineDi
212
222
  }
213
223
  }
214
224
  onLineCount(event: (count: number) => void): Disposable {
215
- this.node.onMaxLineCount(event.bind(this));
225
+ this.node?.onMaxLineCount(event.bind(this));
216
226
  return this;
217
227
  }
218
228
  onData(data: ReplyResponse): void {
219
229
  const { message } = data;
220
230
 
221
231
  const indentMessage = this.formatIndentation(message);
222
- const modifiedModel = this.node.getModifiedModel()!;
232
+ const modifiedModel = this.node?.getModifiedModel()!;
223
233
 
224
234
  const defaultEOL = modifiedModel.getEOL() === EOL.CRLF ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF;
225
235
  const { textBuffer, disposable } = createTextBuffer(indentMessage, defaultEOL);
@@ -227,29 +237,24 @@ export class SideBySideInlineDiffWidget extends BaseInlineDiffPreviewer<InlineDi
227
237
  modifiedModel.pushEditOperations([], singleEditOperation, () => []);
228
238
 
229
239
  disposable.dispose();
230
- this.node.layout();
240
+ this.node?.layout();
231
241
  }
232
242
  onError(error: ErrorResponse): void {
233
- this.node.layout();
243
+ this.node?.layout();
234
244
  }
235
245
  onAbort(): void {
236
- this.node.layout();
246
+ this.node?.layout();
237
247
  }
238
248
  onEnd(): void {
239
- this.node.layout();
249
+ this.node?.layout();
240
250
  }
241
251
  }
242
252
 
243
253
  @Injectable({ multiple: true })
244
254
  export class LiveInlineDiffPreviewer extends BaseInlineDiffPreviewer<InlineStreamDiffHandler> {
245
- createNode(): InlineStreamDiffHandler {
246
- const node = this.injector.get(InlineStreamDiffHandler, [this.monacoEditor, this.selection]);
247
-
248
- this.addDispose(node.onDidEditChange(() => this.layout()));
249
- this.addDispose(node.onDispose(() => this.dispose()));
250
- this.addDispose(node);
251
-
252
- this.addDispose(
255
+ private listenNode(node: InlineStreamDiffHandler): void {
256
+ node.addDispose(node.onDidEditChange(() => this.layout()));
257
+ node.addDispose(
253
258
  node.onPartialEditWidgetListChange((widgets) => {
254
259
  if (widgets.every((widget) => widget.isHidden)) {
255
260
  this.dispose();
@@ -257,22 +262,62 @@ export class LiveInlineDiffPreviewer extends BaseInlineDiffPreviewer<InlineStrea
257
262
  }
258
263
  }),
259
264
  );
265
+
266
+ const dispose = node.onDispose(() => {
267
+ this.dispose();
268
+ dispose.dispose();
269
+ });
270
+
271
+ this.addDispose(node);
272
+ }
273
+
274
+ createNode(): InlineStreamDiffHandler {
275
+ const node = this.injector.get(InlineStreamDiffHandler, [this.monacoEditor]);
276
+ node.initialize(this.selection);
277
+ this.listenNode(node);
260
278
  return node;
261
279
  }
262
- getPosition(): IPosition {
263
- const zone = this.node.getZone();
264
- return Position.lift({ lineNumber: Math.max(0, zone.startLineNumber - 1), column: 1 });
280
+ attachNode(node: InlineStreamDiffHandler): void {
281
+ this.node?.dispose();
282
+ this.node = node;
283
+
284
+ if (node) {
285
+ const snapshot = node.currentSnapshotStore;
286
+ if (snapshot) {
287
+ this.node.restoreDecorationSnapshot(snapshot.decorationSnapshotData);
288
+ this.listenNode(node);
289
+ }
290
+ }
291
+ }
292
+ public createNodeSnapshot(): InlineStreamDiffHandler | undefined {
293
+ if (!this.node) {
294
+ return this.createNode();
295
+ }
296
+
297
+ // 拿前一个 node 的快照信息
298
+ const snapshot = this.node.createSnapshot();
299
+ // 创建新的实例
300
+ const node = this.injector.get(InlineStreamDiffHandler, [this.monacoEditor]);
301
+ node.restoreSnapshot(snapshot);
302
+ return node;
265
303
  }
266
304
 
305
+ getPosition(): IPosition {
306
+ const zone = this.node?.getZone();
307
+ if (zone) {
308
+ return Position.lift({ lineNumber: Math.max(0, zone.startLineNumber - 1), column: 1 });
309
+ }
310
+ return Position.lift({ lineNumber: 1, column: 1 });
311
+ }
267
312
  handleAction(action: EResultKind): void {
268
313
  switch (action) {
269
314
  case EResultKind.ACCEPT:
270
- this.node.acceptAll();
315
+ this.node?.acceptAll();
271
316
  break;
272
317
 
273
318
  case EResultKind.DISCARD:
274
319
  case EResultKind.REGENERATE:
275
- this.node.rejectAll();
320
+ this.node?.rejectAll();
276
321
  break;
277
322
 
278
323
  default:
@@ -288,29 +333,24 @@ export class LiveInlineDiffPreviewer extends BaseInlineDiffPreviewer<InlineStrea
288
333
  }
289
334
  onData(data: ReplyResponse): void {
290
335
  const { message } = data;
291
- this.node.addLinesToDiff(this.formatIndentation(message));
336
+ this.node?.addLinesToDiff(this.formatIndentation(message));
292
337
  }
293
338
  onEnd(): void {
294
- const diffModel = this.node.recompute(EComputerMode.legacy);
295
- this.node.pushRateFinallyDiffStack(diffModel);
339
+ const diffModel = this.node?.recompute(EComputerMode.legacy);
340
+ if (diffModel) {
341
+ this.node?.pushRateFinallyDiffStack(diffModel);
342
+ }
296
343
  }
297
344
  setValue(content: string): void {
298
- const diffModel = this.node.recompute(EComputerMode.legacy, this.formatIndentation(content));
299
- this.node.finallyRender(diffModel);
300
- }
301
- serializeState(): IExtendedSerializedState {
302
- return {
303
- ...this.node.serializeState(),
304
- options: this.options,
305
- };
306
- }
307
- restoreState(state: IExtendedSerializedState): void {
308
- this.node.restoreState(state);
345
+ const diffModel = this.node?.recompute(EComputerMode.legacy, this.formatIndentation(content));
346
+ if (diffModel) {
347
+ this.node?.finallyRender(diffModel);
348
+ }
309
349
  }
310
350
  get onPartialEditEvent() {
311
- return this.node.onPartialEditEvent;
351
+ return this.node?.onPartialEditEvent;
312
352
  }
313
353
  revealFirstDiff(): void {
314
- this.node.revealFirstDiff();
354
+ this.node?.revealFirstDiff();
315
355
  }
316
356
  }
@@ -3,7 +3,16 @@ import { createPortal } from 'react-dom';
3
3
  import ReactDOMClient from 'react-dom/client';
4
4
 
5
5
  import { Autowired, Injectable } from '@opensumi/di';
6
- import { AppConfig, ConfigProvider, Emitter, Event, MonacoService, useInjectable } from '@opensumi/ide-core-browser';
6
+ import {
7
+ AppConfig,
8
+ ConfigProvider,
9
+ Emitter,
10
+ Event,
11
+ MonacoService,
12
+ Schemes,
13
+ randomString,
14
+ useInjectable,
15
+ } from '@opensumi/ide-core-browser';
7
16
  import * as monaco from '@opensumi/ide-monaco';
8
17
  import { ICodeEditor } from '@opensumi/ide-monaco';
9
18
  import { IDiffEditorOptions } from '@opensumi/ide-monaco/lib/browser/monaco-api/editor';
@@ -13,6 +22,7 @@ import { IModelService } from '@opensumi/monaco-editor-core/esm/vs/editor/common
13
22
  import { ZoneWidget } from '@opensumi/monaco-editor-core/esm/vs/editor/contrib/zoneWidget/browser/zoneWidget';
14
23
  import { StandaloneServices } from '@opensumi/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices';
15
24
 
25
+ import { IDiffPreviewerOptions, IInlineDiffPreviewerNode } from './inline-diff-previewer';
16
26
  import styles from './inline-diff-widget.module.less';
17
27
 
18
28
  const diffEditorOptions: IDiffEditorOptions = {
@@ -84,8 +94,24 @@ const DiffContentProvider = React.memo((props: IDiffContentProviderProps) => {
84
94
  const modelService = StandaloneServices.get(IModelService);
85
95
  const languageSelection: ILanguageSelection = { languageId: model.getLanguageId(), onDidChange: Event.None };
86
96
 
87
- const originalModel = modelService.createModel(codeValueInRange, languageSelection);
88
- const modifiedModel = modelService.createModel('', languageSelection);
97
+ const originalModel = modelService.createModel(
98
+ codeValueInRange,
99
+ languageSelection,
100
+ monaco.Uri.from({
101
+ scheme: Schemes.inMemory,
102
+ path: 'inline-diff-widget/' + randomString(8),
103
+ }),
104
+ true,
105
+ );
106
+ const modifiedModel = modelService.createModel(
107
+ '',
108
+ languageSelection,
109
+ monaco.Uri.from({
110
+ scheme: Schemes.inMemory,
111
+ path: 'inline-diff-widget/' + randomString(8),
112
+ }),
113
+ true,
114
+ );
89
115
 
90
116
  diffEditor.setModel({
91
117
  original: originalModel,
@@ -123,7 +149,7 @@ const DiffContentProvider = React.memo((props: IDiffContentProviderProps) => {
123
149
  });
124
150
 
125
151
  @Injectable({ multiple: true })
126
- export class InlineDiffWidget extends ZoneWidget {
152
+ export class InlineDiffWidget extends ZoneWidget implements IInlineDiffPreviewerNode {
127
153
  @Autowired(AppConfig)
128
154
  private configContext: AppConfig;
129
155
 
@@ -137,7 +163,12 @@ export class InlineDiffWidget extends ZoneWidget {
137
163
  private root: ReactDOMClient.Root | null;
138
164
  private diffWidgetHandler: IDiffWidgetHandler | null = null;
139
165
  private resultContainer: HTMLDivElement | null = null;
140
- hiddenArea: monaco.languages.IRange;
166
+ private hiddenArea: monaco.languages.IRange;
167
+
168
+ previewerOptions: IDiffPreviewerOptions;
169
+ setPreviewerOptions(options: IDiffPreviewerOptions): void {
170
+ this.previewerOptions = options;
171
+ }
141
172
 
142
173
  protected _fillContainer(container: HTMLElement): void {
143
174
  this.setCssClass('inline-diff-widget');