@opensumi/ide-ai-native 3.7.1 → 3.7.2-next-1739859371.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 (162) 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 +5 -4
  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/source/base.d.ts +9 -3
  26. package/lib/browser/contrib/intelligent-completions/source/base.d.ts.map +1 -1
  27. package/lib/browser/contrib/intelligent-completions/source/base.js +21 -3
  28. package/lib/browser/contrib/intelligent-completions/source/base.js.map +1 -1
  29. package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts +10 -3
  30. package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts.map +1 -1
  31. package/lib/browser/contrib/intelligent-completions/source/line-change.source.js +95 -22
  32. package/lib/browser/contrib/intelligent-completions/source/line-change.source.js.map +1 -1
  33. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.d.ts +1 -3
  34. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.d.ts.map +1 -1
  35. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.js +13 -20
  36. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.js.map +1 -1
  37. package/lib/browser/contrib/intelligent-completions/source/typing.source.d.ts +9 -0
  38. package/lib/browser/contrib/intelligent-completions/source/typing.source.d.ts.map +1 -0
  39. package/lib/browser/contrib/intelligent-completions/source/typing.source.js +36 -0
  40. package/lib/browser/contrib/intelligent-completions/source/typing.source.js.map +1 -0
  41. package/lib/browser/contrib/terminal/component/terminal-command-suggest-controller.js +2 -2
  42. package/lib/browser/contrib/terminal/component/terminal-command-suggest-controller.js.map +1 -1
  43. package/lib/browser/index.js +1 -1
  44. package/lib/browser/index.js.map +1 -1
  45. package/lib/browser/languages/tree-sitter/wasm-manager.d.ts.map +1 -1
  46. package/lib/browser/languages/tree-sitter/wasm-manager.js +14 -2
  47. package/lib/browser/languages/tree-sitter/wasm-manager.js.map +1 -1
  48. package/lib/browser/layout/ai-layout.d.ts.map +1 -1
  49. package/lib/browser/layout/ai-layout.js +2 -2
  50. package/lib/browser/layout/ai-layout.js.map +1 -1
  51. package/lib/browser/layout/layout.module.less +9 -9
  52. package/lib/browser/layout/tabbar.view.d.ts.map +1 -1
  53. package/lib/browser/layout/tabbar.view.js +5 -6
  54. package/lib/browser/layout/tabbar.view.js.map +1 -1
  55. package/lib/browser/model/enhanceDecorationsCollection.d.ts +14 -10
  56. package/lib/browser/model/enhanceDecorationsCollection.d.ts.map +1 -1
  57. package/lib/browser/model/enhanceDecorationsCollection.js +42 -53
  58. package/lib/browser/model/enhanceDecorationsCollection.js.map +1 -1
  59. package/lib/browser/preferences/schema.d.ts.map +1 -1
  60. package/lib/browser/preferences/schema.js +4 -0
  61. package/lib/browser/preferences/schema.js.map +1 -1
  62. package/lib/browser/types.d.ts +7 -2
  63. package/lib/browser/types.d.ts.map +1 -1
  64. package/lib/browser/types.js.map +1 -1
  65. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.d.ts +2 -1
  66. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.d.ts.map +1 -1
  67. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js +20 -48
  68. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js.map +1 -1
  69. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.d.ts +3 -13
  70. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.d.ts.map +1 -1
  71. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.js +24 -72
  72. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.js.map +1 -1
  73. package/lib/browser/widget/inline-chat/inline-chat.service.d.ts +1 -6
  74. package/lib/browser/widget/inline-chat/inline-chat.service.d.ts.map +1 -1
  75. package/lib/browser/widget/inline-chat/inline-chat.service.js +5 -17
  76. package/lib/browser/widget/inline-chat/inline-chat.service.js.map +1 -1
  77. package/lib/browser/widget/inline-chat/inline-content-widget.d.ts +2 -5
  78. package/lib/browser/widget/inline-chat/inline-content-widget.d.ts.map +1 -1
  79. package/lib/browser/widget/inline-chat/inline-content-widget.js +17 -42
  80. package/lib/browser/widget/inline-chat/inline-content-widget.js.map +1 -1
  81. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts +22 -5
  82. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts.map +1 -1
  83. package/lib/browser/widget/inline-diff/inline-diff-previewer.js +61 -30
  84. package/lib/browser/widget/inline-diff/inline-diff-previewer.js.map +1 -1
  85. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts +8 -12
  86. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts.map +1 -1
  87. package/lib/browser/widget/inline-diff/inline-diff.controller.js +68 -96
  88. package/lib/browser/widget/inline-diff/inline-diff.controller.js.map +1 -1
  89. package/lib/browser/widget/inline-hint/inline-hint.controller.d.ts +0 -1
  90. package/lib/browser/widget/inline-hint/inline-hint.controller.d.ts.map +1 -1
  91. package/lib/browser/widget/inline-hint/inline-hint.controller.js +0 -5
  92. package/lib/browser/widget/inline-hint/inline-hint.controller.js.map +1 -1
  93. package/lib/browser/widget/inline-input/inline-input-widget.d.ts +12 -2
  94. package/lib/browser/widget/inline-input/inline-input-widget.d.ts.map +1 -1
  95. package/lib/browser/widget/inline-input/inline-input-widget.js +26 -18
  96. package/lib/browser/widget/inline-input/inline-input-widget.js.map +1 -1
  97. package/lib/browser/widget/inline-input/inline-input.controller.d.ts +14 -5
  98. package/lib/browser/widget/inline-input/inline-input.controller.d.ts.map +1 -1
  99. package/lib/browser/widget/inline-input/inline-input.controller.js +321 -165
  100. package/lib/browser/widget/inline-input/inline-input.controller.js.map +1 -1
  101. package/lib/browser/widget/inline-input/inline-input.module.less +4 -0
  102. package/lib/browser/widget/inline-input/inline-input.service.d.ts +19 -7
  103. package/lib/browser/widget/inline-input/inline-input.service.d.ts.map +1 -1
  104. package/lib/browser/widget/inline-input/inline-input.service.js +72 -12
  105. package/lib/browser/widget/inline-input/inline-input.service.js.map +1 -1
  106. package/lib/browser/widget/inline-input/model.d.ts +34 -0
  107. package/lib/browser/widget/inline-input/model.d.ts.map +1 -0
  108. package/lib/browser/widget/inline-input/model.js +63 -0
  109. package/lib/browser/widget/inline-input/model.js.map +1 -0
  110. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +8 -19
  111. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  112. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +44 -39
  113. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  114. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts +17 -4
  115. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts.map +1 -1
  116. package/lib/browser/widget/inline-stream-diff/live-preview.component.js +37 -5
  117. package/lib/browser/widget/inline-stream-diff/live-preview.component.js.map +1 -1
  118. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts +7 -11
  119. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts.map +1 -1
  120. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js +33 -77
  121. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js.map +1 -1
  122. package/lib/common/utils.js +2 -2
  123. package/lib/common/utils.js.map +1 -1
  124. package/package.json +21 -21
  125. package/src/browser/ai-core.contextkeys.ts +3 -0
  126. package/src/browser/ai-core.contribution.ts +68 -17
  127. package/src/browser/components/ChatMarkdown.tsx +1 -1
  128. package/src/browser/components/WelcomeMsg.tsx +1 -1
  129. package/src/browser/contrib/intelligent-completions/index.ts +16 -4
  130. package/src/browser/contrib/intelligent-completions/intelligent-completions.contribution.ts +29 -8
  131. package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +86 -55
  132. package/src/browser/contrib/intelligent-completions/source/base.ts +28 -7
  133. package/src/browser/contrib/intelligent-completions/source/line-change.source.ts +129 -22
  134. package/src/browser/contrib/intelligent-completions/source/lint-error.source.ts +19 -31
  135. package/src/browser/contrib/intelligent-completions/source/typing.source.ts +34 -0
  136. package/src/browser/contrib/terminal/component/terminal-command-suggest-controller.tsx +1 -1
  137. package/src/browser/index.ts +2 -2
  138. package/src/browser/languages/tree-sitter/wasm-manager.ts +12 -2
  139. package/src/browser/layout/ai-layout.tsx +5 -2
  140. package/src/browser/layout/layout.module.less +9 -9
  141. package/src/browser/layout/tabbar.view.tsx +10 -8
  142. package/src/browser/model/enhanceDecorationsCollection.ts +62 -77
  143. package/src/browser/preferences/schema.ts +4 -0
  144. package/src/browser/types.ts +5 -3
  145. package/src/browser/widget/inline-chat/inline-chat-editor.controller.ts +29 -64
  146. package/src/browser/widget/inline-chat/inline-chat.feature.registry.ts +23 -90
  147. package/src/browser/widget/inline-chat/inline-chat.service.ts +2 -17
  148. package/src/browser/widget/inline-chat/inline-content-widget.tsx +14 -69
  149. package/src/browser/widget/inline-diff/inline-diff-previewer.ts +87 -32
  150. package/src/browser/widget/inline-diff/inline-diff.controller.ts +90 -114
  151. package/src/browser/widget/inline-hint/inline-hint.controller.ts +1 -7
  152. package/src/browser/widget/inline-input/inline-input-widget.tsx +34 -12
  153. package/src/browser/widget/inline-input/inline-input.controller.ts +454 -242
  154. package/src/browser/widget/inline-input/inline-input.module.less +4 -0
  155. package/src/browser/widget/inline-input/inline-input.service.ts +92 -13
  156. package/src/browser/widget/inline-input/model.ts +74 -0
  157. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +54 -67
  158. package/src/browser/widget/inline-stream-diff/live-preview.component.tsx +45 -6
  159. package/src/browser/widget/inline-stream-diff/live-preview.decoration.tsx +40 -112
  160. package/src/common/utils.ts +2 -2
  161. package/lib/browser/model/styles.module.less +0 -7
  162. package/src/browser/model/styles.module.less +0 -7
@@ -3,31 +3,41 @@ import {
3
3
  CancelResponse,
4
4
  Disposable,
5
5
  Event,
6
+ FRAME_FIVE,
6
7
  FRAME_THREE,
8
+ IAIReporter,
7
9
  IDisposable,
8
- InlineChatFeatureRegistryToken,
10
+ IEventBus,
9
11
  ReplyResponse,
10
12
  RunOnceScheduler,
13
+ localize,
11
14
  } from '@opensumi/ide-core-common';
12
- import { ICodeEditor } from '@opensumi/ide-monaco';
15
+ import { EditorGroupCloseEvent } from '@opensumi/ide-editor/lib/browser';
13
16
  import * as monaco from '@opensumi/ide-monaco';
17
+ import { ICodeEditor } from '@opensumi/ide-monaco';
18
+ import {
19
+ IObservable,
20
+ ISettableObservable,
21
+ observableFromEvent,
22
+ observableValue,
23
+ } from '@opensumi/ide-monaco/lib/common/observable';
24
+ import { MessageService } from '@opensumi/ide-overlay/lib/browser/message.service';
14
25
  import { EditOperation } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/editOperation';
15
26
  import { LineRange } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/lineRange';
16
27
  import { ModelDecorationOptions } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model/textModel';
17
28
 
18
29
  import { AINativeContextKey } from '../../ai-core.contextkeys';
19
30
  import { BaseAIMonacoEditorController } from '../../contrib/base';
20
- import { LanguageParserService } from '../../languages/service';
21
31
  import { ERunStrategy } from '../../types';
22
32
  import { InlineChatController } from '../inline-chat/inline-chat-controller';
23
- import { InlineChatFeatureRegistry } from '../inline-chat/inline-chat.feature.registry';
24
33
  import { EInlineChatStatus, EResultKind } from '../inline-chat/inline-chat.service';
34
+ import { InlineDiffController } from '../inline-diff';
25
35
  import { InlineInputPreviewDecorationID } from '../internal.type';
26
36
 
27
- import { InlineInputChatWidget } from './inline-input-widget';
37
+ import { InlineInputWidget } from './inline-input-widget';
28
38
  import styles from './inline-input.module.less';
29
- import { InlineInputChatService } from './inline-input.service';
30
-
39
+ import { InlineInputService } from './inline-input.service';
40
+ import { InlineInputWidgetStoreInEmptyLine, InlineInputWidgetStoreInSelection } from './model';
31
41
  @Injectable()
32
42
  export class InlineInputController extends BaseAIMonacoEditorController {
33
43
  public static readonly ID = 'editor.contrib.ai.inline.input';
@@ -36,281 +46,483 @@ export class InlineInputController extends BaseAIMonacoEditorController {
36
46
  return editor.getContribution<InlineInputController>(InlineInputController.ID);
37
47
  }
38
48
 
39
- private get inlineInputChatService(): InlineInputChatService {
40
- return this.injector.get(InlineInputChatService);
49
+ private get inlineInputService(): InlineInputService {
50
+ return this.injector.get(InlineInputService);
41
51
  }
42
52
 
43
- private get inlineChatFeatureRegistry(): InlineChatFeatureRegistry {
44
- return this.injector.get(InlineChatFeatureRegistryToken);
53
+ private get aiReporter(): IAIReporter {
54
+ return this.injector.get(IAIReporter);
45
55
  }
46
56
 
47
- private get languageParserService(): LanguageParserService {
48
- return this.injector.get(LanguageParserService);
57
+ private get eventBus(): IEventBus {
58
+ return this.injector.get(IEventBus);
49
59
  }
50
60
 
61
+ private get messageService(): MessageService {
62
+ return this.injector.get(MessageService);
63
+ }
64
+
65
+ private inlineDiffController: InlineDiffController;
66
+ private inputDisposable: Disposable;
67
+ private aiNativeContextKey: AINativeContextKey;
68
+
69
+ private inputValue: ISettableObservable<string>;
70
+ private modelChangeObs: IObservable<monaco.editor.ITextModel, unknown>;
71
+ private inlineInputWidgetStore: Map<
72
+ string,
73
+ InlineInputWidgetStoreInEmptyLine | InlineInputWidgetStoreInSelection | null
74
+ >;
75
+
51
76
  mount(): IDisposable {
52
- return this.registerInlineInputFeature(this.monacoEditor);
77
+ this.inputDisposable = new Disposable();
78
+ this.aiNativeContextKey = this.injector.get(AINativeContextKey, [this.monacoEditor.contextKeyService]);
79
+ this.inlineDiffController = InlineDiffController.get(this.monacoEditor)!;
80
+
81
+ this.inputValue = observableValue(this, '');
82
+ this.modelChangeObs = observableFromEvent<monaco.editor.ITextModel>(
83
+ this,
84
+ this.monacoEditor.onDidChangeModel,
85
+ () => this.monacoEditor.getModel()!,
86
+ );
87
+ this.inlineInputWidgetStore = new Map();
88
+
89
+ this.featureDisposable.addDispose(
90
+ /**
91
+ * 如果在流式过程中,直接关闭了当前文件,则需要销毁 diff previewer 并隐藏 input,恢复原始代码
92
+ */
93
+ this.eventBus.on(EditorGroupCloseEvent, (e: EditorGroupCloseEvent) => {
94
+ const isStreaming = this.aiNativeContextKey.inlineInputWidgetIsStreaming.get();
95
+ if (!isStreaming) {
96
+ return;
97
+ }
98
+
99
+ const resource = e.payload.resource.uri.toString();
100
+ const currentUri = this.monacoEditor.getModel()?.uri.toString();
101
+
102
+ if (currentUri === resource) {
103
+ this.hideInput();
104
+
105
+ const message = localize('aiNative.inline.chat.generating.canceled');
106
+ if (message) {
107
+ this.messageService.info(message);
108
+ }
109
+ }
110
+ }),
111
+ );
112
+
113
+ this.featureDisposable.addDispose(
114
+ this.inlineInputService.onHidden(() => {
115
+ this.hideInput();
116
+ }),
117
+ );
118
+
119
+ this.featureDisposable.addDispose(
120
+ this.inlineInputService.onInteractiveInputVisibleInPosition(async (position) => {
121
+ if (position) {
122
+ this.showInputInEmptyLine(position, this.monacoEditor);
123
+ } else {
124
+ setTimeout(() => this.monacoEditor.focus(), 0);
125
+ }
126
+ }),
127
+ );
128
+
129
+ this.featureDisposable.addDispose(
130
+ this.inlineInputService.onInteractiveInputVisibleInSelection((selection) => {
131
+ if (!selection) {
132
+ return;
133
+ }
134
+
135
+ this.showInputInSelection(selection, this.monacoEditor);
136
+ }),
137
+ );
138
+
139
+ this.featureDisposable.addDispose(this.inputDisposable);
140
+
141
+ return this.featureDisposable;
142
+ }
143
+
144
+ override cancelToken() {
145
+ super.cancelToken();
146
+ this.aiNativeContextKey.inlineInputWidgetIsStreaming.set(false);
147
+ }
148
+
149
+ private hideInput() {
150
+ this.inlineInputWidgetStore.delete(this.monacoEditor.getModel()!.id);
151
+ this.inputDisposable.dispose();
53
152
  }
54
153
 
55
- private async doRequestReadable(
56
- value: string,
57
- widget: InlineInputChatWidget,
58
- monacoEditor: ICodeEditor,
59
- inputDisposable: Disposable,
60
- decoration: monaco.editor.IEditorDecorationsCollection,
61
- hideInput: () => void,
62
- ): Promise<void> {
63
- const handler = this.inlineChatFeatureRegistry.getInteractiveInputHandler();
154
+ private async showInputInEmptyLine(position: monaco.IPosition, monacoEditor: ICodeEditor, defaultValue?: string) {
64
155
  const model = monacoEditor.getModel();
65
156
 
66
- if (!handler || !model) {
157
+ if (!model) {
67
158
  return;
68
159
  }
69
160
 
70
- widget.launchChatStatus(EInlineChatStatus.THINKING);
161
+ const selection = monacoEditor.getSelection();
162
+ if (selection && !selection.isEmpty()) {
163
+ return;
164
+ }
71
165
 
72
- const strategy = await this.inlineChatFeatureRegistry.getInteractiveInputStrategyHandler()(monacoEditor, value);
166
+ this.inputValue.set(defaultValue || '', undefined);
167
+ this.inlineInputWidgetStore.set(model.id, new InlineInputWidgetStoreInEmptyLine(position, defaultValue));
73
168
 
74
- if (strategy === ERunStrategy.EXECUTE && handler.execute) {
75
- handler.execute(monacoEditor, value, this.token);
76
- widget.launchChatStatus(EInlineChatStatus.DONE);
77
- hideInput();
78
- return;
169
+ if (this.inputDisposable) {
170
+ this.inputDisposable.dispose();
171
+ this.inputDisposable = new Disposable();
79
172
  }
80
173
 
81
- if (strategy === ERunStrategy.PREVIEW && handler.providePreviewStrategy) {
82
- const previewResponse = await handler.providePreviewStrategy(monacoEditor, value, this.token);
83
-
84
- if (CancelResponse.is(previewResponse)) {
85
- widget.launchChatStatus(EInlineChatStatus.READY);
86
- hideInput();
87
- return;
88
- }
89
-
90
- if (InlineChatController.is(previewResponse)) {
91
- const controller = previewResponse as InlineChatController;
92
-
93
- let latestContent: string | undefined;
94
- const schedulerEdit: RunOnceScheduler = this.registerDispose(
95
- new RunOnceScheduler(() => {
96
- const range = decoration.getRange(0);
97
- if (range && latestContent) {
98
- model.pushEditOperations(null, [EditOperation.replace(range, latestContent)], () => null);
99
- }
100
- }, 16 * 12.5),
101
- );
102
-
103
- inputDisposable.addDispose([
104
- controller.onData(async (data) => {
105
- if (!ReplyResponse.is(data)) {
106
- return;
107
- }
108
-
109
- latestContent = data.message;
110
-
111
- if (!schedulerEdit.isScheduled()) {
112
- schedulerEdit.schedule();
113
- }
114
- }),
115
- controller.onError((error) => {
116
- widget.launchChatStatus(EInlineChatStatus.ERROR);
117
- }),
118
- controller.onAbort(() => {
119
- widget.launchChatStatus(EInlineChatStatus.READY);
120
- }),
121
- controller.onEnd(() => {
122
- model.pushStackElement();
123
- widget.launchChatStatus(EInlineChatStatus.DONE);
124
- }),
125
- ]);
126
-
127
- controller.listen();
128
- }
174
+ const collection = monacoEditor.createDecorationsCollection();
175
+ const inlineInputWidget = this.injector.get(InlineInputWidget, [monacoEditor, this.inputValue.get()]);
176
+
177
+ // 仅在空行情况下增加装饰逻辑
178
+ collection.append([
179
+ {
180
+ range: monaco.Range.fromPositions(position),
181
+ options: ModelDecorationOptions.register({
182
+ description: InlineInputPreviewDecorationID,
183
+ isWholeLine: true,
184
+ className: styles.input_decoration_readable_container,
185
+ inlineClassName: styles.inline_chat_inserted_range,
186
+ }),
187
+ },
188
+ ]);
189
+
190
+ const decorationRange = collection.getRange(0);
191
+ let preLineRange: LineRange;
192
+ if (decorationRange) {
193
+ preLineRange = LineRange.fromRange(decorationRange);
194
+ inlineInputWidget.show({ position: decorationRange.getStartPosition() });
195
+ this.aiNativeContextKey.inlineInputWidgetIsVisible.set(true);
129
196
  }
130
- }
131
197
 
132
- private registerInlineInputFeature(monacoEditor: ICodeEditor): IDisposable {
133
- const inputDisposable = new Disposable();
134
- const aiNativeContextKey = this.injector.get(AINativeContextKey, [monacoEditor.contextKeyService]);
198
+ this.inputDisposable.addDispose(
199
+ inlineInputWidget.onDispose(() => {
200
+ this.cancelToken();
201
+ collection.clear();
202
+ this.aiNativeContextKey.inlineInputWidgetIsVisible.set(false);
203
+ }),
204
+ );
135
205
 
136
- const hideInput = () => {
137
- inputDisposable.dispose();
138
- };
206
+ this.inputDisposable.addDispose(
207
+ inlineInputWidget.onValueChange((value) => {
208
+ this.inputValue.set(value, undefined);
139
209
 
140
- this.featureDisposable.addDispose(
141
- this.inlineInputChatService.onInteractiveInputVisibleInPosition((position) => {
142
- hideInput();
143
- if (position) {
144
- showInput(position, monacoEditor);
145
- } else {
146
- setTimeout(() => {
147
- monacoEditor.focus();
148
- }, 0);
210
+ const storeData = this.inlineInputWidgetStore.get(model.id);
211
+ if (storeData instanceof InlineInputWidgetStoreInEmptyLine) {
212
+ storeData.setValue(value);
149
213
  }
150
214
  }),
151
215
  );
152
216
 
153
- const showInput = async (position: monaco.Position, monacoEditor: ICodeEditor) => {
154
- this.featureDisposable.addDispose(
155
- monacoEditor.onWillChangeModel(() => {
156
- hideInput();
157
- }),
158
- );
217
+ this.inputDisposable.addDispose(
218
+ inlineInputWidget.onResultClick(async (kind: EResultKind) => {
219
+ const clear = () => {
220
+ const curPosi = collection.getRange(0)!;
221
+
222
+ model.pushStackElement();
223
+ model.pushEditOperations(null, [EditOperation.delete(curPosi)], () => null);
224
+ model.pushStackElement();
225
+ };
226
+
227
+ switch (kind) {
228
+ case EResultKind.ACCEPT:
229
+ this.hideInput();
230
+ break;
231
+ case EResultKind.DISCARD:
232
+ clear();
233
+ this.hideInput();
234
+ break;
235
+ case EResultKind.REGENERATE:
236
+ clear();
237
+ requestAnimationFrame(() => {
238
+ /**
239
+ * 避免在重新生成的时候,因为光标移动,导致 input 的位置不正确
240
+ */
241
+ const curPosi = collection.getRange(0)!;
242
+ const curPosition = curPosi.getStartPosition();
243
+ this.showInputInEmptyLine(curPosition, monacoEditor, this.inputValue.get());
244
+ });
245
+ break;
159
246
 
160
- const model = monacoEditor.getModel();
161
- if (!model) {
162
- return;
163
- }
247
+ default:
248
+ break;
249
+ }
250
+ }),
251
+ );
164
252
 
165
- /**
166
- * 只有当前编辑器的光标聚焦,才会展示
167
- * 用于解决多栏的情况下,同时打开多个 input 的问题
168
- */
169
- const hasFocus = monacoEditor.hasTextFocus();
170
- if (!hasFocus) {
171
- return;
172
- }
173
-
174
- const selection = monacoEditor.getSelection();
175
- if (selection && selection.startLineNumber !== selection.endLineNumber) {
176
- return;
177
- }
178
-
179
- const inlineInputChatWidget = this.injector.get(InlineInputChatWidget, [monacoEditor]);
180
-
181
- const collection = monacoEditor.createDecorationsCollection();
182
- const isEmptyLine = !monacoEditor.getModel()?.getLineContent(position.lineNumber).trim();
183
-
184
- if (!isEmptyLine) {
185
- // 根据光标位置自动检测并选中临近的代码块
186
- const cursorPosition = monacoEditor.getPosition();
187
- const editorModel = monacoEditor.getModel();
188
- const cursor = editorModel?.getOffsetAt(cursorPosition!);
189
- const language = editorModel?.getLanguageId();
190
- const parser = this.languageParserService.createParser(language!);
191
- const codeBlock = await parser?.findNearestCodeBlockWithPosition(editorModel?.getValue() || '', cursor!);
192
-
193
- if (codeBlock) {
194
- const selection = new monaco.Selection(
195
- codeBlock.range.start.line + 1,
196
- codeBlock.range.start.character,
197
- codeBlock.range.end.line + 1,
198
- codeBlock.range.end.character,
199
- );
200
- monacoEditor.setSelection(selection);
201
- } else {
202
- // 选中当前行
203
- monacoEditor.setSelection(new monaco.Selection(position.lineNumber, 1, position.lineNumber, Infinity));
253
+ this.inputDisposable.addDispose(
254
+ Event.debounce(
255
+ collection.onDidChange.bind(collection),
256
+ () => {},
257
+ FRAME_THREE,
258
+ )(() => {
259
+ if (!collection.getRange(0)) {
260
+ return;
204
261
  }
205
- return;
206
- }
207
-
208
- // 仅在空行情况下增加装饰逻辑
209
- collection.append([
210
- {
211
- range: monaco.Range.fromPositions(position),
212
- options: ModelDecorationOptions.register({
213
- description: InlineInputPreviewDecorationID,
214
- isWholeLine: true,
215
- className: styles.input_decoration_readable_container,
216
- inlineClassName: styles.inline_chat_inserted_range,
217
- }),
218
- },
219
- ]);
220
-
221
- const decorationRange = collection.getRange(0);
222
- let preLineRange: LineRange;
223
- if (decorationRange) {
224
- preLineRange = LineRange.fromRange(decorationRange);
225
- inlineInputChatWidget.show({ position: decorationRange.getStartPosition() });
226
- }
227
- aiNativeContextKey.inlineInputWidgetIsVisible.set(true);
228
-
229
- inputDisposable.addDispose(
230
- inlineInputChatWidget.onDispose(() => {
262
+
263
+ const range = collection.getRange(0)!;
264
+ const curLineRange = LineRange.fromRange(range);
265
+ if (!preLineRange.equals(curLineRange)) {
266
+ inlineInputWidget.setOptions({
267
+ position: range.getStartPosition(),
268
+ });
269
+
270
+ inlineInputWidget.layoutContentWidget();
271
+ }
272
+ preLineRange = curLineRange;
273
+ }),
274
+ );
275
+
276
+ this.inputDisposable.addDispose(
277
+ inlineInputWidget.onClose(() => {
278
+ const isStreaming = this.aiNativeContextKey.inlineInputWidgetIsStreaming.get();
279
+ if (isStreaming) {
231
280
  this.cancelToken();
232
- collection.clear();
233
- aiNativeContextKey.inlineInputWidgetIsVisible.set(false);
234
- }),
235
- );
236
-
237
- inputDisposable.addDispose(
238
- inlineInputChatWidget.onResultClick(async (kind: EResultKind) => {
239
- const clear = () => {
240
- const curPosi = collection.getRange(0)!;
241
-
242
- model.pushStackElement();
243
- model.pushEditOperations(null, [EditOperation.delete(curPosi)], () => null);
244
- model.pushStackElement();
245
- };
246
-
247
- switch (kind) {
248
- case EResultKind.ACCEPT:
249
- hideInput();
250
- break;
251
- case EResultKind.DISCARD:
252
- clear();
253
- hideInput();
254
- break;
255
- case EResultKind.REGENERATE:
256
- clear();
257
- await this.doRequestReadable(
258
- inlineInputChatWidget.interactiveInputValue,
259
- inlineInputChatWidget,
260
- monacoEditor,
261
- inputDisposable,
262
- collection,
263
- hideInput,
264
- );
265
- break;
266
-
267
- default:
268
- break;
269
- }
270
- }),
271
- );
272
-
273
- inputDisposable.addDispose(
274
- Event.debounce(
275
- collection.onDidChange.bind(collection),
276
- () => {},
277
- FRAME_THREE,
278
- )(() => {
279
- if (!collection.getRange(0)) {
281
+ } else {
282
+ this.hideInput();
283
+ }
284
+ }),
285
+ );
286
+
287
+ this.inputDisposable.addDispose(
288
+ inlineInputWidget.onSend(async (value) => {
289
+ monacoEditor.focus();
290
+
291
+ const handler = this.inlineInputService.getInteractiveInputHandler();
292
+ const model = monacoEditor.getModel();
293
+
294
+ if (!handler || !model) {
295
+ return;
296
+ }
297
+
298
+ inlineInputWidget.launchChatStatus(EInlineChatStatus.THINKING);
299
+
300
+ const strategy = await this.inlineInputService.getInteractiveInputStrategyHandler()(monacoEditor, value);
301
+ const selection = monaco.Selection.fromPositions(position);
302
+
303
+ if (strategy === ERunStrategy.EXECUTE && handler.execute) {
304
+ handler.execute(monacoEditor, selection, value, this.token);
305
+ inlineInputWidget.launchChatStatus(EInlineChatStatus.DONE);
306
+ this.hideInput();
307
+ return;
308
+ }
309
+
310
+ if (strategy === ERunStrategy.PREVIEW && handler.providePreviewStrategy) {
311
+ const previewResponse = await handler.providePreviewStrategy(monacoEditor, selection, value, this.token);
312
+
313
+ if (CancelResponse.is(previewResponse)) {
314
+ inlineInputWidget.launchChatStatus(EInlineChatStatus.READY);
315
+ this.hideInput();
280
316
  return;
281
317
  }
282
318
 
283
- const range = collection.getRange(0)!;
284
- const curLineRange = LineRange.fromRange(range);
285
- if (!preLineRange.equals(curLineRange)) {
286
- inlineInputChatWidget.setOptions({
287
- position: range.getStartPosition(),
288
- });
289
-
290
- inlineInputChatWidget.layoutContentWidget();
319
+ if (InlineChatController.is(previewResponse)) {
320
+ const controller = previewResponse as InlineChatController;
321
+
322
+ let latestContent: string | undefined;
323
+ const schedulerEdit: RunOnceScheduler = this.registerDispose(
324
+ new RunOnceScheduler(() => {
325
+ const range = collection.getRange(0);
326
+ if (range && latestContent) {
327
+ model.pushEditOperations(null, [EditOperation.replace(range, latestContent)], () => null);
328
+ }
329
+ }, FRAME_FIVE),
330
+ );
331
+
332
+ this.inputDisposable.addDispose([
333
+ controller.onData(async (data) => {
334
+ if (!ReplyResponse.is(data)) {
335
+ return;
336
+ }
337
+
338
+ this.aiNativeContextKey.inlineInputWidgetIsStreaming.set(true);
339
+ latestContent = data.message;
340
+
341
+ if (!schedulerEdit.isScheduled()) {
342
+ schedulerEdit.schedule();
343
+ }
344
+ }),
345
+ controller.onError((error) => {
346
+ this.aiNativeContextKey.inlineInputWidgetIsStreaming.set(false);
347
+ inlineInputWidget.launchChatStatus(EInlineChatStatus.READY);
348
+ }),
349
+ controller.onAbort(() => {
350
+ this.aiNativeContextKey.inlineInputWidgetIsStreaming.set(false);
351
+ model.pushStackElement();
352
+ inlineInputWidget.launchChatStatus(EInlineChatStatus.DONE);
353
+ }),
354
+ controller.onEnd(() => {
355
+ this.aiNativeContextKey.inlineInputWidgetIsStreaming.set(false);
356
+ model.pushStackElement();
357
+ inlineInputWidget.launchChatStatus(EInlineChatStatus.DONE);
358
+ }),
359
+ ]);
360
+
361
+ controller.listen();
291
362
  }
292
- preLineRange = curLineRange;
363
+ }
364
+ }),
365
+ );
366
+
367
+ this.inputDisposable.addDispose(inlineInputWidget);
368
+ }
369
+
370
+ private async showInputInSelection(selection: monaco.Selection, monacoEditor: ICodeEditor, defaultValue?: string) {
371
+ if (this.inputDisposable) {
372
+ this.inputDisposable.dispose();
373
+ this.inputDisposable = new Disposable();
374
+ }
375
+
376
+ const model = monacoEditor.getModel();
377
+ if (!model) {
378
+ return;
379
+ }
380
+
381
+ const decorationsCollection = monacoEditor.createDecorationsCollection();
382
+ decorationsCollection.set([
383
+ {
384
+ range: monaco.Range.fromPositions(
385
+ { lineNumber: selection.startLineNumber, column: 1 },
386
+ {
387
+ lineNumber: selection.endLineNumber,
388
+ column: monacoEditor.getModel()!.getLineMaxColumn(selection.endLineNumber),
389
+ },
390
+ ),
391
+ options: ModelDecorationOptions.register({
392
+ description: InlineInputPreviewDecorationID,
393
+ isWholeLine: true,
394
+ className: styles.input_decoration_pending_container,
293
395
  }),
294
- );
396
+ },
397
+ ]);
398
+ const decorationSelection = monaco.Selection.fromRange(
399
+ decorationsCollection.getRange(0)!,
400
+ selection.getDirection(),
401
+ );
295
402
 
296
- inputDisposable.addDispose(
297
- inlineInputChatWidget.onInteractiveInputValue(async (value) => {
298
- await this.doRequestReadable(
299
- value,
300
- inlineInputChatWidget,
403
+ this.inputValue.set(defaultValue || '', undefined);
404
+ this.inlineInputWidgetStore.set(model.id, new InlineInputWidgetStoreInSelection(decorationSelection, defaultValue));
405
+
406
+ const inlineInputWidget = this.injector.get(InlineInputWidget, [monacoEditor, this.inputValue.get()]);
407
+ inlineInputWidget.show({ selection: decorationSelection });
408
+
409
+ this.aiNativeContextKey.inlineInputWidgetIsVisible.set(true);
410
+
411
+ this.inputDisposable.addDispose(
412
+ inlineInputWidget.onDispose(() => {
413
+ this.cancelToken();
414
+ decorationsCollection.clear();
415
+ this.aiNativeContextKey.inlineInputWidgetIsVisible.set(false);
416
+ }),
417
+ );
418
+
419
+ this.inputDisposable.addDispose(
420
+ inlineInputWidget.onValueChange((value) => {
421
+ this.inputValue.set(value, undefined);
422
+
423
+ const storeData = this.inlineInputWidgetStore.get(model.id);
424
+ if (storeData instanceof InlineInputWidgetStoreInSelection) {
425
+ storeData.setValue(value);
426
+ }
427
+ }),
428
+ );
429
+
430
+ this.inputDisposable.addDispose(
431
+ inlineInputWidget.onClose(() => {
432
+ const isStreaming = this.aiNativeContextKey.inlineInputWidgetIsStreaming.get();
433
+ if (isStreaming) {
434
+ this.cancelToken();
435
+ } else {
436
+ this.hideInput();
437
+ }
438
+ }),
439
+ );
440
+
441
+ this.inputDisposable.addDispose(
442
+ inlineInputWidget.onSend(async (value) => {
443
+ monacoEditor.focus();
444
+
445
+ const handler = this.inlineInputService.getInteractiveInputHandler();
446
+
447
+ if (!handler) {
448
+ return;
449
+ }
450
+
451
+ inlineInputWidget.launchChatStatus(EInlineChatStatus.THINKING);
452
+
453
+ const strategy = await this.inlineInputService.getInteractiveInputStrategyHandler()(monacoEditor, value);
454
+
455
+ if (strategy === ERunStrategy.PREVIEW && handler.providePreviewStrategy) {
456
+ const previewResponse = await handler.providePreviewStrategy(
301
457
  monacoEditor,
302
- inputDisposable,
303
- collection,
304
- hideInput,
458
+ decorationSelection,
459
+ value,
460
+ this.token,
305
461
  );
306
- }),
307
- );
308
462
 
309
- inputDisposable.addDispose(inlineInputChatWidget);
310
- };
463
+ if (CancelResponse.is(previewResponse)) {
464
+ decorationsCollection.clear();
465
+ this.aiNativeContextKey.inlineInputWidgetIsStreaming.set(false);
466
+ inlineInputWidget.launchChatStatus(EInlineChatStatus.DONE);
467
+ return;
468
+ }
311
469
 
312
- this.featureDisposable.addDispose(inputDisposable);
470
+ if (InlineChatController.is(previewResponse)) {
471
+ const chatResponse = previewResponse;
472
+
473
+ this.inputDisposable.addDispose([
474
+ chatResponse.onData((data) => {
475
+ decorationsCollection.clear();
476
+ if (ReplyResponse.is(data)) {
477
+ this.aiNativeContextKey.inlineInputWidgetIsStreaming.set(true);
478
+ }
479
+ }),
480
+ chatResponse.onError((error) => {
481
+ this.aiNativeContextKey.inlineInputWidgetIsStreaming.set(false);
482
+ inlineInputWidget.launchChatStatus(EInlineChatStatus.READY);
483
+ }),
484
+ chatResponse.onAbort(() => {
485
+ decorationsCollection.clear();
486
+ this.aiNativeContextKey.inlineInputWidgetIsStreaming.set(false);
487
+ inlineInputWidget.launchChatStatus(EInlineChatStatus.DONE);
488
+ }),
489
+ chatResponse.onEnd(() => {
490
+ decorationsCollection.clear();
491
+ this.aiNativeContextKey.inlineInputWidgetIsStreaming.set(false);
492
+ inlineInputWidget.launchChatStatus(EInlineChatStatus.DONE);
493
+ }),
494
+ ]);
495
+
496
+ const diffPreviewer = this.inlineDiffController.showPreviewerByStream(monacoEditor, {
497
+ crossSelection: decorationSelection,
498
+ chatResponse,
499
+ });
313
500
 
314
- return this.featureDisposable;
501
+ diffPreviewer.mountWidget(inlineInputWidget);
502
+
503
+ chatResponse.listen();
504
+ }
505
+ } else {
506
+ decorationsCollection.clear();
507
+ inlineInputWidget.launchChatStatus(EInlineChatStatus.READY);
508
+ this.hideInput();
509
+ }
510
+ }),
511
+ );
512
+
513
+ this.inputDisposable.addDispose(
514
+ inlineInputWidget.onResultClick((kind: EResultKind) => {
515
+ this.inlineDiffController.handleAction(kind);
516
+ this.hideInput();
517
+
518
+ if (kind === EResultKind.REGENERATE) {
519
+ requestAnimationFrame(() => {
520
+ this.showInputInSelection(decorationSelection, monacoEditor, this.inputValue.get());
521
+ });
522
+ }
523
+ }),
524
+ );
525
+
526
+ this.inputDisposable.addDispose(inlineInputWidget);
315
527
  }
316
528
  }