@opensumi/ide-ai-native 3.7.1-next-1739439717.0 → 3.7.1-next-1739521933.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/lib/browser/ai-core.contextkeys.d.ts +1 -0
  2. package/lib/browser/ai-core.contextkeys.d.ts.map +1 -1
  3. package/lib/browser/ai-core.contextkeys.js +1 -0
  4. package/lib/browser/ai-core.contextkeys.js.map +1 -1
  5. package/lib/browser/ai-core.contribution.d.ts +2 -1
  6. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  7. package/lib/browser/ai-core.contribution.js +55 -14
  8. package/lib/browser/ai-core.contribution.js.map +1 -1
  9. package/lib/browser/components/utils.d.ts +2 -2
  10. package/lib/browser/contrib/intelligent-completions/index.d.ts +8 -12
  11. package/lib/browser/contrib/intelligent-completions/index.d.ts.map +1 -1
  12. package/lib/browser/contrib/intelligent-completions/index.js.map +1 -1
  13. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.d.ts +1 -0
  14. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.d.ts.map +1 -1
  15. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js +26 -4
  16. package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js.map +1 -1
  17. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts +3 -1
  18. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts.map +1 -1
  19. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js +9 -1
  20. package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js.map +1 -1
  21. package/lib/browser/contrib/intelligent-completions/source/base.d.ts +9 -3
  22. package/lib/browser/contrib/intelligent-completions/source/base.d.ts.map +1 -1
  23. package/lib/browser/contrib/intelligent-completions/source/base.js +21 -3
  24. package/lib/browser/contrib/intelligent-completions/source/base.js.map +1 -1
  25. package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts +0 -3
  26. package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts.map +1 -1
  27. package/lib/browser/contrib/intelligent-completions/source/line-change.source.js +20 -22
  28. package/lib/browser/contrib/intelligent-completions/source/line-change.source.js.map +1 -1
  29. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.d.ts +1 -3
  30. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.d.ts.map +1 -1
  31. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.js +13 -20
  32. package/lib/browser/contrib/intelligent-completions/source/lint-error.source.js.map +1 -1
  33. package/lib/browser/contrib/intelligent-completions/source/typing.source.d.ts +2 -2
  34. package/lib/browser/contrib/intelligent-completions/source/typing.source.d.ts.map +1 -1
  35. package/lib/browser/contrib/intelligent-completions/source/typing.source.js +6 -8
  36. package/lib/browser/contrib/intelligent-completions/source/typing.source.js.map +1 -1
  37. package/lib/browser/contrib/terminal/component/terminal-command-suggest-controller.js +2 -2
  38. package/lib/browser/contrib/terminal/component/terminal-command-suggest-controller.js.map +1 -1
  39. package/lib/browser/index.js +1 -1
  40. package/lib/browser/index.js.map +1 -1
  41. package/lib/browser/layout/ai-layout.d.ts.map +1 -1
  42. package/lib/browser/layout/ai-layout.js +2 -2
  43. package/lib/browser/layout/ai-layout.js.map +1 -1
  44. package/lib/browser/model/enhanceDecorationsCollection.d.ts +14 -10
  45. package/lib/browser/model/enhanceDecorationsCollection.d.ts.map +1 -1
  46. package/lib/browser/model/enhanceDecorationsCollection.js +42 -53
  47. package/lib/browser/model/enhanceDecorationsCollection.js.map +1 -1
  48. package/lib/browser/types.d.ts +2 -1
  49. package/lib/browser/types.d.ts.map +1 -1
  50. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.d.ts +2 -1
  51. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.d.ts.map +1 -1
  52. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js +13 -41
  53. package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js.map +1 -1
  54. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.d.ts +3 -13
  55. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.d.ts.map +1 -1
  56. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.js +24 -72
  57. package/lib/browser/widget/inline-chat/inline-chat.feature.registry.js.map +1 -1
  58. package/lib/browser/widget/inline-chat/inline-chat.service.d.ts +1 -6
  59. package/lib/browser/widget/inline-chat/inline-chat.service.d.ts.map +1 -1
  60. package/lib/browser/widget/inline-chat/inline-chat.service.js +5 -19
  61. package/lib/browser/widget/inline-chat/inline-chat.service.js.map +1 -1
  62. package/lib/browser/widget/inline-chat/inline-content-widget.d.ts +2 -5
  63. package/lib/browser/widget/inline-chat/inline-content-widget.d.ts.map +1 -1
  64. package/lib/browser/widget/inline-chat/inline-content-widget.js +17 -42
  65. package/lib/browser/widget/inline-chat/inline-content-widget.js.map +1 -1
  66. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts +22 -5
  67. package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts.map +1 -1
  68. package/lib/browser/widget/inline-diff/inline-diff-previewer.js +61 -30
  69. package/lib/browser/widget/inline-diff/inline-diff-previewer.js.map +1 -1
  70. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts +8 -12
  71. package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts.map +1 -1
  72. package/lib/browser/widget/inline-diff/inline-diff.controller.js +68 -96
  73. package/lib/browser/widget/inline-diff/inline-diff.controller.js.map +1 -1
  74. package/lib/browser/widget/inline-hint/inline-hint.controller.d.ts +0 -1
  75. package/lib/browser/widget/inline-hint/inline-hint.controller.d.ts.map +1 -1
  76. package/lib/browser/widget/inline-hint/inline-hint.controller.js +0 -5
  77. package/lib/browser/widget/inline-hint/inline-hint.controller.js.map +1 -1
  78. package/lib/browser/widget/inline-input/inline-input-widget.d.ts +12 -2
  79. package/lib/browser/widget/inline-input/inline-input-widget.d.ts.map +1 -1
  80. package/lib/browser/widget/inline-input/inline-input-widget.js +26 -18
  81. package/lib/browser/widget/inline-input/inline-input-widget.js.map +1 -1
  82. package/lib/browser/widget/inline-input/inline-input.controller.d.ts +14 -6
  83. package/lib/browser/widget/inline-input/inline-input.controller.d.ts.map +1 -1
  84. package/lib/browser/widget/inline-input/inline-input.controller.js +320 -169
  85. package/lib/browser/widget/inline-input/inline-input.controller.js.map +1 -1
  86. package/lib/browser/widget/inline-input/inline-input.module.less +4 -0
  87. package/lib/browser/widget/inline-input/inline-input.service.d.ts +19 -7
  88. package/lib/browser/widget/inline-input/inline-input.service.d.ts.map +1 -1
  89. package/lib/browser/widget/inline-input/inline-input.service.js +72 -12
  90. package/lib/browser/widget/inline-input/inline-input.service.js.map +1 -1
  91. package/lib/browser/widget/inline-input/model.d.ts +34 -0
  92. package/lib/browser/widget/inline-input/model.d.ts.map +1 -0
  93. package/lib/browser/widget/inline-input/model.js +63 -0
  94. package/lib/browser/widget/inline-input/model.js.map +1 -0
  95. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +8 -19
  96. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
  97. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +48 -41
  98. package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
  99. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts +17 -4
  100. package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts.map +1 -1
  101. package/lib/browser/widget/inline-stream-diff/live-preview.component.js +37 -5
  102. package/lib/browser/widget/inline-stream-diff/live-preview.component.js.map +1 -1
  103. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts +7 -11
  104. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts.map +1 -1
  105. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js +33 -77
  106. package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js.map +1 -1
  107. package/package.json +21 -21
  108. package/src/browser/ai-core.contextkeys.ts +3 -0
  109. package/src/browser/ai-core.contribution.ts +63 -16
  110. package/src/browser/contrib/intelligent-completions/index.ts +9 -4
  111. package/src/browser/contrib/intelligent-completions/intelligent-completions.contribution.ts +29 -8
  112. package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +13 -1
  113. package/src/browser/contrib/intelligent-completions/source/base.ts +28 -7
  114. package/src/browser/contrib/intelligent-completions/source/line-change.source.ts +31 -26
  115. package/src/browser/contrib/intelligent-completions/source/lint-error.source.ts +19 -31
  116. package/src/browser/contrib/intelligent-completions/source/typing.source.ts +7 -9
  117. package/src/browser/contrib/terminal/component/terminal-command-suggest-controller.tsx +1 -1
  118. package/src/browser/index.ts +2 -2
  119. package/src/browser/layout/ai-layout.tsx +5 -2
  120. package/src/browser/model/enhanceDecorationsCollection.ts +62 -77
  121. package/src/browser/types.ts +2 -2
  122. package/src/browser/widget/inline-chat/inline-chat-editor.controller.ts +21 -56
  123. package/src/browser/widget/inline-chat/inline-chat.feature.registry.ts +23 -90
  124. package/src/browser/widget/inline-chat/inline-chat.service.ts +2 -19
  125. package/src/browser/widget/inline-chat/inline-content-widget.tsx +14 -71
  126. package/src/browser/widget/inline-diff/inline-diff-previewer.ts +87 -32
  127. package/src/browser/widget/inline-diff/inline-diff.controller.ts +90 -114
  128. package/src/browser/widget/inline-hint/inline-hint.controller.ts +1 -7
  129. package/src/browser/widget/inline-input/inline-input-widget.tsx +34 -12
  130. package/src/browser/widget/inline-input/inline-input.controller.ts +453 -247
  131. package/src/browser/widget/inline-input/inline-input.module.less +4 -0
  132. package/src/browser/widget/inline-input/inline-input.service.ts +92 -13
  133. package/src/browser/widget/inline-input/model.ts +74 -0
  134. package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +58 -69
  135. package/src/browser/widget/inline-stream-diff/live-preview.component.tsx +45 -6
  136. package/src/browser/widget/inline-stream-diff/live-preview.decoration.tsx +40 -112
  137. package/lib/browser/model/styles.module.less +0 -7
  138. package/src/browser/model/styles.module.less +0 -7
@@ -1,34 +1,43 @@
1
1
  import { Injectable } from '@opensumi/di';
2
- import { IAIInlineChatService } from '@opensumi/ide-core-browser';
3
2
  import {
4
3
  CancelResponse,
5
4
  Disposable,
6
5
  Event,
6
+ FRAME_FIVE,
7
7
  FRAME_THREE,
8
+ IAIReporter,
8
9
  IDisposable,
9
- InlineChatFeatureRegistryToken,
10
+ IEventBus,
10
11
  ReplyResponse,
11
12
  RunOnceScheduler,
13
+ localize,
12
14
  } from '@opensumi/ide-core-common';
13
- import { ICodeEditor } from '@opensumi/ide-monaco';
15
+ import { EditorGroupCloseEvent } from '@opensumi/ide-editor/lib/browser';
14
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';
15
25
  import { EditOperation } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/editOperation';
16
26
  import { LineRange } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/lineRange';
17
27
  import { ModelDecorationOptions } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model/textModel';
18
28
 
19
29
  import { AINativeContextKey } from '../../ai-core.contextkeys';
20
30
  import { BaseAIMonacoEditorController } from '../../contrib/base';
21
- import { LanguageParserService } from '../../languages/service';
22
31
  import { ERunStrategy } from '../../types';
23
32
  import { InlineChatController } from '../inline-chat/inline-chat-controller';
24
- import { InlineChatFeatureRegistry } from '../inline-chat/inline-chat.feature.registry';
25
- import { AIInlineChatService, EInlineChatStatus, EResultKind } from '../inline-chat/inline-chat.service';
33
+ import { EInlineChatStatus, EResultKind } from '../inline-chat/inline-chat.service';
34
+ import { InlineDiffController } from '../inline-diff';
26
35
  import { InlineInputPreviewDecorationID } from '../internal.type';
27
36
 
28
- import { InlineInputChatWidget } from './inline-input-widget';
37
+ import { InlineInputWidget } from './inline-input-widget';
29
38
  import styles from './inline-input.module.less';
30
- import { InlineInputChatService } from './inline-input.service';
31
-
39
+ import { InlineInputService } from './inline-input.service';
40
+ import { InlineInputWidgetStoreInEmptyLine, InlineInputWidgetStoreInSelection } from './model';
32
41
  @Injectable()
33
42
  export class InlineInputController extends BaseAIMonacoEditorController {
34
43
  public static readonly ID = 'editor.contrib.ai.inline.input';
@@ -37,286 +46,483 @@ export class InlineInputController extends BaseAIMonacoEditorController {
37
46
  return editor.getContribution<InlineInputController>(InlineInputController.ID);
38
47
  }
39
48
 
40
- private get inlineInputChatService(): InlineInputChatService {
41
- return this.injector.get(InlineInputChatService);
49
+ private get inlineInputService(): InlineInputService {
50
+ return this.injector.get(InlineInputService);
42
51
  }
43
52
 
44
- private get inlineChatFeatureRegistry(): InlineChatFeatureRegistry {
45
- return this.injector.get(InlineChatFeatureRegistryToken);
53
+ private get aiReporter(): IAIReporter {
54
+ return this.injector.get(IAIReporter);
46
55
  }
47
56
 
48
- private get languageParserService(): LanguageParserService {
49
- return this.injector.get(LanguageParserService);
57
+ private get eventBus(): IEventBus {
58
+ return this.injector.get(IEventBus);
50
59
  }
51
60
 
52
- private get inlineChatService(): AIInlineChatService {
53
- return this.injector.get(IAIInlineChatService);
61
+ private get messageService(): MessageService {
62
+ return this.injector.get(MessageService);
54
63
  }
55
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
+
56
76
  mount(): IDisposable {
57
- 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);
58
147
  }
59
148
 
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();
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) {
69
155
  const model = monacoEditor.getModel();
70
156
 
71
- if (!handler || !model) {
157
+ if (!model) {
72
158
  return;
73
159
  }
74
160
 
75
- widget.launchChatStatus(EInlineChatStatus.THINKING);
161
+ const selection = monacoEditor.getSelection();
162
+ if (selection && !selection.isEmpty()) {
163
+ return;
164
+ }
76
165
 
77
- const strategy = await this.inlineChatFeatureRegistry.getInteractiveInputStrategyHandler()(monacoEditor, value);
166
+ this.inputValue.set(defaultValue || '', undefined);
167
+ this.inlineInputWidgetStore.set(model.id, new InlineInputWidgetStoreInEmptyLine(position, defaultValue));
78
168
 
79
- if (strategy === ERunStrategy.EXECUTE && handler.execute) {
80
- handler.execute(monacoEditor, value, this.token);
81
- widget.launchChatStatus(EInlineChatStatus.DONE);
82
- hideInput();
83
- return;
169
+ if (this.inputDisposable) {
170
+ this.inputDisposable.dispose();
171
+ this.inputDisposable = new Disposable();
84
172
  }
85
173
 
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
- }
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);
134
196
  }
135
- }
136
197
 
137
- private registerInlineInputFeature(monacoEditor: ICodeEditor): IDisposable {
138
- const inputDisposable = new Disposable();
139
- 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
+ );
140
205
 
141
- const hideInput = () => {
142
- inputDisposable.dispose();
143
- };
206
+ this.inputDisposable.addDispose(
207
+ inlineInputWidget.onValueChange((value) => {
208
+ this.inputValue.set(value, undefined);
144
209
 
145
- this.featureDisposable.addDispose(
146
- this.inlineInputChatService.onInteractiveInputVisibleInPosition((position) => {
147
- hideInput();
148
- if (position) {
149
- showInput(position, monacoEditor);
150
- } else {
151
- setTimeout(() => {
152
- monacoEditor.focus();
153
- }, 0);
210
+ const storeData = this.inlineInputWidgetStore.get(model.id);
211
+ if (storeData instanceof InlineInputWidgetStoreInEmptyLine) {
212
+ storeData.setValue(value);
154
213
  }
155
214
  }),
156
215
  );
157
216
 
158
- const showInput = async (position: monaco.Position, monacoEditor: ICodeEditor) => {
159
- this.featureDisposable.addDispose(
160
- monacoEditor.onWillChangeModel(() => {
161
- hideInput();
162
- }),
163
- );
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;
164
246
 
165
- const model = monacoEditor.getModel();
166
- if (!model) {
167
- return;
168
- }
247
+ default:
248
+ break;
249
+ }
250
+ }),
251
+ );
169
252
 
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);
206
- } else {
207
- // 选中当前行
208
- 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;
209
261
  }
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(() => {
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) {
237
280
  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)) {
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();
286
316
  return;
287
317
  }
288
318
 
289
- const range = collection.getRange(0)!;
290
- const curLineRange = LineRange.fromRange(range);
291
- if (!preLineRange.equals(curLineRange)) {
292
- inlineInputChatWidget.setOptions({
293
- position: range.getStartPosition(),
294
- });
295
-
296
- 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();
297
362
  }
298
- 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,
299
395
  }),
300
- );
396
+ },
397
+ ]);
398
+ const decorationSelection = monaco.Selection.fromRange(
399
+ decorationsCollection.getRange(0)!,
400
+ selection.getDirection(),
401
+ );
301
402
 
302
- inputDisposable.addDispose(
303
- inlineInputChatWidget.onInteractiveInputValue(async (value) => {
304
- await this.doRequestReadable(
305
- value,
306
- 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(
307
457
  monacoEditor,
308
- inputDisposable,
309
- collection,
310
- hideInput,
458
+ decorationSelection,
459
+ value,
460
+ this.token,
311
461
  );
312
- }),
313
- );
314
462
 
315
- inputDisposable.addDispose(inlineInputChatWidget);
316
- };
463
+ if (CancelResponse.is(previewResponse)) {
464
+ decorationsCollection.clear();
465
+ this.aiNativeContextKey.inlineInputWidgetIsStreaming.set(false);
466
+ inlineInputWidget.launchChatStatus(EInlineChatStatus.DONE);
467
+ return;
468
+ }
317
469
 
318
- 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
+ });
319
500
 
320
- 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);
321
527
  }
322
528
  }