@opensumi/ide-ai-native 3.7.1 → 3.7.2-next-1739848467.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 (167) 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 +60 -15
  8. package/lib/browser/ai-core.contribution.js.map +1 -1
  9. package/lib/browser/components/ChatMarkdown.d.ts.map +1 -1
  10. package/lib/browser/components/ChatMarkdown.js.map +1 -1
  11. package/lib/browser/components/WelcomeMsg.js.map +1 -1
  12. package/lib/browser/components/utils.d.ts +2 -2
  13. package/lib/browser/contrib/intelligent-completions/index.d.ts +14 -9
  14. package/lib/browser/contrib/intelligent-completions/index.d.ts.map +1 -1
  15. package/lib/browser/contrib/intelligent-completions/index.js +6 -1
  16. package/lib/browser/contrib/intelligent-completions/index.js.map +1 -1
  17. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.d.ts +1 -0
  18. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.d.ts.map +1 -1
  19. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js +26 -4
  20. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js.map +1 -1
  21. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts +6 -5
  22. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts.map +1 -1
  23. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js +50 -42
  24. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js.map +1 -1
  25. package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.d.ts +4 -0
  26. package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.d.ts.map +1 -1
  27. package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.js +7 -0
  28. package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.js.map +1 -1
  29. package/lib/browser/contrib/intelligent-completions/source/base.d.ts +9 -3
  30. package/lib/browser/contrib/intelligent-completions/source/base.d.ts.map +1 -1
  31. package/lib/browser/contrib/intelligent-completions/source/base.js +21 -3
  32. package/lib/browser/contrib/intelligent-completions/source/base.js.map +1 -1
  33. package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts +10 -3
  34. package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts.map +1 -1
  35. package/lib/browser/contrib/intelligent-completions/source/line-change.source.js +95 -22
  36. package/lib/browser/contrib/intelligent-completions/source/line-change.source.js.map +1 -1
  37. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.d.ts +1 -3
  38. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.d.ts.map +1 -1
  39. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.js +13 -20
  40. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.js.map +1 -1
  41. package/lib/browser/contrib/intelligent-completions/source/typing.source.d.ts +9 -0
  42. package/lib/browser/contrib/intelligent-completions/source/typing.source.d.ts.map +1 -0
  43. package/lib/browser/contrib/intelligent-completions/source/typing.source.js +36 -0
  44. package/lib/browser/contrib/intelligent-completions/source/typing.source.js.map +1 -0
  45. package/lib/browser/contrib/terminal/component/terminal-command-suggest-controller.js +2 -2
  46. package/lib/browser/contrib/terminal/component/terminal-command-suggest-controller.js.map +1 -1
  47. package/lib/browser/index.js +1 -1
  48. package/lib/browser/index.js.map +1 -1
  49. package/lib/browser/languages/tree-sitter/wasm-manager.d.ts.map +1 -1
  50. package/lib/browser/languages/tree-sitter/wasm-manager.js +14 -2
  51. package/lib/browser/languages/tree-sitter/wasm-manager.js.map +1 -1
  52. package/lib/browser/layout/ai-layout.d.ts.map +1 -1
  53. package/lib/browser/layout/ai-layout.js +2 -2
  54. package/lib/browser/layout/ai-layout.js.map +1 -1
  55. package/lib/browser/layout/layout.module.less +9 -9
  56. package/lib/browser/layout/tabbar.view.d.ts.map +1 -1
  57. package/lib/browser/layout/tabbar.view.js +5 -6
  58. package/lib/browser/layout/tabbar.view.js.map +1 -1
  59. package/lib/browser/model/enhanceDecorationsCollection.d.ts +14 -10
  60. package/lib/browser/model/enhanceDecorationsCollection.d.ts.map +1 -1
  61. package/lib/browser/model/enhanceDecorationsCollection.js +42 -53
  62. package/lib/browser/model/enhanceDecorationsCollection.js.map +1 -1
  63. package/lib/browser/preferences/schema.d.ts.map +1 -1
  64. package/lib/browser/preferences/schema.js +4 -0
  65. package/lib/browser/preferences/schema.js.map +1 -1
  66. package/lib/browser/types.d.ts +25 -4
  67. package/lib/browser/types.d.ts.map +1 -1
  68. package/lib/browser/types.js.map +1 -1
  69. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.d.ts +2 -1
  70. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.d.ts.map +1 -1
  71. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js +21 -49
  72. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js.map +1 -1
  73. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.d.ts +3 -13
  74. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.d.ts.map +1 -1
  75. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.js +24 -72
  76. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.js.map +1 -1
  77. package/lib/browser/widget/inline-chat/inline-chat.service.d.ts +1 -6
  78. package/lib/browser/widget/inline-chat/inline-chat.service.d.ts.map +1 -1
  79. package/lib/browser/widget/inline-chat/inline-chat.service.js +5 -17
  80. package/lib/browser/widget/inline-chat/inline-chat.service.js.map +1 -1
  81. package/lib/browser/widget/inline-chat/inline-content-widget.d.ts +2 -5
  82. package/lib/browser/widget/inline-chat/inline-content-widget.d.ts.map +1 -1
  83. package/lib/browser/widget/inline-chat/inline-content-widget.js +17 -42
  84. package/lib/browser/widget/inline-chat/inline-content-widget.js.map +1 -1
  85. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts +22 -5
  86. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts.map +1 -1
  87. package/lib/browser/widget/inline-diff/inline-diff-previewer.js +61 -30
  88. package/lib/browser/widget/inline-diff/inline-diff-previewer.js.map +1 -1
  89. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts +8 -12
  90. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts.map +1 -1
  91. package/lib/browser/widget/inline-diff/inline-diff.controller.js +68 -96
  92. package/lib/browser/widget/inline-diff/inline-diff.controller.js.map +1 -1
  93. package/lib/browser/widget/inline-hint/inline-hint.controller.d.ts +0 -1
  94. package/lib/browser/widget/inline-hint/inline-hint.controller.d.ts.map +1 -1
  95. package/lib/browser/widget/inline-hint/inline-hint.controller.js +0 -5
  96. package/lib/browser/widget/inline-hint/inline-hint.controller.js.map +1 -1
  97. package/lib/browser/widget/inline-input/inline-input-widget.d.ts +12 -2
  98. package/lib/browser/widget/inline-input/inline-input-widget.d.ts.map +1 -1
  99. package/lib/browser/widget/inline-input/inline-input-widget.js +26 -18
  100. package/lib/browser/widget/inline-input/inline-input-widget.js.map +1 -1
  101. package/lib/browser/widget/inline-input/inline-input.controller.d.ts +14 -5
  102. package/lib/browser/widget/inline-input/inline-input.controller.d.ts.map +1 -1
  103. package/lib/browser/widget/inline-input/inline-input.controller.js +321 -165
  104. package/lib/browser/widget/inline-input/inline-input.controller.js.map +1 -1
  105. package/lib/browser/widget/inline-input/inline-input.module.less +4 -0
  106. package/lib/browser/widget/inline-input/inline-input.service.d.ts +19 -7
  107. package/lib/browser/widget/inline-input/inline-input.service.d.ts.map +1 -1
  108. package/lib/browser/widget/inline-input/inline-input.service.js +72 -12
  109. package/lib/browser/widget/inline-input/inline-input.service.js.map +1 -1
  110. package/lib/browser/widget/inline-input/model.d.ts +34 -0
  111. package/lib/browser/widget/inline-input/model.d.ts.map +1 -0
  112. package/lib/browser/widget/inline-input/model.js +63 -0
  113. package/lib/browser/widget/inline-input/model.js.map +1 -0
  114. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +8 -19
  115. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  116. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +44 -39
  117. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  118. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts +17 -4
  119. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts.map +1 -1
  120. package/lib/browser/widget/inline-stream-diff/live-preview.component.js +37 -5
  121. package/lib/browser/widget/inline-stream-diff/live-preview.component.js.map +1 -1
  122. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts +7 -11
  123. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts.map +1 -1
  124. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js +33 -77
  125. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js.map +1 -1
  126. package/lib/common/utils.js +2 -2
  127. package/lib/common/utils.js.map +1 -1
  128. package/package.json +21 -21
  129. package/src/browser/ai-core.contextkeys.ts +3 -0
  130. package/src/browser/ai-core.contribution.ts +68 -17
  131. package/src/browser/components/ChatMarkdown.tsx +1 -1
  132. package/src/browser/components/WelcomeMsg.tsx +1 -1
  133. package/src/browser/contrib/intelligent-completions/index.ts +16 -4
  134. package/src/browser/contrib/intelligent-completions/intelligent-completions.contribution.ts +29 -8
  135. package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +88 -58
  136. package/src/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.ts +11 -0
  137. package/src/browser/contrib/intelligent-completions/source/base.ts +28 -7
  138. package/src/browser/contrib/intelligent-completions/source/line-change.source.ts +129 -22
  139. package/src/browser/contrib/intelligent-completions/source/lint-error.source.ts +19 -31
  140. package/src/browser/contrib/intelligent-completions/source/typing.source.ts +34 -0
  141. package/src/browser/contrib/terminal/component/terminal-command-suggest-controller.tsx +1 -1
  142. package/src/browser/index.ts +2 -2
  143. package/src/browser/languages/tree-sitter/wasm-manager.ts +12 -2
  144. package/src/browser/layout/ai-layout.tsx +5 -2
  145. package/src/browser/layout/layout.module.less +9 -9
  146. package/src/browser/layout/tabbar.view.tsx +10 -8
  147. package/src/browser/model/enhanceDecorationsCollection.ts +62 -77
  148. package/src/browser/preferences/schema.ts +4 -0
  149. package/src/browser/types.ts +40 -5
  150. package/src/browser/widget/inline-chat/inline-chat-editor.controller.ts +30 -65
  151. package/src/browser/widget/inline-chat/inline-chat.feature.registry.ts +23 -90
  152. package/src/browser/widget/inline-chat/inline-chat.service.ts +2 -17
  153. package/src/browser/widget/inline-chat/inline-content-widget.tsx +14 -69
  154. package/src/browser/widget/inline-diff/inline-diff-previewer.ts +87 -32
  155. package/src/browser/widget/inline-diff/inline-diff.controller.ts +90 -114
  156. package/src/browser/widget/inline-hint/inline-hint.controller.ts +1 -7
  157. package/src/browser/widget/inline-input/inline-input-widget.tsx +34 -12
  158. package/src/browser/widget/inline-input/inline-input.controller.ts +454 -242
  159. package/src/browser/widget/inline-input/inline-input.module.less +4 -0
  160. package/src/browser/widget/inline-input/inline-input.service.ts +92 -13
  161. package/src/browser/widget/inline-input/model.ts +74 -0
  162. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +54 -67
  163. package/src/browser/widget/inline-stream-diff/live-preview.component.tsx +45 -6
  164. package/src/browser/widget/inline-stream-diff/live-preview.decoration.tsx +40 -112
  165. package/src/common/utils.ts +2 -2
  166. package/lib/browser/model/styles.module.less +0 -7
  167. 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]),
@@ -254,7 +260,7 @@ export class AINativeBrowserContribution
254
260
  register(
255
261
  IntelligentCompletionsController.ID,
256
262
  new SyncDescriptor(IntelligentCompletionsController, [this.injector]),
257
- EditorContributionInstantiation.AfterFirstRender,
263
+ EditorContributionInstantiation.Eager,
258
264
  );
259
265
  register(
260
266
  InlineCompletionsController.ID,
@@ -365,6 +371,10 @@ export class AINativeBrowserContribution
365
371
  id: AINativeSettingSectionsId.CodeEditsLineChange,
366
372
  localized: 'preference.ai.native.codeEdits.lineChange',
367
373
  },
374
+ {
375
+ id: AINativeSettingSectionsId.CodeEditsTyping,
376
+ localized: 'preference.ai.native.codeEdits.typing',
377
+ },
368
378
  ],
369
379
  });
370
380
  }
@@ -414,14 +424,48 @@ export class AINativeBrowserContribution
414
424
  });
415
425
 
416
426
  commands.registerCommand(AI_INLINE_CHAT_INTERACTIVE_INPUT_VISIBLE, {
417
- execute: (isVisible: boolean) => {
418
- if (isVisible) {
419
- this.inlineInputChatService.visible();
420
- } else {
421
- this.inlineInputChatService.hide();
427
+ execute: async (isVisible: boolean) => {
428
+ if (!isVisible) {
429
+ this.inlineInputService.hide();
430
+ return;
422
431
  }
423
432
 
424
- this.aiInlineChatService._onInteractiveInputVisible.fire(isVisible);
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;
452
+ }
453
+
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
+ }
425
469
  },
426
470
  });
427
471
 
@@ -512,12 +556,12 @@ export class AINativeBrowserContribution
512
556
  when: `editorFocus && ${InlineChatIsVisible.raw}`,
513
557
  });
514
558
 
515
- if (this.inlineChatFeatureRegistry.getInteractiveInputHandler()) {
559
+ if (this.inlineInputService.getInteractiveInputHandler()) {
516
560
  // 当 Inline Chat (浮动组件)展示时,通过 CMD K 唤起 Inline Input
517
561
  keybindings.registerKeybinding(
518
562
  {
519
563
  command: AI_INLINE_CHAT_INTERACTIVE_INPUT_VISIBLE.id,
520
- keybinding: 'ctrlcmd+k',
564
+ keybinding: this.aiNativeConfigService.inlineChat.inputKeybinding,
521
565
  args: true,
522
566
  priority: 0,
523
567
  when: `editorFocus && (${InlineChatIsVisible.raw} || inlineSuggestionVisible)`,
@@ -532,11 +576,18 @@ export class AINativeBrowserContribution
532
576
  priority: 0,
533
577
  when: `editorFocus && ${InlineInputWidgetIsVisible.raw}`,
534
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
+ });
535
586
  // 当出现 CMD K 展示信息时,通过快捷键快速唤起 Inline Input
536
587
  keybindings.registerKeybinding(
537
588
  {
538
589
  command: AI_INLINE_CHAT_INTERACTIVE_INPUT_VISIBLE.id,
539
- keybinding: 'ctrlcmd+k',
590
+ keybinding: this.aiNativeConfigService.inlineChat.inputKeybinding,
540
591
  args: true,
541
592
  priority: 0,
542
593
  when: `editorFocus && ${InlineHintWidgetIsVisible.raw} && ${InlineChatIsVisible.not}`,
@@ -1,5 +1,5 @@
1
1
  import cls from 'classnames';
2
- import React, { ReactNode, useEffect, useRef, useState } from 'react';
2
+ import React, { useEffect, useRef, useState } from 'react';
3
3
 
4
4
  import { MarkdownReactParser, MarkdownReactRenderer } from '@opensumi/ide-components/lib/markdown-react';
5
5
  import { IMarkedOptions, marked } from '@opensumi/ide-components/lib/utils';
@@ -14,7 +14,7 @@ import {
14
14
  import { isMarkdownString } from '@opensumi/monaco-editor-core/esm/vs/base/common/htmlContent';
15
15
 
16
16
  import 'react-chat-elements/dist/main.css';
17
- import { IChatAgentService, IChatReplyFollowup, ISampleQuestions } from '../../common';
17
+ import { IChatAgentService, ISampleQuestions } from '../../common';
18
18
  import { ChatService } from '../chat/chat.api.service';
19
19
  import { ChatFeatureRegistry } from '../chat/chat.feature.registry';
20
20
  import { ChatRenderRegistry } from '../chat/chat.render.registry';
@@ -1,9 +1,15 @@
1
1
  import { Disposable, ECodeEditsSourceTyping } from '@opensumi/ide-core-common';
2
- import { IPosition, IRange, InlineCompletion } from '@opensumi/ide-monaco';
2
+ import { IModelContentChangedEvent, IPosition, IRange, InlineCompletion } from '@opensumi/ide-monaco';
3
3
 
4
4
  import type { ILineChangeData } from './source/line-change.source';
5
5
  import type { ILinterErrorData } from './source/lint-error.source';
6
6
 
7
+ /**
8
+ * 有效弃用时间(毫秒)
9
+ * 在可见的情况下超过 750ms 弃用才算有效数据,否则视为无效数据
10
+ */
11
+ export const VALID_TIME = 750;
12
+
7
13
  export interface IIntelligentCompletionsResult<T = any> {
8
14
  readonly items: InlineCompletion[];
9
15
  /**
@@ -12,9 +18,15 @@ export interface IIntelligentCompletionsResult<T = any> {
12
18
  extra?: T;
13
19
  }
14
20
 
15
- export type ICodeEditsContextBean =
16
- | { typing: ECodeEditsSourceTyping.LinterErrors; position: IPosition; data: ILinterErrorData }
17
- | { typing: ECodeEditsSourceTyping.LineChange; position: IPosition; data: ILineChangeData };
21
+ export interface ICodeEditsContextBean {
22
+ typing: ECodeEditsSourceTyping;
23
+ position: IPosition;
24
+ data: {
25
+ [ECodeEditsSourceTyping.LinterErrors]?: ILinterErrorData;
26
+ [ECodeEditsSourceTyping.LineChange]?: ILineChangeData;
27
+ [ECodeEditsSourceTyping.Typing]?: IModelContentChangedEvent;
28
+ };
29
+ }
18
30
 
19
31
  export interface ICodeEdit {
20
32
  /**
@@ -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
  }
@@ -1,4 +1,10 @@
1
- import { Key, KeybindingRegistry, KeybindingScope, PreferenceService } from '@opensumi/ide-core-browser';
1
+ import {
2
+ ContextKeyChangeEvent,
3
+ Key,
4
+ KeybindingRegistry,
5
+ KeybindingScope,
6
+ PreferenceService,
7
+ } from '@opensumi/ide-core-browser';
2
8
  import { MultiLineEditsIsVisible } from '@opensumi/ide-core-browser/lib/contextkey/ai-native';
3
9
  import {
4
10
  AINativeSettingSectionsId,
@@ -13,10 +19,16 @@ import {
13
19
  import { Emitter, ICodeEditor, ICursorPositionChangedEvent, IRange, ITextModel, Range } from '@opensumi/ide-monaco';
14
20
  import {
15
21
  IObservable,
22
+ IObservableSignal,
16
23
  ISettableObservable,
24
+ ITransaction,
17
25
  autorun,
18
26
  autorunWithStoreHandleChanges,
19
27
  derived,
28
+ derivedHandleChanges,
29
+ derivedOpts,
30
+ observableFromEvent,
31
+ observableSignal,
20
32
  observableValue,
21
33
  transaction,
22
34
  } from '@opensumi/ide-monaco/lib/common/observable';
@@ -28,7 +40,7 @@ import { InlineCompletionsController } from '@opensumi/monaco-editor-core/esm/vs
28
40
  import {
29
41
  SuggestItemInfo,
30
42
  SuggestWidgetAdaptor,
31
- } from '@opensumi/monaco-editor-core/esm/vs/editor/contrib/inlineCompletions/browser/model/suggestWidgetAdaptor';
43
+ } from '@opensumi/monaco-editor-core/esm/vs/editor/contrib/inlineCompletions/browser/model/suggestWidgetAdapter';
32
44
  import { ContextKeyExpr } from '@opensumi/monaco-editor-core/esm/vs/platform/contextkey/common/contextkey';
33
45
 
34
46
  import { AINativeContextKey } from '../../ai-core.contextkeys';
@@ -47,8 +59,9 @@ import { IntelligentCompletionsRegistry } from './intelligent-completions.featur
47
59
  import { CodeEditsSourceCollection } from './source/base';
48
60
  import { LineChangeCodeEditsSource } from './source/line-change.source';
49
61
  import { LintErrorCodeEditsSource } from './source/lint-error.source';
62
+ import { TypingCodeEditsSource } from './source/typing.source';
50
63
 
51
- import { CodeEditsResultValue } from './index';
64
+ import { CodeEditsResultValue, VALID_TIME } from './index';
52
65
 
53
66
  export class IntelligentCompletionsController extends BaseAIMonacoEditorController {
54
67
  public static readonly ID = 'editor.contrib.ai.intelligent.completions';
@@ -83,22 +96,32 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
83
96
  private codeEditsSourceCollection: CodeEditsSourceCollection;
84
97
  private aiNativeContextKey: AINativeContextKey;
85
98
  private rewriteWidget: RewriteWidget | null;
86
- private whenMultiLineEditsVisibleDisposable: Disposable;
99
+ private codeEditsTriggerSignal: IObservableSignal<void>;
100
+ private multiLineEditsIsVisibleObs: IObservable<boolean>;
87
101
 
88
102
  public mount(): IDisposable {
89
103
  this.handlerAlwaysVisiblePreference();
90
104
 
91
105
  this.codeEditsResult = observableValue<CodeEditsResultValue | undefined>(this, undefined);
106
+ this.codeEditsTriggerSignal = observableSignal(this);
92
107
 
93
- this.whenMultiLineEditsVisibleDisposable = new Disposable();
94
108
  this.multiLineDecorationModel = new MultiLineDecorationModel(this.monacoEditor);
95
109
  this.additionsDeletionsDecorationModel = new AdditionsDeletionsDecorationModel(this.monacoEditor);
96
110
  this.aiNativeContextKey = this.injector.get(AINativeContextKey, [this.monacoEditor.contextKeyService]);
97
111
  this.codeEditsSourceCollection = this.injector.get(CodeEditsSourceCollection, [
98
- [LintErrorCodeEditsSource, LineChangeCodeEditsSource],
112
+ [LintErrorCodeEditsSource, LineChangeCodeEditsSource, TypingCodeEditsSource],
99
113
  this.monacoEditor,
100
114
  ]);
101
115
 
116
+ const multiLineEditsIsVisibleKey = new Set([MultiLineEditsIsVisible.raw]);
117
+ this.multiLineEditsIsVisibleObs = observableFromEvent(
118
+ this,
119
+ Event.filter(this.aiNativeContextKey.contextKeyService!.onDidChangeContext, (e: ContextKeyChangeEvent) =>
120
+ e.payload.affectsSome(multiLineEditsIsVisibleKey),
121
+ ),
122
+ () => !!this.aiNativeContextKey.multiLineEditsIsVisible.get(),
123
+ );
124
+
102
125
  this.registerFeature(this.monacoEditor);
103
126
  return this.featureDisposable;
104
127
  }
@@ -143,8 +166,7 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
143
166
  model?.inlineCompletionState.read(reader);
144
167
 
145
168
  const suggestWidgetSelectedItem = inlineCompletionsController['_suggestWidgetSelectedItem'] as IObservable<
146
- SuggestItemInfo | undefined,
147
- unknown
169
+ SuggestItemInfo | undefined
148
170
  >;
149
171
  const selectedItem = suggestWidgetSelectedItem.get();
150
172
  if (selectedItem) {
@@ -253,26 +275,6 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
253
275
  this.additionsDeletionsDecorationModel.updateDeletionsDecoration(wordChanges, range, eol);
254
276
  this.renderRewriteWidget(wordChanges, model, range, insertTextString);
255
277
  }
256
-
257
- if (this.whenMultiLineEditsVisibleDisposable.disposed) {
258
- this.whenMultiLineEditsVisibleDisposable = new Disposable();
259
- }
260
- // 监听当前光标位置的变化,如果超出 range 区域则表示弃用
261
- this.whenMultiLineEditsVisibleDisposable.addDispose(
262
- this.monacoEditor.onDidChangeCursorPosition((event: ICursorPositionChangedEvent) => {
263
- const isVisible = this.aiNativeContextKey.multiLineEditsIsVisible.get();
264
- if (isVisible) {
265
- const position = event.position;
266
- if (position.lineNumber < range.startLineNumber || position.lineNumber > range.endLineNumber) {
267
- runWhenIdle(() => {
268
- this.discard.get();
269
- });
270
- }
271
- } else {
272
- this.whenMultiLineEditsVisibleDisposable.dispose();
273
- }
274
- }),
275
- );
276
278
  }
277
279
 
278
280
  private async renderRewriteWidget(
@@ -335,36 +337,52 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
335
337
  const { range, insertText } = codeEditsResult.items[0];
336
338
  const newCode = insertText;
337
339
  const originCode = this.model.getValueInRange(range);
338
- return (type: keyof Pick<CodeEditsRT, 'isReceive' | 'isDrop' | 'isValid'>) => {
339
- contextBean.reporterEnd({
340
- [type]: true,
340
+ return (type: keyof Pick<CodeEditsRT, 'isReceive' | 'isDrop' | 'isValid'>, defaultValue: boolean = true) => {
341
+ const data = {
342
+ [type]: defaultValue,
341
343
  code: newCode,
342
344
  originCode,
343
- });
345
+ };
346
+
347
+ contextBean.reporterEnd(data);
344
348
  };
345
349
  }
346
350
  });
347
351
 
348
- private lastVisibleTime = derived(this, (reader) => {
349
- const isVisible = this.aiNativeContextKey.multiLineEditsIsVisible.get();
350
- return isVisible ? Date.now() : undefined;
351
- });
352
-
353
- public discard = derived(this, (reader) => {
354
- const lastVisibleTime = this.lastVisibleTime.read(reader);
355
- const report = this.reportData.read(reader);
356
-
357
- // 在可见的情况下超过 750ms 弃用才算有效数据,否则视为取消
358
- if (lastVisibleTime && Date.now() - lastVisibleTime > 750) {
359
- report?.('isDrop');
360
- } else {
361
- report?.('isValid');
362
- }
352
+ public discard = derivedHandleChanges(
353
+ {
354
+ owner: this,
355
+ createEmptyChangeSummary: () => ({ lastVisibleTime: Date.now() }),
356
+ handleChange: (context, changeSummary) => {
357
+ if (context.didChange(this.multiLineEditsIsVisibleObs)) {
358
+ changeSummary.lastVisibleTime = Date.now();
359
+ return this.multiLineEditsIsVisibleObs.get();
360
+ }
361
+ return false;
362
+ },
363
+ equalityComparer: () => false,
364
+ },
365
+ (reader, changeSummary) => {
366
+ this.multiLineEditsIsVisibleObs.read(reader);
367
+
368
+ const lastVisibleTime = changeSummary.lastVisibleTime;
369
+ const report = this.reportData.read(reader);
370
+ let isValid = false;
371
+
372
+ if (lastVisibleTime && Date.now() - lastVisibleTime > VALID_TIME) {
373
+ isValid = true;
374
+ report?.('isDrop');
375
+ } else {
376
+ isValid = false;
377
+ report?.('isValid', false);
378
+ }
363
379
 
364
- this.hide();
365
- });
380
+ this.hide();
381
+ return isValid;
382
+ },
383
+ );
366
384
 
367
- public accept = derived(this, (reader) => {
385
+ public accept = derivedOpts({ owner: this, equalsFn: () => false }, (reader) => {
368
386
  const report = this.reportData.read(reader);
369
387
  report?.('isReceive');
370
388
 
@@ -392,6 +410,10 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
392
410
  this.hide();
393
411
  });
394
412
 
413
+ public trigger(tx: ITransaction): void {
414
+ this.codeEditsTriggerSignal.trigger(tx);
415
+ }
416
+
395
417
  private registerFeature(monacoEditor: ICodeEditor): void {
396
418
  this.featureDisposable.addDispose(
397
419
  Event.any<any>(
@@ -403,14 +425,19 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
403
425
  }),
404
426
  );
405
427
 
406
- const multiLineEditsIsVisibleKey = new Set([MultiLineEditsIsVisible.raw]);
407
- this.featureDisposable.addDispose(this.whenMultiLineEditsVisibleDisposable);
428
+ // 监听当前光标位置的变化,如果超出 range 区域则表示弃用
408
429
  this.featureDisposable.addDispose(
409
- this.aiNativeContextKey.contextKeyService!.onDidChangeContext((e) => {
410
- if (e.payload.affectsSome(multiLineEditsIsVisibleKey)) {
411
- const isVisible = this.aiNativeContextKey.multiLineEditsIsVisible.get();
412
- if (!isVisible) {
413
- this.whenMultiLineEditsVisibleDisposable.dispose();
430
+ this.monacoEditor.onDidChangeCursorPosition((event: ICursorPositionChangedEvent) => {
431
+ const isVisible = this.multiLineEditsIsVisibleObs.get();
432
+ const completionModel = this.codeEditsResult.get();
433
+
434
+ if (isVisible && completionModel) {
435
+ const position = event.position;
436
+ const range = completionModel.items[0].range;
437
+ if (position.lineNumber < range.startLineNumber || position.lineNumber > range.endLineNumber) {
438
+ runWhenIdle(() => {
439
+ this.discard.get();
440
+ });
414
441
  }
415
442
  }
416
443
  }),
@@ -431,16 +458,19 @@ export class IntelligentCompletionsController extends BaseAIMonacoEditorControll
431
458
  autorunWithStoreHandleChanges(
432
459
  {
433
460
  createEmptyChangeSummary: () => ({}),
434
- handleChange: (context, changeSummary) => {
461
+ handleChange: (context) => {
435
462
  if (context.didChange(this.codeEditsSourceCollection.codeEditsContextBean)) {
436
463
  // 如果上一次补全结果还在,则不重复请求
437
464
  const isVisible = this.aiNativeContextKey.multiLineEditsIsVisible.get();
438
465
  return !isVisible;
466
+ } else if (context.didChange(this.codeEditsTriggerSignal)) {
467
+ return true;
439
468
  }
440
469
  return false;
441
470
  },
442
471
  },
443
472
  async (reader, _, store) => {
473
+ this.codeEditsTriggerSignal.read(reader);
444
474
  const context = this.codeEditsSourceCollection.codeEditsContextBean.read(reader);
445
475
 
446
476
  const provider = this.intelligentCompletionsRegistry.getCodeEditsProvider();
@@ -1,5 +1,6 @@
1
1
  import { Injectable } from '@opensumi/di';
2
2
  import { Disposable } from '@opensumi/ide-core-common';
3
+ import { InlineEditProvider } from '@opensumi/ide-monaco';
3
4
 
4
5
  import { ICodeEditsProvider, IIntelligentCompletionProvider, IIntelligentCompletionsRegistry } from '../../types';
5
6
 
@@ -7,6 +8,7 @@ import { ICodeEditsProvider, IIntelligentCompletionProvider, IIntelligentComplet
7
8
  export class IntelligentCompletionsRegistry extends Disposable implements IIntelligentCompletionsRegistry {
8
9
  private inlineCompletionsProvider: IIntelligentCompletionProvider | undefined;
9
10
  private codeEditsProvider: ICodeEditsProvider | undefined;
11
+ private inlineEditProvider: InlineEditProvider | undefined;
10
12
 
11
13
  registerIntelligentCompletionProvider(provider: IIntelligentCompletionProvider): void {
12
14
  this.inlineCompletionsProvider = provider;
@@ -16,6 +18,10 @@ export class IntelligentCompletionsRegistry extends Disposable implements IIntel
16
18
  this.inlineCompletionsProvider = provider;
17
19
  }
18
20
 
21
+ registerInlineEditProvider(provider: InlineEditProvider): void {
22
+ this.inlineEditProvider = provider;
23
+ }
24
+
19
25
  registerCodeEditsProvider(provider: ICodeEditsProvider): void {
20
26
  this.codeEditsProvider = provider;
21
27
  }
@@ -27,4 +33,9 @@ export class IntelligentCompletionsRegistry extends Disposable implements IIntel
27
33
  getCodeEditsProvider(): ICodeEditsProvider | undefined {
28
34
  return this.codeEditsProvider;
29
35
  }
36
+
37
+ getInlineEditProvider(): InlineEditProvider | undefined {
38
+ // TODO: 支持模块内调用
39
+ return this.inlineEditProvider;
40
+ }
30
41
  }