@opensumi/ide-ai-native 3.2.5 → 3.2.6-next-1724809247.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.
- package/lib/browser/ai-core.contribution.d.ts +1 -0
- package/lib/browser/ai-core.contribution.d.ts.map +1 -1
- package/lib/browser/ai-core.contribution.js +12 -23
- package/lib/browser/ai-core.contribution.js.map +1 -1
- package/lib/browser/ai-editor.contribution.d.ts +1 -0
- package/lib/browser/ai-editor.contribution.d.ts.map +1 -1
- package/lib/browser/ai-editor.contribution.js +8 -0
- package/lib/browser/ai-editor.contribution.js.map +1 -1
- package/lib/browser/chat/chat-agent.service.d.ts +1 -0
- package/lib/browser/chat/chat-agent.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-agent.service.js +1 -3
- package/lib/browser/chat/chat-agent.service.js.map +1 -1
- package/lib/browser/chat/chat.module.less +1 -0
- package/lib/browser/chat/chat.view.d.ts.map +1 -1
- package/lib/browser/chat/chat.view.js +21 -3
- package/lib/browser/chat/chat.view.js.map +1 -1
- package/lib/browser/components/ChatEditor.d.ts.map +1 -1
- package/lib/browser/components/ChatEditor.js +2 -2
- package/lib/browser/components/ChatEditor.js.map +1 -1
- package/lib/browser/components/ChatMarkdown.js +1 -1
- package/lib/browser/components/ChatMarkdown.js.map +1 -1
- package/lib/browser/components/ChatThinking.d.ts.map +1 -1
- package/lib/browser/components/ChatThinking.js +2 -2
- package/lib/browser/components/ChatThinking.js.map +1 -1
- package/lib/browser/contextkey/ai-native.contextkey.service.d.ts +1 -0
- package/lib/browser/contextkey/ai-native.contextkey.service.d.ts.map +1 -1
- package/lib/browser/contextkey/ai-native.contextkey.service.js +1 -0
- package/lib/browser/contextkey/ai-native.contextkey.service.js.map +1 -1
- package/lib/browser/contrib/inline-completions/completeProvider.d.ts +4 -31
- package/lib/browser/contrib/inline-completions/completeProvider.d.ts.map +1 -1
- package/lib/browser/contrib/inline-completions/completeProvider.js +3 -224
- package/lib/browser/contrib/inline-completions/completeProvider.js.map +1 -1
- package/lib/browser/contrib/inline-completions/inline-completions.handler.d.ts +1 -3
- package/lib/browser/contrib/inline-completions/inline-completions.handler.d.ts.map +1 -1
- package/lib/browser/contrib/inline-completions/inline-completions.handler.js +8 -20
- package/lib/browser/contrib/inline-completions/inline-completions.handler.js.map +1 -1
- package/lib/browser/contrib/inline-completions/model/competionModel.d.ts +2 -2
- package/lib/browser/contrib/inline-completions/model/competionModel.d.ts.map +1 -1
- package/lib/browser/contrib/inline-completions/model/inlineCompletionRequestTask.d.ts +28 -0
- package/lib/browser/contrib/inline-completions/model/inlineCompletionRequestTask.d.ts.map +1 -0
- package/lib/browser/contrib/inline-completions/model/inlineCompletionRequestTask.js +209 -0
- package/lib/browser/contrib/inline-completions/model/inlineCompletionRequestTask.js.map +1 -0
- package/lib/browser/contrib/inline-completions/promptCache.d.ts +3 -2
- package/lib/browser/contrib/inline-completions/promptCache.d.ts.map +1 -1
- package/lib/browser/contrib/inline-completions/promptCache.js.map +1 -1
- package/lib/browser/contrib/inline-completions/service/ai-completions.service.d.ts +5 -6
- package/lib/browser/contrib/inline-completions/service/ai-completions.service.d.ts.map +1 -1
- package/lib/browser/contrib/inline-completions/service/ai-completions.service.js +33 -23
- package/lib/browser/contrib/inline-completions/service/ai-completions.service.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/diff-computer.d.ts +18 -0
- package/lib/browser/contrib/intelligent-completions/diff-computer.d.ts.map +1 -0
- package/lib/browser/contrib/intelligent-completions/diff-computer.js +144 -0
- package/lib/browser/contrib/intelligent-completions/diff-computer.js.map +1 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.d.ts +8 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.d.ts.map +1 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js +47 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.contribution.js.map +1 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.d.ts +15 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.d.ts.map +1 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.d.ts +8 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.d.ts.map +1 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.js +19 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.js.map +1 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.handler.d.ts +20 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.handler.d.ts.map +1 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.handler.js +94 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.handler.js.map +1 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.js +3 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.js.map +1 -0
- package/lib/browser/contrib/intelligent-completions/multi-line.decoration.d.ts +33 -0
- package/lib/browser/contrib/intelligent-completions/multi-line.decoration.d.ts.map +1 -0
- package/lib/browser/contrib/intelligent-completions/multi-line.decoration.js +258 -0
- package/lib/browser/contrib/intelligent-completions/multi-line.decoration.js.map +1 -0
- package/lib/browser/contrib/merge-conflict/merge-conflict.feature.registry.d.ts +0 -1
- package/lib/browser/contrib/merge-conflict/merge-conflict.feature.registry.d.ts.map +1 -1
- package/lib/browser/contrib/merge-conflict/merge-conflict.feature.registry.js +0 -3
- package/lib/browser/contrib/merge-conflict/merge-conflict.feature.registry.js.map +1 -1
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +7 -0
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/layout/ai-layout.d.ts.map +1 -1
- package/lib/browser/layout/ai-layout.js +4 -4
- package/lib/browser/layout/ai-layout.js.map +1 -1
- package/lib/browser/layout/layout.module.less +0 -9
- package/lib/browser/model/enhanceDecorationsCollection.d.ts +38 -4
- package/lib/browser/model/enhanceDecorationsCollection.d.ts.map +1 -1
- package/lib/browser/model/enhanceDecorationsCollection.js +44 -23
- package/lib/browser/model/enhanceDecorationsCollection.js.map +1 -1
- package/lib/browser/types.d.ts +20 -13
- package/lib/browser/types.d.ts.map +1 -1
- package/lib/browser/types.js +0 -4
- package/lib/browser/types.js.map +1 -1
- package/lib/browser/widget/inline-chat/inline-chat.handler.d.ts.map +1 -1
- package/lib/browser/widget/inline-chat/inline-chat.handler.js +18 -10
- package/lib/browser/widget/inline-chat/inline-chat.handler.js.map +1 -1
- package/lib/browser/widget/inline-chat/inline-content-widget.d.ts +5 -2
- package/lib/browser/widget/inline-chat/inline-content-widget.d.ts.map +1 -1
- package/lib/browser/widget/inline-chat/inline-content-widget.js +45 -53
- package/lib/browser/widget/inline-chat/inline-content-widget.js.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts +16 -14
- package/lib/browser/widget/inline-diff/inline-diff-previewer.d.ts.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff-previewer.js +98 -46
- package/lib/browser/widget/inline-diff/inline-diff-previewer.js.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff-widget.d.ts +5 -2
- package/lib/browser/widget/inline-diff/inline-diff-widget.d.ts.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff-widget.js +11 -2
- package/lib/browser/widget/inline-diff/inline-diff-widget.js.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff.handler.d.ts +12 -13
- package/lib/browser/widget/inline-diff/inline-diff.handler.d.ts.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff.handler.js +69 -77
- package/lib/browser/widget/inline-diff/inline-diff.handler.js.map +1 -1
- package/lib/browser/widget/inline-input/inline-input-widget.d.ts +1 -0
- package/lib/browser/widget/inline-input/inline-input-widget.d.ts.map +1 -1
- package/lib/browser/widget/inline-input/inline-input-widget.js +1 -0
- package/lib/browser/widget/inline-input/inline-input-widget.js.map +1 -1
- package/lib/browser/widget/inline-input/inline-input.handler.js +2 -2
- package/lib/browser/widget/inline-input/inline-input.handler.js.map +1 -1
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts +28 -15
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.d.ts.map +1 -1
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js +56 -31
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.handler.js.map +1 -1
- package/lib/browser/widget/inline-stream-diff/inline-stream-diff.module.less +9 -6
- package/lib/browser/widget/inline-stream-diff/live-preview-stack.d.ts +21 -0
- package/lib/browser/widget/inline-stream-diff/live-preview-stack.d.ts.map +1 -0
- package/lib/browser/widget/inline-stream-diff/live-preview-stack.js +41 -0
- package/lib/browser/widget/inline-stream-diff/live-preview-stack.js.map +1 -0
- package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts +105 -0
- package/lib/browser/widget/inline-stream-diff/live-preview.component.d.ts.map +1 -0
- package/lib/browser/widget/inline-stream-diff/live-preview.component.js +237 -0
- package/lib/browser/widget/inline-stream-diff/live-preview.component.js.map +1 -0
- package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts +27 -103
- package/lib/browser/widget/inline-stream-diff/live-preview.decoration.d.ts.map +1 -1
- package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js +186 -370
- package/lib/browser/widget/inline-stream-diff/live-preview.decoration.js.map +1 -1
- package/lib/common/index.d.ts +1 -0
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js.map +1 -1
- package/package.json +19 -19
- package/src/browser/ai-core.contribution.ts +12 -26
- package/src/browser/ai-editor.contribution.ts +9 -0
- package/src/browser/chat/chat-agent.service.ts +1 -3
- package/src/browser/chat/chat.module.less +1 -0
- package/src/browser/chat/chat.view.tsx +48 -3
- package/src/browser/components/ChatEditor.tsx +14 -2
- package/src/browser/components/ChatMarkdown.tsx +1 -1
- package/src/browser/components/ChatThinking.tsx +3 -1
- package/src/browser/contextkey/ai-native.contextkey.service.ts +3 -0
- package/src/browser/contrib/inline-completions/completeProvider.ts +7 -289
- package/src/browser/contrib/inline-completions/inline-completions.handler.ts +15 -22
- package/src/browser/contrib/inline-completions/model/competionModel.ts +3 -2
- package/src/browser/contrib/inline-completions/model/inlineCompletionRequestTask.ts +270 -0
- package/src/browser/contrib/inline-completions/promptCache.ts +3 -2
- package/src/browser/contrib/inline-completions/service/ai-completions.service.ts +37 -36
- package/src/browser/contrib/intelligent-completions/diff-computer.ts +185 -0
- package/src/browser/contrib/intelligent-completions/intelligent-completions.contribution.ts +54 -0
- package/src/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.ts +17 -0
- package/src/browser/contrib/intelligent-completions/intelligent-completions.handler.ts +130 -0
- package/src/browser/contrib/intelligent-completions/intelligent-completions.ts +15 -0
- package/src/browser/contrib/intelligent-completions/multi-line.decoration.ts +325 -0
- package/src/browser/contrib/merge-conflict/merge-conflict.feature.registry.ts +0 -4
- package/src/browser/index.ts +8 -1
- package/src/browser/layout/ai-layout.tsx +7 -1
- package/src/browser/layout/layout.module.less +0 -9
- package/src/browser/model/enhanceDecorationsCollection.ts +71 -34
- package/src/browser/types.ts +27 -14
- package/src/browser/widget/inline-chat/inline-chat.handler.ts +20 -16
- package/src/browser/widget/inline-chat/inline-content-widget.tsx +58 -61
- package/src/browser/widget/inline-diff/inline-diff-previewer.ts +102 -62
- package/src/browser/widget/inline-diff/inline-diff-widget.tsx +36 -5
- package/src/browser/widget/inline-diff/inline-diff.handler.ts +82 -94
- package/src/browser/widget/inline-input/inline-input-widget.tsx +1 -0
- package/src/browser/widget/inline-input/inline-input.handler.ts +2 -2
- package/src/browser/widget/inline-stream-diff/inline-stream-diff.handler.tsx +108 -45
- package/src/browser/widget/inline-stream-diff/inline-stream-diff.module.less +9 -6
- package/src/browser/widget/inline-stream-diff/live-preview-stack.ts +52 -0
- package/src/browser/widget/inline-stream-diff/live-preview.component.tsx +388 -0
- package/src/browser/widget/inline-stream-diff/live-preview.decoration.tsx +244 -544
- package/src/common/index.ts +2 -0
|
@@ -3,13 +3,14 @@ import {
|
|
|
3
3
|
AINativeSettingSectionsId,
|
|
4
4
|
DisposableStore,
|
|
5
5
|
IAICompletionOption,
|
|
6
|
-
IAICompletionResultModel,
|
|
7
6
|
IDisposable,
|
|
8
7
|
PreferenceService,
|
|
9
8
|
StaleLRUMap,
|
|
10
9
|
} from '@opensumi/ide-core-browser';
|
|
11
10
|
import { IHashCalculateService } from '@opensumi/ide-core-common/lib/hash-calculate/hash-calculate';
|
|
12
11
|
|
|
12
|
+
import { IIntelligentCompletionsResult } from '../intelligent-completions/intelligent-completions';
|
|
13
|
+
|
|
13
14
|
/**
|
|
14
15
|
* 缓存服务
|
|
15
16
|
* 1. 过期时间为 1min
|
|
@@ -25,7 +26,7 @@ export class PromptCache implements IDisposable {
|
|
|
25
26
|
@Autowired(PreferenceService)
|
|
26
27
|
private preferenceService: PreferenceService;
|
|
27
28
|
|
|
28
|
-
private cacheMap = new StaleLRUMap<string,
|
|
29
|
+
private cacheMap = new StaleLRUMap<string, IIntelligentCompletionsResult & { relationId: string }>(15, 10, 60 * 1000);
|
|
29
30
|
|
|
30
31
|
protected calculateCacheKey(requestBean: IAICompletionOption) {
|
|
31
32
|
const content = requestBean.prompt;
|
|
@@ -10,11 +10,13 @@ import {
|
|
|
10
10
|
IAICompletionOption,
|
|
11
11
|
IAICompletionResultModel,
|
|
12
12
|
IAIReportCompletionOption,
|
|
13
|
+
IntelligentCompletionsRegistryToken,
|
|
13
14
|
} from '@opensumi/ide-core-common';
|
|
14
15
|
import { CompletionRT, IAIReporter } from '@opensumi/ide-core-common/lib/types/ai-native/reporter';
|
|
15
|
-
import * as monaco from '@opensumi/ide-monaco';
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { IIntelligentCompletionsResult } from '../../intelligent-completions/intelligent-completions';
|
|
18
|
+
import { IntelligentCompletionsRegistry } from '../../intelligent-completions/intelligent-completions.feature.registry';
|
|
19
|
+
import { IntelligentCompletionsHandler } from '../../intelligent-completions/intelligent-completions.handler';
|
|
18
20
|
|
|
19
21
|
@Injectable()
|
|
20
22
|
export class AICompletionsService extends Disposable {
|
|
@@ -29,6 +31,12 @@ export class AICompletionsService extends Disposable {
|
|
|
29
31
|
@Autowired(IAIReporter)
|
|
30
32
|
private readonly aiReporter: IAIReporter;
|
|
31
33
|
|
|
34
|
+
@Autowired(IntelligentCompletionsRegistryToken)
|
|
35
|
+
private readonly intelligentCompletionsRegistry: IntelligentCompletionsRegistry;
|
|
36
|
+
|
|
37
|
+
@Autowired(IntelligentCompletionsHandler)
|
|
38
|
+
private readonly intelligentCompletionsHandler: IntelligentCompletionsHandler;
|
|
39
|
+
|
|
32
40
|
private readonly _onVisibleCompletion = new Emitter<boolean>();
|
|
33
41
|
public readonly onVisibleCompletion: Event<boolean> = this._onVisibleCompletion.event;
|
|
34
42
|
|
|
@@ -43,8 +51,6 @@ export class AICompletionsService extends Disposable {
|
|
|
43
51
|
private lastRelationId: string;
|
|
44
52
|
private lastRenderTime: number;
|
|
45
53
|
private lastCompletionUseTime: number;
|
|
46
|
-
// 中间件拓展 inlinecompletion
|
|
47
|
-
private lastMiddlewareInlineCompletion?: IProvideInlineCompletionsSignature;
|
|
48
54
|
|
|
49
55
|
protected validCompletionThreshold = 750;
|
|
50
56
|
|
|
@@ -60,41 +66,36 @@ export class AICompletionsService extends Disposable {
|
|
|
60
66
|
return this._isVisibleCompletion;
|
|
61
67
|
}
|
|
62
68
|
|
|
63
|
-
public async complete(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
position: monaco.Position,
|
|
67
|
-
token: monaco.CancellationToken,
|
|
68
|
-
): Promise<IAICompletionResultModel | null> {
|
|
69
|
-
const doCompletion = async (data: IAICompletionOption) => {
|
|
70
|
-
if (!this.aiBackService.requestCompletion) {
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
this.isDefaultCompletionModel = true;
|
|
76
|
-
const completionStart = Date.now();
|
|
77
|
-
const result = (await this.aiBackService.requestCompletion(
|
|
78
|
-
data,
|
|
79
|
-
this.cancelIndicator.token,
|
|
80
|
-
)) as IAICompletionResultModel;
|
|
81
|
-
this.recordCompletionUseTime(completionStart);
|
|
82
|
-
return result;
|
|
83
|
-
} catch (error) {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
};
|
|
69
|
+
public async complete(data: IAICompletionOption): Promise<IIntelligentCompletionsResult | undefined> {
|
|
70
|
+
this.isDefaultCompletionModel = true;
|
|
71
|
+
const completionStart = Date.now();
|
|
87
72
|
|
|
88
|
-
|
|
89
|
-
this.isDefaultCompletionModel = false;
|
|
90
|
-
return this.lastMiddlewareInlineCompletion(model, position, token, doCompletion, data);
|
|
91
|
-
}
|
|
73
|
+
const provider = this.intelligentCompletionsRegistry.getProvider();
|
|
92
74
|
|
|
93
|
-
|
|
94
|
-
|
|
75
|
+
if (provider) {
|
|
76
|
+
return this.intelligentCompletionsHandler.fetchProvider(data);
|
|
77
|
+
}
|
|
95
78
|
|
|
96
|
-
|
|
97
|
-
|
|
79
|
+
// 兼容旧的 requestCompletion 接口
|
|
80
|
+
try {
|
|
81
|
+
const result = (await this.aiBackService.requestCompletion?.(
|
|
82
|
+
data,
|
|
83
|
+
this.cancelIndicator.token,
|
|
84
|
+
)) as IAICompletionResultModel;
|
|
85
|
+
this.recordCompletionUseTime(completionStart);
|
|
86
|
+
|
|
87
|
+
const { sessionId, codeModelList, isCancel } = result;
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
items: codeModelList.map((model) => ({ ...model, insertText: model.content })),
|
|
91
|
+
extra: {
|
|
92
|
+
sessionId,
|
|
93
|
+
isCancel,
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
} catch (error) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
public async report(data: IAIReportCompletionOption) {
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { empty } from '@opensumi/ide-utils/lib/strings';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export interface IDiffChangeResult {
|
|
7
|
+
added?: boolean;
|
|
8
|
+
removed?: boolean;
|
|
9
|
+
value: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface IResultWithCount extends IDiffChangeResult {
|
|
13
|
+
count: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface IElement {
|
|
17
|
+
newPos: number;
|
|
18
|
+
changeResult: IResultWithCount[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class MultiLineDiffComputer {
|
|
22
|
+
private equals(a: string, b: string | undefined): boolean {
|
|
23
|
+
return a === b;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private extractCommon(element: IElement, modified: string[], original: string[], diagonal: number): number {
|
|
27
|
+
const modifiedLength = modified.length;
|
|
28
|
+
const originalLength = original.length;
|
|
29
|
+
|
|
30
|
+
let newPos = element.newPos;
|
|
31
|
+
let originalPos = newPos - diagonal;
|
|
32
|
+
let commonCount = 0;
|
|
33
|
+
|
|
34
|
+
while (
|
|
35
|
+
newPos + 1 < modifiedLength &&
|
|
36
|
+
originalPos + 1 < originalLength &&
|
|
37
|
+
this.equals(modified[newPos + 1], original[originalPos + 1])
|
|
38
|
+
) {
|
|
39
|
+
// 如果相等,则移动到下一个位置并计数加一
|
|
40
|
+
newPos++;
|
|
41
|
+
originalPos++;
|
|
42
|
+
commonCount++;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 如果找到公共部分,则记录新位置
|
|
46
|
+
if (commonCount) {
|
|
47
|
+
element.changeResult.push({ count: commonCount, value: empty });
|
|
48
|
+
element.newPos = newPos;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return originalPos;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public diff(originalContent: string, modifiedContent: string): IResultWithCount[] | undefined {
|
|
55
|
+
const cloneElement = (element: IElement): IElement => ({
|
|
56
|
+
newPos: element.newPos,
|
|
57
|
+
changeResult: [...element.changeResult],
|
|
58
|
+
});
|
|
59
|
+
const join = (content: string[]) => content.join(empty);
|
|
60
|
+
|
|
61
|
+
const processElements = (changeResult: IResultWithCount[], modified: string[], original: string[]) => {
|
|
62
|
+
const modifiedLength = changeResult.length;
|
|
63
|
+
|
|
64
|
+
let originalIndex = 0;
|
|
65
|
+
let modifiedIndex = 0;
|
|
66
|
+
let originalCount = 0;
|
|
67
|
+
|
|
68
|
+
for (; originalIndex < modifiedLength; originalIndex++) {
|
|
69
|
+
const changeItem = changeResult[originalIndex];
|
|
70
|
+
// 如果标记为删除,则从原始内容中提取对应的值
|
|
71
|
+
if (changeItem.removed) {
|
|
72
|
+
changeItem.value = join(original.slice(originalCount, originalCount + changeItem.count));
|
|
73
|
+
originalCount += changeItem.count;
|
|
74
|
+
// 如果前一个元素被标记为添加,则交换位置
|
|
75
|
+
if (originalIndex && changeResult[originalIndex - 1].added) {
|
|
76
|
+
[changeResult[originalIndex - 1], changeResult[originalIndex]] = [
|
|
77
|
+
changeResult[originalIndex],
|
|
78
|
+
changeResult[originalIndex - 1],
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
changeItem.value = join(modified.slice(modifiedIndex, modifiedIndex + changeItem.count));
|
|
83
|
+
modifiedIndex += changeItem.count;
|
|
84
|
+
|
|
85
|
+
if (!changeItem.added) {
|
|
86
|
+
originalCount += changeItem.count;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 如果最后一个元素是空字符串,则合并到前一个元素当中
|
|
92
|
+
if (
|
|
93
|
+
modifiedLength > 1 &&
|
|
94
|
+
typeof changeResult[modifiedLength - 1].value === 'string' &&
|
|
95
|
+
(changeResult[modifiedLength - 1].added || changeResult[modifiedLength - 1].removed) &&
|
|
96
|
+
this.equals(empty, changeResult[modifiedLength - 1].value)
|
|
97
|
+
) {
|
|
98
|
+
changeResult[modifiedLength - 2].value += changeResult[modifiedLength - 1].value;
|
|
99
|
+
changeResult.pop();
|
|
100
|
+
}
|
|
101
|
+
return changeResult;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const tokenizeOriginal = originalContent.split(empty).filter(Boolean);
|
|
105
|
+
const tokenizeModified = modifiedContent.split(empty).filter(Boolean);
|
|
106
|
+
const originalLength = tokenizeOriginal.length;
|
|
107
|
+
const modifiedLength = tokenizeModified.length;
|
|
108
|
+
const maxLength = originalLength + modifiedLength;
|
|
109
|
+
|
|
110
|
+
const elements: Array<IElement | undefined> = [{ newPos: -1, changeResult: [] }];
|
|
111
|
+
const initialDiagonal = this.extractCommon(elements[0]!, tokenizeModified, tokenizeOriginal, 0);
|
|
112
|
+
|
|
113
|
+
const pushElement = (changeResult: IResultWithCount[], added?: boolean, removed?: boolean) => {
|
|
114
|
+
const len = changeResult.length;
|
|
115
|
+
const latestResult = changeResult[len - 1];
|
|
116
|
+
if (len > 0 && latestResult.added === added && latestResult.removed === removed) {
|
|
117
|
+
changeResult[len - 1] = { count: latestResult.count + 1, added, removed, value: empty };
|
|
118
|
+
} else {
|
|
119
|
+
changeResult.push({ count: 1, added, removed, value: empty });
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
let diagonal = 1;
|
|
124
|
+
|
|
125
|
+
// 如果初始位置加 1 大于或等于原始长度,并且初始的公共部分的位置加 1 大于或等于修改后的长度,则直接返回修改后的内容
|
|
126
|
+
if (elements[0]!.newPos + 1 >= originalLength && initialDiagonal + 1 >= modifiedLength) {
|
|
127
|
+
return [
|
|
128
|
+
{
|
|
129
|
+
value: join(tokenizeModified),
|
|
130
|
+
count: tokenizeModified.length,
|
|
131
|
+
},
|
|
132
|
+
];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const execDiff = () => {
|
|
136
|
+
for (let diagonalIndex = -diagonal; diagonalIndex <= diagonal; diagonalIndex += 2) {
|
|
137
|
+
const leftElement = elements[diagonalIndex - 1];
|
|
138
|
+
const rightElement = elements[diagonalIndex + 1];
|
|
139
|
+
|
|
140
|
+
let element: IElement;
|
|
141
|
+
let originalPos = (rightElement ? rightElement.newPos : 0) - diagonalIndex;
|
|
142
|
+
|
|
143
|
+
// 如果左边有元素,则将其标记为未知
|
|
144
|
+
if (leftElement) {
|
|
145
|
+
elements[diagonalIndex - 1] = undefined;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const canMoveLeft = leftElement && leftElement.newPos + 1 < modifiedLength;
|
|
149
|
+
const canMoveRight = rightElement && 0 <= originalPos && originalPos < originalLength;
|
|
150
|
+
|
|
151
|
+
// 如果不能向左或向右移动,则跳过
|
|
152
|
+
if (!canMoveLeft && !canMoveRight) {
|
|
153
|
+
elements[diagonalIndex] = undefined;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// 根据移动方向选择元素
|
|
158
|
+
if (!canMoveLeft || (canMoveRight && leftElement.newPos < rightElement.newPos)) {
|
|
159
|
+
element = cloneElement(rightElement!);
|
|
160
|
+
pushElement(element.changeResult, undefined, true);
|
|
161
|
+
} else {
|
|
162
|
+
element = leftElement;
|
|
163
|
+
element.newPos++;
|
|
164
|
+
pushElement(element.changeResult, true, undefined);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
originalPos = this.extractCommon(element, tokenizeModified, tokenizeOriginal, diagonalIndex);
|
|
168
|
+
|
|
169
|
+
if (element.newPos + 1 >= modifiedLength && originalPos + 1 >= originalLength) {
|
|
170
|
+
return processElements(element.changeResult, tokenizeModified, tokenizeOriginal);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
elements[diagonalIndex] = element;
|
|
174
|
+
}
|
|
175
|
+
diagonal++;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
while (diagonal <= maxLength) {
|
|
179
|
+
const diffResult = execDiff();
|
|
180
|
+
if (diffResult) {
|
|
181
|
+
return diffResult;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Autowired } from '@opensumi/di';
|
|
2
|
+
import { Key } from '@opensumi/ide-core-browser';
|
|
3
|
+
import {
|
|
4
|
+
ClientAppContribution,
|
|
5
|
+
KeybindingContribution,
|
|
6
|
+
KeybindingRegistry,
|
|
7
|
+
KeybindingScope,
|
|
8
|
+
} from '@opensumi/ide-core-browser';
|
|
9
|
+
import {
|
|
10
|
+
AI_MULTI_LINE_COMPLETION_ACCEPT,
|
|
11
|
+
AI_MULTI_LINE_COMPLETION_HIDE,
|
|
12
|
+
} from '@opensumi/ide-core-browser/lib/ai-native/command';
|
|
13
|
+
import { MultiLineCompletionsIsVisible } from '@opensumi/ide-core-browser/lib/contextkey/ai-native';
|
|
14
|
+
import { CommandContribution, CommandRegistry, Domain } from '@opensumi/ide-core-common';
|
|
15
|
+
|
|
16
|
+
import { IntelligentCompletionsHandler } from './intelligent-completions.handler';
|
|
17
|
+
|
|
18
|
+
@Domain(ClientAppContribution, KeybindingContribution, CommandContribution)
|
|
19
|
+
export class IntelligentCompletionsContribution implements KeybindingContribution, CommandContribution {
|
|
20
|
+
@Autowired(IntelligentCompletionsHandler)
|
|
21
|
+
private readonly intelligentCompletionsHandler: IntelligentCompletionsHandler;
|
|
22
|
+
|
|
23
|
+
registerCommands(commands: CommandRegistry): void {
|
|
24
|
+
commands.registerCommand(AI_MULTI_LINE_COMPLETION_HIDE, {
|
|
25
|
+
execute: () => {
|
|
26
|
+
this.intelligentCompletionsHandler.hide();
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
commands.registerCommand(AI_MULTI_LINE_COMPLETION_ACCEPT, {
|
|
31
|
+
execute: () => {
|
|
32
|
+
this.intelligentCompletionsHandler.accept();
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
registerKeybindings(keybindings: KeybindingRegistry): void {
|
|
38
|
+
keybindings.registerKeybinding({
|
|
39
|
+
command: AI_MULTI_LINE_COMPLETION_HIDE.id,
|
|
40
|
+
keybinding: Key.ESCAPE.code,
|
|
41
|
+
when: MultiLineCompletionsIsVisible.raw,
|
|
42
|
+
priority: 100,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
keybindings.registerKeybinding(
|
|
46
|
+
{
|
|
47
|
+
command: AI_MULTI_LINE_COMPLETION_ACCEPT.id,
|
|
48
|
+
keybinding: Key.TAB.code,
|
|
49
|
+
when: MultiLineCompletionsIsVisible.raw,
|
|
50
|
+
},
|
|
51
|
+
KeybindingScope.USER,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Injectable } from '@opensumi/di';
|
|
2
|
+
import { Disposable } from '@opensumi/ide-core-common';
|
|
3
|
+
|
|
4
|
+
import { IIntelligentCompletionProvider, IIntelligentCompletionsRegistry } from '../../types';
|
|
5
|
+
|
|
6
|
+
@Injectable()
|
|
7
|
+
export class IntelligentCompletionsRegistry extends Disposable implements IIntelligentCompletionsRegistry {
|
|
8
|
+
private provider: IIntelligentCompletionProvider | undefined;
|
|
9
|
+
|
|
10
|
+
registerIntelligentCompletionProvider(provider: IIntelligentCompletionProvider): void {
|
|
11
|
+
this.provider = provider;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getProvider(): IIntelligentCompletionProvider | undefined {
|
|
15
|
+
return this.provider;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { Autowired, INJECTOR_TOKEN, Injectable, Injector } from '@opensumi/di';
|
|
2
|
+
import {
|
|
3
|
+
CancellationTokenSource,
|
|
4
|
+
Disposable,
|
|
5
|
+
IAICompletionOption,
|
|
6
|
+
IDisposable,
|
|
7
|
+
IntelligentCompletionsRegistryToken,
|
|
8
|
+
} from '@opensumi/ide-core-common';
|
|
9
|
+
import { IEditor } from '@opensumi/ide-editor';
|
|
10
|
+
import { ICodeEditor, Position } from '@opensumi/ide-monaco';
|
|
11
|
+
import { EditOperation } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/editOperation';
|
|
12
|
+
|
|
13
|
+
import { AINativeContextKey } from '../../contextkey/ai-native.contextkey.service';
|
|
14
|
+
|
|
15
|
+
import { MultiLineDiffComputer } from './diff-computer';
|
|
16
|
+
import { IIntelligentCompletionsResult } from './intelligent-completions';
|
|
17
|
+
import { IntelligentCompletionsRegistry } from './intelligent-completions.feature.registry';
|
|
18
|
+
import { MultiLineDecorationModel } from './multi-line.decoration';
|
|
19
|
+
|
|
20
|
+
@Injectable()
|
|
21
|
+
export class IntelligentCompletionsHandler extends Disposable {
|
|
22
|
+
@Autowired(INJECTOR_TOKEN)
|
|
23
|
+
private readonly injector: Injector;
|
|
24
|
+
|
|
25
|
+
@Autowired(IntelligentCompletionsRegistryToken)
|
|
26
|
+
private intelligentCompletionsRegistry: IntelligentCompletionsRegistry;
|
|
27
|
+
|
|
28
|
+
private cancelIndicator = new CancellationTokenSource();
|
|
29
|
+
|
|
30
|
+
private cancelToken() {
|
|
31
|
+
this.cancelIndicator.cancel();
|
|
32
|
+
this.cancelIndicator = new CancellationTokenSource();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private multiLineDiffComputer: MultiLineDiffComputer = new MultiLineDiffComputer();
|
|
36
|
+
private multiLineDecorationModel: MultiLineDecorationModel;
|
|
37
|
+
|
|
38
|
+
private editor: IEditor;
|
|
39
|
+
private aiNativeContextKey: AINativeContextKey;
|
|
40
|
+
|
|
41
|
+
private get monacoEditor(): ICodeEditor {
|
|
42
|
+
return this.editor.monacoEditor;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public async fetchProvider(bean: IAICompletionOption): Promise<IIntelligentCompletionsResult | undefined> {
|
|
46
|
+
const provider = this.intelligentCompletionsRegistry.getProvider();
|
|
47
|
+
if (!provider) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const position = this.monacoEditor.getPosition()!;
|
|
52
|
+
const intelligentCompletionModel = await provider(this.monacoEditor, position, bean, this.cancelIndicator.token);
|
|
53
|
+
|
|
54
|
+
if (
|
|
55
|
+
intelligentCompletionModel &&
|
|
56
|
+
intelligentCompletionModel.enableMultiLine &&
|
|
57
|
+
intelligentCompletionModel.items.length > 0
|
|
58
|
+
) {
|
|
59
|
+
return this.applyInlineDecorations(intelligentCompletionModel);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return intelligentCompletionModel;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public applyInlineDecorations(completionModel: IIntelligentCompletionsResult) {
|
|
66
|
+
const { items } = completionModel;
|
|
67
|
+
|
|
68
|
+
const position = this.monacoEditor.getPosition()!;
|
|
69
|
+
const model = this.monacoEditor.getModel();
|
|
70
|
+
const { range, insertText } = items[0];
|
|
71
|
+
|
|
72
|
+
// 如果只是开启了 enableMultiLine 而没有传递 range ,则不显示 multi line
|
|
73
|
+
if (!range) {
|
|
74
|
+
return completionModel;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const originalContent = model?.getValueInRange(range);
|
|
78
|
+
|
|
79
|
+
const diffComputerResult = this.multiLineDiffComputer.diff(originalContent!, insertText.toString());
|
|
80
|
+
|
|
81
|
+
if (diffComputerResult) {
|
|
82
|
+
const inlineModifications = this.multiLineDecorationModel.applyInlineDecorations(
|
|
83
|
+
this.monacoEditor,
|
|
84
|
+
diffComputerResult,
|
|
85
|
+
position.lineNumber,
|
|
86
|
+
position,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
if (inlineModifications) {
|
|
90
|
+
this.aiNativeContextKey.multiLineCompletionsIsVisible.set(true);
|
|
91
|
+
this.multiLineDecorationModel.updateLineModificationDecorations(inlineModifications);
|
|
92
|
+
} else {
|
|
93
|
+
this.aiNativeContextKey.multiLineCompletionsIsVisible.reset();
|
|
94
|
+
this.multiLineDecorationModel.clearDecorations();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public hide() {
|
|
100
|
+
this.cancelToken();
|
|
101
|
+
this.aiNativeContextKey.multiLineCompletionsIsVisible.reset();
|
|
102
|
+
this.multiLineDecorationModel.clearDecorations();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public accept() {
|
|
106
|
+
const edits = this.multiLineDecorationModel.getEdits();
|
|
107
|
+
|
|
108
|
+
this.editor.monacoEditor.pushUndoStop();
|
|
109
|
+
this.editor.monacoEditor.executeEdits(
|
|
110
|
+
'multiLineCompletions.accept',
|
|
111
|
+
edits.map((edit) =>
|
|
112
|
+
EditOperation.insert(
|
|
113
|
+
Position.lift({ lineNumber: edit.range.startLineNumber, column: edit.range.startColumn }),
|
|
114
|
+
edit.text,
|
|
115
|
+
),
|
|
116
|
+
),
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
this.hide();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public registerFeature(editor: IEditor): IDisposable {
|
|
123
|
+
this.editor = editor;
|
|
124
|
+
const { monacoEditor } = editor;
|
|
125
|
+
|
|
126
|
+
this.multiLineDecorationModel = new MultiLineDecorationModel(monacoEditor);
|
|
127
|
+
this.aiNativeContextKey = this.injector.get(AINativeContextKey, [monacoEditor.contextKeyService]);
|
|
128
|
+
return this;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { InlineCompletion } from '@opensumi/ide-monaco';
|
|
2
|
+
|
|
3
|
+
export interface IIntelligentCompletionsResult<T = any> {
|
|
4
|
+
readonly items: InlineCompletion[];
|
|
5
|
+
/**
|
|
6
|
+
* 是否开启多行补全
|
|
7
|
+
* 开启后,items 中的 range 必填
|
|
8
|
+
* 否则显示默认的 inline completion
|
|
9
|
+
*/
|
|
10
|
+
readonly enableMultiLine?: boolean | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* 定义的额外信息
|
|
13
|
+
*/
|
|
14
|
+
extra?: T;
|
|
15
|
+
}
|