@opensumi/ide-ai-native 3.7.1-next-1739439717.0 → 3.7.1-next-1739448958.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 (119) hide show
  1. package/lib/browser/ai-core.contextkeys.d.ts +1 -0
  2. package/lib/browser/ai-core.contextkeys.d.ts.map +1 -1
  3. package/lib/browser/ai-core.contextkeys.js +1 -0
  4. package/lib/browser/ai-core.contextkeys.js.map +1 -1
  5. package/lib/browser/ai-core.contribution.d.ts +2 -1
  6. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  7. package/lib/browser/ai-core.contribution.js +55 -14
  8. package/lib/browser/ai-core.contribution.js.map +1 -1
  9. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.d.ts +1 -0
  10. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.d.ts.map +1 -1
  11. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js +26 -4
  12. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js.map +1 -1
  13. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts +3 -1
  14. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts.map +1 -1
  15. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js +9 -1
  16. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js.map +1 -1
  17. package/lib/browser/contrib/intelligent-completions/source/base.d.ts +1 -2
  18. package/lib/browser/contrib/intelligent-completions/source/base.d.ts.map +1 -1
  19. package/lib/browser/contrib/intelligent-completions/source/base.js.map +1 -1
  20. package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts +2 -3
  21. package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts.map +1 -1
  22. package/lib/browser/contrib/intelligent-completions/source/line-change.source.js +51 -21
  23. package/lib/browser/contrib/intelligent-completions/source/line-change.source.js.map +1 -1
  24. package/lib/browser/index.js +1 -1
  25. package/lib/browser/index.js.map +1 -1
  26. package/lib/browser/layout/ai-layout.d.ts.map +1 -1
  27. package/lib/browser/layout/ai-layout.js +2 -2
  28. package/lib/browser/layout/ai-layout.js.map +1 -1
  29. package/lib/browser/model/enhanceDecorationsCollection.d.ts +14 -10
  30. package/lib/browser/model/enhanceDecorationsCollection.d.ts.map +1 -1
  31. package/lib/browser/model/enhanceDecorationsCollection.js +42 -53
  32. package/lib/browser/model/enhanceDecorationsCollection.js.map +1 -1
  33. package/lib/browser/types.d.ts +2 -1
  34. package/lib/browser/types.d.ts.map +1 -1
  35. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.d.ts +2 -1
  36. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.d.ts.map +1 -1
  37. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js +13 -41
  38. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js.map +1 -1
  39. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.d.ts +3 -13
  40. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.d.ts.map +1 -1
  41. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.js +24 -72
  42. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.js.map +1 -1
  43. package/lib/browser/widget/inline-chat/inline-chat.service.d.ts +1 -6
  44. package/lib/browser/widget/inline-chat/inline-chat.service.d.ts.map +1 -1
  45. package/lib/browser/widget/inline-chat/inline-chat.service.js +5 -19
  46. package/lib/browser/widget/inline-chat/inline-chat.service.js.map +1 -1
  47. package/lib/browser/widget/inline-chat/inline-content-widget.d.ts +2 -5
  48. package/lib/browser/widget/inline-chat/inline-content-widget.d.ts.map +1 -1
  49. package/lib/browser/widget/inline-chat/inline-content-widget.js +17 -42
  50. package/lib/browser/widget/inline-chat/inline-content-widget.js.map +1 -1
  51. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts +22 -5
  52. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts.map +1 -1
  53. package/lib/browser/widget/inline-diff/inline-diff-previewer.js +61 -30
  54. package/lib/browser/widget/inline-diff/inline-diff-previewer.js.map +1 -1
  55. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts +8 -12
  56. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts.map +1 -1
  57. package/lib/browser/widget/inline-diff/inline-diff.controller.js +68 -96
  58. package/lib/browser/widget/inline-diff/inline-diff.controller.js.map +1 -1
  59. package/lib/browser/widget/inline-hint/inline-hint.controller.d.ts +0 -1
  60. package/lib/browser/widget/inline-hint/inline-hint.controller.d.ts.map +1 -1
  61. package/lib/browser/widget/inline-hint/inline-hint.controller.js +0 -5
  62. package/lib/browser/widget/inline-hint/inline-hint.controller.js.map +1 -1
  63. package/lib/browser/widget/inline-input/inline-input-widget.d.ts +12 -2
  64. package/lib/browser/widget/inline-input/inline-input-widget.d.ts.map +1 -1
  65. package/lib/browser/widget/inline-input/inline-input-widget.js +26 -18
  66. package/lib/browser/widget/inline-input/inline-input-widget.js.map +1 -1
  67. package/lib/browser/widget/inline-input/inline-input.controller.d.ts +14 -6
  68. package/lib/browser/widget/inline-input/inline-input.controller.d.ts.map +1 -1
  69. package/lib/browser/widget/inline-input/inline-input.controller.js +320 -169
  70. package/lib/browser/widget/inline-input/inline-input.controller.js.map +1 -1
  71. package/lib/browser/widget/inline-input/inline-input.module.less +4 -0
  72. package/lib/browser/widget/inline-input/inline-input.service.d.ts +19 -7
  73. package/lib/browser/widget/inline-input/inline-input.service.d.ts.map +1 -1
  74. package/lib/browser/widget/inline-input/inline-input.service.js +72 -12
  75. package/lib/browser/widget/inline-input/inline-input.service.js.map +1 -1
  76. package/lib/browser/widget/inline-input/model.d.ts +34 -0
  77. package/lib/browser/widget/inline-input/model.d.ts.map +1 -0
  78. package/lib/browser/widget/inline-input/model.js +63 -0
  79. package/lib/browser/widget/inline-input/model.js.map +1 -0
  80. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +8 -19
  81. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  82. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +48 -41
  83. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  84. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts +17 -4
  85. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts.map +1 -1
  86. package/lib/browser/widget/inline-stream-diff/live-preview.component.js +37 -5
  87. package/lib/browser/widget/inline-stream-diff/live-preview.component.js.map +1 -1
  88. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts +7 -11
  89. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts.map +1 -1
  90. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js +33 -77
  91. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js.map +1 -1
  92. package/package.json +21 -21
  93. package/src/browser/ai-core.contextkeys.ts +3 -0
  94. package/src/browser/ai-core.contribution.ts +63 -16
  95. package/src/browser/contrib/intelligent-completions/intelligent-completions.contribution.ts +29 -8
  96. package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +13 -1
  97. package/src/browser/contrib/intelligent-completions/source/base.ts +0 -2
  98. package/src/browser/contrib/intelligent-completions/source/line-change.source.ts +79 -24
  99. package/src/browser/index.ts +2 -2
  100. package/src/browser/layout/ai-layout.tsx +5 -2
  101. package/src/browser/model/enhanceDecorationsCollection.ts +62 -77
  102. package/src/browser/types.ts +2 -2
  103. package/src/browser/widget/inline-chat/inline-chat-editor.controller.ts +21 -56
  104. package/src/browser/widget/inline-chat/inline-chat.feature.registry.ts +23 -90
  105. package/src/browser/widget/inline-chat/inline-chat.service.ts +2 -19
  106. package/src/browser/widget/inline-chat/inline-content-widget.tsx +14 -71
  107. package/src/browser/widget/inline-diff/inline-diff-previewer.ts +87 -32
  108. package/src/browser/widget/inline-diff/inline-diff.controller.ts +90 -114
  109. package/src/browser/widget/inline-hint/inline-hint.controller.ts +1 -7
  110. package/src/browser/widget/inline-input/inline-input-widget.tsx +34 -12
  111. package/src/browser/widget/inline-input/inline-input.controller.ts +453 -247
  112. package/src/browser/widget/inline-input/inline-input.module.less +4 -0
  113. package/src/browser/widget/inline-input/inline-input.service.ts +92 -13
  114. package/src/browser/widget/inline-input/model.ts +74 -0
  115. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +58 -69
  116. package/src/browser/widget/inline-stream-diff/live-preview.component.tsx +45 -6
  117. package/src/browser/widget/inline-stream-diff/live-preview.decoration.tsx +40 -112
  118. package/lib/browser/model/styles.module.less +0 -7
  119. package/src/browser/model/styles.module.less +0 -7
@@ -27,6 +27,7 @@ import {
27
27
  } from '@opensumi/ide-core-browser';
28
28
  import {
29
29
  AI_CHAT_VISIBLE,
30
+ AI_INLINE_CHAT_INTERACTIVE_INPUT_CANCEL,
30
31
  AI_INLINE_CHAT_INTERACTIVE_INPUT_VISIBLE,
31
32
  AI_INLINE_CHAT_VISIBLE,
32
33
  AI_INLINE_COMPLETION_REPORTER,
@@ -37,6 +38,7 @@ import {
37
38
  InlineChatIsVisible,
38
39
  InlineDiffPartialEditsIsVisible,
39
40
  InlineHintWidgetIsVisible,
41
+ InlineInputWidgetIsStreaming,
40
42
  InlineInputWidgetIsVisible,
41
43
  } from '@opensumi/ide-core-browser/lib/contextkey/ai-native';
42
44
  import { DesignLayoutConfig } from '@opensumi/ide-core-browser/lib/layout/constants';
@@ -56,8 +58,9 @@ import {
56
58
  runWhenIdle,
57
59
  } from '@opensumi/ide-core-common';
58
60
  import { DESIGN_MENU_BAR_RIGHT } from '@opensumi/ide-design';
59
- import { IEditor } from '@opensumi/ide-editor';
61
+ import { IEditor, WorkbenchEditorService } from '@opensumi/ide-editor';
60
62
  import { BrowserEditorContribution, IEditorFeatureRegistry } from '@opensumi/ide-editor/lib/browser';
63
+ import { WorkbenchEditorServiceImpl } from '@opensumi/ide-editor/lib/browser/workbench-editor.service';
61
64
  import { IMainLayoutService } from '@opensumi/ide-main-layout';
62
65
  import { ISettingRegistry, SettingContribution } from '@opensumi/ide-preferences';
63
66
  import { EditorContributionInstantiation } from '@opensumi/monaco-editor-core/esm/vs/editor/browser/editorExtensions';
@@ -101,11 +104,11 @@ import {
101
104
  } from './types';
102
105
  import { InlineChatEditorController } from './widget/inline-chat/inline-chat-editor.controller';
103
106
  import { InlineChatFeatureRegistry } from './widget/inline-chat/inline-chat.feature.registry';
104
- import { AIInlineChatService } from './widget/inline-chat/inline-chat.service';
107
+ import { InlineChatService } from './widget/inline-chat/inline-chat.service';
105
108
  import { InlineDiffController } from './widget/inline-diff/inline-diff.controller';
106
109
  import { InlineHintController } from './widget/inline-hint/inline-hint.controller';
107
110
  import { InlineInputController } from './widget/inline-input/inline-input.controller';
108
- import { InlineInputChatService } from './widget/inline-input/inline-input.service';
111
+ import { InlineInputService } from './widget/inline-input/inline-input.service';
109
112
  import { InlineStreamDiffService } from './widget/inline-stream-diff/inline-stream-diff.service';
110
113
  import { SumiLightBulbWidget } from './widget/light-bulb';
111
114
 
@@ -191,10 +194,10 @@ export class AINativeBrowserContribution
191
194
  private readonly chatProxyService: ChatProxyService;
192
195
 
193
196
  @Autowired(IAIInlineChatService)
194
- private readonly aiInlineChatService: AIInlineChatService;
197
+ private readonly aiInlineChatService: InlineChatService;
195
198
 
196
- @Autowired(InlineInputChatService)
197
- private readonly inlineInputChatService: InlineInputChatService;
199
+ @Autowired(InlineInputService)
200
+ private readonly inlineInputService: InlineInputService;
198
201
 
199
202
  @Autowired(InlineStreamDiffService)
200
203
  private readonly inlineStreamDiffService: InlineStreamDiffService;
@@ -205,6 +208,9 @@ export class AINativeBrowserContribution
205
208
  @Autowired(CodeActionSingleHandler)
206
209
  private readonly codeActionSingleHandler: CodeActionSingleHandler;
207
210
 
211
+ @Autowired(WorkbenchEditorService)
212
+ private readonly workbenchEditorService: WorkbenchEditorServiceImpl;
213
+
208
214
  constructor() {
209
215
  this.registerFeature();
210
216
  }
@@ -237,7 +243,7 @@ export class AINativeBrowserContribution
237
243
  EditorContributionInstantiation.BeforeFirstInteraction,
238
244
  );
239
245
 
240
- if (this.inlineChatFeatureRegistry.getInteractiveInputHandler()) {
246
+ if (this.inlineInputService.getInteractiveInputHandler()) {
241
247
  register(
242
248
  InlineHintController.ID,
243
249
  new SyncDescriptor(InlineHintController, [this.injector]),
@@ -418,14 +424,48 @@ export class AINativeBrowserContribution
418
424
  });
419
425
 
420
426
  commands.registerCommand(AI_INLINE_CHAT_INTERACTIVE_INPUT_VISIBLE, {
421
- execute: (isVisible: boolean) => {
422
- if (isVisible) {
423
- this.inlineInputChatService.visible();
424
- } else {
425
- this.inlineInputChatService.hide();
427
+ execute: async (isVisible: boolean) => {
428
+ if (!isVisible) {
429
+ this.inlineInputService.hide();
430
+ return;
431
+ }
432
+
433
+ // 每次在展示 inline input 的时候,先隐藏 inline chat
434
+ this.commandService.executeCommand(AI_INLINE_CHAT_VISIBLE.id, false);
435
+
436
+ const editor = this.workbenchEditorService.currentCodeEditor;
437
+ if (!editor) {
438
+ return;
439
+ }
440
+
441
+ const position = editor.monacoEditor.getPosition();
442
+ if (!position) {
443
+ return;
444
+ }
445
+
446
+ const selection = editor.monacoEditor.getSelection();
447
+ const isEmptyLine = position ? editor.monacoEditor.getModel()?.getLineLength(position.lineNumber) === 0 : false;
448
+
449
+ if (isEmptyLine) {
450
+ this.inlineInputService.visibleByPosition(position);
451
+ return;
426
452
  }
427
453
 
428
- this.aiInlineChatService._onInteractiveInputVisible.fire(isVisible);
454
+ if (selection && !selection.isEmpty()) {
455
+ this.inlineInputService.visibleBySelection(selection);
456
+ return;
457
+ }
458
+
459
+ this.inlineInputService.visibleByNearestCodeBlock(position, editor.monacoEditor);
460
+ },
461
+ });
462
+
463
+ commands.registerCommand(AI_INLINE_CHAT_INTERACTIVE_INPUT_CANCEL, {
464
+ execute: () => {
465
+ const editor = this.workbenchEditorService.currentCodeEditor;
466
+ if (editor) {
467
+ InlineInputController.get(editor.monacoEditor)?.cancelToken();
468
+ }
429
469
  },
430
470
  });
431
471
 
@@ -516,12 +556,12 @@ export class AINativeBrowserContribution
516
556
  when: `editorFocus && ${InlineChatIsVisible.raw}`,
517
557
  });
518
558
 
519
- if (this.inlineChatFeatureRegistry.getInteractiveInputHandler()) {
559
+ if (this.inlineInputService.getInteractiveInputHandler()) {
520
560
  // 当 Inline Chat (浮动组件)展示时,通过 CMD K 唤起 Inline Input
521
561
  keybindings.registerKeybinding(
522
562
  {
523
563
  command: AI_INLINE_CHAT_INTERACTIVE_INPUT_VISIBLE.id,
524
- keybinding: 'ctrlcmd+k',
564
+ keybinding: this.aiNativeConfigService.inlineChat.inputKeybinding,
525
565
  args: true,
526
566
  priority: 0,
527
567
  when: `editorFocus && (${InlineChatIsVisible.raw} || inlineSuggestionVisible)`,
@@ -536,11 +576,18 @@ export class AINativeBrowserContribution
536
576
  priority: 0,
537
577
  when: `editorFocus && ${InlineInputWidgetIsVisible.raw}`,
538
578
  });
579
+ // 当 Inline Input 流式编辑时,通过 ESC 退出
580
+ keybindings.registerKeybinding({
581
+ command: AI_INLINE_CHAT_INTERACTIVE_INPUT_CANCEL.id,
582
+ keybinding: 'esc',
583
+ priority: 1,
584
+ when: `editorFocus && ${InlineInputWidgetIsStreaming.raw}`,
585
+ });
539
586
  // 当出现 CMD K 展示信息时,通过快捷键快速唤起 Inline Input
540
587
  keybindings.registerKeybinding(
541
588
  {
542
589
  command: AI_INLINE_CHAT_INTERACTIVE_INPUT_VISIBLE.id,
543
- keybinding: 'ctrlcmd+k',
590
+ keybinding: this.aiNativeConfigService.inlineChat.inputKeybinding,
544
591
  args: true,
545
592
  priority: 0,
546
593
  when: `editorFocus && ${InlineHintWidgetIsVisible.raw} && ${InlineChatIsVisible.not}`,
@@ -1,19 +1,18 @@
1
1
  import { Autowired } from '@opensumi/di';
2
2
  import {
3
+ AINativeConfigService,
3
4
  ClientAppContribution,
4
5
  Key,
5
6
  KeybindingContribution,
6
7
  KeybindingRegistry,
7
8
  KeybindingScope,
8
9
  } from '@opensumi/ide-core-browser';
9
- import {
10
- AI_MULTI_LINE_COMPLETION_ACCEPT,
11
- AI_MULTI_LINE_COMPLETION_DISCARD,
12
- } from '@opensumi/ide-core-browser/lib/ai-native/command';
10
+ import { AI_CODE_EDITS_COMMANDS } from '@opensumi/ide-core-browser/lib/ai-native/command';
13
11
  import { MultiLineEditsIsVisible } from '@opensumi/ide-core-browser/lib/contextkey/ai-native';
14
12
  import { CommandContribution, CommandRegistry, Domain } from '@opensumi/ide-core-common';
15
13
  import { WorkbenchEditorService } from '@opensumi/ide-editor';
16
14
  import { WorkbenchEditorServiceImpl } from '@opensumi/ide-editor/lib/browser/workbench-editor.service';
15
+ import { transaction } from '@opensumi/ide-monaco/lib/common/observable';
17
16
 
18
17
  import { IntelligentCompletionsController } from './intelligent-completions.controller';
19
18
 
@@ -22,8 +21,11 @@ export class IntelligentCompletionsContribution implements KeybindingContributio
22
21
  @Autowired(WorkbenchEditorService)
23
22
  private readonly workbenchEditorService: WorkbenchEditorServiceImpl;
24
23
 
24
+ @Autowired(AINativeConfigService)
25
+ private readonly aiNativeConfigService: AINativeConfigService;
26
+
25
27
  registerCommands(commands: CommandRegistry): void {
26
- commands.registerCommand(AI_MULTI_LINE_COMPLETION_DISCARD, {
28
+ commands.registerCommand(AI_CODE_EDITS_COMMANDS.DISCARD, {
27
29
  execute: () => {
28
30
  const editor = this.workbenchEditorService.currentCodeEditor;
29
31
  if (editor) {
@@ -32,7 +34,7 @@ export class IntelligentCompletionsContribution implements KeybindingContributio
32
34
  },
33
35
  });
34
36
 
35
- commands.registerCommand(AI_MULTI_LINE_COMPLETION_ACCEPT, {
37
+ commands.registerCommand(AI_CODE_EDITS_COMMANDS.ACCEPT, {
36
38
  execute: () => {
37
39
  const editor = this.workbenchEditorService.currentCodeEditor;
38
40
  if (editor) {
@@ -40,11 +42,24 @@ export class IntelligentCompletionsContribution implements KeybindingContributio
40
42
  }
41
43
  },
42
44
  });
45
+
46
+ commands.registerCommand(AI_CODE_EDITS_COMMANDS.TRIGGER, {
47
+ execute: () => {
48
+ const editor = this.workbenchEditorService.currentCodeEditor;
49
+ if (editor) {
50
+ transaction((tx) => {
51
+ IntelligentCompletionsController.get(editor.monacoEditor)?.trigger(tx);
52
+ });
53
+ }
54
+ },
55
+ });
43
56
  }
44
57
 
45
58
  registerKeybindings(keybindings: KeybindingRegistry): void {
59
+ const { codeEdits } = this.aiNativeConfigService;
60
+
46
61
  keybindings.registerKeybinding({
47
- command: AI_MULTI_LINE_COMPLETION_DISCARD.id,
62
+ command: AI_CODE_EDITS_COMMANDS.DISCARD.id,
48
63
  keybinding: Key.ESCAPE.code,
49
64
  when: MultiLineEditsIsVisible.raw,
50
65
  priority: 100,
@@ -52,11 +67,17 @@ export class IntelligentCompletionsContribution implements KeybindingContributio
52
67
 
53
68
  keybindings.registerKeybinding(
54
69
  {
55
- command: AI_MULTI_LINE_COMPLETION_ACCEPT.id,
70
+ command: AI_CODE_EDITS_COMMANDS.ACCEPT.id,
56
71
  keybinding: Key.TAB.code,
57
72
  when: MultiLineEditsIsVisible.raw,
58
73
  },
59
74
  KeybindingScope.USER,
60
75
  );
76
+
77
+ keybindings.registerKeybinding({
78
+ command: AI_CODE_EDITS_COMMANDS.TRIGGER.id,
79
+ keybinding: codeEdits.triggerKeybinding,
80
+ when: 'editorFocus',
81
+ });
61
82
  }
62
83
  }
@@ -13,10 +13,13 @@ import {
13
13
  import { Emitter, ICodeEditor, ICursorPositionChangedEvent, IRange, ITextModel, Range } from '@opensumi/ide-monaco';
14
14
  import {
15
15
  IObservable,
16
+ IObservableSignal,
16
17
  ISettableObservable,
18
+ ITransaction,
17
19
  autorun,
18
20
  autorunWithStoreHandleChanges,
19
21
  derived,
22
+ observableSignal,
20
23
  observableValue,
21
24
  transaction,
22
25
  } from '@opensumi/ide-monaco/lib/common/observable';
@@ -85,11 +88,13 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
85
88
  private aiNativeContextKey: AINativeContextKey;
86
89
  private rewriteWidget: RewriteWidget | null;
87
90
  private whenMultiLineEditsVisibleDisposable: Disposable;
91
+ private codeEditsTriggerSignal: IObservableSignal<void>;
88
92
 
89
93
  public mount(): IDisposable {
90
94
  this.handlerAlwaysVisiblePreference();
91
95
 
92
96
  this.codeEditsResult = observableValue<CodeEditsResultValue | undefined>(this, undefined);
97
+ this.codeEditsTriggerSignal = observableSignal(this);
93
98
 
94
99
  this.whenMultiLineEditsVisibleDisposable = new Disposable();
95
100
  this.multiLineDecorationModel = new MultiLineDecorationModel(this.monacoEditor);
@@ -393,6 +398,10 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
393
398
  this.hide();
394
399
  });
395
400
 
401
+ public trigger(tx: ITransaction): void {
402
+ this.codeEditsTriggerSignal.trigger(tx);
403
+ }
404
+
396
405
  private registerFeature(monacoEditor: ICodeEditor): void {
397
406
  this.featureDisposable.addDispose(
398
407
  Event.any<any>(
@@ -432,16 +441,19 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
432
441
  autorunWithStoreHandleChanges(
433
442
  {
434
443
  createEmptyChangeSummary: () => ({}),
435
- handleChange: (context, changeSummary) => {
444
+ handleChange: (context) => {
436
445
  if (context.didChange(this.codeEditsSourceCollection.codeEditsContextBean)) {
437
446
  // 如果上一次补全结果还在,则不重复请求
438
447
  const isVisible = this.aiNativeContextKey.multiLineEditsIsVisible.get();
439
448
  return !isVisible;
449
+ } else if (context.didChange(this.codeEditsTriggerSignal)) {
450
+ return true;
440
451
  }
441
452
  return false;
442
453
  },
443
454
  },
444
455
  async (reader, _, store) => {
456
+ this.codeEditsTriggerSignal.read(reader);
445
457
  const context = this.codeEditsSourceCollection.codeEditsContextBean.read(reader);
446
458
 
447
459
  const provider = this.intelligentCompletionsRegistry.getCodeEditsProvider();
@@ -69,8 +69,6 @@ export abstract class BaseCodeEditsSource extends Disposable {
69
69
  private cancellationTokenSource = new CancellationTokenSource();
70
70
  private readonly relationID = observableValue<string | undefined>(this, undefined);
71
71
 
72
- protected abstract doTrigger(...args: any[]): MaybePromise<void>;
73
-
74
72
  public readonly codeEditsContextBean = disposableObservableValue<CodeEditsContextBean | undefined>(this, undefined);
75
73
  public abstract priority: number;
76
74
  public abstract mount(): IDisposable;
@@ -1,47 +1,102 @@
1
1
  import { Injectable } from '@opensumi/di';
2
2
  import { AINativeSettingSectionsId, ECodeEditsSourceTyping, IDisposable } from '@opensumi/ide-core-common';
3
- import { ICursorPositionChangedEvent, Position } from '@opensumi/ide-monaco';
3
+ import { ICursorPositionChangedEvent, IModelContentChangedEvent } from '@opensumi/ide-monaco';
4
+ import {
5
+ autorunDelta,
6
+ derivedHandleChanges,
7
+ observableFromEvent,
8
+ recomputeInitiallyAndOnChange,
9
+ } from '@opensumi/ide-monaco/lib/common/observable';
4
10
 
5
11
  import { BaseCodeEditsSource } from './base';
6
12
 
7
13
  export interface ILineChangeData {
8
14
  currentLineNumber: number;
9
15
  preLineNumber?: number;
16
+ change?: IModelContentChangedEvent;
10
17
  }
11
18
 
12
19
  @Injectable({ multiple: true })
13
20
  export class LineChangeCodeEditsSource extends BaseCodeEditsSource {
14
21
  public priority = 2;
15
22
 
16
- private prePosition = this.monacoEditor.getPosition();
17
-
18
23
  public mount(): IDisposable {
24
+ const modelContentChangeObs = observableFromEvent<IModelContentChangedEvent>(
25
+ this,
26
+ this.monacoEditor.onDidChangeModelContent,
27
+ (event: IModelContentChangedEvent) => event,
28
+ );
29
+ const positionChangeObs = observableFromEvent<ICursorPositionChangedEvent>(
30
+ this,
31
+ this.monacoEditor.onDidChangeCursorPosition,
32
+ (event: ICursorPositionChangedEvent) => event,
33
+ );
34
+
35
+ const latestModelContentChangeObs = derivedHandleChanges(
36
+ {
37
+ owner: this,
38
+ createEmptyChangeSummary: () => ({ change: undefined }),
39
+ handleChange: (ctx, changeSummary: { change: IModelContentChangedEvent | undefined }) => {
40
+ // 如果只是改了光标则设置 change 为空,避免获取到缓存的 change
41
+ if (ctx.didChange(positionChangeObs)) {
42
+ changeSummary.change = undefined;
43
+ } else {
44
+ changeSummary.change = modelContentChangeObs.get();
45
+ }
46
+ return true;
47
+ },
48
+ },
49
+ (reader, changeSummary) => {
50
+ positionChangeObs.read(reader);
51
+ modelContentChangeObs.read(reader);
52
+ return changeSummary.change;
53
+ },
54
+ );
55
+
56
+ this.addDispose(recomputeInitiallyAndOnChange(latestModelContentChangeObs));
57
+
58
+ let lastModelContent: IModelContentChangedEvent | undefined;
19
59
  this.addDispose(
20
- this.monacoEditor.onDidChangeCursorPosition((event: ICursorPositionChangedEvent) => {
21
- const currentPosition = event.position;
22
- if (this.prePosition && this.prePosition.lineNumber !== currentPosition.lineNumber) {
23
- this.doTrigger(currentPosition);
24
- this.prePosition = currentPosition;
25
- }
60
+ /**
61
+ * 由于 monaco 的 changeModelContent 事件比 changeCursorPosition 事件先触发,所以这里需要拿上一次的值进行消费
62
+ * 否则永远返回 undefined
63
+ */
64
+ autorunDelta(latestModelContentChangeObs, ({ lastValue }) => {
65
+ lastModelContent = lastValue;
26
66
  }),
27
67
  );
28
- return this;
29
- }
30
68
 
31
- protected doTrigger(position: Position) {
32
- const isLineChangeEnabled = this.preferenceService.getValid(AINativeSettingSectionsId.CodeEditsLineChange, false);
69
+ this.addDispose(
70
+ autorunDelta(positionChangeObs, ({ lastValue, newValue }) => {
71
+ const contentChange = lastModelContent;
33
72
 
34
- if (!isLineChangeEnabled || !position) {
35
- return;
36
- }
73
+ const isLineChangeEnabled = this.preferenceService.getValid(
74
+ AINativeSettingSectionsId.CodeEditsLineChange,
75
+ false,
76
+ );
77
+ if (!isLineChangeEnabled) {
78
+ return false;
79
+ }
37
80
 
38
- this.setBean({
39
- typing: ECodeEditsSourceTyping.LineChange,
40
- position,
41
- data: {
42
- preLineNumber: this.prePosition?.lineNumber,
43
- currentLineNumber: position.lineNumber,
44
- },
45
- });
81
+ const prePosition = lastValue?.position;
82
+ const currentPosition = newValue?.position;
83
+ if (prePosition && prePosition.lineNumber !== currentPosition?.lineNumber) {
84
+ this.setBean({
85
+ typing: ECodeEditsSourceTyping.LineChange,
86
+ position: currentPosition,
87
+ data: {
88
+ preLineNumber: prePosition.lineNumber,
89
+ currentLineNumber: currentPosition.lineNumber,
90
+ change: contentChange,
91
+ },
92
+ });
93
+ }
94
+
95
+ // 消费完之后设置为 undefined,避免下次获取到缓存的值
96
+ lastModelContent = undefined;
97
+ }),
98
+ );
99
+
100
+ return this;
46
101
  }
47
102
  }
@@ -46,7 +46,7 @@ import { LanguageParserService } from './languages/service';
46
46
  import { AINativePreferencesContribution } from './preferences';
47
47
  import { AINativeCoreContribution } from './types';
48
48
  import { InlineChatFeatureRegistry } from './widget/inline-chat/inline-chat.feature.registry';
49
- import { AIInlineChatService } from './widget/inline-chat/inline-chat.service';
49
+ import { InlineChatService } from './widget/inline-chat/inline-chat.service';
50
50
  import { InlineDiffService } from './widget/inline-diff';
51
51
 
52
52
  @Injectable()
@@ -90,7 +90,7 @@ export class AINativeModule extends BrowserModule {
90
90
  },
91
91
  {
92
92
  token: IAIInlineChatService,
93
- useClass: AIInlineChatService,
93
+ useClass: InlineChatService,
94
94
  },
95
95
  {
96
96
  token: IChatManagerService,
@@ -10,11 +10,14 @@ export const AILayout = () => {
10
10
  const { layout } = getStorageValue();
11
11
  const designLayoutConfig = useInjectable(DesignLayoutConfig);
12
12
 
13
- const defaultRightSize = useMemo(() => designLayoutConfig.useMergeRightWithLeftPanel ? 0 : 49, [designLayoutConfig.useMergeRightWithLeftPanel]);
13
+ const defaultRightSize = useMemo(
14
+ () => (designLayoutConfig.useMergeRightWithLeftPanel ? 0 : 49),
15
+ [designLayoutConfig.useMergeRightWithLeftPanel],
16
+ );
14
17
 
15
18
  return (
16
19
  <BoxPanel direction='top-to-bottom'>
17
- <SlotRenderer id='top' defaultSize={layout.top?.currentId ? layout.top?.size || 35 : 0} slot='top' />
20
+ <SlotRenderer id='top' defaultSize={layout.top?.currentId ? layout.top?.size || 32 : 32} slot='top' />
18
21
  <SplitPanel
19
22
  id='main-horizontal-ai'
20
23
  flex={1}