From dda72444fd6dc4a416923f91b0823bd67d149f3d Mon Sep 17 00:00:00 2001 From: "qingyi.xjh" Date: Fri, 6 Sep 2024 17:13:24 +0800 Subject: [PATCH 1/4] feat: support problem fix components --- .../src/browser/ai-core.contribution.ts | 7 +++ .../problem-fix/problem-fix.component.tsx | 33 +++++++++++++ .../problem-fix.feature.registry.ts | 16 +++++++ .../problem-fix/problem-fix.handler.ts | 48 +++++++++++++++++++ .../problem-fix/problem-fix.module.less | 5 ++ .../problem-fix/problem-fix.service.ts | 17 +++++++ packages/ai-native/src/browser/index.ts | 11 ++++- packages/ai-native/src/browser/types.ts | 10 +++- .../src/ai-native/ai-config.service.ts | 1 + .../core-common/src/types/ai-native/index.ts | 5 ++ packages/i18n/src/common/en-US.lang.ts | 2 + packages/i18n/src/common/zh-CN.lang.ts | 2 + 12 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 packages/ai-native/src/browser/contrib/problem-fix/problem-fix.component.tsx create mode 100644 packages/ai-native/src/browser/contrib/problem-fix/problem-fix.feature.registry.ts create mode 100644 packages/ai-native/src/browser/contrib/problem-fix/problem-fix.handler.ts create mode 100644 packages/ai-native/src/browser/contrib/problem-fix/problem-fix.module.less create mode 100644 packages/ai-native/src/browser/contrib/problem-fix/problem-fix.service.ts diff --git a/packages/ai-native/src/browser/ai-core.contribution.ts b/packages/ai-native/src/browser/ai-core.contribution.ts index 0985570eff..737f59dad6 100644 --- a/packages/ai-native/src/browser/ai-core.contribution.ts +++ b/packages/ai-native/src/browser/ai-core.contribution.ts @@ -76,6 +76,7 @@ import { CodeActionHandler } from './contrib/code-action/code-action.handler'; import { AIInlineCompletionsProvider } from './contrib/inline-completions/completeProvider'; import { InlineCompletionHandler } from './contrib/inline-completions/inline-completions.handler'; import { AICompletionsService } from './contrib/inline-completions/service/ai-completions.service'; +import { ProblemFixHandler } from './contrib/problem-fix/problem-fix.handler'; import { RenameHandler } from './contrib/rename/rename.handler'; import { AIRunToolbar } from './contrib/run-toolbar/run-toolbar'; import { AIChatTabRenderer, AILeftTabRenderer, AIRightTabRenderer } from './layout/tabbar.view'; @@ -176,6 +177,9 @@ export class AINativeBrowserContribution @Autowired(RenameHandler) private readonly renameHandler: RenameHandler; + @Autowired(ProblemFixHandler) + private readonly problemfixHandler: ProblemFixHandler; + @Autowired(InlineCompletionHandler) private readonly inlineCompletionHandler: InlineCompletionHandler; @@ -223,6 +227,9 @@ export class AINativeBrowserContribution if (this.aiNativeConfigService.capabilities.supportsRenameSuggestions) { this.renameHandler.load(); } + if (this.aiNativeConfigService.capabilities.supportsProblemFix) { + this.problemfixHandler.load(); + } if (this.aiNativeConfigService.capabilities.supportsInlineCompletion) { this.inlineCompletionHandler.load(); } diff --git a/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.component.tsx b/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.component.tsx new file mode 100644 index 0000000000..7dff70c322 --- /dev/null +++ b/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.component.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; + +import { Button } from '@opensumi/ide-components'; +import { AppConfig, ConfigProvider } from '@opensumi/ide-core-browser'; +import { localize } from '@opensumi/ide-core-common'; + +import styles from './problem-fix.module.less'; + +export const ProblemFixComponent = () => { + const handleClick = () => {}; + + return ( + + ); +}; + +export const MarkerHoverParticipantComponent = { + mount(container: DocumentFragment, configContext: AppConfig) { + const dom = document.createElement('div'); + dom.className = styles.problem_fix_btn_container; + + ReactDOM.createRoot(dom).render( + + + , + ); + + container.appendChild(dom); + }, +}; diff --git a/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.feature.registry.ts b/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.feature.registry.ts new file mode 100644 index 0000000000..eec3372673 --- /dev/null +++ b/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.feature.registry.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@opensumi/di'; + +import { IProblemFixProviderRegistry, NewSymbolNamesProviderFn } from '../../types'; + +@Injectable() +export class ProblemFixProviderRegistry implements IProblemFixProviderRegistry { + registerHoverFixProvider(provider: NewSymbolNamesProviderFn): void { + throw new Error('Method not implemented.'); + } + + registerFixProvider(provider: NewSymbolNamesProviderFn): void {} + + getFixProviders(): NewSymbolNamesProviderFn[] { + return []; + } +} diff --git a/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.handler.ts b/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.handler.ts new file mode 100644 index 0000000000..8ea624e767 --- /dev/null +++ b/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.handler.ts @@ -0,0 +1,48 @@ +import { Autowired, INJECTOR_TOKEN, Injectable, Injector } from '@opensumi/di'; +import { AppConfig } from '@opensumi/ide-core-browser'; +import { Disposable } from '@opensumi/ide-core-common'; +import { + HoverParticipantRegistry, + IEditorHoverRenderContext, +} from '@opensumi/monaco-editor-core/esm/vs/editor/contrib/hover/browser/hoverTypes'; +import { + MarkerHover, + MarkerHoverParticipant, +} from '@opensumi/monaco-editor-core/esm/vs/editor/contrib/hover/browser/markerHoverParticipant'; + +import { IAIMonacoContribHandler } from '../base'; + +import { MarkerHoverParticipantComponent } from './problem-fix.component'; + +class AIMonacoHoverParticipant extends MarkerHoverParticipant { + static injector: Injector; + + override renderHoverParts(context: IEditorHoverRenderContext, hoverParts: MarkerHover[]) { + const disposable = super.renderHoverParts(context, hoverParts); + + const { fragment } = context; + MarkerHoverParticipantComponent.mount(fragment, AIMonacoHoverParticipant.injector.get(AppConfig)); + + return disposable; + } +} + +@Injectable() +export class ProblemFixHandler extends IAIMonacoContribHandler { + @Autowired(INJECTOR_TOKEN) + private readonly injector: Injector; + + doContribute() { + const disposable = new Disposable(); + + // 先去掉 monaco 默认的 MarkerHoverParticipant + HoverParticipantRegistry._participants = HoverParticipantRegistry._participants.filter( + (participant) => participant !== MarkerHoverParticipant, + ); + + AIMonacoHoverParticipant.injector = this.injector; + HoverParticipantRegistry.register(AIMonacoHoverParticipant); + + return disposable; + } +} diff --git a/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.module.less b/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.module.less new file mode 100644 index 0000000000..55d55b5082 --- /dev/null +++ b/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.module.less @@ -0,0 +1,5 @@ +.problem_fix_btn_container { + margin-left: 8px; + margin-bottom: 8px; + height: 22px; +} diff --git a/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.service.ts b/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.service.ts new file mode 100644 index 0000000000..b852bc7cd4 --- /dev/null +++ b/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.service.ts @@ -0,0 +1,17 @@ +import { Autowired, Injectable } from '@opensumi/di'; +import { + CancellationToken, + ProblemFixRegistryToken, + RenameCandidatesProviderRegistryToken, +} from '@opensumi/ide-core-common'; +import { IRange, ITextModel, NewSymbolName } from '@opensumi/ide-monaco'; + +import { IProblemFixProviderRegistry, IRenameCandidatesProviderRegistry } from '../../types'; + +@Injectable() +export class ProblemFixService { + @Autowired(ProblemFixRegistryToken) + private readonly problemFixProviderRegistry: IProblemFixProviderRegistry; + + async provideProblemFix(model: ITextModel, range: IRange, token: CancellationToken) {} +} diff --git a/packages/ai-native/src/browser/index.ts b/packages/ai-native/src/browser/index.ts index cca8fc70e8..80779d9899 100644 --- a/packages/ai-native/src/browser/index.ts +++ b/packages/ai-native/src/browser/index.ts @@ -13,7 +13,11 @@ import { RenameCandidatesProviderRegistryToken, ResolveConflictRegistryToken, } from '@opensumi/ide-core-browser'; -import { IntelligentCompletionsRegistryToken, TerminalRegistryToken } from '@opensumi/ide-core-common'; +import { + IntelligentCompletionsRegistryToken, + ProblemFixRegistryToken, + TerminalRegistryToken, +} from '@opensumi/ide-core-common'; import { ChatProxyServiceToken, IChatAgentService, IChatInternalService, IChatManagerService } from '../common'; @@ -32,6 +36,7 @@ import { IntelligentCompletionsRegistry } from './contrib/intelligent-completion import { InterfaceNavigationContribution } from './contrib/interface-navigation/interface-navigation.contribution'; import { MergeConflictContribution } from './contrib/merge-conflict'; import { ResolveConflictRegistry } from './contrib/merge-conflict/merge-conflict.feature.registry'; +import { ProblemFixProviderRegistry } from './contrib/problem-fix/problem-fix.feature.registry'; import { RenameCandidatesProviderRegistry } from './contrib/rename/rename.feature.registry'; import { TerminalAIContribution } from './contrib/terminal/terminal-ai.contributon'; import { TerminalFeatureRegistry } from './contrib/terminal/terminal.feature.registry'; @@ -112,6 +117,10 @@ export class AINativeModule extends BrowserModule { token: RenameCandidatesProviderRegistryToken, useClass: RenameCandidatesProviderRegistry, }, + { + token: ProblemFixRegistryToken, + useClass: ProblemFixProviderRegistry, + }, { token: TerminalRegistryToken, useClass: TerminalFeatureRegistry, diff --git a/packages/ai-native/src/browser/types.ts b/packages/ai-native/src/browser/types.ts index 86440ed45c..09606d1f4a 100644 --- a/packages/ai-native/src/browser/types.ts +++ b/packages/ai-native/src/browser/types.ts @@ -13,7 +13,7 @@ import { MaybePromise, MergeConflictEditorMode, } from '@opensumi/ide-core-common'; -import { ICodeEditor, IRange, ITextModel, NewSymbolNamesProvider, Position } from '@opensumi/ide-monaco'; +import { ICodeEditor, ITextModel, NewSymbolNamesProvider, Position } from '@opensumi/ide-monaco'; import { SumiReadableStream } from '@opensumi/ide-utils/lib/stream'; import { IChatWelcomeMessageContent, ISampleQuestions, ITerminalCommandSuggestionDesc } from '../common'; @@ -206,6 +206,10 @@ export interface IIntelligentCompletionsRegistry { registerIntelligentCompletionProvider(provider: IIntelligentCompletionProvider): void; } +export interface IProblemFixProviderRegistry { + registerHoverFixProvider(provider: NewSymbolNamesProviderFn): void; +} + export const AINativeCoreContribution = Symbol('AINativeCoreContribution'); export interface AINativeCoreContribution { @@ -230,6 +234,10 @@ export interface AINativeCoreContribution { * 注册智能重命名相关功能 */ registerRenameProvider?(registry: IRenameCandidatesProviderRegistry): void; + /** + * 注册智能修复相关功能 + */ + registerProblemFixFeature?(registry: IProblemFixProviderRegistry): void; /** * 注册智能终端相关功能 */ diff --git a/packages/core-browser/src/ai-native/ai-config.service.ts b/packages/core-browser/src/ai-native/ai-config.service.ts index 0ff0e7ca60..d7d7754005 100644 --- a/packages/core-browser/src/ai-native/ai-config.service.ts +++ b/packages/core-browser/src/ai-native/ai-config.service.ts @@ -11,6 +11,7 @@ const DEFAULT_CAPABILITIES: Required = { supportsInlineCompletion: true, supportsConflictResolve: true, supportsRenameSuggestions: true, + supportsProblemFix: true, supportsTerminalDetection: true, supportsTerminalCommandSuggest: true, }; diff --git a/packages/core-common/src/types/ai-native/index.ts b/packages/core-common/src/types/ai-native/index.ts index 76417fe614..a03d28aed0 100644 --- a/packages/core-common/src/types/ai-native/index.ts +++ b/packages/core-common/src/types/ai-native/index.ts @@ -32,6 +32,10 @@ export interface IAINativeCapabilities { * Use ai to provide rename suggestions */ supportsRenameSuggestions?: boolean; + /** + * Use ai to provide fix error or warning + */ + supportsProblemFix?: boolean; /** * Use ai terminal detection capabilities */ @@ -227,6 +231,7 @@ export const ChatFeatureRegistryToken = Symbol('ChatFeatureRegistryToken'); export const ChatRenderRegistryToken = Symbol('ChatRenderRegistryToken'); export const ResolveConflictRegistryToken = Symbol('ResolveConflictRegistryToken'); export const RenameCandidatesProviderRegistryToken = Symbol('RenameCandidatesProviderRegistryToken'); +export const ProblemFixRegistryToken = Symbol('ProblemFixRegistryToken'); export const TerminalRegistryToken = Symbol('TerminalRegistryToken'); export const IntelligentCompletionsRegistryToken = Symbol('IntelligentCompletionsRegistryToken'); diff --git a/packages/i18n/src/common/en-US.lang.ts b/packages/i18n/src/common/en-US.lang.ts index 9e03db04d4..a35f6f3b7c 100644 --- a/packages/i18n/src/common/en-US.lang.ts +++ b/packages/i18n/src/common/en-US.lang.ts @@ -1458,6 +1458,8 @@ export const localizationBundle = { 'aiNative.inline.chat.input.placeholder.default': 'Ask Copilot(shift + enter newline)', 'aiNative.inline.hint.widget.placeholder': '{0} to inline chat', + 'aiNative.inline.problem.fix.title': 'Fix with AI', + 'aiNative.resolve.conflict.dialog.afresh': 'Are you sure you want to regenerate?', 'aiNative.resolve.conflict.dialog.detection': 'It is detected that you have made modifications. Regeneration will overwrite\nyour modifications. Are you sure to regenerate?', diff --git a/packages/i18n/src/common/zh-CN.lang.ts b/packages/i18n/src/common/zh-CN.lang.ts index e4d5140b1f..28a2ee1ec1 100644 --- a/packages/i18n/src/common/zh-CN.lang.ts +++ b/packages/i18n/src/common/zh-CN.lang.ts @@ -1224,6 +1224,8 @@ export const localizationBundle = { 'aiNative.inline.chat.input.placeholder.default': '可以问我任何问题,支持 shift + 回车换行', 'aiNative.inline.hint.widget.placeholder': '按 {0} 唤起 Inline Chat', + 'aiNative.inline.problem.fix.title': 'AI 修复', + 'aiNative.resolve.conflict.dialog.afresh': '你确定要重新生成吗?', 'aiNative.resolve.conflict.dialog.detection': '检测到您已做了修改,重新生成会覆盖掉\n您修改的部分,是否确认进行重新生成。', From 250fe2e044446deca59a3e98a884648f5c78a872 Mon Sep 17 00:00:00 2001 From: "qingyi.xjh" Date: Mon, 9 Sep 2024 16:59:20 +0800 Subject: [PATCH 2/4] chore: implement hover fix api --- .../src/browser/ai-core.contribution.ts | 6 +++ .../src/browser/ai-editor.contribution.ts | 7 +++ .../problem-fix/problem-fix.component.tsx | 37 ++++++++++----- .../problem-fix.feature.registry.ts | 14 +++--- .../problem-fix/problem-fix.handler.ts | 46 ++++++++++++++++++- .../problem-fix/problem-fix.service.ts | 20 ++++---- packages/ai-native/src/browser/types.ts | 18 +++++++- .../widget/inline-chat/inline-chat.handler.ts | 1 - .../ai-native/ai-native.contribution.ts | 20 ++++++++ 9 files changed, 133 insertions(+), 36 deletions(-) diff --git a/packages/ai-native/src/browser/ai-core.contribution.ts b/packages/ai-native/src/browser/ai-core.contribution.ts index 737f59dad6..5467b39aa2 100644 --- a/packages/ai-native/src/browser/ai-core.contribution.ts +++ b/packages/ai-native/src/browser/ai-core.contribution.ts @@ -46,6 +46,7 @@ import { CommandService, InlineChatFeatureRegistryToken, IntelligentCompletionsRegistryToken, + ProblemFixRegistryToken, RenameCandidatesProviderRegistryToken, ResolveConflictRegistryToken, TerminalRegistryToken, @@ -86,6 +87,7 @@ import { IChatFeatureRegistry, IChatRenderRegistry, IIntelligentCompletionsRegistry, + IProblemFixProviderRegistry, IRenameCandidatesProviderRegistry, IResolveConflictRegistry, ITerminalProviderRegistry, @@ -144,6 +146,9 @@ export class AINativeBrowserContribution @Autowired(IntelligentCompletionsRegistryToken) private readonly intelligentCompletionsRegistry: IIntelligentCompletionsRegistry; + @Autowired(ProblemFixRegistryToken) + private readonly problemFixProviderRegistry: IProblemFixProviderRegistry; + @Autowired(AINativeConfigService) private readonly aiNativeConfigService: AINativeConfigService; @@ -247,6 +252,7 @@ export class AINativeBrowserContribution contribution.registerChatRender?.(this.chatRenderRegistry); contribution.registerTerminalProvider?.(this.terminalProviderRegistry); contribution.registerIntelligentCompletionFeature?.(this.intelligentCompletionsRegistry); + contribution.registerProblemFixFeature?.(this.problemFixProviderRegistry); }); } diff --git a/packages/ai-native/src/browser/ai-editor.contribution.ts b/packages/ai-native/src/browser/ai-editor.contribution.ts index 4690751979..bb6d2bf288 100644 --- a/packages/ai-native/src/browser/ai-editor.contribution.ts +++ b/packages/ai-native/src/browser/ai-editor.contribution.ts @@ -10,6 +10,7 @@ import { BrowserCodeEditor, BrowserDiffEditor } from '@opensumi/ide-editor/lib/b import { CodeActionHandler } from './contrib/code-action/code-action.handler'; import { InlineCompletionHandler } from './contrib/inline-completions/inline-completions.handler'; import { IntelligentCompletionsHandler } from './contrib/intelligent-completions/intelligent-completions.handler'; +import { ProblemFixHandler } from './contrib/problem-fix/problem-fix.handler'; import { InlineChatFeatureRegistry } from './widget/inline-chat/inline-chat.feature.registry'; import { InlineChatHandler } from './widget/inline-chat/inline-chat.handler'; import { InlineDiffHandler } from './widget/inline-diff/inline-diff.handler'; @@ -42,6 +43,9 @@ export class AIEditorContribution extends Disposable implements IEditorFeatureCo @Autowired(InlineCompletionHandler) private readonly inlineCompletionHandler: InlineCompletionHandler; + @Autowired(ProblemFixHandler) + private readonly problemfixHandler: ProblemFixHandler; + @Autowired(IntelligentCompletionsHandler) private readonly intelligentCompletionsHandler: IntelligentCompletionsHandler; @@ -191,6 +195,9 @@ export class AIEditorContribution extends Disposable implements IEditorFeatureCo if (this.aiNativeConfigService.capabilities.supportsInlineChat) { this.modelSessionDisposable.addDispose(this.codeActionHandler.mountEditor(editor)); } + if (this.aiNativeConfigService.capabilities.supportsProblemFix) { + this.modelSessionDisposable.addDispose(this.problemfixHandler.mountEditor(editor)); + } this.modelSessionDisposable.addDispose(this.inlineDiffHandler.mountEditor(editor)); } diff --git a/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.component.tsx b/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.component.tsx index 7dff70c322..bdae2ee3f8 100644 --- a/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.component.tsx +++ b/packages/ai-native/src/browser/contrib/problem-fix/problem-fix.component.tsx @@ -2,13 +2,23 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; import { Button } from '@opensumi/ide-components'; -import { AppConfig, ConfigProvider } from '@opensumi/ide-core-browser'; +import { AppConfig, ConfigProvider, useInjectable } from '@opensumi/ide-core-browser'; import { localize } from '@opensumi/ide-core-common'; +import { MarkerHover } from '@opensumi/monaco-editor-core/esm/vs/editor/contrib/hover/browser/markerHoverParticipant'; import styles from './problem-fix.module.less'; +import { ProblemFixService } from './problem-fix.service'; -export const ProblemFixComponent = () => { - const handleClick = () => {}; +interface IProblemFixComponentProps { + part: MarkerHover; +} + +export const ProblemFixComponent = ({ part }: IProblemFixComponentProps) => { + const problemFixService = useInjectable(ProblemFixService); + + const handleClick = () => { + problemFixService.triggerHoverFix(part); + }; return (