From 7344d6ec70f18d8421b3636156bfd45086fef880 Mon Sep 17 00:00:00 2001 From: Keval Prajapati Date: Fri, 14 Jun 2024 12:59:07 +0530 Subject: [PATCH 1/2] Removes DAS dependency in contextual code --- vscode/src/action-managers/refactor-agent.ts | 5 +- vscode/src/extension.ts | 45 ++---- vscode/src/providers/chat_view_provider.ts | 88 ++++++----- vscode/src/repository/http-utils.ts | 4 +- vscode/src/shared/types/FileTracker.ts | 18 --- vscode/src/shared/types/LspAnalyzer.ts | 26 ---- .../tools/create/inline_code_completion.ts | 23 +-- .../refactor/refactor_from_instructions.ts | 7 +- vscode/src/utilities/command-manager.ts | 3 +- vscode/src/utilities/contextual-code.ts | 138 +++++++----------- 10 files changed, 117 insertions(+), 240 deletions(-) delete mode 100644 vscode/src/shared/types/FileTracker.ts delete mode 100644 vscode/src/shared/types/LspAnalyzer.ts diff --git a/vscode/src/action-managers/refactor-agent.ts b/vscode/src/action-managers/refactor-agent.ts index e82157d3..d988ea52 100644 --- a/vscode/src/action-managers/refactor-agent.ts +++ b/vscode/src/action-managers/refactor-agent.ts @@ -1,14 +1,13 @@ import * as vscode from 'vscode'; import { GeminiRepository } from '../repository/gemini-repository'; import { refactorCode } from '../tools/refactor/refactor_from_instructions'; -import { ILspAnalyzer } from '../shared/types/LspAnalyzer'; import { dartCodeExtensionIdentifier } from '../shared/types/constants'; import { FlutterGPTViewProvider } from '../providers/chat_view_provider'; export class RefactorActionManager { constructor() { } - static async handleRequest(chips: any, chipIds: string[], data: any, aiRepo: GeminiRepository, context: vscode.ExtensionContext, analyzer: ILspAnalyzer, flutterGPTViewProvider: FlutterGPTViewProvider) { + static async handleRequest(chips: any, chipIds: string[], data: any, aiRepo: GeminiRepository, context: vscode.ExtensionContext, flutterGPTViewProvider: FlutterGPTViewProvider) { var instructions = data.instructions as string; var chip; for (const chipId of chipIds) { @@ -29,7 +28,7 @@ export class RefactorActionManager { } const selection = chip.referenceData.selection; const range: vscode.Range = new vscode.Range(new vscode.Position(selection.start.line, selection.start.character), new vscode.Position(selection.end.line, selection.end.character)); - const optimizedCode = await refactorCode(aiRepo!, context.globalState, range, analyzer, undefined, context, flutterGPTViewProvider, editor, instructions.trim(), false); + const optimizedCode = await refactorCode(aiRepo!, context.globalState, range, undefined, context, flutterGPTViewProvider, editor, instructions.trim(), false); return { role: "dash", parts: 'Do you want to merge these changes?', messageId: "", data: { 'chip': chip, diff --git a/vscode/src/extension.ts b/vscode/src/extension.ts index 50619d9d..c3b7e18d 100644 --- a/vscode/src/extension.ts +++ b/vscode/src/extension.ts @@ -7,7 +7,6 @@ import { activateTelemetry, logEvent } from './utilities/telemetry-reporter'; import * as dotenv from 'dotenv'; import path = require('path'); // import { ExtensionVersionManager } from './utilities/update-check'; -import { ILspAnalyzer } from './shared/types/LspAnalyzer'; import { dartCodeExtensionIdentifier } from './shared/types/constants'; import { GeminiRepository } from './repository/gemini-repository'; import { FlutterGPTViewProvider } from './providers/chat_view_provider'; @@ -28,7 +27,6 @@ export async function activate(context: vscode.ExtensionContext) { activateTelemetry(context); - const analyzer: ILspAnalyzer = await getAnalyzerExports(); // Initiate cache manager const cacheManager = CacheManager.getInstance(context.globalState, context.workspaceState); @@ -38,18 +36,18 @@ export async function activate(context: vscode.ExtensionContext) { dotenv.config({ path: path.join(__dirname, '../.env') }); const geminiRepo = initGemini(); - const chatViewProvider = initWebview(context, geminiRepo, analyzer); + const chatViewProvider = initWebview(context, geminiRepo,); var _inlineErrorCommand: vscode.Disposable; - if (geminiRepo){ - initFlutterExtension(context, geminiRepo, analyzer, chatViewProvider); + if (geminiRepo) { + initFlutterExtension(context, geminiRepo, chatViewProvider); } else { _inlineErrorCommand = vscode.commands.registerCommand('dash.createInlineCodeCompletion', () => { showMissingApiKey(); }); } - + setupManager.onDidChangeSetup((event) => { switch (event) { case SetupStep.github: @@ -58,45 +56,28 @@ export async function activate(context: vscode.ExtensionContext) { case SetupStep.apiKey: // re-register Flutter Extension Commands const geminiRepo = initGemini(); - if (geminiRepo){ + if (geminiRepo) { if (_inlineErrorCommand) { // Dispose the error command if it exists _inlineErrorCommand!.dispose(); } chatViewProvider.aiRepo = geminiRepo; - initFlutterExtension(context, geminiRepo, analyzer, chatViewProvider); + initFlutterExtension(context, geminiRepo, chatViewProvider); } break; case SetupStep.executable: // Handle any executable related side-effects break; - } + } }); vscode.workspace.registerTextDocumentContentProvider(tempScheme, virtualDocumentProvider); logEvent('activated'); } -async function getAnalyzerExports(): Promise { - // Get analyzer from Dart extension - const dartExt = vscode.extensions.getExtension(dartCodeExtensionIdentifier); - if (!dartExt) { - // This should not happen since the FlutterGPT extension has a dependency on the Dart one - // but just in case, we'd like to give a useful error message. - vscode.window.showWarningMessage("Kindly install 'Dart' extension to activate FlutterGPT"); - } - await dartExt?.activate(); - - if (!dartExt?.exports) { - console.error("The Dart extension did not provide an exported API. Maybe it failed to activate or is not the latest version?"); - } - - return dartExt?.exports._privateApi.analyzer; -} - -function initWebview(context: vscode.ExtensionContext, geminiRepo?: GeminiRepository, analyzer?: ILspAnalyzer) { +function initWebview(context: vscode.ExtensionContext, geminiRepo?: GeminiRepository,) { // Create a new FlutterGPTViewProvider instance and register it with the extension's context - const chatProvider = new FlutterGPTViewProvider(context.extensionUri, context, geminiRepo, analyzer); + const chatProvider = new FlutterGPTViewProvider(context.extensionUri, context, geminiRepo); // Register the provider with the extension's context context.subscriptions.push( vscode.window.registerWebviewViewProvider(FlutterGPTViewProvider.viewType, chatProvider, @@ -109,19 +90,19 @@ function initWebview(context: vscode.ExtensionContext, geminiRepo?: GeminiReposi return chatProvider; } -function initFlutterExtension(context: vscode.ExtensionContext, geminiRepo: GeminiRepository, analyzer: ILspAnalyzer, chatViewProvider: FlutterGPTViewProvider) { +function initFlutterExtension(context: vscode.ExtensionContext, geminiRepo: GeminiRepository, chatViewProvider: FlutterGPTViewProvider) { // const refactorActionProvider = new RefactorActionProvider(analyzer, geminiRepo, context); // context.subscriptions.push(vscode.languages.registerCodeActionsProvider(activeFileFilters, refactorActionProvider)); // const hoverProvider = new AIHoverProvider(geminiRepo, analyzer); // context.subscriptions.push(vscode.languages.registerHoverProvider(activeFileFilters, hoverProvider)); - + //TODO: Renable after moving to CommandDash // const errorActionProvider = new ErrorCodeActionProvider(analyzer, geminiRepo, context); // context.subscriptions.push(vscode.languages.registerCodeActionsProvider(activeFileFilters, errorActionProvider)); - initCommands(context, geminiRepo, analyzer, chatViewProvider); + initCommands(context, geminiRepo, chatViewProvider); } @@ -130,7 +111,7 @@ function initGemini(): GeminiRepository | undefined { console.debug("creating new gemini repo instance"); var apiKey = Auth.getInstance().getApiKey(); if (!apiKey) { - return ; + return; } return new GeminiRepository(apiKey); } diff --git a/vscode/src/providers/chat_view_provider.ts b/vscode/src/providers/chat_view_provider.ts index 04580774..b3fb6f28 100644 --- a/vscode/src/providers/chat_view_provider.ts +++ b/vscode/src/providers/chat_view_provider.ts @@ -5,7 +5,6 @@ import { GeminiRepository } from "../repository/gemini-repository"; import { dartCodeExtensionIdentifier } from "../shared/types/constants"; import { logError, logEvent } from "../utilities/telemetry-reporter"; import { refactorCode } from "../tools/refactor/refactor_from_instructions"; -import { ILspAnalyzer } from "../shared/types/LspAnalyzer"; import { RefactorActionManager } from "../action-managers/refactor-agent"; import { DiffViewAgent } from "../action-managers/diff-view-agent"; import { shortcutInlineCodeRefactor } from "../utilities/shortcut-hint-utils"; @@ -26,7 +25,6 @@ export class FlutterGPTViewProvider implements vscode.WebviewViewProvider { private setupManager = SetupManager.getInstance(); private _activeAgent: string = ''; aiRepo?: GeminiRepository; - analyzer?: ILspAnalyzer; private tasksMap: any = {}; private _publicConversationHistory: Array<{ [agent: string]: { role: string, parts: string, messageId?: string, data?: any, buttons?: string[], agent?: string, slug?: string } }> = []; /// reference documents for particular activated agent for througout chat history @@ -37,10 +35,8 @@ export class FlutterGPTViewProvider implements vscode.WebviewViewProvider { constructor(private readonly _extensionUri: vscode.Uri, private context: vscode.ExtensionContext, aiRepo?: GeminiRepository, - analyzer?: ILspAnalyzer, ) { this.aiRepo = aiRepo; - this.analyzer = analyzer; } // Public method to post a message to the webview @@ -67,7 +63,7 @@ export class FlutterGPTViewProvider implements vscode.WebviewViewProvider { // set the HTML for the webview webviewView.webview.html = this._getHtmlForWebview(webviewView.webview); - + // this.setupManager.deleteGithub(); // add an event listener for messages received by the webview webviewView.webview.onDidReceiveMessage(async (data) => { switch (data.type) { @@ -224,23 +220,23 @@ export class FlutterGPTViewProvider implements vscode.WebviewViewProvider { console.log('error while uninstalling agents: ', error); } } -private async _updateInstalledAgents(response: any) { - const getInstallAgents = await StorageManager.instance.getInstallAgents(); - const _getInstallAgents = JSON.parse(getInstallAgents); - - for (const agentName in _getInstallAgents.agents) { - const matchedAgent = response.find((agent: any) => { - let bool1 = agent.name === agentName.replace('@', ''); - let bool2 = agent.testing === _getInstallAgents.agents[agentName].testing; - return bool1 && bool2; - }); + private async _updateInstalledAgents(response: any) { + const getInstallAgents = await StorageManager.instance.getInstallAgents(); + const _getInstallAgents = JSON.parse(getInstallAgents); + + for (const agentName in _getInstallAgents.agents) { + const matchedAgent = response.find((agent: any) => { + let bool1 = agent.name === agentName.replace('@', ''); + let bool2 = agent.testing === _getInstallAgents.agents[agentName].testing; + return bool1 && bool2; + }); - if (matchedAgent) { - const agentDetails = await this._fetchAgent(matchedAgent.name, matchedAgent.versions[0].version, matchedAgent.testing); - this._storingAgentsLocally(agentDetails); + if (matchedAgent) { + const agentDetails = await this._fetchAgent(matchedAgent.name, matchedAgent.versions[0].version, matchedAgent.testing); + this._storingAgentsLocally(agentDetails); + } } } -} private async _fetchAgentsAPI(backgroundUpdate: boolean = false) { try { const config: AxiosRequestConfig = { @@ -252,13 +248,13 @@ private async _updateInstalledAgents(response: any) { } }; let response = await makeAuthorizedHttpRequest(config, this.context); - - if (backgroundUpdate){ + + if (backgroundUpdate) { this._updateInstalledAgents(response); } else { this._view?.webview.postMessage({ type: 'fetchedAgents', value: JSON.stringify(response) }); } - + } catch (error) { console.log('error: while fetching the get-agent-list api', error); } @@ -381,28 +377,28 @@ private async _updateInstalledAgents(response: any) { const client = DartCLIClient.getInstance(); const task = client.newTask(); - task.onProcessStep('context', async (message) => { - const args = message.params.args; - let uri: vscode.Uri = vscode.Uri.parse(args.filePath); - let document = await vscode.workspace.openTextDocument(uri); - - - let range = new vscode.Range( - new vscode.Position(args.range.start.line, args.range.start.character), - new vscode.Position(args.range.end.line - 1, args.range.end.character), - ); - try { - let contextualCode = await new ContextualCodeProvider().getContextualCodeInput( - document, range, this.analyzer!, undefined - ); - - task.sendStepResponse(message, { - "context": contextualCode, - }); - } catch (error) { - console.log(error); - } - }); + // task.onProcessStep('context', async (message) => { + // const args = message.params.args; + // let uri: vscode.Uri = vscode.Uri.parse(args.filePath); + // let document = await vscode.workspace.openTextDocument(uri); + + + // let range = new vscode.Range( + // new vscode.Position(args.range.start.line, args.range.start.character), + // new vscode.Position(args.range.end.line - 1, args.range.end.character), + // ); + // try { + // let contextualCode = await new ContextualCodeProvider().getContextualCodeInput( + // document, range, this.analyzer!, undefined + // ); + + // task.sendStepResponse(message, { + // "context": contextualCode, + // }); + // } catch (error) { + // console.log(error); + // } + // }); task.onProcessStep('append_to_chat', async (message) => { this._publicConversationHistory.push({ [this._activeAgent]: { role: 'model', parts: message.params.args.message } }); @@ -412,7 +408,7 @@ private async _updateInstalledAgents(response: any) { task.sendStepResponse(message, {}); }); - task.onProcessStep('chat_document_update', async (message)=>{ + task.onProcessStep('chat_document_update', async (message) => { this.chatDocuments[this._activeAgent] = message.params.args.content; task.sendStepResponse(message, {}); }); @@ -544,7 +540,7 @@ private async _updateInstalledAgents(response: any) { this._publicConversationHistory.push({ [this._activeAgent]: { role: 'user', parts: data.message, agent: '/refactor' } }); this._view?.webview.postMessage({ type: 'displayMessages', value: this._publicConversationHistory }); this._view?.webview.postMessage({ type: 'showLoadingIndicator' }); - const result = await RefactorActionManager.handleRequest(chipsData, chipIds, data, this.aiRepo!, this.context, this.analyzer!, this); + const result = await RefactorActionManager.handleRequest(chipsData, chipIds, data, this.aiRepo!, this.context, this); this._view?.webview.postMessage({ type: 'hideLoadingIndicator' }); // this._publicConversationHistory.push(result); this._view?.webview.postMessage({ type: 'displayMessages', value: this._publicConversationHistory }); diff --git a/vscode/src/repository/http-utils.ts b/vscode/src/repository/http-utils.ts index 6a9abb39..1b1f7e41 100644 --- a/vscode/src/repository/http-utils.ts +++ b/vscode/src/repository/http-utils.ts @@ -47,7 +47,7 @@ export async function makeAuthorizedHttpRequest(config: AxiosRequestConfig, c context.globalState.update('access_token', newAccessToken); return makeAuthorizedHttpRequest(config, context); } - throw new Error(`Error: ${error.response?.data.error.code} received with status code ${error.response?.status}.\nMessage: ${error.response?.data.error.message}`); + throw new Error(`Error: ${error.code} received with status code ${error.response?.status}.\nMessage: ${error.response?.data.error.message}`); } else { throw new Error(`Failed to make HTTP request: ${error}`); }; @@ -68,7 +68,7 @@ export async function refreshAccessToken(refreshToken: string, context: vscode.E Authorization: `Bearer ${refreshToken}` } }); - + return response.data.access_token; } catch (error) { if (axios.isAxiosError(error)) { diff --git a/vscode/src/shared/types/FileTracker.ts b/vscode/src/shared/types/FileTracker.ts deleted file mode 100644 index a9e3d234..00000000 --- a/vscode/src/shared/types/FileTracker.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { CancellationToken, TextDocument, Uri } from "vscode"; - -import { LanguageClient, Logger } from "vscode-languageclient/node"; -import { FlutterOutline, Outline, WorkspaceContext } from "./custom_protocols"; -import { IAmDisposable } from "./interfaces"; - -export interface ILspFileTracker extends IAmDisposable { - getOutlineFor(file: Uri | string): Outline | undefined; - waitForOutline(document: TextDocument, token?: CancellationToken): Promise; - waitForOutlineWithLength(document: TextDocument, length: number, token: CancellationToken): Promise; - getFlutterOutlineFor(file: Uri | string): FlutterOutline | undefined; - waitForFlutterOutlineWithLength(document: TextDocument, length: number, token: CancellationToken): Promise; - supportsPackageTest(file: Uri | string): boolean | undefined; -} - -export interface ILspFileTrackerConstructor { - new(logger: Logger, analyzer: LanguageClient, wsContext: WorkspaceContext): ILspFileTracker; -} diff --git a/vscode/src/shared/types/LspAnalyzer.ts b/vscode/src/shared/types/LspAnalyzer.ts deleted file mode 100644 index cd290127..00000000 --- a/vscode/src/shared/types/LspAnalyzer.ts +++ /dev/null @@ -1,26 +0,0 @@ - -import * as vs from 'vscode'; -import * as ls from 'vscode-languageclient'; -import { LanguageClient } from "vscode-languageclient/node"; -import { ILspFileTracker } from './FileTracker'; - -export interface ILspAnalyzer { - readonly client: LanguageClient; - readonly fileTracker: ILspFileTracker; // Replace with the actual type - readonly snippetTextEdits: any; // Replace with the actual type - readonly refactors: any; // Replace with the actual type - readonly statusItem: vs.LanguageStatusItem; - - forceReanalyze(): Promise; - getDiagnosticServerPort(): Promise<{ port: number }>; - getSuper(params: ls.TextDocumentPositionParams): Promise; - completeStatement(params: ls.TextDocumentPositionParams): Promise; - // Any additional methods and properties should be included here. -} - - - - - - - \ No newline at end of file diff --git a/vscode/src/tools/create/inline_code_completion.ts b/vscode/src/tools/create/inline_code_completion.ts index cde92c44..4a99fb2f 100644 --- a/vscode/src/tools/create/inline_code_completion.ts +++ b/vscode/src/tools/create/inline_code_completion.ts @@ -4,7 +4,6 @@ import { logError, logEvent } from '../../utilities/telemetry-reporter'; import path = require('path'); import { extractDartCode, filterSurroundingCode } from '../../utilities/code-processing'; import { ContextualCodeProvider } from '../../utilities/contextual-code'; -import { ILspAnalyzer } from '../../shared/types/LspAnalyzer'; import { dartCodeExtensionIdentifier } from '../../shared/types/constants'; import { CacheManager } from '../../utilities/cache-manager'; @@ -78,7 +77,7 @@ export async function createInlineCodeCompletion() { }, async (progress, token: vscode.CancellationToken) => { const cacheManager = CacheManager.getInstance(); cacheManager.incrementInlineCompletionCount(); - const out = await generateSuggestions(); + const out = await generateSuggestions(); const editor = vscode.window.activeTextEditor; if (editor) { replaceLineOfCode(editor?.selection.active.line, out[0]); @@ -103,7 +102,7 @@ async function generateSuggestions(): Promise { ///TODO: Replace with Generation Repository var relevantFiles = await GeminiRepository.getInstance().findClosestDartFiles("Current file content:" + editor.document.getText() + "\n\n" + "Line of code:" + currentLineContent, undefined, true, filepath); // Add code for all the elements used in the file. - const contextualCode = await new ContextualCodeProvider().getContextualCodeForCompletion(editor.document, getDartAnalyser()); + const contextualCode = await new ContextualCodeProvider().getContextualCodeForCompletion(editor.document,); if (contextualCode && contextualCode.length > 0) { // contextual code might not be available in all cases. Improvements are planned for contextual code gen. // TODO: avoid duplications from the relevant files. relevantFiles = relevantFiles + "\n" + contextualCode; @@ -139,7 +138,7 @@ async function generateSuggestions(): Promise { } catch (error: Error | unknown) { logError('inline-code-completion-error', error); - if (error instanceof Error) { + if (error instanceof Error) { vscode.window.showErrorMessage(`${error.message}`); } else { vscode.window.showErrorMessage(`Failed to generate code: ${error}`); @@ -147,19 +146,3 @@ async function generateSuggestions(): Promise { return []; } } - -function getDartAnalyser() { // This could be in a wider scope. - const dartExt = vscode.extensions.getExtension(dartCodeExtensionIdentifier); - if (!dartExt) { - // This should not happen since the FlutterGPT extension has a dependency on the Dart one - // but just in case, we'd like to give a useful error message. - vscode.window.showWarningMessage("Kindly install 'Dart' extension to activate FlutterGPT"); - } - // Assumption is the dart extension is already activated - if (!dartExt?.exports) { - console.error("The Dart extension did not provide an exported API. Maybe it failed to activate or is not the latest version?"); - } - - const analyzer: ILspAnalyzer = dartExt?.exports._privateApi.analyzer; - return analyzer; -} diff --git a/vscode/src/tools/refactor/refactor_from_instructions.ts b/vscode/src/tools/refactor/refactor_from_instructions.ts index 93af69bb..7d1c120e 100644 --- a/vscode/src/tools/refactor/refactor_from_instructions.ts +++ b/vscode/src/tools/refactor/refactor_from_instructions.ts @@ -1,14 +1,13 @@ import * as vscode from 'vscode'; import { extractDartCode, filterSurroundingCode } from '../../utilities/code-processing'; import { logError, logEvent } from '../../utilities/telemetry-reporter'; -import { ILspAnalyzer } from '../../shared/types/LspAnalyzer'; import { ContextualCodeProvider } from '../../utilities/contextual-code'; import { handleDiffViewAndMerge } from '../../utilities/diff-utils'; import { GenerationRepository } from '../../repository/generation-repository'; import { FlutterGPTViewProvider } from '../../providers/chat_view_provider'; import * as path from 'path'; -export async function refactorCode(generationRepository: GenerationRepository, globalState: vscode.Memento, range: vscode.Range | undefined, analyzer: ILspAnalyzer, elementname: string | undefined, context: vscode.ExtensionContext, flutterGPTViewProvider: FlutterGPTViewProvider, usedEditor: vscode.TextEditor | undefined, instructions: string | undefined, showLoadingIndicator: boolean = true): Promise { +export async function refactorCode(generationRepository: GenerationRepository, globalState: vscode.Memento, range: vscode.Range | undefined, elementname: string | undefined, context: vscode.ExtensionContext, flutterGPTViewProvider: FlutterGPTViewProvider, usedEditor: vscode.TextEditor | undefined, instructions: string | undefined, showLoadingIndicator: boolean = true): Promise { logEvent('refactor-code', { 'type': 'refractor' }); try { const editor = usedEditor === undefined ? vscode.window.activeTextEditor : usedEditor; @@ -61,8 +60,8 @@ export async function refactorCode(generationRepository: GenerationRepository, g flutterGPTViewProvider.postMessageToWebview({ type: 'commandActionRefactor', value: JSON.stringify({ filePath, - relativePath: relativePath.trim(), - referenceContent: `\`${relativePath.trim()}\`\n\`\`\`\n${selectedText.toString()}\n\`\`\`\n`, + relativePath: relativePath.trim(), + referenceContent: `\`${relativePath.trim()}\`\n\`\`\`\n${selectedText.toString()}\n\`\`\`\n`, referenceData: { 'selection': { 'start': { diff --git a/vscode/src/utilities/command-manager.ts b/vscode/src/utilities/command-manager.ts index 5c7a8abb..448b6336 100644 --- a/vscode/src/utilities/command-manager.ts +++ b/vscode/src/utilities/command-manager.ts @@ -26,7 +26,6 @@ import { createWidgetFromDescription } from '../tools/create/widget_from_descrip import { createCodeFromBlueprint } from '../tools/create/code_from_blueprint'; import { createCodeFromDescription } from '../tools/create/code_from_description'; import { refactorCode } from '../tools/refactor/refactor_from_instructions'; -import { ILspAnalyzer } from '../shared/types/LspAnalyzer'; import { GeminiRepository } from '../repository/gemini-repository'; import { fixErrors } from '../tools/refactor/fix_errors'; import { optimizeCode } from '../tools/refactor/optimize_code'; @@ -68,7 +67,7 @@ export function registerCommand( } } -export function initCommands(context: vscode.ExtensionContext, geminiRepo: any, analyzer: any, flutterGPTViewProvider: FlutterGPTViewProvider) { +export function initCommands(context: vscode.ExtensionContext, geminiRepo: any, flutterGPTViewProvider: FlutterGPTViewProvider) { const commands = [ { name: 'dash.attachToDash', handler: () => addToReference(context.globalState, flutterGPTViewProvider), options: { isCommand: true, isMenu: true, isShortcut: false } }, { name: 'dash.createWidget', handler: async () => createWidgetFromDescription(geminiRepo, context.globalState), options: { isCommand: true, isMenu: true, isShortcut: false } }, diff --git a/vscode/src/utilities/contextual-code.ts b/vscode/src/utilities/contextual-code.ts index a3f341d2..6bd76948 100644 --- a/vscode/src/utilities/contextual-code.ts +++ b/vscode/src/utilities/contextual-code.ts @@ -2,7 +2,6 @@ import path = require('path'); import * as vscode from 'vscode'; import { SemanticTokensRegistrationType, SemanticTokensProviderShape, SymbolKind } from 'vscode-languageclient'; -import { ILspAnalyzer } from '../shared/types/LspAnalyzer'; import { Outline } from '../shared/types/custom_protocols'; import { getCodeForRange, isPositionInElementDefinitionRange } from '../shared/utils'; import { Token } from '../shared/types/token'; @@ -11,49 +10,20 @@ import * as fs from 'fs'; export class ContextualCodeProvider { // This should return code, filepath and range for the contextual code - public async getContextualCodeInput(document: vscode.TextDocument, range: vscode.Range, analyzer: ILspAnalyzer, elementname: string | undefined): Promise<{ filePath: string}[] | undefined> { + public async getContextualCodeInput(document: vscode.TextDocument, range: vscode.Range, elementname: string | undefined): Promise<{ filePath: string }[] | undefined> { - const checkSymbols = (symbols: Outline[]): Outline | undefined => { - for (const symbol of symbols) { - if (isPositionInElementDefinitionRange(symbol, range.start)) { - return symbol; - } - if (symbol.children) { - const result = checkSymbols(symbol.children); - if (result !== undefined) { - return result; - } - } - } - return undefined; - }; - // get the target symbol if the elementname is not provided. This is the case when the user selects a range of code. - // The elementName is used to avoid adding target symbol in the contextual code. - if (elementname === undefined) { - const outline = await analyzer.fileTracker.waitForOutline(document); - - if (outline === undefined) { - return undefined; - } - const outlineSymbols = outline?.children || []; - // parse the outline to get all top level symbols - const symbol = checkSymbols(outlineSymbols); - if (symbol !== undefined) { - elementname = symbol.element.name; - } - } - const docTokens = await this.getDocumentTokens(document, analyzer, range); + const docTokens = await this.getDocumentTokens(document, range); const tokensByFilePath = this.getTokensFilePathMap(docTokens, document); // Iterate over the new Map to construct the desired string - let codes: { filePath: string}[] = []; + let codes: { filePath: string }[] = []; for (const [filePath, tokenCodes] of tokensByFilePath) { const absoluteFilePath = path.join(vscode.workspace.rootPath || '', filePath); var codeObject: { filePath: string } = { - filePath: absoluteFilePath, + filePath: absoluteFilePath, }; codes.push(codeObject); } @@ -62,38 +32,9 @@ export class ContextualCodeProvider { // gets the contextual code for the given range. // Contextual code is the code for all the symbols referenced in the range. - public async getContextualCode(document: vscode.TextDocument, range: vscode.Range, analyzer: ILspAnalyzer, elementname: string | undefined): Promise { - const checkSymbols = (symbols: Outline[]): Outline | undefined => { - for (const symbol of symbols) { - if (isPositionInElementDefinitionRange(symbol, range.start)) { - return symbol; - } - if (symbol.children) { - const result = checkSymbols(symbol.children); - if (result !== undefined) { - return result; - } - } - } - return undefined; - }; + public async getContextualCode(document: vscode.TextDocument, range: vscode.Range, elementname: string | undefined): Promise { - // get the target symbol if the elementname is not provided. This is the case when the user selects a range of code. - // The elementName is used to avoid adding target symbol in the contextual code. - if (elementname === undefined) { - const outline = await analyzer.fileTracker.waitForOutline(document); - - if (outline === undefined) { - return undefined; - } - const outlineSymbols = outline?.children || []; - // parse the outline to get all top level symbols - const symbol = checkSymbols(outlineSymbols); - if (symbol !== undefined) { - elementname = symbol.element.name; - } - } - const docTokens = await this.getDocumentTokens(document, analyzer, range); + const docTokens = await this.getDocumentTokens(document, range); const tokensByFilePath = this.getTokensFilePathMap(docTokens, document); @@ -112,9 +53,9 @@ export class ContextualCodeProvider { // gets the contextual code for the whole file. // Used for inline completions to handle cases where there is no method or class in context. - public async getContextualCodeForCompletion(document: vscode.TextDocument, analyzer: ILspAnalyzer,): Promise { + public async getContextualCodeForCompletion(document: vscode.TextDocument,): Promise { // provide code for tokens in the whole file. Avoid duplicate code for the same file. - const docTokens = await this.getDocumentTokens(document, analyzer, new vscode.Range(0, 0, document.lineCount - 1, 0)); + const docTokens = await this.getDocumentTokens(document, new vscode.Range(0, 0, document.lineCount - 1, 0)); const tokensByFilePath = this.getTokensFilePathMap(docTokens, document); @@ -132,15 +73,17 @@ export class ContextualCodeProvider { - private async getDocumentTokens(document: vscode.TextDocument, analyzer: ILspAnalyzer, range: vscode.Range): Promise { + private async getDocumentTokens(document: vscode.TextDocument, range: vscode.Range): Promise { - let tokenSource = new vscode.CancellationTokenSource(); - const shape = analyzer.client.getFeature(SemanticTokensRegistrationType.method).getProvider(document) as SemanticTokensProviderShape | undefined; - const semanticTokens = await shape?.range?.provideDocumentRangeSemanticTokens(document, range, tokenSource.token); - if (semanticTokens === undefined || semanticTokens?.data === undefined) { - return []; - } - let tokens = await this.parseTokens(semanticTokens?.data!, document, analyzer); + // const semanticTokens = await shape?.range?.provideDocumentRangeSemanticTokens(document, range, tokenSource.token); + // if (semanticTokens === undefined || semanticTokens?.data === undefined) { + // return []; + // } + const semanticTokens = await vscode.commands.executeCommand( + 'vscode.provideDocumentSemanticTokens', + document.uri + ); + let tokens = await this.parseTokens(semanticTokens?.data!, document,); return tokens; @@ -169,7 +112,7 @@ export class ContextualCodeProvider { } - private async parseTokens(tokensArray: Uint32Array, document: vscode.TextDocument, analyzer: ILspAnalyzer): Promise { + private async parseTokens(tokensArray: Uint32Array, document: vscode.TextDocument,): Promise { const tokens: Token[] = []; let currentLine = 0; let currentStart = 0; @@ -194,13 +137,23 @@ export class ContextualCodeProvider { const cancellationToken = new vscode.CancellationTokenSource(); - const definitionProvider = analyzer.client.getFeature('textDocument/definition').getProvider(document); - if (definitionProvider === undefined) { - continue; - } - let definition = await definitionProvider?.provideDefinition(document, range.start, cancellationToken.token) as vscode.LocationLink[]; - - let uri = definition[0]?.targetUri; + console.log("range", range); + let definition: { + targetUri?: vscode.Uri; + targetRange?: vscode.Range; + uri: vscode.Uri; + range: vscode.Range; + }[] = await vscode.commands.executeCommand('vscode.executeDefinitionProvider', document.uri, range.start, cancellationToken.token); + console.log(typeof (definition[0])); + + // const definitionProvider = + // // await vscode.commands.executeCommand('vscode.executeDefinitionProvider', document.uri, range.start, cancellationToken.token); + // analyzer.client.getFeature('textDocument/definition').getProvider(document); + // if (definitionProvider === undefined) { + // continue; + // } + // let definition_analyzer = await definitionProvider?.provideDefinition(document, range.start, cancellationToken.token) as vscode.LocationLink[]; + let uri = definition[0]?.targetUri ?? definition[0].uri; if (uri) { // check if same file as document. // We don't want to show the code for the same file as we already pass the for for full file in the prompt. @@ -208,13 +161,19 @@ export class ContextualCodeProvider { // We add the code only for files in the current workspace. This is to avoid code from the sdk and other packages. // TODO: Add support for code from other packages as well. This will be better for users who modulize their code into packages. let workspaceFolder = vscode.workspace.getWorkspaceFolder(uri); - if (workspaceFolder && this.toAddInContextualCode(this.getSymbolKind(tokenType))) { - const code = await getCodeForRange(uri, definition[0].targetRange); + const legend = await vscode.commands.executeCommand( + 'vscode.provideDocumentSemanticTokensLegend', + document.uri + ); + console.log(legend); + var symbolkind = this.getSymbolKind(tokenType, legend); + if (workspaceFolder && this.toAddInContextualCode(this.getSymbolKind(tokenType, legend))) { + const code = await getCodeForRange(uri, definition[0].targetRange ?? definition[0].range); if (code) { tokens.push({ name: name, tokenTypeNumber: tokenType, - tokenType: this.getSymbolKind(tokenType), + tokenType: this.getSymbolKind(tokenType, legend), line: currentLine, start: currentStart, length: length, @@ -246,7 +205,12 @@ export class ContextualCodeProvider { } } - private getSymbolKind(kindNumber: number): string | undefined { + private getSymbolKind(kindNumber: number, legend: vscode.SemanticTokensLegend): string | undefined { + var kind = legend.tokenTypes[kindNumber]; + if (kind === "function") { + return 'Method'; + } + return kind; switch (kindNumber) { case 2: return "Class"; From 63b20e19ce6c9c11f9ebd2f835afbf8e5e7a2131 Mon Sep 17 00:00:00 2001 From: Samyak Jain <56000318+samyakkkk@users.noreply.github.com> Date: Mon, 17 Jun 2024 14:23:58 +0530 Subject: [PATCH 2/2] (fix): remove dart dependency requirements --- vscode/package.json | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/vscode/package.json b/vscode/package.json index 0f4a6b1e..41c704a8 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -37,9 +37,7 @@ "activationEvents": [ "onLanguage:dart" ], - "extensionDependencies": [ - "Dart-Code.dart-code" - ], + "extensionDependencies": [], "main": "./out/extension.js", "contributes": { "extensionKind": [ @@ -69,7 +67,7 @@ "properties": { "fluttergpt.apiKey": { "type": "string", - "markdownDescription": "Gemini API KEY(https://makersuite.google.com/)" + "markdownDescription": "Gemini API KEY (https://aistudio.google.com/)" } } }, @@ -126,10 +124,6 @@ } ], "editor/context": [ - { - "submenu": "dash.createMenu", - "group": "dash-menu-group@1" - }, { "command": "dash.attachToDash.menu", "when": "editorHasSelection", @@ -156,12 +150,7 @@ "dash.createMenu": [ ] }, - "submenus": [ - { - "id": "dash.createMenu", - "label": "CommandDash: Create" - } - ] + "submenus": [] }, "scripts": { "vscode:prepublish": "npm run -S esbuild-base",