@opensumi/ide-ai-native 3.7.1-next-1739439717.0 → 3.7.1-next-1739521933.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 (138) 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/components/utils.d.ts +2 -2
  10. package/lib/browser/contrib/intelligent-completions/index.d.ts +8 -12
  11. package/lib/browser/contrib/intelligent-completions/index.d.ts.map +1 -1
  12. package/lib/browser/contrib/intelligent-completions/index.js.map +1 -1
  13. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.d.ts +1 -0
  14. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.d.ts.map +1 -1
  15. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js +26 -4
  16. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js.map +1 -1
  17. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts +3 -1
  18. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts.map +1 -1
  19. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js +9 -1
  20. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js.map +1 -1
  21. package/lib/browser/contrib/intelligent-completions/source/base.d.ts +9 -3
  22. package/lib/browser/contrib/intelligent-completions/source/base.d.ts.map +1 -1
  23. package/lib/browser/contrib/intelligent-completions/source/base.js +21 -3
  24. package/lib/browser/contrib/intelligent-completions/source/base.js.map +1 -1
  25. package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts +0 -3
  26. package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts.map +1 -1
  27. package/lib/browser/contrib/intelligent-completions/source/line-change.source.js +20 -22
  28. package/lib/browser/contrib/intelligent-completions/source/line-change.source.js.map +1 -1
  29. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.d.ts +1 -3
  30. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.d.ts.map +1 -1
  31. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.js +13 -20
  32. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.js.map +1 -1
  33. package/lib/browser/contrib/intelligent-completions/source/typing.source.d.ts +2 -2
  34. package/lib/browser/contrib/intelligent-completions/source/typing.source.d.ts.map +1 -1
  35. package/lib/browser/contrib/intelligent-completions/source/typing.source.js +6 -8
  36. package/lib/browser/contrib/intelligent-completions/source/typing.source.js.map +1 -1
  37. package/lib/browser/contrib/terminal/component/terminal-command-suggest-controller.js +2 -2
  38. package/lib/browser/contrib/terminal/component/terminal-command-suggest-controller.js.map +1 -1
  39. package/lib/browser/index.js +1 -1
  40. package/lib/browser/index.js.map +1 -1
  41. package/lib/browser/layout/ai-layout.d.ts.map +1 -1
  42. package/lib/browser/layout/ai-layout.js +2 -2
  43. package/lib/browser/layout/ai-layout.js.map +1 -1
  44. package/lib/browser/model/enhanceDecorationsCollection.d.ts +14 -10
  45. package/lib/browser/model/enhanceDecorationsCollection.d.ts.map +1 -1
  46. package/lib/browser/model/enhanceDecorationsCollection.js +42 -53
  47. package/lib/browser/model/enhanceDecorationsCollection.js.map +1 -1
  48. package/lib/browser/types.d.ts +2 -1
  49. package/lib/browser/types.d.ts.map +1 -1
  50. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.d.ts +2 -1
  51. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.d.ts.map +1 -1
  52. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js +13 -41
  53. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js.map +1 -1
  54. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.d.ts +3 -13
  55. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.d.ts.map +1 -1
  56. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.js +24 -72
  57. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.js.map +1 -1
  58. package/lib/browser/widget/inline-chat/inline-chat.service.d.ts +1 -6
  59. package/lib/browser/widget/inline-chat/inline-chat.service.d.ts.map +1 -1
  60. package/lib/browser/widget/inline-chat/inline-chat.service.js +5 -19
  61. package/lib/browser/widget/inline-chat/inline-chat.service.js.map +1 -1
  62. package/lib/browser/widget/inline-chat/inline-content-widget.d.ts +2 -5
  63. package/lib/browser/widget/inline-chat/inline-content-widget.d.ts.map +1 -1
  64. package/lib/browser/widget/inline-chat/inline-content-widget.js +17 -42
  65. package/lib/browser/widget/inline-chat/inline-content-widget.js.map +1 -1
  66. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts +22 -5
  67. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts.map +1 -1
  68. package/lib/browser/widget/inline-diff/inline-diff-previewer.js +61 -30
  69. package/lib/browser/widget/inline-diff/inline-diff-previewer.js.map +1 -1
  70. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts +8 -12
  71. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts.map +1 -1
  72. package/lib/browser/widget/inline-diff/inline-diff.controller.js +68 -96
  73. package/lib/browser/widget/inline-diff/inline-diff.controller.js.map +1 -1
  74. package/lib/browser/widget/inline-hint/inline-hint.controller.d.ts +0 -1
  75. package/lib/browser/widget/inline-hint/inline-hint.controller.d.ts.map +1 -1
  76. package/lib/browser/widget/inline-hint/inline-hint.controller.js +0 -5
  77. package/lib/browser/widget/inline-hint/inline-hint.controller.js.map +1 -1
  78. package/lib/browser/widget/inline-input/inline-input-widget.d.ts +12 -2
  79. package/lib/browser/widget/inline-input/inline-input-widget.d.ts.map +1 -1
  80. package/lib/browser/widget/inline-input/inline-input-widget.js +26 -18
  81. package/lib/browser/widget/inline-input/inline-input-widget.js.map +1 -1
  82. package/lib/browser/widget/inline-input/inline-input.controller.d.ts +14 -6
  83. package/lib/browser/widget/inline-input/inline-input.controller.d.ts.map +1 -1
  84. package/lib/browser/widget/inline-input/inline-input.controller.js +320 -169
  85. package/lib/browser/widget/inline-input/inline-input.controller.js.map +1 -1
  86. package/lib/browser/widget/inline-input/inline-input.module.less +4 -0
  87. package/lib/browser/widget/inline-input/inline-input.service.d.ts +19 -7
  88. package/lib/browser/widget/inline-input/inline-input.service.d.ts.map +1 -1
  89. package/lib/browser/widget/inline-input/inline-input.service.js +72 -12
  90. package/lib/browser/widget/inline-input/inline-input.service.js.map +1 -1
  91. package/lib/browser/widget/inline-input/model.d.ts +34 -0
  92. package/lib/browser/widget/inline-input/model.d.ts.map +1 -0
  93. package/lib/browser/widget/inline-input/model.js +63 -0
  94. package/lib/browser/widget/inline-input/model.js.map +1 -0
  95. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +8 -19
  96. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  97. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +48 -41
  98. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  99. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts +17 -4
  100. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts.map +1 -1
  101. package/lib/browser/widget/inline-stream-diff/live-preview.component.js +37 -5
  102. package/lib/browser/widget/inline-stream-diff/live-preview.component.js.map +1 -1
  103. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts +7 -11
  104. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts.map +1 -1
  105. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js +33 -77
  106. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js.map +1 -1
  107. package/package.json +21 -21
  108. package/src/browser/ai-core.contextkeys.ts +3 -0
  109. package/src/browser/ai-core.contribution.ts +63 -16
  110. package/src/browser/contrib/intelligent-completions/index.ts +9 -4
  111. package/src/browser/contrib/intelligent-completions/intelligent-completions.contribution.ts +29 -8
  112. package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +13 -1
  113. package/src/browser/contrib/intelligent-completions/source/base.ts +28 -7
  114. package/src/browser/contrib/intelligent-completions/source/line-change.source.ts +31 -26
  115. package/src/browser/contrib/intelligent-completions/source/lint-error.source.ts +19 -31
  116. package/src/browser/contrib/intelligent-completions/source/typing.source.ts +7 -9
  117. package/src/browser/contrib/terminal/component/terminal-command-suggest-controller.tsx +1 -1
  118. package/src/browser/index.ts +2 -2
  119. package/src/browser/layout/ai-layout.tsx +5 -2
  120. package/src/browser/model/enhanceDecorationsCollection.ts +62 -77
  121. package/src/browser/types.ts +2 -2
  122. package/src/browser/widget/inline-chat/inline-chat-editor.controller.ts +21 -56
  123. package/src/browser/widget/inline-chat/inline-chat.feature.registry.ts +23 -90
  124. package/src/browser/widget/inline-chat/inline-chat.service.ts +2 -19
  125. package/src/browser/widget/inline-chat/inline-content-widget.tsx +14 -71
  126. package/src/browser/widget/inline-diff/inline-diff-previewer.ts +87 -32
  127. package/src/browser/widget/inline-diff/inline-diff.controller.ts +90 -114
  128. package/src/browser/widget/inline-hint/inline-hint.controller.ts +1 -7
  129. package/src/browser/widget/inline-input/inline-input-widget.tsx +34 -12
  130. package/src/browser/widget/inline-input/inline-input.controller.ts +453 -247
  131. package/src/browser/widget/inline-input/inline-input.module.less +4 -0
  132. package/src/browser/widget/inline-input/inline-input.service.ts +92 -13
  133. package/src/browser/widget/inline-input/model.ts +74 -0
  134. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +58 -69
  135. package/src/browser/widget/inline-stream-diff/live-preview.component.tsx +45 -6
  136. package/src/browser/widget/inline-stream-diff/live-preview.decoration.tsx +40 -112
  137. package/lib/browser/model/styles.module.less +0 -7
  138. 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}`,
@@ -12,10 +12,15 @@ export interface IIntelligentCompletionsResult<T = any> {
12
12
  extra?: T;
13
13
  }
14
14
 
15
- export type ICodeEditsContextBean =
16
- | { typing: ECodeEditsSourceTyping.LinterErrors; position: IPosition; data: ILinterErrorData }
17
- | { typing: ECodeEditsSourceTyping.LineChange; position: IPosition; data: ILineChangeData }
18
- | { typing: ECodeEditsSourceTyping.Typing; position: IPosition; data: IModelContentChangedEvent };
15
+ export interface ICodeEditsContextBean {
16
+ typing: ECodeEditsSourceTyping;
17
+ position: IPosition;
18
+ data: {
19
+ [ECodeEditsSourceTyping.LinterErrors]?: ILinterErrorData;
20
+ [ECodeEditsSourceTyping.LineChange]?: ILineChangeData;
21
+ [ECodeEditsSourceTyping.Typing]?: IModelContentChangedEvent;
22
+ };
23
+ }
19
24
 
20
25
  export interface ICodeEdit {
21
26
  /**
@@ -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();
@@ -7,7 +7,6 @@ import {
7
7
  Disposable,
8
8
  IAIReporter,
9
9
  IDisposable,
10
- MaybePromise,
11
10
  uuid,
12
11
  } from '@opensumi/ide-core-common';
13
12
  import { CancellationTokenSource, ICodeEditor } from '@opensumi/ide-monaco';
@@ -37,14 +36,26 @@ export class CodeEditsContextBean extends Disposable {
37
36
  return this.raw;
38
37
  }
39
38
 
39
+ public get typing() {
40
+ return this.raw.typing;
41
+ }
42
+
40
43
  public get position() {
41
44
  return this.raw.position;
42
45
  }
43
46
 
47
+ public get data() {
48
+ return this.raw.data;
49
+ }
50
+
44
51
  public get token() {
45
52
  return this.source.token;
46
53
  }
47
54
 
55
+ public joinData(data: ICodeEditsContextBean['data']) {
56
+ this.raw.data = { ...this.data, ...data };
57
+ }
58
+
48
59
  public reporterStart() {
49
60
  return this.source.reporterStart();
50
61
  }
@@ -69,8 +80,6 @@ export abstract class BaseCodeEditsSource extends Disposable {
69
80
  private cancellationTokenSource = new CancellationTokenSource();
70
81
  private readonly relationID = observableValue<string | undefined>(this, undefined);
71
82
 
72
- protected abstract doTrigger(...args: any[]): MaybePromise<void>;
73
-
74
83
  public readonly codeEditsContextBean = disposableObservableValue<CodeEditsContextBean | undefined>(this, undefined);
75
84
  public abstract priority: number;
76
85
  public abstract mount(): IDisposable;
@@ -100,9 +109,9 @@ export abstract class BaseCodeEditsSource extends Disposable {
100
109
  });
101
110
  }
102
111
 
103
- protected setBean(bean: ICodeEditsContextBean) {
112
+ protected setBean(bean: Omit<ICodeEditsContextBean, 'position'>) {
104
113
  transaction((tx) => {
105
- const context = new CodeEditsContextBean(bean, this);
114
+ const context = new CodeEditsContextBean({ ...bean, position: this.monacoEditor.getPosition()! }, this);
106
115
  this.codeEditsContextBean.set(context, tx);
107
116
  });
108
117
  }
@@ -112,7 +121,7 @@ export abstract class BaseCodeEditsSource extends Disposable {
112
121
  if (context) {
113
122
  const relationID = this.aiReporter.start(AIServiceType.CodeEdits, {
114
123
  type: AIServiceType.CodeEdits,
115
- actionSource: context?.bean.typing,
124
+ actionSource: context?.typing,
116
125
  });
117
126
 
118
127
  transaction((tx) => {
@@ -168,11 +177,23 @@ export class CodeEditsSourceCollection extends Disposable {
168
177
 
169
178
  for (const source of lastSources) {
170
179
  const value = source.codeEditsContextBean.get();
180
+ if (!value) {
181
+ return;
182
+ }
183
+
184
+ if (!contextBean) {
185
+ contextBean = value;
186
+ }
171
187
 
172
- if (value && value.priority >= highestPriority) {
188
+ if (value.priority >= highestPriority) {
173
189
  highestPriority = value.priority;
190
+
191
+ value.joinData(contextBean.data);
174
192
  contextBean = value;
175
193
  }
194
+
195
+ // 将多个 source 的 data 合并到一起
196
+ contextBean.joinData(value.data);
176
197
  }
177
198
 
178
199
  transaction((tx) => {
@@ -1,6 +1,7 @@
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 } from '@opensumi/ide-monaco';
4
+ import { autorunDelta, observableFromEvent } from '@opensumi/ide-monaco/lib/common/observable';
4
5
 
5
6
  import { BaseCodeEditsSource } from './base';
6
7
 
@@ -11,37 +12,41 @@ export interface ILineChangeData {
11
12
 
12
13
  @Injectable({ multiple: true })
13
14
  export class LineChangeCodeEditsSource extends BaseCodeEditsSource {
14
- public priority = 2;
15
-
16
- private prePosition = this.monacoEditor.getPosition();
15
+ public priority = 1;
17
16
 
18
17
  public mount(): IDisposable {
18
+ const positionChangeObs = observableFromEvent<ICursorPositionChangedEvent>(
19
+ this,
20
+ this.monacoEditor.onDidChangeCursorPosition,
21
+ (event: ICursorPositionChangedEvent) => event,
22
+ );
23
+
19
24
  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
+ autorunDelta(positionChangeObs, ({ lastValue, newValue }) => {
26
+ const isLineChangeEnabled = this.preferenceService.getValid(
27
+ AINativeSettingSectionsId.CodeEditsLineChange,
28
+ false,
29
+ );
30
+ if (!isLineChangeEnabled) {
31
+ return false;
32
+ }
33
+
34
+ const prePosition = lastValue?.position;
35
+ const currentPosition = newValue?.position;
36
+ if (prePosition && prePosition.lineNumber !== currentPosition?.lineNumber) {
37
+ this.setBean({
38
+ typing: ECodeEditsSourceTyping.LineChange,
39
+ data: {
40
+ [ECodeEditsSourceTyping.LineChange]: {
41
+ preLineNumber: prePosition.lineNumber,
42
+ currentLineNumber: currentPosition.lineNumber,
43
+ },
44
+ },
45
+ });
25
46
  }
26
47
  }),
27
48
  );
28
- return this;
29
- }
30
-
31
- protected doTrigger(position: Position) {
32
- const isLineChangeEnabled = this.preferenceService.getValid(AINativeSettingSectionsId.CodeEditsLineChange, false);
33
49
 
34
- if (!isLineChangeEnabled || !position) {
35
- return;
36
- }
37
-
38
- this.setBean({
39
- typing: ECodeEditsSourceTyping.LineChange,
40
- position,
41
- data: {
42
- preLineNumber: this.prePosition?.lineNumber,
43
- currentLineNumber: position.lineNumber,
44
- },
45
- });
50
+ return this;
46
51
  }
47
52
  }
@@ -1,14 +1,8 @@
1
- import { Autowired, Injectable } from '@opensumi/di';
2
- import {
3
- AINativeSettingSectionsId,
4
- ECodeEditsSourceTyping,
5
- Event,
6
- FRAME_THREE,
7
- IDisposable,
8
- } from '@opensumi/ide-core-common';
1
+ import { Injectable } from '@opensumi/di';
2
+ import { AINativeSettingSectionsId, ECodeEditsSourceTyping, IDisposable } from '@opensumi/ide-core-common';
9
3
  import { ICursorPositionChangedEvent, IPosition, Position } from '@opensumi/ide-monaco';
10
4
  import { URI } from '@opensumi/ide-monaco/lib/browser/monaco-api';
11
- import { IWorkspaceService } from '@opensumi/ide-workspace';
5
+ import { autorunDelta, observableFromEvent } from '@opensumi/ide-monaco/lib/common/observable';
12
6
  import { StandaloneServices } from '@opensumi/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneServices';
13
7
  import {
14
8
  IMarker,
@@ -20,7 +14,6 @@ import {
20
14
  import { BaseCodeEditsSource } from './base';
21
15
 
22
16
  export interface ILinterErrorData {
23
- relativeWorkspacePath: string;
24
17
  errors: Array<IMarkerErrorData>;
25
18
  }
26
19
 
@@ -58,22 +51,19 @@ namespace MarkerErrorData {
58
51
 
59
52
  @Injectable({ multiple: true })
60
53
  export class LintErrorCodeEditsSource extends BaseCodeEditsSource {
61
- public priority = 1;
62
-
63
- @Autowired(IWorkspaceService)
64
- private readonly workspaceService: IWorkspaceService;
54
+ public priority = 0;
65
55
 
66
56
  public mount(): IDisposable {
67
- let prePosition = this.monacoEditor.getPosition();
57
+ const positionChangeObs = observableFromEvent<ICursorPositionChangedEvent>(
58
+ this,
59
+ this.monacoEditor.onDidChangeCursorPosition,
60
+ (event: ICursorPositionChangedEvent) => event,
61
+ );
68
62
 
69
63
  this.addDispose(
70
- // 仅在光标的行号发生变化时,才触发
71
- Event.debounce(
72
- this.monacoEditor.onDidChangeCursorPosition,
73
- (_, e) => e,
74
- FRAME_THREE,
75
- )(async (event: ICursorPositionChangedEvent) => {
76
- const currentPosition = event.position;
64
+ autorunDelta(positionChangeObs, ({ lastValue, newValue }) => {
65
+ const prePosition = lastValue?.position;
66
+ const currentPosition = newValue?.position;
77
67
 
78
68
  // 如果是 selection 则不触发
79
69
  const selection = this.monacoEditor.getSelection();
@@ -81,16 +71,16 @@ export class LintErrorCodeEditsSource extends BaseCodeEditsSource {
81
71
  return;
82
72
  }
83
73
 
84
- if (prePosition && prePosition.lineNumber !== currentPosition.lineNumber) {
85
- await this.doTrigger(currentPosition);
74
+ // 仅在光标的行号发生变化时,才触发
75
+ if (prePosition && prePosition.lineNumber !== currentPosition?.lineNumber) {
76
+ this.doTrigger(currentPosition);
86
77
  }
87
- prePosition = currentPosition;
88
78
  }),
89
79
  );
90
80
  return this;
91
81
  }
92
82
 
93
- protected async doTrigger(position: Position) {
83
+ protected doTrigger(position: Position) {
94
84
  const isLintErrorsEnabled = this.preferenceService.getValid(AINativeSettingSectionsId.CodeEditsLintErrors, false);
95
85
 
96
86
  if (!isLintErrorsEnabled || !this.model) {
@@ -104,14 +94,12 @@ export class LintErrorCodeEditsSource extends BaseCodeEditsSource {
104
94
  markers = markers.filter((marker) => Math.abs(marker.startLineNumber - position.lineNumber) <= 1);
105
95
 
106
96
  if (markers.length) {
107
- const relativeWorkspacePath = await this.workspaceService.asRelativePath(resource.path);
108
-
109
97
  this.setBean({
110
98
  typing: ECodeEditsSourceTyping.LinterErrors,
111
- position,
112
99
  data: {
113
- relativeWorkspacePath: relativeWorkspacePath?.path ?? resource.path,
114
- errors: markers.map((marker) => MarkerErrorData.toData(marker)),
100
+ [ECodeEditsSourceTyping.LinterErrors]: {
101
+ errors: markers.map((marker) => MarkerErrorData.toData(marker)),
102
+ },
115
103
  },
116
104
  });
117
105
  }
@@ -1,26 +1,23 @@
1
1
  import { Injectable } from '@opensumi/di';
2
2
  import { AINativeSettingSectionsId, ECodeEditsSourceTyping, IDisposable } from '@opensumi/ide-core-common';
3
- import { IModelContentChangedEvent, Position } from '@opensumi/ide-monaco';
3
+ import { IModelContentChangedEvent } from '@opensumi/ide-monaco';
4
4
 
5
5
  import { BaseCodeEditsSource } from './base';
6
6
 
7
7
  @Injectable({ multiple: true })
8
8
  export class TypingCodeEditsSource extends BaseCodeEditsSource {
9
- public priority = 0;
9
+ public priority = 2;
10
10
 
11
11
  public mount(): IDisposable {
12
12
  this.addDispose(
13
13
  this.monacoEditor.onDidChangeModelContent((event: IModelContentChangedEvent) => {
14
- const position = this.monacoEditor.getPosition();
15
- if (position) {
16
- this.doTrigger(position, event);
17
- }
14
+ this.doTrigger(event);
18
15
  }),
19
16
  );
20
17
  return this;
21
18
  }
22
19
 
23
- protected async doTrigger(position: Position, data: IModelContentChangedEvent) {
20
+ protected async doTrigger(data: IModelContentChangedEvent) {
24
21
  const isTypingEnabled = this.preferenceService.getValid(AINativeSettingSectionsId.CodeEditsTyping, false);
25
22
 
26
23
  if (!isTypingEnabled || !this.model) {
@@ -29,8 +26,9 @@ export class TypingCodeEditsSource extends BaseCodeEditsSource {
29
26
 
30
27
  this.setBean({
31
28
  typing: ECodeEditsSourceTyping.Typing,
32
- position,
33
- data,
29
+ data: {
30
+ [ECodeEditsSourceTyping.Typing]: data,
31
+ },
34
32
  });
35
33
  }
36
34
  }
@@ -1,4 +1,4 @@
1
- import { debounce } from 'lodash';
1
+ import debounce from 'lodash/debounce';
2
2
  import React, { useCallback, useEffect, useRef, useState } from 'react';
3
3
 
4
4
  import { Emitter, localize } from '@opensumi/ide-core-browser';
@@ -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}