@opensumi/ide-ai-native 3.7.1-next-1739428766.0 → 3.7.1-next-1739439717.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 (126) hide show
  1. package/lib/browser/ai-core.contextkeys.d.ts +0 -1
  2. package/lib/browser/ai-core.contextkeys.d.ts.map +1 -1
  3. package/lib/browser/ai-core.contextkeys.js +0 -1
  4. package/lib/browser/ai-core.contextkeys.js.map +1 -1
  5. package/lib/browser/ai-core.contribution.d.ts +1 -2
  6. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  7. package/lib/browser/ai-core.contribution.js +14 -55
  8. package/lib/browser/ai-core.contribution.js.map +1 -1
  9. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.d.ts +0 -1
  10. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.d.ts.map +1 -1
  11. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js +4 -26
  12. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js.map +1 -1
  13. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts +1 -3
  14. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts.map +1 -1
  15. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js +1 -9
  16. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js.map +1 -1
  17. package/lib/browser/contrib/intelligent-completions/source/base.d.ts +2 -1
  18. package/lib/browser/contrib/intelligent-completions/source/base.d.ts.map +1 -1
  19. package/lib/browser/contrib/intelligent-completions/source/base.js.map +1 -1
  20. package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts +3 -2
  21. package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts.map +1 -1
  22. package/lib/browser/contrib/intelligent-completions/source/line-change.source.js +21 -51
  23. package/lib/browser/contrib/intelligent-completions/source/line-change.source.js.map +1 -1
  24. package/lib/browser/contrib/terminal/component/terminal-command-suggest-controller.js +2 -2
  25. package/lib/browser/contrib/terminal/component/terminal-command-suggest-controller.js.map +1 -1
  26. package/lib/browser/index.js +1 -1
  27. package/lib/browser/index.js.map +1 -1
  28. package/lib/browser/layout/ai-layout.d.ts.map +1 -1
  29. package/lib/browser/layout/ai-layout.js +2 -2
  30. package/lib/browser/layout/ai-layout.js.map +1 -1
  31. package/lib/browser/model/enhanceDecorationsCollection.d.ts +10 -14
  32. package/lib/browser/model/enhanceDecorationsCollection.d.ts.map +1 -1
  33. package/lib/browser/model/enhanceDecorationsCollection.js +53 -42
  34. package/lib/browser/model/enhanceDecorationsCollection.js.map +1 -1
  35. package/lib/browser/model/styles.module.less +7 -0
  36. package/lib/browser/types.d.ts +2 -7
  37. package/lib/browser/types.d.ts.map +1 -1
  38. package/lib/browser/types.js.map +1 -1
  39. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.d.ts +1 -2
  40. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.d.ts.map +1 -1
  41. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js +48 -20
  42. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js.map +1 -1
  43. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.d.ts +13 -3
  44. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.d.ts.map +1 -1
  45. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.js +72 -24
  46. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.js.map +1 -1
  47. package/lib/browser/widget/inline-chat/inline-chat.service.d.ts +6 -1
  48. package/lib/browser/widget/inline-chat/inline-chat.service.d.ts.map +1 -1
  49. package/lib/browser/widget/inline-chat/inline-chat.service.js +19 -5
  50. package/lib/browser/widget/inline-chat/inline-chat.service.js.map +1 -1
  51. package/lib/browser/widget/inline-chat/inline-content-widget.d.ts +5 -2
  52. package/lib/browser/widget/inline-chat/inline-content-widget.d.ts.map +1 -1
  53. package/lib/browser/widget/inline-chat/inline-content-widget.js +42 -17
  54. package/lib/browser/widget/inline-chat/inline-content-widget.js.map +1 -1
  55. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts +5 -22
  56. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts.map +1 -1
  57. package/lib/browser/widget/inline-diff/inline-diff-previewer.js +30 -61
  58. package/lib/browser/widget/inline-diff/inline-diff-previewer.js.map +1 -1
  59. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts +12 -8
  60. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts.map +1 -1
  61. package/lib/browser/widget/inline-diff/inline-diff.controller.js +96 -68
  62. package/lib/browser/widget/inline-diff/inline-diff.controller.js.map +1 -1
  63. package/lib/browser/widget/inline-hint/inline-hint.controller.d.ts +1 -0
  64. package/lib/browser/widget/inline-hint/inline-hint.controller.d.ts.map +1 -1
  65. package/lib/browser/widget/inline-hint/inline-hint.controller.js +5 -0
  66. package/lib/browser/widget/inline-hint/inline-hint.controller.js.map +1 -1
  67. package/lib/browser/widget/inline-input/inline-input-widget.d.ts +2 -12
  68. package/lib/browser/widget/inline-input/inline-input-widget.d.ts.map +1 -1
  69. package/lib/browser/widget/inline-input/inline-input-widget.js +18 -26
  70. package/lib/browser/widget/inline-input/inline-input-widget.js.map +1 -1
  71. package/lib/browser/widget/inline-input/inline-input.controller.d.ts +6 -14
  72. package/lib/browser/widget/inline-input/inline-input.controller.d.ts.map +1 -1
  73. package/lib/browser/widget/inline-input/inline-input.controller.js +169 -320
  74. package/lib/browser/widget/inline-input/inline-input.controller.js.map +1 -1
  75. package/lib/browser/widget/inline-input/inline-input.module.less +0 -4
  76. package/lib/browser/widget/inline-input/inline-input.service.d.ts +7 -19
  77. package/lib/browser/widget/inline-input/inline-input.service.d.ts.map +1 -1
  78. package/lib/browser/widget/inline-input/inline-input.service.js +12 -72
  79. package/lib/browser/widget/inline-input/inline-input.service.js.map +1 -1
  80. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +19 -8
  81. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  82. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +39 -44
  83. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  84. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts +4 -17
  85. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts.map +1 -1
  86. package/lib/browser/widget/inline-stream-diff/live-preview.component.js +5 -37
  87. package/lib/browser/widget/inline-stream-diff/live-preview.component.js.map +1 -1
  88. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts +11 -7
  89. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts.map +1 -1
  90. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js +77 -33
  91. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js.map +1 -1
  92. package/lib/common/utils.js +2 -2
  93. package/lib/common/utils.js.map +1 -1
  94. package/package.json +21 -21
  95. package/src/browser/ai-core.contextkeys.ts +0 -3
  96. package/src/browser/ai-core.contribution.ts +16 -63
  97. package/src/browser/contrib/intelligent-completions/intelligent-completions.contribution.ts +8 -29
  98. package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +1 -13
  99. package/src/browser/contrib/intelligent-completions/source/base.ts +2 -0
  100. package/src/browser/contrib/intelligent-completions/source/line-change.source.ts +24 -79
  101. package/src/browser/contrib/terminal/component/terminal-command-suggest-controller.tsx +1 -1
  102. package/src/browser/index.ts +2 -2
  103. package/src/browser/layout/ai-layout.tsx +2 -5
  104. package/src/browser/model/enhanceDecorationsCollection.ts +77 -62
  105. package/src/browser/model/styles.module.less +7 -0
  106. package/src/browser/types.ts +3 -5
  107. package/src/browser/widget/inline-chat/inline-chat-editor.controller.ts +64 -29
  108. package/src/browser/widget/inline-chat/inline-chat.feature.registry.ts +90 -23
  109. package/src/browser/widget/inline-chat/inline-chat.service.ts +19 -2
  110. package/src/browser/widget/inline-chat/inline-content-widget.tsx +71 -14
  111. package/src/browser/widget/inline-diff/inline-diff-previewer.ts +32 -87
  112. package/src/browser/widget/inline-diff/inline-diff.controller.ts +114 -90
  113. package/src/browser/widget/inline-hint/inline-hint.controller.ts +7 -1
  114. package/src/browser/widget/inline-input/inline-input-widget.tsx +12 -34
  115. package/src/browser/widget/inline-input/inline-input.controller.ts +247 -453
  116. package/src/browser/widget/inline-input/inline-input.module.less +0 -4
  117. package/src/browser/widget/inline-input/inline-input.service.ts +13 -92
  118. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +67 -54
  119. package/src/browser/widget/inline-stream-diff/live-preview.component.tsx +6 -45
  120. package/src/browser/widget/inline-stream-diff/live-preview.decoration.tsx +112 -40
  121. package/src/common/utils.ts +2 -2
  122. package/lib/browser/widget/inline-input/model.d.ts +0 -34
  123. package/lib/browser/widget/inline-input/model.d.ts.map +0 -1
  124. package/lib/browser/widget/inline-input/model.js +0 -63
  125. package/lib/browser/widget/inline-input/model.js.map +0 -1
  126. package/src/browser/widget/inline-input/model.ts +0 -74
@@ -1,43 +1,34 @@
1
1
  import { Injectable } from '@opensumi/di';
2
+ import { IAIInlineChatService } from '@opensumi/ide-core-browser';
2
3
  import {
3
4
  CancelResponse,
4
5
  Disposable,
5
6
  Event,
6
- FRAME_FIVE,
7
7
  FRAME_THREE,
8
- IAIReporter,
9
8
  IDisposable,
10
- IEventBus,
9
+ InlineChatFeatureRegistryToken,
11
10
  ReplyResponse,
12
11
  RunOnceScheduler,
13
- localize,
14
12
  } from '@opensumi/ide-core-common';
15
- import { EditorGroupCloseEvent } from '@opensumi/ide-editor/lib/browser';
16
- import * as monaco from '@opensumi/ide-monaco';
17
13
  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
+ import * as monaco from '@opensumi/ide-monaco';
25
15
  import { EditOperation } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/editOperation';
26
16
  import { LineRange } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/lineRange';
27
17
  import { ModelDecorationOptions } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model/textModel';
28
18
 
29
19
  import { AINativeContextKey } from '../../ai-core.contextkeys';
30
20
  import { BaseAIMonacoEditorController } from '../../contrib/base';
21
+ import { LanguageParserService } from '../../languages/service';
31
22
  import { ERunStrategy } from '../../types';
32
23
  import { InlineChatController } from '../inline-chat/inline-chat-controller';
33
- import { EInlineChatStatus, EResultKind } from '../inline-chat/inline-chat.service';
34
- import { InlineDiffController } from '../inline-diff';
24
+ import { InlineChatFeatureRegistry } from '../inline-chat/inline-chat.feature.registry';
25
+ import { AIInlineChatService, EInlineChatStatus, EResultKind } from '../inline-chat/inline-chat.service';
35
26
  import { InlineInputPreviewDecorationID } from '../internal.type';
36
27
 
37
- import { InlineInputWidget } from './inline-input-widget';
28
+ import { InlineInputChatWidget } from './inline-input-widget';
38
29
  import styles from './inline-input.module.less';
39
- import { InlineInputService } from './inline-input.service';
40
- import { InlineInputWidgetStoreInEmptyLine, InlineInputWidgetStoreInSelection } from './model';
30
+ import { InlineInputChatService } from './inline-input.service';
31
+
41
32
  @Injectable()
42
33
  export class InlineInputController extends BaseAIMonacoEditorController {
43
34
  public static readonly ID = 'editor.contrib.ai.inline.input';
@@ -46,483 +37,286 @@ export class InlineInputController extends BaseAIMonacoEditorController {
46
37
  return editor.getContribution<InlineInputController>(InlineInputController.ID);
47
38
  }
48
39
 
49
- private get inlineInputService(): InlineInputService {
50
- return this.injector.get(InlineInputService);
40
+ private get inlineInputChatService(): InlineInputChatService {
41
+ return this.injector.get(InlineInputChatService);
51
42
  }
52
43
 
53
- private get aiReporter(): IAIReporter {
54
- return this.injector.get(IAIReporter);
44
+ private get inlineChatFeatureRegistry(): InlineChatFeatureRegistry {
45
+ return this.injector.get(InlineChatFeatureRegistryToken);
55
46
  }
56
47
 
57
- private get eventBus(): IEventBus {
58
- return this.injector.get(IEventBus);
48
+ private get languageParserService(): LanguageParserService {
49
+ return this.injector.get(LanguageParserService);
59
50
  }
60
51
 
61
- private get messageService(): MessageService {
62
- return this.injector.get(MessageService);
52
+ private get inlineChatService(): AIInlineChatService {
53
+ return this.injector.get(IAIInlineChatService);
63
54
  }
64
55
 
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
-
76
56
  mount(): IDisposable {
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);
57
+ return this.registerInlineInputFeature(this.monacoEditor);
147
58
  }
148
59
 
149
- private hideInput() {
150
- this.inlineInputWidgetStore.delete(this.monacoEditor.getModel()!.id);
151
- this.inputDisposable.dispose();
152
- }
153
-
154
- private async showInputInEmptyLine(position: monaco.IPosition, monacoEditor: ICodeEditor, defaultValue?: string) {
60
+ private async doRequestReadable(
61
+ value: string,
62
+ widget: InlineInputChatWidget,
63
+ monacoEditor: ICodeEditor,
64
+ inputDisposable: Disposable,
65
+ decoration: monaco.editor.IEditorDecorationsCollection,
66
+ hideInput: () => void,
67
+ ): Promise<void> {
68
+ const handler = this.inlineChatFeatureRegistry.getInteractiveInputHandler();
155
69
  const model = monacoEditor.getModel();
156
70
 
157
- if (!model) {
71
+ if (!handler || !model) {
158
72
  return;
159
73
  }
160
74
 
161
- const selection = monacoEditor.getSelection();
162
- if (selection && !selection.isEmpty()) {
163
- return;
164
- }
75
+ widget.launchChatStatus(EInlineChatStatus.THINKING);
165
76
 
166
- this.inputValue.set(defaultValue || '', undefined);
167
- this.inlineInputWidgetStore.set(model.id, new InlineInputWidgetStoreInEmptyLine(position, defaultValue));
77
+ const strategy = await this.inlineChatFeatureRegistry.getInteractiveInputStrategyHandler()(monacoEditor, value);
168
78
 
169
- if (this.inputDisposable) {
170
- this.inputDisposable.dispose();
171
- this.inputDisposable = new Disposable();
79
+ if (strategy === ERunStrategy.EXECUTE && handler.execute) {
80
+ handler.execute(monacoEditor, value, this.token);
81
+ widget.launchChatStatus(EInlineChatStatus.DONE);
82
+ hideInput();
83
+ return;
172
84
  }
173
85
 
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);
86
+ if (strategy === ERunStrategy.PREVIEW && handler.providePreviewStrategy) {
87
+ const previewResponse = await handler.providePreviewStrategy(monacoEditor, value, this.token);
88
+
89
+ if (CancelResponse.is(previewResponse)) {
90
+ widget.launchChatStatus(EInlineChatStatus.READY);
91
+ hideInput();
92
+ return;
93
+ }
94
+
95
+ if (InlineChatController.is(previewResponse)) {
96
+ const controller = previewResponse as InlineChatController;
97
+
98
+ let latestContent: string | undefined;
99
+ const schedulerEdit: RunOnceScheduler = this.registerDispose(
100
+ new RunOnceScheduler(() => {
101
+ const range = decoration.getRange(0);
102
+ if (range && latestContent) {
103
+ model.pushEditOperations(null, [EditOperation.replace(range, latestContent)], () => null);
104
+ }
105
+ }, 16 * 12.5),
106
+ );
107
+
108
+ inputDisposable.addDispose([
109
+ controller.onData(async (data) => {
110
+ if (!ReplyResponse.is(data)) {
111
+ return;
112
+ }
113
+
114
+ latestContent = data.message;
115
+
116
+ if (!schedulerEdit.isScheduled()) {
117
+ schedulerEdit.schedule();
118
+ }
119
+ }),
120
+ controller.onError((error) => {
121
+ widget.launchChatStatus(EInlineChatStatus.ERROR);
122
+ }),
123
+ controller.onAbort(() => {
124
+ widget.launchChatStatus(EInlineChatStatus.READY);
125
+ }),
126
+ controller.onEnd(() => {
127
+ model.pushStackElement();
128
+ widget.launchChatStatus(EInlineChatStatus.DONE);
129
+ }),
130
+ ]);
131
+
132
+ controller.listen();
133
+ }
196
134
  }
135
+ }
197
136
 
198
- this.inputDisposable.addDispose(
199
- inlineInputWidget.onDispose(() => {
200
- this.cancelToken();
201
- collection.clear();
202
- this.aiNativeContextKey.inlineInputWidgetIsVisible.set(false);
203
- }),
204
- );
205
-
206
- this.inputDisposable.addDispose(
207
- inlineInputWidget.onValueChange((value) => {
208
- this.inputValue.set(value, undefined);
209
-
210
- const storeData = this.inlineInputWidgetStore.get(model.id);
211
- if (storeData instanceof InlineInputWidgetStoreInEmptyLine) {
212
- storeData.setValue(value);
213
- }
214
- }),
215
- );
216
-
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;
246
-
247
- default:
248
- break;
249
- }
250
- }),
251
- );
252
-
253
- this.inputDisposable.addDispose(
254
- Event.debounce(
255
- collection.onDidChange.bind(collection),
256
- () => {},
257
- FRAME_THREE,
258
- )(() => {
259
- if (!collection.getRange(0)) {
260
- return;
261
- }
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
- });
137
+ private registerInlineInputFeature(monacoEditor: ICodeEditor): IDisposable {
138
+ const inputDisposable = new Disposable();
139
+ const aiNativeContextKey = this.injector.get(AINativeContextKey, [monacoEditor.contextKeyService]);
269
140
 
270
- inlineInputWidget.layoutContentWidget();
271
- }
272
- preLineRange = curLineRange;
273
- }),
274
- );
141
+ const hideInput = () => {
142
+ inputDisposable.dispose();
143
+ };
275
144
 
276
- this.inputDisposable.addDispose(
277
- inlineInputWidget.onClose(() => {
278
- const isStreaming = this.aiNativeContextKey.inlineInputWidgetIsStreaming.get();
279
- if (isStreaming) {
280
- this.cancelToken();
145
+ this.featureDisposable.addDispose(
146
+ this.inlineInputChatService.onInteractiveInputVisibleInPosition((position) => {
147
+ hideInput();
148
+ if (position) {
149
+ showInput(position, monacoEditor);
281
150
  } 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();
316
- return;
317
- }
318
-
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();
362
- }
151
+ setTimeout(() => {
152
+ monacoEditor.focus();
153
+ }, 0);
363
154
  }
364
155
  }),
365
156
  );
366
157
 
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,
158
+ const showInput = async (position: monaco.Position, monacoEditor: ICodeEditor) => {
159
+ this.featureDisposable.addDispose(
160
+ monacoEditor.onWillChangeModel(() => {
161
+ hideInput();
395
162
  }),
396
- },
397
- ]);
398
- const decorationSelection = monaco.Selection.fromRange(
399
- decorationsCollection.getRange(0)!,
400
- selection.getDirection(),
401
- );
402
-
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 });
163
+ );
408
164
 
409
- this.aiNativeContextKey.inlineInputWidgetIsVisible.set(true);
165
+ const model = monacoEditor.getModel();
166
+ if (!model) {
167
+ return;
168
+ }
410
169
 
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();
170
+ /**
171
+ * 只有当前编辑器的光标聚焦,才会展示
172
+ * 用于解决多栏的情况下,同时打开多个 input 的问题
173
+ */
174
+ const hasFocus = monacoEditor.hasTextFocus();
175
+ if (!hasFocus) {
176
+ return;
177
+ }
178
+
179
+ const selection = monacoEditor.getSelection();
180
+ if (selection && selection.startLineNumber !== selection.endLineNumber) {
181
+ return;
182
+ }
183
+
184
+ const inlineInputChatWidget = this.injector.get(InlineInputChatWidget, [monacoEditor]);
185
+
186
+ const collection = monacoEditor.createDecorationsCollection();
187
+ const isEmptyLine = !monacoEditor.getModel()?.getLineContent(position.lineNumber).trim();
188
+
189
+ if (!isEmptyLine) {
190
+ // 根据光标位置自动检测并选中临近的代码块
191
+ const cursorPosition = monacoEditor.getPosition();
192
+ const editorModel = monacoEditor.getModel();
193
+ const cursor = editorModel?.getOffsetAt(cursorPosition!);
194
+ const language = editorModel?.getLanguageId();
195
+ const parser = this.languageParserService.createParser(language!);
196
+ const codeBlock = await parser?.findNearestCodeBlockWithPosition(editorModel?.getValue() || '', cursor!);
197
+
198
+ if (codeBlock) {
199
+ const selection = new monaco.Selection(
200
+ codeBlock.range.start.line + 1,
201
+ codeBlock.range.start.character,
202
+ codeBlock.range.end.line + 1,
203
+ codeBlock.range.end.character,
204
+ );
205
+ monacoEditor.setSelection(selection);
435
206
  } 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;
207
+ // 选中当前行
208
+ monacoEditor.setSelection(new monaco.Selection(position.lineNumber, 1, position.lineNumber, Infinity));
449
209
  }
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(
457
- monacoEditor,
458
- decorationSelection,
459
- value,
460
- this.token,
461
- );
462
-
463
- if (CancelResponse.is(previewResponse)) {
464
- decorationsCollection.clear();
465
- this.aiNativeContextKey.inlineInputWidgetIsStreaming.set(false);
466
- inlineInputWidget.launchChatStatus(EInlineChatStatus.DONE);
210
+ this.inlineChatService.launchInputVisible(true);
211
+ return;
212
+ }
213
+
214
+ // 仅在空行情况下增加装饰逻辑
215
+ collection.append([
216
+ {
217
+ range: monaco.Range.fromPositions(position),
218
+ options: ModelDecorationOptions.register({
219
+ description: InlineInputPreviewDecorationID,
220
+ isWholeLine: true,
221
+ className: styles.input_decoration_readable_container,
222
+ inlineClassName: styles.inline_chat_inserted_range,
223
+ }),
224
+ },
225
+ ]);
226
+
227
+ const decorationRange = collection.getRange(0);
228
+ let preLineRange: LineRange;
229
+ if (decorationRange) {
230
+ preLineRange = LineRange.fromRange(decorationRange);
231
+ inlineInputChatWidget.show({ position: decorationRange.getStartPosition() });
232
+ }
233
+ aiNativeContextKey.inlineInputWidgetIsVisible.set(true);
234
+
235
+ inputDisposable.addDispose(
236
+ inlineInputChatWidget.onDispose(() => {
237
+ this.cancelToken();
238
+ collection.clear();
239
+ aiNativeContextKey.inlineInputWidgetIsVisible.set(false);
240
+ }),
241
+ );
242
+
243
+ inputDisposable.addDispose(
244
+ inlineInputChatWidget.onResultClick(async (kind: EResultKind) => {
245
+ const clear = () => {
246
+ const curPosi = collection.getRange(0)!;
247
+
248
+ model.pushStackElement();
249
+ model.pushEditOperations(null, [EditOperation.delete(curPosi)], () => null);
250
+ model.pushStackElement();
251
+ };
252
+
253
+ switch (kind) {
254
+ case EResultKind.ACCEPT:
255
+ hideInput();
256
+ break;
257
+ case EResultKind.DISCARD:
258
+ clear();
259
+ hideInput();
260
+ break;
261
+ case EResultKind.REGENERATE:
262
+ clear();
263
+ await this.doRequestReadable(
264
+ inlineInputChatWidget.interactiveInputValue,
265
+ inlineInputChatWidget,
266
+ monacoEditor,
267
+ inputDisposable,
268
+ collection,
269
+ hideInput,
270
+ );
271
+ break;
272
+
273
+ default:
274
+ break;
275
+ }
276
+ }),
277
+ );
278
+
279
+ inputDisposable.addDispose(
280
+ Event.debounce(
281
+ collection.onDidChange.bind(collection),
282
+ () => {},
283
+ FRAME_THREE,
284
+ )(() => {
285
+ if (!collection.getRange(0)) {
467
286
  return;
468
287
  }
469
288
 
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,
289
+ const range = collection.getRange(0)!;
290
+ const curLineRange = LineRange.fromRange(range);
291
+ if (!preLineRange.equals(curLineRange)) {
292
+ inlineInputChatWidget.setOptions({
293
+ position: range.getStartPosition(),
499
294
  });
500
295
 
501
- diffPreviewer.mountWidget(inlineInputWidget);
502
-
503
- chatResponse.listen();
296
+ inlineInputChatWidget.layoutContentWidget();
504
297
  }
505
- } else {
506
- decorationsCollection.clear();
507
- inlineInputWidget.launchChatStatus(EInlineChatStatus.READY);
508
- this.hideInput();
509
- }
510
- }),
511
- );
298
+ preLineRange = curLineRange;
299
+ }),
300
+ );
512
301
 
513
- this.inputDisposable.addDispose(
514
- inlineInputWidget.onResultClick((kind: EResultKind) => {
515
- this.inlineDiffController.handleAction(kind);
516
- this.hideInput();
302
+ inputDisposable.addDispose(
303
+ inlineInputChatWidget.onInteractiveInputValue(async (value) => {
304
+ await this.doRequestReadable(
305
+ value,
306
+ inlineInputChatWidget,
307
+ monacoEditor,
308
+ inputDisposable,
309
+ collection,
310
+ hideInput,
311
+ );
312
+ }),
313
+ );
517
314
 
518
- if (kind === EResultKind.REGENERATE) {
519
- requestAnimationFrame(() => {
520
- this.showInputInSelection(decorationSelection, monacoEditor, this.inputValue.get());
521
- });
522
- }
523
- }),
524
- );
315
+ inputDisposable.addDispose(inlineInputChatWidget);
316
+ };
525
317
 
526
- this.inputDisposable.addDispose(inlineInputWidget);
318
+ this.featureDisposable.addDispose(inputDisposable);
319
+
320
+ return this.featureDisposable;
527
321
  }
528
322
  }