From 81416cdc2065130b78577e607eb5e31f44527561 Mon Sep 17 00:00:00 2001 From: "Wu, Zhenyu" Date: Mon, 18 Mar 2024 16:45:12 +0800 Subject: [PATCH] :alien: Fix incompatible APIs --- .../unit-tests/ui/bitbake-commands.test.ts | 2 +- .../ui/bitbake-recipes-view.test.ts | 2 +- .../ui/bitbake-terminal-links.test.ts | 2 +- .../ui/devtool-workspaces-view.test.ts | 2 +- client/src/__tests__/utils/vscodeMock.ts | 2 +- client/src/documentLinkProvider.ts | 10 +- client/src/driver/BitBakeProjectScanner.ts | 34 +- client/src/driver/BitbakeDriver.ts | 208 ++++----- client/src/driver/BitbakeESDK.ts | 2 +- client/src/driver/BitbakeRecipeScanner.ts | 112 ++--- client/src/extension.ts | 138 +++--- .../language/EmbeddedLanguageDocsManager.ts | 32 +- client/src/language/RequestManager.ts | 4 +- client/src/language/codeActionProvider.ts | 113 ----- client/src/language/diagnosticsSupport.ts | 128 ------ client/src/language/languageClient.ts | 112 ++--- client/src/language/languageConfiguration.ts | 123 ------ client/src/language/middlewareCompletion.ts | 58 --- client/src/language/middlewareDefinition.ts | 159 ------- client/src/language/middlewareHover.ts | 94 ----- client/src/language/middlewareReferences.ts | 75 ---- client/src/language/utils/definitions.ts | 67 --- .../language/utils/embeddedLanguagesUtils.ts | 56 --- .../src/language/utils/textDocumentUtils.ts | 11 - client/src/lib/package.json | 3 +- .../src/__tests__/utils/output-logger.test.ts | 2 +- client/src/lib/src/types/requests.ts | 2 +- client/src/ui/BitbakeCommands.ts | 398 +++++++++--------- client/src/ui/BitbakeConfigPicker.ts | 20 +- client/src/ui/BitbakeRecipesView.ts | 34 +- client/src/ui/BitbakeStatusBar.ts | 96 ++--- client/src/ui/BitbakeTaskProvider.ts | 80 ---- client/src/ui/BitbakeTerminal.ts | 194 --------- client/src/ui/BitbakeTerminalLinkProvider.ts | 48 --- client/src/ui/BitbakeTerminalProfile.ts | 46 -- client/src/ui/BitbakeWorkspace.ts | 2 +- client/src/ui/ClientNotificationManager.ts | 4 +- client/src/ui/DevtoolWorkspacesView.ts | 90 ---- client/src/utils/ProcessUtils.ts | 71 ---- 39 files changed, 613 insertions(+), 2023 deletions(-) delete mode 100644 client/src/language/codeActionProvider.ts delete mode 100644 client/src/language/diagnosticsSupport.ts delete mode 100644 client/src/language/languageConfiguration.ts delete mode 100644 client/src/language/middlewareCompletion.ts delete mode 100644 client/src/language/middlewareDefinition.ts delete mode 100644 client/src/language/middlewareHover.ts delete mode 100644 client/src/language/middlewareReferences.ts delete mode 100644 client/src/language/utils/definitions.ts delete mode 100644 client/src/language/utils/embeddedLanguagesUtils.ts delete mode 100644 client/src/language/utils/textDocumentUtils.ts delete mode 100644 client/src/ui/BitbakeTaskProvider.ts delete mode 100644 client/src/ui/BitbakeTerminal.ts delete mode 100644 client/src/ui/BitbakeTerminalLinkProvider.ts delete mode 100644 client/src/ui/BitbakeTerminalProfile.ts delete mode 100644 client/src/ui/DevtoolWorkspacesView.ts delete mode 100644 client/src/utils/ProcessUtils.ts diff --git a/client/src/__tests__/unit-tests/ui/bitbake-commands.test.ts b/client/src/__tests__/unit-tests/ui/bitbake-commands.test.ts index 21e41d696..36997e294 100644 --- a/client/src/__tests__/unit-tests/ui/bitbake-commands.test.ts +++ b/client/src/__tests__/unit-tests/ui/bitbake-commands.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import * as vscode from 'vscode' +import * as vscode from 'coc.nvim' import { BitbakeWorkspace } from '../../../ui/BitbakeWorkspace' import { BitBakeProjectScanner } from '../../../driver/BitBakeProjectScanner' import { BitbakeDriver } from '../../../driver/BitbakeDriver' diff --git a/client/src/__tests__/unit-tests/ui/bitbake-recipes-view.test.ts b/client/src/__tests__/unit-tests/ui/bitbake-recipes-view.test.ts index e7e465c10..fea1233ea 100644 --- a/client/src/__tests__/unit-tests/ui/bitbake-recipes-view.test.ts +++ b/client/src/__tests__/unit-tests/ui/bitbake-recipes-view.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import * as vscode from 'vscode' +import * as vscode from 'coc.nvim' import { type BitbakeRecipeTreeItem, BitbakeRecipesView } from '../../../ui/BitbakeRecipesView' import { BitbakeWorkspace } from '../../../ui/BitbakeWorkspace' import { BitBakeProjectScanner } from '../../../driver/BitBakeProjectScanner' diff --git a/client/src/__tests__/unit-tests/ui/bitbake-terminal-links.test.ts b/client/src/__tests__/unit-tests/ui/bitbake-terminal-links.test.ts index 962f08d27..41f11295d 100644 --- a/client/src/__tests__/unit-tests/ui/bitbake-terminal-links.test.ts +++ b/client/src/__tests__/unit-tests/ui/bitbake-terminal-links.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import * as vscode from 'vscode' +import * as vscode from 'coc.nvim' import { BitbakeTerminalLinkProvider } from '../../../ui/BitbakeTerminalLinkProvider' import { type BitBakeProjectScanner } from '../../../driver/BitBakeProjectScanner' diff --git a/client/src/__tests__/unit-tests/ui/devtool-workspaces-view.test.ts b/client/src/__tests__/unit-tests/ui/devtool-workspaces-view.test.ts index 43011aa31..b7b203788 100644 --- a/client/src/__tests__/unit-tests/ui/devtool-workspaces-view.test.ts +++ b/client/src/__tests__/unit-tests/ui/devtool-workspaces-view.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import * as vscode from 'vscode' +import * as vscode from 'coc.nvim' import { type DevtoolWorkspaceTreeItem, DevtoolWorkspacesView } from '../../../ui/DevtoolWorkspacesView' import { BitBakeProjectScanner } from '../../../driver/BitBakeProjectScanner' import { type BitbakeScanResult } from '../../../lib/src/types/BitbakeScanResult' diff --git a/client/src/__tests__/utils/vscodeMock.ts b/client/src/__tests__/utils/vscodeMock.ts index 2b59e55e6..7d1c43f1d 100644 --- a/client/src/__tests__/utils/vscodeMock.ts +++ b/client/src/__tests__/utils/vscodeMock.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import * as vscode from 'vscode' +import * as vscode from 'coc.nvim' // This sets up a mock that will simulate the firing of vscode events // The events are fired automatically when the event is created diff --git a/client/src/documentLinkProvider.ts b/client/src/documentLinkProvider.ts index b653cfc62..aa2ddb77c 100644 --- a/client/src/documentLinkProvider.ts +++ b/client/src/documentLinkProvider.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import vscode from 'vscode' -import { type LanguageClient } from 'vscode-languageclient/node' +import vscode from 'coc.nvim' +import { type LanguageClient, Uri } from 'coc.nvim' import { RequestMethod, type RequestResult } from './lib/src/types/requests' import { logger } from './lib/src/utils/OutputLogger' import path from 'path' @@ -77,7 +77,7 @@ export class BitbakeDocumentLinkProvider implements vscode.DocumentLinkProvider // Handle files: provide a direct link to the file const fileUri = foundFiles.find(file => this.basenameIsEqual(file.fsPath, link.value)) if (fileUri !== undefined) { - documentLinks.push({ ...new vscode.DocumentLink(link.range, fileUri), tooltip: 'Bitbake: Go to file' }) + documentLinks.push({ ...vscode.DocumentLink.create(link.range, fileUri.toString()), tooltip: 'Bitbake: Go to file' }) continue } @@ -90,7 +90,7 @@ export class BitbakeDocumentLinkProvider implements vscode.DocumentLinkProvider */ const targetUri = vscode.Uri.parse(`command:revealInExplorer?${encodeURIComponent(JSON.stringify(vscode.Uri.parse(foundDir)))}`) // targetUri = vscode.Uri.parse('file://' + foundDir) - documentLinks.push({ ...new vscode.DocumentLink(link.range, targetUri), tooltip: 'Bitbake: Reveal in explorer' }) + documentLinks.push({ ...vscode.DocumentLink.create(link.range, targetUri.toString()), tooltip: 'Bitbake: Reveal in explorer' }) } } @@ -99,6 +99,6 @@ export class BitbakeDocumentLinkProvider implements vscode.DocumentLinkProvider async provideDocumentLinks (document: vscode.TextDocument, token: vscode.CancellationToken): Promise { const linksData = await this.client.sendRequest(RequestMethod.getLinksInDocument, { documentUri: document.uri.toString() }) - return await this.resolveUris(document.uri, linksData, token) + return await this.resolveUris(Uri.parse(document.uri), linksData, token) } } diff --git a/client/src/driver/BitBakeProjectScanner.ts b/client/src/driver/BitBakeProjectScanner.ts index 2bf4ee118..e3054c246 100644 --- a/client/src/driver/BitBakeProjectScanner.ts +++ b/client/src/driver/BitBakeProjectScanner.ts @@ -6,7 +6,7 @@ import find from 'find' import path from 'path' import EventEmitter from 'events' -import * as vscode from 'vscode' +import * as vscode from 'coc.nvim' import { logger } from '../lib/src/utils/OutputLogger' @@ -19,11 +19,11 @@ import type { } from '../lib/src/types/BitbakeScanResult' import { type BitbakeDriver } from './BitbakeDriver' -import { type LanguageClient } from 'vscode-languageclient/node' +import { type LanguageClient } from 'coc.nvim' import fs from 'fs' -import { runBitbakeTerminalCustomCommand } from '../ui/BitbakeTerminal' +// import { runBitbakeTerminalCustomCommand } from '../ui/BitbakeTerminal' import { bitbakeESDKMode } from './BitbakeESDK' -import { finishProcessExecution } from '../utils/ProcessUtils' +// import { finishProcessExecution } from '../utils/ProcessUtils' import { extractRecipeName, extractRecipeVersion } from '../lib/src/utils/files' interface ScannStatus { @@ -245,12 +245,12 @@ export class BitBakeProjectScanner { // Showing a modal here because this can only happend through the command devtool-update-recipe which is not used often if (!quiet) { await vscode.window.showErrorMessage( - 'Bitbake extension couldn\'t locate a file.', { + 'Bitbake extension couldn\'t locate a file.', /* { modal: true, detail: `It looks like you are using the bitbake.commandWrapper setting to use a docker container.\n Couldn't find ${inputPath} corresponding paths inside and outside of the container.\n You should adjust your docker volumes to use the same URIs as those present on your host machine.` - }) + } */) } return resolvedPath } @@ -269,9 +269,10 @@ You should adjust your docker volumes to use the same URIs as those present on y } private async existsInContainer (containerPath: string): Promise { - const process = runBitbakeTerminalCustomCommand(this._bitbakeDriver, 'test -e ' + containerPath, 'BitBake: Test file', true) - const res = finishProcessExecution(process, async () => { await this.bitbakeDriver.killBitbake() }) - return (await res).status === 0 + // const process = runBitbakeTerminalCustomCommand(this._bitbakeDriver, 'test -e ' + containerPath, 'BitBake: Test file', true) + // const res = finishProcessExecution(process, async () => { await this.bitbakeDriver.killBitbake() }) + // return (await res).status === 0 + return true; } private searchFiles (pattern: string): ElementInfo[] { @@ -460,13 +461,14 @@ You should adjust your docker volumes to use the same URIs as those present on y if (this._bitbakeDriver === undefined) { throw new Error('Bitbake driver is not set') } - const result = await finishProcessExecution(runBitbakeTerminalCustomCommand(this._bitbakeDriver, command, 'BitBake: Scan Project', true), - async () => { await this.bitbakeDriver.killBitbake() }) - if (result.status !== 0) { - logger.error(`Failed to execute bitbake command: ${command}`) - throw new Error(`Failed to execute bitbake command: ${command}\r\n${result.stderr.toString()}`) - } - return result.output.toString() + // const result = await finishProcessExecution(runBitbakeTerminalCustomCommand(this._bitbakeDriver, command, 'BitBake: Scan Project', true), + // async () => { await this.bitbakeDriver.killBitbake() }) + // if (result.status !== 0) { + // logger.error(`Failed to execute bitbake command: ${command}`) + // throw new Error(`Failed to execute bitbake command: ${command}\r\n${result.stderr.toString()}`) + // } + // return result.output.toString() + return ""; } } diff --git a/client/src/driver/BitbakeDriver.ts b/client/src/driver/BitbakeDriver.ts index 124146924..e80b4bda1 100644 --- a/client/src/driver/BitbakeDriver.ts +++ b/client/src/driver/BitbakeDriver.ts @@ -9,18 +9,18 @@ import fs from 'fs' import { logger } from '../lib/src/utils/OutputLogger' import { type BitbakeSettings, loadBitbakeSettings, sanitizeForShell, type BitbakeBuildConfigSettings, getBuildSetting } from '../lib/src/BitbakeSettings' import { clientNotificationManager } from '../ui/ClientNotificationManager' -import { type BitbakeTaskDefinition } from '../ui/BitbakeTaskProvider' -import { runBitbakeTerminalCustomCommand } from '../ui/BitbakeTerminal' +// import { type BitbakeTaskDefinition } from '../ui/BitbakeTaskProvider' +// import { runBitbakeTerminalCustomCommand } from '../ui/BitbakeTerminal' import { bitbakeESDKMode, setBitbakeESDKMode } from './BitbakeESDK' -import { BITBAKE_EXIT_TIMEOUT, finishProcessExecution, pty } from '../utils/ProcessUtils' +// import { BITBAKE_EXIT_TIMEOUT, finishProcessExecution, pty } from '../utils/ProcessUtils' -import { type IPty } from 'node-pty' +// import { type IPty } from 'node-pty' /// This class is responsible for wrapping up all bitbake classes and exposing them to the extension export class BitbakeDriver { bitbakeSettings: BitbakeSettings = { pathToBitbakeFolder: '' } activeBuildConfiguration: string = 'No BitBake configuration' - bitbakeProcess: IPty | undefined + bitbakeProcess: /* IPty | */undefined bitbakeProcessCommand: string | undefined onBitbakeProcessChange: EventEmitter = new EventEmitter() @@ -45,32 +45,32 @@ export class BitbakeDriver { } /// Execute a command in the bitbake environment - async spawnBitbakeProcess (command: string): Promise { - const { shell, script } = this.prepareCommand(command) - const cwd = this.getBuildConfig('workingDirectory') - await this.waitForBitbakeToFinish() - logger.debug(`Executing Bitbake command with ${shell} in ${cwd}: ${script}`) - const child = pty.spawn( - shell, - ['-c', script], - { - cwd, - env: { ...process.env, ...this.getBuildConfig('shellEnv') } - } - ) - this.bitbakeProcess = child - this.bitbakeProcessCommand = command - const listener = child.onData(() => { - this.onBitbakeProcessChange.emit('spawn', command) - listener.dispose() - }) - child.onExit(() => { - this.bitbakeProcess = undefined - this.bitbakeProcessCommand = undefined - this.onBitbakeProcessChange.emit('close') - }) - return child - } + // async spawnBitbakeProcess (command: string): Promise { + // const { shell, script } = this.prepareCommand(command) + // const cwd = this.getBuildConfig('workingDirectory') + // await this.waitForBitbakeToFinish() + // logger.debug(`Executing Bitbake command with ${shell} in ${cwd}: ${script}`) + // const child = pty.spawn( + // shell, + // ['-c', script], + // { + // cwd, + // env: { ...process.env, ...this.getBuildConfig('shellEnv') } + // } + // ) + // this.bitbakeProcess = child + // this.bitbakeProcessCommand = command + // const listener = child.onData(() => { + // this.onBitbakeProcessChange.emit('spawn', command) + // listener.dispose() + // }) + // child.onExit(() => { + // this.bitbakeProcess = undefined + // this.bitbakeProcessCommand = undefined + // this.onBitbakeProcessChange.emit('close') + // }) + // return child + // } prepareCommand (command: string): { shell: string @@ -118,56 +118,56 @@ export class BitbakeDriver { // We could test for devtool and bitbake to know if we are in an eSDK or not const command = 'which devtool bitbake || true' - const process = runBitbakeTerminalCustomCommand(this, command, 'Bitbake: Sanity test', true) - const ret = await finishProcessExecution(process, async () => { await this.killBitbake() }) - const outLines = ret.stdout.toString().split(/\r?\n/g) - - if (outLines.filter((line) => /devtool$/.test(line)).length === 0) { - clientNotificationManager.showBitbakeSettingsError('devtool not found in $PATH\nSee Bitbake Terminal for command output.') - return false - } - - if (outLines.filter((line) => /bitbake$/.test(line)).length === 0) { - setBitbakeESDKMode(true) - } else { - setBitbakeESDKMode(false) - } + // const process = runBitbakeTerminalCustomCommand(this, command, 'Bitbake: Sanity test', true) + // const ret = await finishProcessExecution(process, async () => { await this.killBitbake() }) + // const outLines = ret.stdout.toString().split(/\r?\n/g) + + // if (outLines.filter((line: any) => /devtool$/.test(line)).length === 0) { + // clientNotificationManager.showBitbakeSettingsError('devtool not found in $PATH\nSee Bitbake Terminal for command output.') + // return false + // } + // + // if (outLines.filter((line: any) => /bitbake$/.test(line)).length === 0) { + // setBitbakeESDKMode(true) + // } else { + // setBitbakeESDKMode(false) + // } logger.info(`Bitbake settings are sane, eSDK mode: ${bitbakeESDKMode}`) return true } - composeBitbakeCommand (bitbakeTaskDefinition: BitbakeTaskDefinition): string { - if (bitbakeTaskDefinition.specialCommand !== undefined) { - return sanitizeForShell(bitbakeTaskDefinition.specialCommand) as string - } - - const OPTIONS_MAP: Record = { - continue: '-k', - force: '-f', - parseOnly: '-p', - env: '-e' - } - - let command = 'bitbake' - - bitbakeTaskDefinition.recipes?.forEach(recipe => { - command = appendCommandParam(command, `${sanitizeForShell(recipe)}`) - }) - if (bitbakeTaskDefinition.task !== undefined) { - command = appendCommandParam(command, `-c ${sanitizeForShell(bitbakeTaskDefinition.task)}`) - } - const options = bitbakeTaskDefinition.options - if (options !== undefined) { - Object.keys(options).forEach(key => { - if (options[key as keyof BitbakeTaskDefinition['options']] === true) { - command = appendCommandParam(command, OPTIONS_MAP[key as keyof BitbakeTaskDefinition['options']]) - } - }) - } - - return command - } + // composeBitbakeCommand (bitbakeTaskDefinition: BitbakeTaskDefinition): string { + // if (bitbakeTaskDefinition.specialCommand !== undefined) { + // return sanitizeForShell(bitbakeTaskDefinition.specialCommand) as string + // } + // + // const OPTIONS_MAP: Record = { + // continue: '-k', + // force: '-f', + // parseOnly: '-p', + // env: '-e' + // } + // + // let command = 'bitbake' + // + // bitbakeTaskDefinition.recipes?.forEach(recipe => { + // command = appendCommandParam(command, `${sanitizeForShell(recipe)}`) + // }) + // if (bitbakeTaskDefinition.task !== undefined) { + // command = appendCommandParam(command, `-c ${sanitizeForShell(bitbakeTaskDefinition.task)}`) + // } + // const options = bitbakeTaskDefinition.options + // if (options !== undefined) { + // Object.keys(options).forEach(key => { + // if (options[key as keyof BitbakeTaskDefinition['options']] === true) { + // command = appendCommandParam(command, OPTIONS_MAP[key as keyof BitbakeTaskDefinition['options']]) + // } + // }) + // } + // + // return command + // } composeInteractiveCommand (): string { return 'bash' @@ -188,7 +188,7 @@ export class BitbakeDriver { } /// Try to stop bitbake or terminate it after a timeout - async killBitbake (timeout: number = BITBAKE_EXIT_TIMEOUT): Promise { + async killBitbake (timeout: number/* = BITBAKE_EXIT_TIMEOUT */): Promise { if (this.bitbakeProcess === undefined) { logger.warn('Tried to stop bitbake but no process was running') return @@ -199,14 +199,14 @@ export class BitbakeDriver { throw Error('Bitbake process command is undefined') } let processStopped = false - processToStop.onExit(() => { - processStopped = true - logger.debug('Bitbake process successfully terminated') - }) + // processToStop.onExit(() => { + // processStopped = true + // logger.debug('Bitbake process successfully terminated') + // }) // The first SIGINT will wait for current build tasks to complete if (!await this.killDockerContainer(commandToStop)) { - processToStop?.kill('SIGINT') + // processToStop?.kill('SIGINT') } // The second SIGINT will interrupt build tasks after a timeout @@ -214,7 +214,7 @@ export class BitbakeDriver { if (!processStopped) { void this.killDockerContainer(commandToStop).then((result) => { if (!result) { - processToStop.kill('SIGINT') + // processToStop.kill('SIGINT') } }) } @@ -225,7 +225,7 @@ export class BitbakeDriver { if (!processStopped) { void this.killDockerContainer(commandToStop).then((result) => { if (!result) { - processToStop.kill('SIGINT') + // processToStop.kill('SIGINT') } }) } @@ -239,26 +239,26 @@ export class BitbakeDriver { // Our process will look something like this in `ps`: // deribau+ 405680 405597 21 17:13 ? 00:00:00 python3 /home/deribaucourt/Workspace/yocto-vscode/yocto/yocto-build/sources/poky/bitbake/bin/bitbake linux-yocto - const ps = pty.spawn('ps', ['-efwwa'], {}) - const ret = await finishProcessExecution(Promise.resolve(ps)) - - const stdout = ret.stdout.toString() - const lines = stdout.split(/\r?\n/g).slice(1, -1) - let bitbakeProcesses = lines.filter((line) => line.split(/\s+/)[7] === 'python3') - bitbakeProcesses = bitbakeProcesses.filter((line) => line.includes(command)) - logger.debug('Bitbake process: ' + JSON.stringify(bitbakeProcesses)) - - if (bitbakeProcesses.length > 1) { - logger.warn('Multiple bitbake process found. Could not determine which one to stop.') - return false - } - - if (bitbakeProcesses.length === 1) { - const pid = bitbakeProcesses[0].split(/\s+/)[1] - logger.info('Stopping bitbake process with PID: ' + pid) - pty.spawn('kill', ['-s', 'SIGINT', pid], {}) - return true - } + // const ps = pty.spawn('ps', ['-efwwa'], {}) + // const ret = await finishProcessExecution(Promise.resolve(ps)) + // + // const stdout = ret.stdout.toString() + // const lines = stdout.split(/\r?\n/g).slice(1, -1) + // let bitbakeProcesses = lines.filter((line: any) => line.split(/\s+/)[7] === 'python3') + // bitbakeProcesses = bitbakeProcesses.filter((line: any) => line.includes(command)) + // logger.debug('Bitbake process: ' + JSON.stringify(bitbakeProcesses)) + // + // if (bitbakeProcesses.length > 1) { + // logger.warn('Multiple bitbake process found. Could not determine which one to stop.') + // return false + // } + // + // if (bitbakeProcesses.length === 1) { + // const pid = bitbakeProcesses[0].split(/\s+/)[1] + // logger.info('Stopping bitbake process with PID: ' + pid) + // // pty.spawn('kill', ['-s', 'SIGINT', pid], {}) + // return true + // } return false } diff --git a/client/src/driver/BitbakeESDK.ts b/client/src/driver/BitbakeESDK.ts index 0a4450c59..19d4c1950 100644 --- a/client/src/driver/BitbakeESDK.ts +++ b/client/src/driver/BitbakeESDK.ts @@ -9,7 +9,7 @@ import { type DevtoolWorkspaceInfo } from '../lib/src/types/BitbakeScanResult' import { loadJsonFile, setJsonProperty, saveJsonFile, mergeJsonArray } from '../utils/JSONFile' import fs from 'fs' import { logger } from '../lib/src/utils/OutputLogger' -import { type LanguageClient } from 'vscode-languageclient/node' +import { type LanguageClient } from 'coc.nvim' import { getVariableValue } from '../language/languageClient' import { type BitBakeProjectScanner } from './BitBakeProjectScanner' diff --git a/client/src/driver/BitbakeRecipeScanner.ts b/client/src/driver/BitbakeRecipeScanner.ts index 7c589b762..c88af913e 100644 --- a/client/src/driver/BitbakeRecipeScanner.ts +++ b/client/src/driver/BitbakeRecipeScanner.ts @@ -3,11 +3,11 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import * as vscode from 'vscode' -import { type LanguageClient } from 'vscode-languageclient/node' +import * as vscode from 'coc.nvim' +import { type LanguageClient } from 'coc.nvim' import { logger } from '../lib/src/utils/OutputLogger' -import { runBitbakeTask } from '../ui/BitbakeCommands' -import { type BitbakeCustomExecution, type BitbakeTaskProvider } from '../ui/BitbakeTaskProvider' +// import { runBitbakeTask } from '../ui/BitbakeCommands' +// import { type BitbakeCustomExecution, type BitbakeTaskProvider } from '../ui/BitbakeTaskProvider' import { RequestMethod, type RequestParams } from '../lib/src/types/requests' export class BitbakeRecipeScanner implements vscode.Disposable { @@ -16,10 +16,10 @@ export class BitbakeRecipeScanner implements vscode.Disposable { private _languageClient: LanguageClient | undefined private _pendingRecipeScanTasks: vscode.Task | null = null - readonly serverRecipeScanComplete = new vscode.EventEmitter() + // readonly serverRecipeScanComplete = new vscode.EventEmitter() dispose (): void { - this.serverRecipeScanComplete.dispose() + // this.serverRecipeScanComplete.dispose() } /** @@ -30,67 +30,67 @@ export class BitbakeRecipeScanner implements vscode.Disposable { * @param triggeredByCommandPalette If the scan was triggered by the command palette * @returns */ - async scan (chosenRecipe: string, taskProvider: BitbakeTaskProvider, uri: any): Promise { + async scan (chosenRecipe: string, /* taskProvider: BitbakeTaskProvider, */uri: any): Promise { if (chosenRecipe === '') { logger.debug('[BitbakeRecipeScanner] No recipe chosen for scan') return } const taskName = BitbakeRecipeScanner.taskName - const scanRecipeEnvTask = new vscode.Task( - { type: 'bitbake', recipes: [chosenRecipe], uri, options: { parseOnly: true, env: true } }, - vscode.TaskScope.Workspace, - taskName, - 'bitbake' - ) + // const scanRecipeEnvTask = new vscode.Task( + // { type: 'bitbake', recipes: [chosenRecipe], uri, options: { parseOnly: true, env: true } }, + // vscode.TaskScope.Workspace, + // taskName, + // 'bitbake' + // ) - const runningTasks = vscode.tasks.taskExecutions - if (runningTasks.some((execution) => execution.task.name === taskName)) { - logger.debug('[BitbakeRecipeScanner] Recipe scan is already running, pushing to pending tasks') - this._pendingRecipeScanTasks = scanRecipeEnvTask - return - } + // const runningTasks = vscode.tasks.taskExecutions + // if (runningTasks.some((execution) => execution.task.name === taskName)) { + // logger.debug('[BitbakeRecipeScanner] Recipe scan is already running, pushing to pending tasks') + // this._pendingRecipeScanTasks = scanRecipeEnvTask + // return + // } - await runBitbakeTask(scanRecipeEnvTask, taskProvider) + // await runBitbakeTask(scanRecipeEnvTask, taskProvider) // Wait for the task and server side to have done the processing - await new Promise((resolve) => { - const disposable = this.serverRecipeScanComplete.event((uri) => { - if (uri === scanRecipeEnvTask.definition.uri) { - disposable.dispose() - resolve() - } - }) - }) + // await new Promise((resolve) => { + // const disposable = this.serverRecipeScanComplete.event((uri) => { + // if (uri === scanRecipeEnvTask.definition.uri) { + // disposable.dispose() + // resolve() + // } + // }) + // }) } - subscribeToTaskEnd (context: vscode.ExtensionContext, taskProvider: BitbakeTaskProvider): void { - context.subscriptions.push(vscode.tasks.onDidEndTask(async (e) => { - if (e.execution.task.name === 'Bitbake: Scan recipe env') { - const uri = e.execution.task.definition.uri - const chosenRecipe = e.execution.task.definition.recipes[0] - - const executionEngine = e.execution.task.execution as BitbakeCustomExecution - if (executionEngine !== undefined) { - const scanResults = executionEngine.pty?.outputDataString ?? '' - if (this._languageClient === undefined) { - logger.error('[onDidEndTask] Language client not set, unable to forward recipe environment to the server') - } else { - if (scanResults !== '' && uri !== undefined && chosenRecipe !== undefined) { - logger.debug('[onDidEndTask] Sending recipe environment to the server') - const requestParam: RequestParams['ProcessRecipeScanResults'] = { scanResults, uri, chosenRecipe } - await this._languageClient.sendRequest(RequestMethod.ProcessRecipeScanResults, requestParam) - this.serverRecipeScanComplete.fire(uri) - } - } - } - - if (this._pendingRecipeScanTasks !== null) { - logger.debug(`[onDidEndTask] Running the pending recipe scan task. url: ${this._pendingRecipeScanTasks.definition.uri}`) - await runBitbakeTask(this._pendingRecipeScanTasks, taskProvider) - this._pendingRecipeScanTasks = null - } - } - })) + subscribeToTaskEnd (context: vscode.ExtensionContext, /* taskProvider: BitbakeTaskProvider */): void { + // context.subscriptions.push(vscode.tasks.onDidEndTask(async (e) => { + // if (e.execution.task.name === 'Bitbake: Scan recipe env') { + // const uri = e.execution.task.definition.uri + // const chosenRecipe = e.execution.task.definition.recipes[0] + // + // const executionEngine = e.execution.task.execution as BitbakeCustomExecution + // if (executionEngine !== undefined) { + // const scanResults = executionEngine.pty?.outputDataString ?? '' + // if (this._languageClient === undefined) { + // logger.error('[onDidEndTask] Language client not set, unable to forward recipe environment to the server') + // } else { + // if (scanResults !== '' && uri !== undefined && chosenRecipe !== undefined) { + // logger.debug('[onDidEndTask] Sending recipe environment to the server') + // const requestParam: RequestParams['ProcessRecipeScanResults'] = { scanResults, uri, chosenRecipe } + // await this._languageClient.sendRequest(RequestMethod.ProcessRecipeScanResults, requestParam) + // this.serverRecipeScanComplete.fire(uri) + // } + // } + // } + // + // if (this._pendingRecipeScanTasks !== null) { + // logger.debug(`[onDidEndTask] Running the pending recipe scan task. url: ${this._pendingRecipeScanTasks.definition.uri}`) + // await runBitbakeTask(this._pendingRecipeScanTasks, taskProvider) + // this._pendingRecipeScanTasks = null + // } + // } + // })) } setLanguageClient (client: LanguageClient): void { diff --git a/client/src/extension.ts b/client/src/extension.ts index ea159bf66..d06369a40 100644 --- a/client/src/extension.ts +++ b/client/src/extension.ts @@ -3,40 +3,40 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import * as vscode from 'vscode' -import { type LanguageClient } from 'vscode-languageclient/node' +import * as vscode from 'coc.nvim' +import { type LanguageClient, Uri } from 'coc.nvim' import { clientNotificationManager } from './ui/ClientNotificationManager' import { logger } from './lib/src/utils/OutputLogger' import { activateLanguageServer, deactivateLanguageServer } from './language/languageClient' import { BitbakeDriver } from './driver/BitbakeDriver' -import { BitbakeTaskProvider } from './ui/BitbakeTaskProvider' +// import { BitbakeTaskProvider } from './ui/BitbakeTaskProvider' import { registerBitbakeCommands, registerDevtoolCommands } from './ui/BitbakeCommands' import { BitbakeWorkspace } from './ui/BitbakeWorkspace' import { BitbakeRecipesView } from './ui/BitbakeRecipesView' import { BitbakeStatusBar } from './ui/BitbakeStatusBar' import { BitBakeProjectScanner } from './driver/BitBakeProjectScanner' import { BitbakeDocumentLinkProvider } from './documentLinkProvider' -import { DevtoolWorkspacesView } from './ui/DevtoolWorkspacesView' +// import { DevtoolWorkspacesView } from './ui/DevtoolWorkspacesView' import path from 'path' import bitbakeRecipeScanner from './driver/BitbakeRecipeScanner' -import { BitbakeTerminalProfileProvider } from './ui/BitbakeTerminalProfile' -import { BitbakeTerminalLinkProvider } from './ui/BitbakeTerminalLinkProvider' +// import { BitbakeTerminalProfileProvider } from './ui/BitbakeTerminalProfile' +// import { BitbakeTerminalLinkProvider } from './ui/BitbakeTerminalLinkProvider' import { extractRecipeName } from './lib/src/utils/files' import { BitbakeConfigPicker } from './ui/BitbakeConfigPicker' import { scanContainsData } from './lib/src/types/BitbakeScanResult' -import { reviewDiagnostics } from './language/diagnosticsSupport' +// import { reviewDiagnostics } from './language/diagnosticsSupport' let client: LanguageClient const bitbakeDriver: BitbakeDriver = new BitbakeDriver() -let bitbakeTaskProvider: BitbakeTaskProvider +// let bitbakeTaskProvider: BitbakeTaskProvider let taskProvider: vscode.Disposable const bitbakeWorkspace: BitbakeWorkspace = new BitbakeWorkspace() export let bitbakeExtensionContext: vscode.ExtensionContext // eslint-disable-next-line @typescript-eslint/no-unused-vars let bitbakeRecipesView: BitbakeRecipesView | undefined -let devtoolWorkspacesView: DevtoolWorkspacesView | undefined -let terminalProvider: BitbakeTerminalProfileProvider | undefined +// let devtoolWorkspacesView: DevtoolWorkspacesView | undefined +// let terminalProvider: BitbakeTerminalProfileProvider | undefined function loadLoggerSettings (): void { logger.level = vscode.workspace.getConfiguration('bitbake').get('loggingLevel') ?? 'info' @@ -75,89 +75,89 @@ async function disableInteferingSettings (): Promise { } } -async function installExtensions (extensionId: string): Promise { - await vscode.window.showInformationMessage(`The extension ${extensionId} is required for yocto-project.yocto-bitbake to work properly. Do you want to install it?`, 'Install', 'Show extension page', 'Cancel') - .then((item) => { - if (item === 'Install') { - void vscode.window.withProgress({ - location: vscode.ProgressLocation.Notification, - title: `Installing ${extensionId}...`, - cancellable: false - }, async (progress, token) => { - try { - await vscode.commands.executeCommand('workbench.extensions.installExtension', extensionId).then(() => { - progress.report({ message: `${extensionId} has been installed` }) - }) - } catch (error) { - await vscode.window.showErrorMessage(`Failed to install ${extensionId}: ${JSON.stringify(error)}`) - } - }) - } else if (item === 'Show extension page') { - void vscode.commands.executeCommand('extension.open', extensionId) - } - }) -} +// async function installExtensions (extensionId: string): Promise { +// await vscode.window.showInformationMessage(`The extension ${extensionId} is required for yocto-project.yocto-bitbake to work properly. Do you want to install it?`, 'Install', 'Show extension page', 'Cancel') +// .then((item) => { +// if (item === 'Install') { +// void vscode.window.withProgress({ +// location: vscode.ProgressLocation.Notification, +// title: `Installing ${extensionId}...`, +// cancellable: false +// }, async (progress, token) => { +// try { +// await vscode.commands.executeCommand('workbench.extensions.installExtension', extensionId).then(() => { +// progress.report({ message: `${extensionId} has been installed` }) +// }) +// } catch (error) { +// await vscode.window.showErrorMessage(`Failed to install ${extensionId}: ${JSON.stringify(error)}`) +// } +// }) +// } else if (item === 'Show extension page') { +// void vscode.commands.executeCommand('extension.open', extensionId) +// } +// }) +// } export async function activate (context: vscode.ExtensionContext): Promise { - const requiredExtensions = [ - 'mads-hartmann.bash-ide-vscode', // https://marketplace.visualstudio.com/items?itemName=mads-hartmann.bash-ide-vscode - 'ms-python.python' // https://marketplace.visualstudio.com/items?itemName=ms-python.python - ] - - for (const extensionId of requiredExtensions) { - // mads-hartmann.bash-ide-vscode is not currently available in the web version of VSCode, thus do not install it - if (vscode.extensions.getExtension(extensionId) === undefined && vscode.env.uiKind !== vscode.UIKind.Web) { - await installExtensions(extensionId) - } - } + // const requiredExtensions = [ + // 'mads-hartmann.bash-ide-vscode', // https://marketplace.visualstudio.com/items?itemName=mads-hartmann.bash-ide-vscode + // 'ms-python.python' // https://marketplace.visualstudio.com/items?itemName=ms-python.python + // ] + // + // for (const extensionId of requiredExtensions) { + // // mads-hartmann.bash-ide-vscode is not currently available in the web version of VSCode, thus do not install it + // if (vscode.extensions.getExtension(extensionId) === undefined && vscode.env.uiKind !== vscode.UIKind.Web) { + // await installExtensions(extensionId) + // } + // } logger.outputChannel = vscode.window.createOutputChannel('BitBake') loadLoggerSettings() bitbakeExtensionContext = context logger.debug('Loaded bitbake workspace settings: ' + JSON.stringify(vscode.workspace.getConfiguration('bitbake'))) - bitbakeDriver.loadSettings(vscode.workspace.getConfiguration('bitbake'), vscode.workspace.workspaceFolders?.[0].uri.fsPath) + bitbakeDriver.loadSettings(vscode.workspace.getConfiguration('bitbake'), Uri.parse(vscode.workspace.workspaceFolders?.[0].uri).fsPath) const bitBakeProjectScanner: BitBakeProjectScanner = new BitBakeProjectScanner(bitbakeDriver) updatePythonPath() await disableInteferingSettings() bitbakeWorkspace.loadBitbakeWorkspace(context.workspaceState) - bitbakeTaskProvider = new BitbakeTaskProvider(bitbakeDriver) + // bitbakeTaskProvider = new BitbakeTaskProvider(bitbakeDriver) client = await activateLanguageServer(context, bitBakeProjectScanner) bitBakeProjectScanner.setClient(client) - taskProvider = vscode.tasks.registerTaskProvider('bitbake', bitbakeTaskProvider) + // taskProvider = vscode.tasks.registerTaskProvider('bitbake', bitbakeTaskProvider) context.subscriptions.push(bitbakeRecipeScanner) bitbakeRecipeScanner.setLanguageClient(client) - bitbakeRecipeScanner.subscribeToTaskEnd(context, bitbakeTaskProvider) - context.subscriptions.push( - bitbakeRecipeScanner.serverRecipeScanComplete.event(reviewDiagnostics) - ) + // bitbakeRecipeScanner.subscribeToTaskEnd(context, bitbakeTaskProvider) + // context.subscriptions.push( + // bitbakeRecipeScanner.serverRecipeScanComplete.event(reviewDiagnostics) + // ) clientNotificationManager.setMemento(context.workspaceState) bitbakeRecipesView = new BitbakeRecipesView(bitbakeWorkspace, bitBakeProjectScanner) bitbakeRecipesView.registerView(context) - devtoolWorkspacesView = new DevtoolWorkspacesView(bitBakeProjectScanner) - devtoolWorkspacesView.registerView(context) - void vscode.commands.executeCommand('setContext', 'bitbake.active', true) + // devtoolWorkspacesView = new DevtoolWorkspacesView(bitBakeProjectScanner) + // devtoolWorkspacesView.registerView(context) + // void vscode.commands.executeCommand('setContext', 'bitbake.active', true) const bitbakeStatusBar = new BitbakeStatusBar(bitBakeProjectScanner) context.subscriptions.push(bitbakeStatusBar.statusBarItem) const bitbakeConfigPicker = new BitbakeConfigPicker(bitbakeDriver.bitbakeSettings, context) context.subscriptions.push(bitbakeConfigPicker.statusBarItem) bitbakeDriver.activeBuildConfiguration = bitbakeConfigPicker.activeBuildConfiguration - terminalProvider = new BitbakeTerminalProfileProvider(bitbakeDriver) - vscode.window.registerTerminalProfileProvider('bitbake.terminal', terminalProvider) - const terminalLinkProvider = new BitbakeTerminalLinkProvider(bitBakeProjectScanner) - vscode.window.registerTerminalLinkProvider(terminalLinkProvider) + // terminalProvider = new BitbakeTerminalProfileProvider(bitbakeDriver) + // vscode.window.registerTerminalProfileProvider('bitbake.terminal', terminalProvider) + // const terminalLinkProvider = new BitbakeTerminalLinkProvider(bitBakeProjectScanner) + // vscode.window.registerTerminalLinkProvider(terminalLinkProvider) const provider = new BitbakeDocumentLinkProvider(client) const selector = { scheme: 'file', language: 'bitbake' } - context.subscriptions.push(vscode.languages.registerDocumentLinkProvider(selector, provider)) + context.subscriptions.push(vscode.languages.registerDocumentLinkProvider([selector], provider)) // Handle settings change for bitbake driver context.subscriptions.push(vscode.workspace.onDidChangeConfiguration(async (event) => { const currentSettings = vscode.workspace.getConfiguration('bitbake') - bitbakeDriver.loadSettings(currentSettings, vscode.workspace.workspaceFolders?.[0].uri.fsPath) + bitbakeDriver.loadSettings(currentSettings, Uri.parse(vscode.workspace.workspaceFolders?.[0].uri).fsPath) if (event.affectsConfiguration('bitbake.shellEnv') || event.affectsConfiguration('bitbake.workingDirectory') || event.affectsConfiguration('bitbake.pathToEnvScript') || @@ -182,24 +182,24 @@ export async function activate (context: vscode.ExtensionContext): Promise context.subscriptions.push(vscode.workspace.onDidChangeWorkspaceFolders((event) => { logger.debug('Bitbake workspace changed: ' + JSON.stringify(event)) loadLoggerSettings() - bitbakeDriver.loadSettings(vscode.workspace.getConfiguration('bitbake'), vscode.workspace.workspaceFolders?.[0].uri.fsPath) + bitbakeDriver.loadSettings(vscode.workspace.getConfiguration('bitbake'), Uri.parse(vscode.workspace.workspaceFolders?.[0].uri).fsPath) bitbakeConfigPicker.updateStatusBar(bitbakeDriver.bitbakeSettings) updatePythonPath() bitbakeWorkspace.loadBitbakeWorkspace(context.workspaceState) })) - context.subscriptions.push(bitbakeConfigPicker.onActiveConfigChanged.event((config) => { - bitbakeDriver.activeBuildConfiguration = config - // Re-scaning here would be very cumbersome, the user should do it manually if desired - })) + // context.subscriptions.push(bitbakeConfigPicker.onActiveConfigChanged.event((config: any) => { + // bitbakeDriver.activeBuildConfiguration = config + // // Re-scaning here would be very cumbersome, the user should do it manually if desired + // })) // Check if the document that was just closed was the last one for a recipe context.subscriptions.push(vscode.workspace.onDidCloseTextDocument((document: vscode.TextDocument) => { const ext = ['.bb', '.bbappend', '.inc'] - const { fsPath } = document.uri + const { fsPath } = Uri.parse(document.uri) if (ext.includes(path.extname(fsPath))) { const recipeName = extractRecipeName(fsPath) const recipeFile = vscode.window.visibleTextEditors.find((editor) => { - return ext.includes(path.extname(editor.document.uri.fsPath)) && extractRecipeName(editor.document.uri.fsPath) === recipeName + return ext.includes(path.extname(Uri.parse(editor.document.uri).fsPath)) && extractRecipeName(Uri.parse(editor.document.uri).fsPath) === recipeName }) if (recipeFile === undefined) { logger.debug(`No files related to the recipe ${recipeName}, sending notification to remove scan results`) @@ -208,7 +208,7 @@ export async function activate (context: vscode.ExtensionContext): Promise } })) - registerBitbakeCommands(context, bitbakeWorkspace, bitbakeTaskProvider, bitBakeProjectScanner, terminalProvider, client) + registerBitbakeCommands(context, bitbakeWorkspace, /* bitbakeTaskProvider, */bitBakeProjectScanner, /* terminalProvider, */client) registerDevtoolCommands(context, bitbakeWorkspace, bitBakeProjectScanner, client) logger.info('Congratulations, your extension "BitBake" is now active!') @@ -216,12 +216,12 @@ export async function activate (context: vscode.ExtensionContext): Promise void vscode.commands.executeCommand('bitbake.rescan-project') } -export function deactivate (): Thenable | undefined { +export function deactivate (): Promise | undefined { // The server has to be handled before the disposables. // Otherwise it might attempt to use anything that has been disposed. return deactivateLanguageServer(client) .then(() => { - taskProvider.dispose() + // taskProvider.dispose() logger.outputChannel?.dispose() }) } diff --git a/client/src/language/EmbeddedLanguageDocsManager.ts b/client/src/language/EmbeddedLanguageDocsManager.ts index c580ac700..57233c716 100644 --- a/client/src/language/EmbeddedLanguageDocsManager.ts +++ b/client/src/language/EmbeddedLanguageDocsManager.ts @@ -8,7 +8,7 @@ import fs from 'fs' import { type EmbeddedLanguageDoc, type EmbeddedLanguageType } from '../lib/src/types/embedded-languages' import { logger } from '../lib/src/utils/OutputLogger' -import { Range, Uri, WorkspaceEdit, workspace } from 'vscode' +import { Range, Uri, WorkspaceEdit, workspace } from 'coc.nvim' import { hashString } from '../lib/src/utils/hash' const EMBEDDED_DOCUMENTS_FOLDER = 'embedded-documents' @@ -120,20 +120,20 @@ export default class EmbeddedLanguageDocsManager { private async updateEmbeddedLanguageDocFile (embeddedLanguageDoc: EmbeddedLanguageDoc, uri: Uri): Promise { const document = await workspace.openTextDocument(uri) - if (document.isDirty) { - this.filesWaitingToUpdate.set(uri.toString(), embeddedLanguageDoc) - return - } - const fullRange = new Range( - document.positionAt(0), - document.positionAt(document.getText().length) - ) - const workspaceEdit = new WorkspaceEdit() - workspaceEdit.replace(uri, fullRange, embeddedLanguageDoc.content) - await workspace.applyEdit(workspaceEdit) - // Sometimes document closes before the saving, so we open it again just in case - await workspace.openTextDocument(uri) - await document.save() + // if (document.isDirty) { + // this.filesWaitingToUpdate.set(uri.toString(), embeddedLanguageDoc) + // return + // } + // const fullRange = Range.create( + // document.positionAt(0), + // document.positionAt(document.getText().length) + // ) + // const workspaceEdit = new WorkspaceEdit() + // workspaceEdit.replace(uri, fullRange, embeddedLanguageDoc.content) + // await workspace.applyEdit(workspaceEdit) + // // Sometimes document closes before the saving, so we open it again just in case + // await workspace.openTextDocument(uri) + // await document.save() this.registerEmbeddedLanguageDocInfos(embeddedLanguageDoc, uri) const fileWaitingToUpdate = this.filesWaitingToUpdate.get(uri.toString()) if (fileWaitingToUpdate !== undefined) { @@ -148,7 +148,7 @@ export default class EmbeddedLanguageDocsManager { return undefined } try { - await workspace.fs.writeFile(uri, Buffer.from(embeddedLanguageDoc.content)) + // await workspace.fs.writeFile(uri, Buffer.from(embeddedLanguageDoc.content)) await workspace.openTextDocument(uri) } catch (err) { logger.error(`Failed to create embedded document: ${err as any}`) diff --git a/client/src/language/RequestManager.ts b/client/src/language/RequestManager.ts index aa438b9cc..ad29dd99e 100644 --- a/client/src/language/RequestManager.ts +++ b/client/src/language/RequestManager.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import { type Position } from 'vscode' -import { type LanguageClient } from 'vscode-languageclient/node' +import { type Position } from 'coc.nvim' +import { type LanguageClient } from 'coc.nvim' import { RequestMethod, type RequestParams, type RequestResult } from '../lib/src/types/requests' import { getAllVariableValues } from './languageClient' diff --git a/client/src/language/codeActionProvider.ts b/client/src/language/codeActionProvider.ts deleted file mode 100644 index 86d78d386..000000000 --- a/client/src/language/codeActionProvider.ts +++ /dev/null @@ -1,113 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import vscode from 'vscode' -import { requestsManager } from './RequestManager' -import { embeddedLanguageDocsManager } from './EmbeddedLanguageDocsManager' -import { getEmbeddedLanguageDocRange, getOriginalDocPosition } from './utils/embeddedLanguagesUtils' -import { logger } from '../lib/src/utils/OutputLogger' -import { type Range } from 'vscode-languageclient' -import { type EmbeddedLanguageType } from '../lib/src/types/embedded-languages' -import { getIndentationOnLine } from './utils/textDocumentUtils' - -export class BitbakeCodeActionProvider implements vscode.CodeActionProvider { - async provideCodeActions (document: vscode.TextDocument, range: vscode.Range | vscode.Selection, context: vscode.CodeActionContext, token: vscode.CancellationToken): Promise { - const diagnostics = context.diagnostics - const actions = await Promise.all( - diagnostics.map(async (diagnostic) => await buildActionFromDiagnostic(document, diagnostic)) - ).then((results) => results.flat()) - return actions - } -} - -const buildActionFromDiagnostic = async (document: vscode.TextDocument, diagnostic: vscode.Diagnostic): Promise => { - const originalRange = diagnostic.range - const embeddedLanguageType = await requestsManager.getEmbeddedLanguageTypeOnPosition(document.uri.toString(), originalRange.start) - if (embeddedLanguageType === undefined || embeddedLanguageType === null) { - // We currently do not provide fixes for the Bitbake language, we only forwards embedded language fixes - return [] - } else { - return await buildActionFromEmbeddedLanguageDiagnostic(document, originalRange, embeddedLanguageType) - } -} - -const buildActionFromEmbeddedLanguageDiagnostic = async ( - document: vscode.TextDocument, - originalRange: vscode.Range, - embeddedLanguageType: EmbeddedLanguageType -): Promise => { - const embeddedLanguageDocInfos = embeddedLanguageDocsManager.getEmbeddedLanguageDocInfos(document.uri, embeddedLanguageType) - if (embeddedLanguageDocInfos === undefined || embeddedLanguageDocInfos === null) { - return [] - } - const embeddedLanguageTextDocument = await vscode.workspace.openTextDocument(embeddedLanguageDocInfos.uri) - const embeddedRange = getEmbeddedLanguageDocRange( - document, - embeddedLanguageTextDocument, - embeddedLanguageDocInfos.characterIndexes, - originalRange - ) - - const tempActions = await vscode.commands.executeCommand( - 'vscode.executeCodeActionProvider', - embeddedLanguageDocInfos.uri, - embeddedRange - ) - - const actions: vscode.CodeAction[] = [] - tempActions.forEach((action) => { - switch (action.command?.command) { - case 'python.addImport': - handlePythonAddImport(action, document, embeddedLanguageTextDocument, embeddedLanguageDocInfos.characterIndexes) - break - default: - return - } - actions.push(action) - }) - - return actions -} - -type PythonAddImportArguments = [ - path: string, - range: Range, - targetName: string, - moduleName: string | null, -] -const handlePythonAddImport = ( - action: vscode.CodeAction, - originalTextDocument: vscode.TextDocument, - embeddedLanguageTextDocument: vscode.TextDocument, - characterIndexes: number[] -): void => { - if (action.command === undefined) { - return - } - if (action.command?.command !== 'python.addImport') { - logger.error(`[handlePythonAddImport] Invalid command ${action.command?.command} (should be 'python.addImport')`) - return - } - const [, range, targetName, moduleName] = action.command?.arguments as PythonAddImportArguments - const originalStartPosition = getOriginalDocPosition( - originalTextDocument, - embeddedLanguageTextDocument, - characterIndexes, - new vscode.Position(range.start.line, range.start.character) - ) - if (originalStartPosition === undefined) { - return - } - const indentationOnLine = getIndentationOnLine(originalTextDocument, originalStartPosition.line) - const moduleSpecification = moduleName !== null ? `from ${moduleName} ` : '' - const workspaceEdit = new vscode.WorkspaceEdit() - workspaceEdit.insert( - originalTextDocument.uri, - new vscode.Position(originalStartPosition.line, 0), - `${indentationOnLine}${moduleSpecification}import ${targetName}\n` - ) - delete action.command - action.edit = workspaceEdit -} diff --git a/client/src/language/diagnosticsSupport.ts b/client/src/language/diagnosticsSupport.ts deleted file mode 100644 index 332ffdc68..000000000 --- a/client/src/language/diagnosticsSupport.ts +++ /dev/null @@ -1,128 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import * as vscode from 'vscode' - -import { getOriginalDocRange } from './utils/embeddedLanguagesUtils' -import { embeddedLanguageDocsManager } from './EmbeddedLanguageDocsManager' -import { type EmbeddedLanguageType } from '../lib/src/types/embedded-languages' -import { requestsManager } from '../language/RequestManager' -import path from 'path' -import { extractRecipeName } from '../lib/src/utils/files' -import { logger } from '../lib/src/utils/OutputLogger' -import { commonDirectoriesVariables } from '../lib/src/availableVariables' - -const diagnosticCollections = { - bash: vscode.languages.createDiagnosticCollection('bitbake-bash'), - python: vscode.languages.createDiagnosticCollection('bitbake-python') -} - -// Create diagnostics for an "original document" from the diagnostics of its "embedded language documents" -// It ignores the uris for documents that are not "embedded language documents" -export const updateDiagnostics = async (uri: vscode.Uri): Promise => { - logger.debug(`[updateDiagnostics] for uri: ${uri.toString()}`) - const embeddedLanguageType = getEmbeddedLanguageType(uri) - if (embeddedLanguageType === undefined) { - return - } - const originalUri = embeddedLanguageDocsManager.getOriginalUri(uri) - if (originalUri === undefined) { - return - } - const originalTextDocument = vscode.workspace.textDocuments.find((textDocument) => textDocument.uri.toString() === originalUri.toString()) - if (originalTextDocument === undefined) { - // The original TextDocument is probably closed. Thus the user would not see the diagnostics anyway. - // We don't attempt to reopen it. We were previously doing so, and it was causing trouble. Here what we assume was going on: - // At first everything looked fine, but it became an issue when too many files had been opened (around thirty). - // The oldest files were being "garbage collected", then immediately reopened, which would cause the next oldest files to be "garbage collected", and so on. - // The whole thing would create lot of flickering in the diagnostics, and make the extension slow. - return - } - - const embeddedLanguageDocInfos = embeddedLanguageDocsManager.getEmbeddedLanguageDocInfos( - originalTextDocument.uri, - embeddedLanguageType - ) - if (embeddedLanguageDocInfos === undefined) { - return - } - const embeddedLanguageDoc = await vscode.workspace.openTextDocument(embeddedLanguageDocInfos.uri.fsPath) - const dirtyDiagnostics = vscode.languages.getDiagnostics(embeddedLanguageDocInfos.uri) - const cleanDiagnostics: vscode.Diagnostic[] = [] - const diagnosticCollection = diagnosticCollections[embeddedLanguageType] - - const recipe = extractRecipeName(originalUri.fsPath) - const variableValues = await requestsManager.getAllVariableValues(recipe) - - await Promise.all(dirtyDiagnostics.map(async (diagnostic) => { - if (await checkIsIgnoredShellcheckSc2154(diagnostic, variableValues)) { - return - } - if (diagnostic.range === undefined) { - cleanDiagnostics.push(diagnostic) - } - const newRange = getOriginalDocRange( - originalTextDocument, - embeddedLanguageDoc, - embeddedLanguageDocInfos.characterIndexes, - diagnostic.range - ) - if (newRange === undefined) { - return - } - const newDiagnostic = { - ...diagnostic, - range: newRange, - source: `${diagnostic.source}, ${diagnosticCollection.name}` - } - cleanDiagnostics.push(newDiagnostic) - })) - diagnosticCollection.set(originalTextDocument.uri, cleanDiagnostics) -} - -// Regenerate diagnostics for all "original documents" that already have diagnostics -// This is intended to be called when a new scan finished, so diagnostics can be updated with the available information. -export const reviewDiagnostics = async (): Promise => { - logger.debug('[reviewDiagnostics]') - const allDiagnostics = vscode.languages.getDiagnostics() - await Promise.all(allDiagnostics.map(async ([uri, _diagnostics]): Promise => { - // uri might be for an "original document", an "embedded language document", and even something else. - // updateDiagnostics ignores the uris that are not for an "embedded language documents" - await updateDiagnostics(uri) - })) -} - -const getEmbeddedLanguageType = (uri: vscode.Uri): EmbeddedLanguageType | undefined => { - const fileExtension = path.extname(uri.fsPath) - if (fileExtension === '.py') { - return 'python' - } - if (fileExtension === '.sh') { - return 'bash' - } - return undefined -} - -const checkIsIgnoredShellcheckSc2154 = async ( - diagnostic: vscode.Diagnostic, - variablevalues: Array<{ name: string, value: string }> | undefined -): Promise => { - if (diagnostic.source?.includes('shellcheck') !== true && diagnostic.code !== 'SC2154') { - return false - } - const message = diagnostic.message - const match = message.match(/^(?\w+) is referenced but not assigned\.$/) - const variableName = match?.groups?.variableName - if (variableName === undefined) { - return false - } - - if (variablevalues === undefined) { - // We use a static list of common directories as fallback when the scan is not done - return commonDirectoriesVariables.has(variableName) - } - - return variablevalues.some((variable) => variable.name === variableName) -} diff --git a/client/src/language/languageClient.ts b/client/src/language/languageClient.ts index 378e3d861..912aee9fe 100644 --- a/client/src/language/languageClient.ts +++ b/client/src/language/languageClient.ts @@ -11,29 +11,29 @@ import { window, commands, languages, - TabInputText, + // TabInputText, Uri -} from 'vscode' +} from 'coc.nvim' import { LanguageClient, type LanguageClientOptions, TransportKind, type ServerOptions -} from 'vscode-languageclient/node' -import { middlewareProvideCompletion } from './middlewareCompletion' -import { middlewareProvideHover } from './middlewareHover' +} from 'coc.nvim' +// import { middlewareProvideCompletion } from './middlewareCompletion' +// import { middlewareProvideHover } from './middlewareHover' import { requestsManager } from './RequestManager' -import { middlewareProvideDefinition } from './middlewareDefinition' +// import { middlewareProvideDefinition } from './middlewareDefinition' import { embeddedLanguageDocsManager } from './EmbeddedLanguageDocsManager' import { logger } from '../lib/src/utils/OutputLogger' import { NotificationMethod, type NotificationParams } from '../lib/src/types/notifications' -import { updateDiagnostics } from './diagnosticsSupport' -import { getLanguageConfiguration } from './languageConfiguration' -import { BitbakeCodeActionProvider } from './codeActionProvider' +// import { updateDiagnostics } from './diagnosticsSupport' +// import { getLanguageConfiguration } from './languageConfiguration' +// import { BitbakeCodeActionProvider } from './codeActionProvider' import { type BitBakeProjectScanner } from '../driver/BitBakeProjectScanner' -import * as vscode from 'vscode' -import { middlewareProvideReferences } from './middlewareReferences' +import * as vscode from 'coc.nvim' +// import { middlewareProvideReferences } from './middlewareReferences' export async function activateLanguageServer (context: ExtensionContext, bitBakeProjectScanner: BitBakeProjectScanner): Promise { const serverModule = context.asAbsolutePath(path.join('server', 'server.js')) @@ -63,31 +63,31 @@ export async function activateLanguageServer (context: ExtensionContext, bitBake initializationOptions: { extensionPath: context.extensionPath }, - middleware: { - provideCompletionItem: middlewareProvideCompletion, - provideDefinition: middlewareProvideDefinition, - provideHover: middlewareProvideHover, - provideReferences: middlewareProvideReferences - } + // middleware: { + // provideCompletionItem: middlewareProvideCompletion, + // provideDefinition: middlewareProvideDefinition, + // provideHover: middlewareProvideHover, + // provideReferences: middlewareProvideReferences + // } } - languages.setLanguageConfiguration('bitbake', getLanguageConfiguration()) - - languages.onDidChangeDiagnostics(e => { - e.uris.forEach(uri => { - void updateDiagnostics(uri) - }) - }) - - context.subscriptions.push( - languages.registerCodeActionsProvider('bitbake', new BitbakeCodeActionProvider()) - ) - - if (context.storageUri?.fsPath === undefined) { - logger.error('Failed to get storage path') - } else { - await embeddedLanguageDocsManager.setStoragePath(context.storageUri.fsPath) - } + // languages.setLanguageConfiguration('bitbake', getLanguageConfiguration()) + // + // languages.onDidChangeDiagnostics(e => { + // e.uris.forEach(uri => { + // void updateDiagnostics(uri) + // }) + // }) + // + // context.subscriptions.push( + // languages.registerCodeActionsProvider('bitbake', new BitbakeCodeActionProvider()) + // ) + // + // if (context.storageUri?.fsPath === undefined) { + // logger.error('Failed to get storage path') + // } else { + // await embeddedLanguageDocsManager.setStoragePath(context.storageUri.fsPath) + // } // Create the language client and start the client. const client: LanguageClient = new LanguageClient('bitbake', 'Bitbake Language Server', serverOptions, clientOptions) @@ -126,27 +126,27 @@ export async function activateLanguageServer (context: ExtensionContext, bitBake void embeddedLanguageDocsManager.saveEmbeddedLanguageDocs(embeddedLanguageDocs) }) - window.tabGroups.onDidChangeTabs((event) => { - [...event.opened, ...event.changed].forEach((tab) => { - if (tab.input instanceof TabInputText) { - const uri = tab.input.uri - if (embeddedLanguageDocsManager.embeddedLanguageDocsFolder === undefined) { - return - } - // Close embedded document tabs when they open automatically - if (uri.fsPath.includes(embeddedLanguageDocsManager.embeddedLanguageDocsFolder)) { - if ( - // Prevent prompt to appear on unsaved files - !tab.isDirty && - // Make possible to open embedded documents in a tab - !tab.isPreview && !tab.isActive && !tab.isPinned - ) { - void window.tabGroups.close(tab, false) - } - } - } - }) - }) + // window.tabGroups.onDidChangeTabs((event) => { + // [...event.opened, ...event.changed].forEach((tab) => { + // if (tab.input instanceof TabInputText) { + // const uri = tab.input.uri + // if (embeddedLanguageDocsManager.embeddedLanguageDocsFolder === undefined) { + // return + // } + // // Close embedded document tabs when they open automatically + // if (uri.fsPath.includes(embeddedLanguageDocsManager.embeddedLanguageDocsFolder)) { + // if ( + // // Prevent prompt to appear on unsaved files + // !tab.isDirty && + // // Make possible to open embedded documents in a tab + // !tab.isPreview && !tab.isActive && !tab.isPinned + // ) { + // void window.tabGroups.close(tab, false) + // } + // } + // } + // }) + // }) // Start the client and launch the server await client.start() @@ -176,7 +176,7 @@ export async function getScanResult< if ((value === undefined || value === null) && canTriggerScan) { // We may not have scanned the recipe yet. Let's try again. const progressOptions: vscode.ProgressOptions = { - location: vscode.ProgressLocation.Notification, + // location: vscode.ProgressLocation.Notification, title: `Recipe ${params.recipe} has not been scanned yet. Scanning now...`, cancellable: false } diff --git a/client/src/language/languageConfiguration.ts b/client/src/language/languageConfiguration.ts deleted file mode 100644 index c47f82400..000000000 --- a/client/src/language/languageConfiguration.ts +++ /dev/null @@ -1,123 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import { IndentAction, type LanguageConfiguration } from 'vscode' -import { verboseRegExp } from '../lib/src/utils/regexp' - -export function getLanguageConfiguration (): LanguageConfiguration { - return { - // These rules are from vscode-python extension. We assume Python rules won't interfere into bash code or regular BitBake code. - // The comments are also from vscode-python, and refer to issues on its repository. - // https://github.com/microsoft/vscode-python/blob/63cf2633919f694bf62e104129f050f8a0a3f85b/src/client/language/languageConfiguration.ts - onEnterRules: [ - // multi-line separator - { - beforeText: verboseRegExp(` - ^ - (?! \\s+ \\\\ ) - [^#\n]+ - \\\\ - $ - `), - action: { - indentAction: IndentAction.Indent - } - }, - // continue comments - { - beforeText: /^\s*#.*/, - afterText: /.+$/, - action: { - indentAction: IndentAction.None, - appendText: '# ' - } - }, - // indent on enter (block-beginning statements) - { - /** - * This does not handle all cases. However, it does handle nearly all usage. - * Here's what it does not cover: - * - the statement is split over multiple lines (and hence the ":" is on a different line) - * - the code block is inlined (after the ":") - * - there are multiple statements on the line (separated by semicolons) - * Also note that `lambda` is purposefully excluded. - */ - beforeText: verboseRegExp(` - ^ - \\s* - (?: - (?: - (?: - class | - def | - async \\s+ def | - except | - for | - async \\s+ for | - if | - elif | - while | - with | - async \\s+ with | - match | - case - ) - \\b .* - ) | - else | - try | - finally - ) - \\s* - [:] - \\s* - (?: [#] .* )? - $ - `), - action: { - indentAction: IndentAction.Indent - } - }, - // outdent on enter (block-ending statements) - { - /** - * This does not handle all cases. Notable omissions here are - * "return" and "raise" which are complicated by the need to - * only outdent when the cursor is at the end of an expression - * rather than, say, between the parentheses of a tail-call or - * exception construction. (see issue #10583) - */ - beforeText: verboseRegExp(` - ^ - (?: - (?: - \\s* - (?: - pass - ) - ) | - (?: - \\s+ - (?: - raise | - break | - continue - ) - ) - ) - \\s* - (?: [#] .* )? - $ - `), - action: { - indentAction: IndentAction.Outdent - } - } - // Note that we do not currently have an auto-dedent - // solution for "elif", "else", "except", and "finally". - // We had one but had to remove it (see issue #6886). - ] - } -} diff --git a/client/src/language/middlewareCompletion.ts b/client/src/language/middlewareCompletion.ts deleted file mode 100644 index 8f74b61f5..000000000 --- a/client/src/language/middlewareCompletion.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import { CompletionList, commands, Range, workspace } from 'vscode' -import { type CompletionMiddleware } from 'vscode-languageclient/node' - -import { requestsManager } from './RequestManager' -import { getEmbeddedLanguageDocPosition, getOriginalDocRange } from './utils/embeddedLanguagesUtils' -import { embeddedLanguageDocsManager } from './EmbeddedLanguageDocsManager' -import { mergeArraysDistinctly } from '../lib/src/utils/arrays' - -export const middlewareProvideCompletion: CompletionMiddleware['provideCompletionItem'] = async (document, position, context, token, next) => { - const nextResult = await next(document, position, context, token) ?? [] - - const embeddedLanguageType = await requestsManager.getEmbeddedLanguageTypeOnPosition(document.uri.toString(), position) - if (embeddedLanguageType === undefined || embeddedLanguageType === null) { - return nextResult - } - const embeddedLanguageDocInfos = embeddedLanguageDocsManager.getEmbeddedLanguageDocInfos(document.uri, embeddedLanguageType) - if (embeddedLanguageDocInfos === undefined || embeddedLanguageDocInfos === null) { - return - } - const embeddedLanguageTextDocument = await workspace.openTextDocument(embeddedLanguageDocInfos.uri) - const adjustedPosition = getEmbeddedLanguageDocPosition( - document, - embeddedLanguageTextDocument, - embeddedLanguageDocInfos.characterIndexes, - position - ) - const vdocUri = embeddedLanguageTextDocument.uri - const pulledCompletionList = await commands.executeCommand( - 'vscode.executeCompletionItemProvider', - vdocUri, - adjustedPosition, - context.triggerCharacter - ) - pulledCompletionList.items.forEach((item) => { - if (item.range === undefined) { - // pass - } else if (item.range instanceof Range) { - item.range = getOriginalDocRange(document, embeddedLanguageTextDocument, embeddedLanguageDocInfos.characterIndexes, item.range) - } else { - const inserting = getOriginalDocRange(document, embeddedLanguageTextDocument, embeddedLanguageDocInfos.characterIndexes, item.range.inserting) - const replacing = getOriginalDocRange(document, embeddedLanguageTextDocument, embeddedLanguageDocInfos.characterIndexes, item.range.replacing) - if (inserting === undefined || replacing === undefined) { - return - } - item.range = { inserting, replacing } - } - }) - return mergeArraysDistinctly( - (completionItem) => completionItem.label, - pulledCompletionList.items, - nextResult instanceof CompletionList ? nextResult.items : nextResult - ) -} diff --git a/client/src/language/middlewareDefinition.ts b/client/src/language/middlewareDefinition.ts deleted file mode 100644 index 9b6acd0db..000000000 --- a/client/src/language/middlewareDefinition.ts +++ /dev/null @@ -1,159 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import { Location, Position, Range, commands, type LocationLink, type TextDocument, workspace } from 'vscode' -import { type DefinitionMiddleware } from 'vscode-languageclient' - -import { requestsManager } from './RequestManager' -import { getEmbeddedLanguageDocPosition, getOriginalDocRange } from './utils/embeddedLanguagesUtils' -import { logger } from '../lib/src/utils/OutputLogger' -import { type EmbeddedLanguageDocInfos, embeddedLanguageDocsManager } from './EmbeddedLanguageDocsManager' -import { changeDefinitionUri, checkIsDefinitionRangeEqual, checkIsDefinitionUriEqual, convertToSameDefinitionType, getDefinitionUri } from './utils/definitions' - -export const middlewareProvideDefinition: DefinitionMiddleware['provideDefinition'] = async (document, position, token, next) => { - logger.debug(`[middlewareProvideDefinition] ${document.uri.toString()}, line ${position.line}, character ${position.character}`) - const nextResult = await next(document, position, token) - if ((Array.isArray(nextResult) && nextResult.length !== 0) || (!Array.isArray(nextResult) && nextResult !== undefined)) { - logger.debug('[middlewareProvideDefinition] returning nextResult') - return nextResult - } - const embeddedLanguageType = await requestsManager.getEmbeddedLanguageTypeOnPosition(document.uri.toString(), position) - if (embeddedLanguageType === undefined || embeddedLanguageType === null) { - return - } - const embeddedLanguageDocInfos = embeddedLanguageDocsManager.getEmbeddedLanguageDocInfos(document.uri, embeddedLanguageType) - logger.debug(`[middlewareProvideDefinition] embeddedLanguageDoc ${embeddedLanguageDocInfos?.uri as any}`) - if (embeddedLanguageDocInfos === undefined || embeddedLanguageDocInfos === null) { - return - } - const embeddedLanguageTextDocument = await workspace.openTextDocument(embeddedLanguageDocInfos.uri) - const adjustedPosition = getEmbeddedLanguageDocPosition( - document, - embeddedLanguageTextDocument, - embeddedLanguageDocInfos.characterIndexes, - position - ) - const tempResult = await commands.executeCommand( - 'vscode.executeDefinitionProvider', - embeddedLanguageDocInfos.uri, - adjustedPosition - ) - - // This check's purpose is only to please TypeScript. - // We'd rather have a pointless check than losing the type assurance provided by TypeScript. - if (checkIsArrayLocation(tempResult)) { - return await processDefinitions(tempResult, document, embeddedLanguageTextDocument, embeddedLanguageDocInfos) - } else { - return await processDefinitions(tempResult, document, embeddedLanguageTextDocument, embeddedLanguageDocInfos) - } -} - -const checkIsArrayLocation = (array: Location[] | LocationLink[]): array is Location[] => { - return array[0] instanceof Location -} - -const processDefinitions = async ( - definitions: DefinitionType[], - originalTextDocument: TextDocument, - embeddedLanguageTextDocument: TextDocument, - embeddedLanguageDocInfos: EmbeddedLanguageDocInfos -): Promise => { - const result: DefinitionType[] = [] - await Promise.all(definitions.map(async (definition) => { - if (!checkIsDefinitionUriEqual(definition, embeddedLanguageDocInfos.uri)) { - result.push(definition) // only definitions located on the embedded language documents need ajustments - return - } - if (embeddedLanguageDocInfos.language === 'python') { - for (const redirectionFunction of redirectionFunctions) { - const redirection = await redirectionFunction(definition) - if (redirection !== undefined) { - result.push(...redirection) - return - } - } - } - changeDefinitionUri(definition, originalTextDocument.uri) - const couldAjustRange = ajustDefinitionRange(definition, originalTextDocument, embeddedLanguageTextDocument, embeddedLanguageDocInfos.characterIndexes) - if (couldAjustRange) { - result.push(definition) - } - })) - return result -} - -// Map the range of the definition from the embedded language document to the original document -// return whether the adjustment could be done or not -const ajustDefinitionRange = ( - definition: Location | LocationLink, - originalTextDocument: TextDocument, - embeddedLanguageTextDocument: TextDocument, - characterIndexes: number[] -): boolean => { - if (definition instanceof Location) { - const newRange = getOriginalDocRange(originalTextDocument, embeddedLanguageTextDocument, characterIndexes, definition.range) - if (newRange === undefined) { - return false - } - definition.range = newRange - } else { - const newTargetRange = getOriginalDocRange(originalTextDocument, embeddedLanguageTextDocument, characterIndexes, definition.targetRange) - if (newTargetRange === undefined) { - return false - } - definition.targetRange = newTargetRange - if (definition.targetSelectionRange !== undefined) { - const newTargetSelectionRange = getOriginalDocRange(originalTextDocument, embeddedLanguageTextDocument, characterIndexes, definition.targetSelectionRange) - if (newTargetSelectionRange !== undefined) { - return false - } - definition.targetSelectionRange = newTargetRange - } - } - return true -} - -// Redirect a definition to an other definition -// For example, `d` of `d.getVar('')` is redirected to the definition of `data_smart.DataSmart()` -const redirectDefinition = async ( - initialDefinition: DefinitionType, // The definition that might be redirected - testedRange: Range, // The range for which a redirection would be made - redirectedPosition: Position // The new position to look at -): Promise => { - if (!checkIsDefinitionRangeEqual(initialDefinition, testedRange)) { - return - } - const uri = getDefinitionUri(initialDefinition) - const redirectedResult = await commands.executeCommand( - 'vscode.executeDefinitionProvider', - uri, - redirectedPosition - ) - // The middleware is expecting to return `Location[] | LocationLink[]`, not `(Location | LocationLink)[]` - // Ensure all the new definitions have the same type has the reference definition - return redirectedResult.map((redirectedDefinition) => convertToSameDefinitionType(initialDefinition, redirectedDefinition)) -} - -export const dRange = new Range(2, 0, 2, 1) // Where `d` is located in the embedded language document -export const dataSmartPosition = new Position(2, 19) // Where `DataSmart` (data_smart.DataSmart()) is reachable in the embedded language document - -// Handle `d` in `d.getVar('')` -const getDefinitionOfD = async ( - definition: DefinitionType -): Promise => { - return await redirectDefinition(definition, dRange, dataSmartPosition) -} - -export const eRange = new Range(3, 0, 3, 1) // Where `e` is located in the embedded language document -export const eventPosition = new Position(3, 14) // Where `Event` (event.Event()) is reachable in the embedded language document - -// Handle `e` in `e.data.getVar('')` -const getDefinitionOfE = async ( - definition: DefinitionType -): Promise => { - return await redirectDefinition(definition, eRange, eventPosition) -} - -const redirectionFunctions = [getDefinitionOfD, getDefinitionOfE] diff --git a/client/src/language/middlewareHover.ts b/client/src/language/middlewareHover.ts deleted file mode 100644 index cdee7ea0b..000000000 --- a/client/src/language/middlewareHover.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import { type HoverMiddleware } from 'vscode-languageclient' -import { type Hover, commands, workspace, MarkdownString, type TextDocument, Position } from 'vscode' - -import { getEmbeddedLanguageDocPosition, getOriginalDocPosition } from './utils/embeddedLanguagesUtils' -import { type EmbeddedLanguageDocInfos, embeddedLanguageDocsManager } from './EmbeddedLanguageDocsManager' -import { requestsManager } from './RequestManager' -import path from 'path' - -export const middlewareProvideHover: HoverMiddleware['provideHover'] = async (document, position, token, next) => { - const nextResult = await next(document, position, token) - if (nextResult !== undefined && nextResult !== null) { - return nextResult - } - const embeddedLanguageType = await requestsManager.getEmbeddedLanguageTypeOnPosition(document.uri.toString(), position) - if (embeddedLanguageType === undefined || embeddedLanguageType === null) { - return - } - const embeddedLanguageDocInfos = embeddedLanguageDocsManager.getEmbeddedLanguageDocInfos(document.uri, embeddedLanguageType) - if (embeddedLanguageDocInfos === undefined || embeddedLanguageDocInfos === null) { - return - } - const embeddedLanguageTextDocument = await workspace.openTextDocument(embeddedLanguageDocInfos.uri) - const adjustedPosition = getEmbeddedLanguageDocPosition( - document, - embeddedLanguageTextDocument, - embeddedLanguageDocInfos.characterIndexes, - position - ) - const hovers = await commands.executeCommand( - 'vscode.executeHoverProvider', - embeddedLanguageDocInfos.uri, - adjustedPosition - ) - const selectedHover = hovers.find((hover) => { - const contents = hover.contents - return contents.find((content) => { - if (content instanceof MarkdownString) { - return content.value !== '' - } - return content !== '' - }) - }) - if (selectedHover !== undefined) { - fixBashIdeIssue(selectedHover, embeddedLanguageDocInfos, document, embeddedLanguageTextDocument) - } - return selectedHover -} - -const fixBashIdeIssue = (hover: Hover, embeddedLanguageDocInfos: EmbeddedLanguageDocInfos, document: TextDocument, embeddedLanguageTextDocument: TextDocument): void => { - if (embeddedLanguageDocInfos.language !== 'bash') { - return - } - - hover.contents.forEach((content) => { - if (content instanceof MarkdownString) { - fixBashIdeRelativePath(content, embeddedLanguageDocInfos, document) - fixBashIdeLine(content, embeddedLanguageDocInfos, document, embeddedLanguageTextDocument) - } - }) -} - -// Bash IDE gives relative paths relative to the embedded language document. This path does not make any sense to the user. -// This makes the path relative to the document the user is looking at instead. -const fixBashIdeRelativePath = (content: MarkdownString, embeddedLanguageDocInfos: EmbeddedLanguageDocInfos, document: TextDocument): void => { - // ex: Function: **bbwarn** - *defined in ../../../../../../../../../poky/meta/classes-global/logging.bbclass* - const match = content.value.match(/^Function: \*\*\b\w+\b\*\* - \*defined in (?.*\.bbclass)\*/) - const wrongRelativePath = match?.groups?.path - if (wrongRelativePath === undefined) { - return - } - const absolutePath = path.resolve(path.dirname(embeddedLanguageDocInfos.uri.fsPath), wrongRelativePath) - const fixedRelativePath = path.relative(path.dirname(document.uri.fsPath), absolutePath) - content.value = content.value.replace(wrongRelativePath, fixedRelativePath) -} - -const fixBashIdeLine = (content: MarkdownString, embeddedLanguageDocInfos: EmbeddedLanguageDocInfos, document: TextDocument, embeddedLanguageTextDocument: TextDocument): void => { - // ex: Function: **bbwarn** - *defined on line 12* - const match = content.value.match(/^(Function|Variable): \*\*\b\w+\b\*\* - \*defined on line (?\d+)/) - const wrongLine = match?.groups?.line - if (wrongLine === undefined) { - return - } - const fixedPosition = getOriginalDocPosition(document, embeddedLanguageTextDocument, embeddedLanguageDocInfos.characterIndexes, new Position(parseInt(wrongLine) - 1, 0)) - if (fixedPosition === undefined) { - return - } - const fixedLine = fixedPosition.line + 1 - content.value = content.value.replace(wrongLine, fixedLine.toString()) -} diff --git a/client/src/language/middlewareReferences.ts b/client/src/language/middlewareReferences.ts deleted file mode 100644 index 373e61e03..000000000 --- a/client/src/language/middlewareReferences.ts +++ /dev/null @@ -1,75 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import { type ReferencesMiddleware } from 'vscode-languageclient' -import { type EmbeddedLanguageDocInfos, embeddedLanguageDocsManager } from './EmbeddedLanguageDocsManager' -import { requestsManager } from './RequestManager' -import { type Location, commands, workspace, type TextDocument } from 'vscode' -import { getEmbeddedLanguageDocPosition, getOriginalDocRange } from './utils/embeddedLanguagesUtils' - -export const middlewareProvideReferences: ReferencesMiddleware['provideReferences'] = async (document, position, options, token, next) => { - const nextResult = await next(document, position, options, token) - if (nextResult !== undefined && nextResult !== null) { - return nextResult - } - const embeddedLanguageType = await requestsManager.getEmbeddedLanguageTypeOnPosition(document.uri.toString(), position) - if (embeddedLanguageType === undefined || embeddedLanguageType === null) { - return - } - const embeddedLanguageDocInfos = embeddedLanguageDocsManager.getEmbeddedLanguageDocInfos(document.uri, embeddedLanguageType) - if (embeddedLanguageDocInfos === undefined || embeddedLanguageDocInfos === null) { - return - } - const embeddedLanguageTextDocument = await workspace.openTextDocument(embeddedLanguageDocInfos.uri) - const adjustedPosition = getEmbeddedLanguageDocPosition( - document, - embeddedLanguageTextDocument, - embeddedLanguageDocInfos.characterIndexes, - position - ) - const tempResult = await commands.executeCommand( - 'vscode.executeReferenceProvider', - embeddedLanguageDocInfos.uri, - adjustedPosition - ) - - return processReferences(tempResult, document, embeddedLanguageTextDocument, embeddedLanguageDocInfos) -} - -const processReferences = ( - references: Location[], - originalTextDocument: TextDocument, - embeddedLanguageTextDocument: TextDocument, - embeddedLanguageDocInfos: EmbeddedLanguageDocInfos -): Location[] => { - const result: Location[] = [] - references.forEach((reference) => { - if (reference.uri.fsPath !== embeddedLanguageDocInfos.uri.fsPath) { - if (reference.uri.fsPath.includes(embeddedLanguageDocsManager.embeddedLanguageDocsFolder as string)) { - // This is a reference to an other embedded language document. It has to be ignored. - return - } - // only references located on the embedded language documents need ajustments - result.push(reference) - return - } - reference.uri = originalTextDocument.uri - - const newRange = getOriginalDocRange( - originalTextDocument, - embeddedLanguageTextDocument, - embeddedLanguageDocInfos.characterIndexes, - reference.range - ) - - if (newRange === undefined) { - return - } - reference.range = newRange - result.push(reference) - }) - - return result -} diff --git a/client/src/language/utils/definitions.ts b/client/src/language/utils/definitions.ts deleted file mode 100644 index 86bc6b89e..000000000 --- a/client/src/language/utils/definitions.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import { Location, type LocationLink, type Range, type Uri } from 'vscode' - -export const checkIsDefinitionUriEqual = (definition: Location | LocationLink, uri: Uri): boolean => { - if (definition instanceof Location) { - return definition.uri.fsPath === uri.fsPath - } - return definition.targetUri.fsPath === uri.fsPath -} - -export const changeDefinitionUri = (definition: Location | LocationLink, uri: Uri): void => { - if (definition instanceof Location) { - definition.uri = uri - } else { - definition.targetUri = uri - } -} - -export const getDefinitionUri = (definition: Location | LocationLink): Uri => { - if (definition instanceof Location) { - return definition.uri - } - return definition.targetUri -} - -export const checkIsDefinitionRangeEqual = (definition: Location | LocationLink, range: Range): boolean => { - if (definition instanceof Location) { - return definition.range.isEqual(range) - } - return definition.targetRange.isEqual(range) -} - -export const convertDefinitionToLocation = (definition: Location | LocationLink): Location => { - if (definition instanceof Location) { - return definition - } - return { - uri: definition.targetUri, - range: definition.targetRange - } -} - -export const convertDefinitionToLocationLink = (definition: Location | LocationLink): LocationLink => { - if (definition instanceof Location) { - return { - targetUri: definition.uri, - targetRange: definition.range, - targetSelectionRange: definition.range - } - } - return definition -} - -export const convertToSameDefinitionType = ( - referenceDefinition: DefinitionType, - definitionToConvert: Location | LocationLink -): DefinitionType => { - if (referenceDefinition instanceof Location) { - return convertDefinitionToLocation(definitionToConvert) as DefinitionType - } else { - return convertDefinitionToLocationLink(definitionToConvert) as DefinitionType - } -} diff --git a/client/src/language/utils/embeddedLanguagesUtils.ts b/client/src/language/utils/embeddedLanguagesUtils.ts deleted file mode 100644 index c42dd26a3..000000000 --- a/client/src/language/utils/embeddedLanguagesUtils.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import { type Position, Range, type TextDocument } from 'vscode' - -export const getOriginalDocRange = ( - originalTextDocument: TextDocument, - embeddedLanguageTextDocument: TextDocument, - characterIndexes: number[], - embeddedRange: Range -): Range | undefined => { - const start = getOriginalDocPosition(originalTextDocument, embeddedLanguageTextDocument, characterIndexes, embeddedRange.start) - const end = getOriginalDocPosition(originalTextDocument, embeddedLanguageTextDocument, characterIndexes, embeddedRange.end) - if (start === undefined || end === undefined) { - return - } - return new Range(start, end) -} - -export const getOriginalDocPosition = ( - originalTextDocument: TextDocument, - embeddedLanguageTextDocument: TextDocument, - characterIndexes: number[], - embeddedPosition: Position -): Position | undefined => { - const embeddedLanguageOffset = embeddedLanguageTextDocument.offsetAt(embeddedPosition) - const originalOffset = characterIndexes.findIndex(index => index === embeddedLanguageOffset) - if (originalOffset === -1) { - return - } - return originalTextDocument.positionAt(originalOffset) -} - -export const getEmbeddedLanguageDocPosition = ( - originalTextDocument: TextDocument, - embeddedLanguageTextDocument: TextDocument, - characterIndexes: number[], - originalPosition: Position -): Position => { - const originalOffset = originalTextDocument.offsetAt(originalPosition) - const embeddedLanguageDocOffset = characterIndexes[originalOffset] - return embeddedLanguageTextDocument.positionAt(embeddedLanguageDocOffset) -} - -export const getEmbeddedLanguageDocRange = ( - originalTextDocument: TextDocument, - embeddedLanguageTextDocument: TextDocument, - characterIndexes: number[], - originalRange: Range -): Range => { - const start = getEmbeddedLanguageDocPosition(originalTextDocument, embeddedLanguageTextDocument, characterIndexes, originalRange.start) - const end = getEmbeddedLanguageDocPosition(originalTextDocument, embeddedLanguageTextDocument, characterIndexes, originalRange.end) - return new Range(start, end) -} diff --git a/client/src/language/utils/textDocumentUtils.ts b/client/src/language/utils/textDocumentUtils.ts deleted file mode 100644 index 249ed67db..000000000 --- a/client/src/language/utils/textDocumentUtils.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import { type TextDocument } from 'vscode' - -export const getIndentationOnLine = (document: TextDocument, lineNumber: number): string => { - const line = document.lineAt(lineNumber) - return line.text.slice(0, line.firstNonWhitespaceCharacterIndex) -} diff --git a/client/src/lib/package.json b/client/src/lib/package.json index d3661d79a..fb74ce65f 100644 --- a/client/src/lib/package.json +++ b/client/src/lib/package.json @@ -14,6 +14,5 @@ "repository": { "type": "git", "url": "https://github.com/yoctoproject/vscode-bitbake.git" - }, - "scripts": {} + } } diff --git a/client/src/lib/src/__tests__/utils/output-logger.test.ts b/client/src/lib/src/__tests__/utils/output-logger.test.ts index f23497d78..2584a1eb4 100644 --- a/client/src/lib/src/__tests__/utils/output-logger.test.ts +++ b/client/src/lib/src/__tests__/utils/output-logger.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import * as vscode from 'vscode' +import * as vscode from 'coc.nvim' import { logger } from '../../utils/OutputLogger' jest.mock('vscode') diff --git a/client/src/lib/src/types/requests.ts b/client/src/lib/src/types/requests.ts index 33036aee7..f7afb1266 100644 --- a/client/src/lib/src/types/requests.ts +++ b/client/src/lib/src/types/requests.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import { type Range, type Position } from 'vscode' +import { type Range, type Position } from 'coc.nvim' import { type EmbeddedLanguageType } from './embedded-languages' export enum RequestType { diff --git a/client/src/ui/BitbakeCommands.ts b/client/src/ui/BitbakeCommands.ts index 9d647fa97..68d7c9378 100644 --- a/client/src/ui/BitbakeCommands.ts +++ b/client/src/ui/BitbakeCommands.ts @@ -5,7 +5,7 @@ /// This files contains the VSCode commands exposed by the extension -import * as vscode from 'vscode' +import * as vscode from 'coc.nvim' import fs from 'fs' import { logger } from '../lib/src/utils/OutputLogger' @@ -14,51 +14,51 @@ import path from 'path' import { BitbakeRecipeTreeItem } from './BitbakeRecipesView' import { type BitBakeProjectScanner } from '../driver/BitBakeProjectScanner' import { extractRecipeName } from '../lib/src/utils/files' -import { runBitbakeTerminal, runBitbakeTerminalCustomCommand } from './BitbakeTerminal' +// import { runBitbakeTerminal, runBitbakeTerminalCustomCommand } from './BitbakeTerminal' import { type BitbakeDriver } from '../driver/BitbakeDriver' import { sanitizeForShell } from '../lib/src/BitbakeSettings' -import { type BitbakeTaskDefinition, type BitbakeTaskProvider } from './BitbakeTaskProvider' +// import { type BitbakeTaskDefinition, type BitbakeTaskProvider } from './BitbakeTaskProvider' import { type DevtoolWorkspaceInfo, type LayerInfo } from '../lib/src/types/BitbakeScanResult' -import { DevtoolWorkspaceTreeItem } from './DevtoolWorkspacesView' +// import { DevtoolWorkspaceTreeItem } from './DevtoolWorkspacesView' import { type SpawnSyncReturns } from 'child_process' import { clientNotificationManager } from './ClientNotificationManager' import { bitbakeESDKMode, configureDevtoolSDKFallback, generateCPPProperties } from '../driver/BitbakeESDK' import bitbakeRecipeScanner from '../driver/BitbakeRecipeScanner' -import { type BitbakeTerminalProfileProvider, openBitbakeTerminalProfile } from './BitbakeTerminalProfile' +// import { type BitbakeTerminalProfileProvider, openBitbakeTerminalProfile } from './BitbakeTerminalProfile' import { mergeArraysDistinctly } from '../lib/src/utils/arrays' -import { finishProcessExecution } from '../utils/ProcessUtils' -import { type LanguageClient } from 'vscode-languageclient/node' +// import { finishProcessExecution } from '../utils/ProcessUtils' +import { type LanguageClient } from 'coc.nvim' import { getVariableValue } from '../language/languageClient' let parsingPending = false let bitbakeSanity = false -export function registerBitbakeCommands (context: vscode.ExtensionContext, bitbakeWorkspace: BitbakeWorkspace, bitbakeTaskProvider: BitbakeTaskProvider, bitBakeProjectScanner: BitBakeProjectScanner, bitbakeTerminalProfileProvider: BitbakeTerminalProfileProvider, client: LanguageClient): void { - context.subscriptions.push(vscode.commands.registerCommand('bitbake.parse-recipes', async () => { await parseAllrecipes(bitbakeWorkspace, bitbakeTaskProvider) })) +export function registerBitbakeCommands (context: vscode.ExtensionContext, bitbakeWorkspace: BitbakeWorkspace, /* bitbakeTaskProvider: BitbakeTaskProvider, */bitBakeProjectScanner: BitBakeProjectScanner, /* bitbakeTerminalProfileProvider: BitbakeTerminalProfileProvider, */client: LanguageClient): void { + // context.subscriptions.push(vscode.commands.registerCommand('bitbake.parse-recipes', async () => { await parseAllrecipes(bitbakeWorkspace, bitbakeTaskProvider) })) context.subscriptions.push(vscode.commands.registerCommand('bitbake.build-recipe', async (uri) => { await buildRecipeCommand(bitbakeWorkspace, bitBakeProjectScanner, uri) })) context.subscriptions.push(vscode.commands.registerCommand('bitbake.clean-recipe', async (uri) => { await cleanRecipeCommand(bitbakeWorkspace, bitBakeProjectScanner, uri) })) - context.subscriptions.push(vscode.commands.registerCommand('bitbake.scan-recipe-env', async (uri) => { await scanRecipeCommand(bitbakeWorkspace, bitbakeTaskProvider, bitBakeProjectScanner, uri) })) + // context.subscriptions.push(vscode.commands.registerCommand('bitbake.scan-recipe-env', async (uri) => { await scanRecipeCommand(bitbakeWorkspace, bitbakeTaskProvider, bitBakeProjectScanner, uri) })) context.subscriptions.push(vscode.commands.registerCommand('bitbake.run-task', async (uri, task) => { await runTaskCommand(bitbakeWorkspace, bitBakeProjectScanner, client, uri, task) })) context.subscriptions.push(vscode.commands.registerCommand('bitbake.drop-recipe', async (uri) => { await dropRecipe(bitbakeWorkspace, bitBakeProjectScanner, uri) })) context.subscriptions.push(vscode.commands.registerCommand('bitbake.drop-all-recipes', async () => { await dropAllRecipes(bitbakeWorkspace) })) context.subscriptions.push(vscode.commands.registerCommand('bitbake.watch-recipe', async (recipe) => { await addActiveRecipe(bitbakeWorkspace, bitBakeProjectScanner, recipe) })) context.subscriptions.push(vscode.commands.registerCommand('bitbake.rescan-project', async () => { await rescanProject(bitBakeProjectScanner) })) - context.subscriptions.push(vscode.commands.registerCommand('bitbake.terminal-profile', async () => { await openBitbakeTerminalProfile(bitbakeTerminalProfileProvider) })) - context.subscriptions.push(vscode.commands.registerCommand('bitbake.open-recipe-workdir', async (uri) => { await openRecipeWorkdirCommand(bitbakeWorkspace, bitBakeProjectScanner, client, uri) })) - context.subscriptions.push(vscode.commands.registerCommand('bitbake.recipe-devshell', async (uri) => { await openBitbakeDevshell(bitbakeTerminalProfileProvider, bitbakeWorkspace, bitBakeProjectScanner, uri) })) - context.subscriptions.push(vscode.commands.registerCommand('bitbake.collapse-list', async () => { await collapseActiveList() })) + // context.subscriptions.push(vscode.commands.registerCommand('bitbake.terminal-profile', async () => { await openBitbakeTerminalProfile(bitbakeTerminalProfileProvider) })) + // context.subscriptions.push(vscode.commands.registerCommand('bitbake.open-recipe-workdir', async (uri) => { await openRecipeWorkdirCommand(bitbakeWorkspace, bitBakeProjectScanner, client, uri) })) + // context.subscriptions.push(vscode.commands.registerCommand('bitbake.recipe-devshell', async (uri) => { await openBitbakeDevshell(bitbakeTerminalProfileProvider, bitbakeWorkspace, bitBakeProjectScanner, uri) })) + // context.subscriptions.push(vscode.commands.registerCommand('bitbake.collapse-list', async () => { await collapseActiveList() })) // Handles enqueued parsing requests (onSave) - context.subscriptions.push( - vscode.tasks.onDidEndTask((e) => { - if (e.execution.task.name === 'Bitbake: Parse') { - if (parsingPending) { - parsingPending = false - void parseAllrecipes(bitbakeWorkspace, bitbakeTaskProvider) - } - } - }) - ) + // context.subscriptions.push( + // vscode.tasks.onDidEndTask((e) => { + // if (e.execution.task.name === 'Bitbake: Parse') { + // if (parsingPending) { + // parsingPending = false + // void parseAllrecipes(bitbakeWorkspace, bitbakeTaskProvider) + // } + // } + // }) + // ) } export function registerDevtoolCommands (context: vscode.ExtensionContext, bitbakeWorkspace: BitbakeWorkspace, bitBakeProjectScanner: BitBakeProjectScanner, client: LanguageClient): void { @@ -73,52 +73,52 @@ export function registerDevtoolCommands (context: vscode.ExtensionContext, bitba context.subscriptions.push(vscode.commands.registerCommand('bitbake.devtool-clean', async (uri) => { await devtoolCleanCommand(bitbakeWorkspace, bitBakeProjectScanner, uri) })) } -async function parseAllrecipes (bitbakeWorkspace: BitbakeWorkspace, taskProvider: BitbakeTaskProvider): Promise { - logger.debug('Command: parse-recipes') - - if (!bitbakeSanity && !(await taskProvider.bitbakeDriver?.checkBitbakeSettingsSanity())) { - logger.warn('bitbake settings are not sane, skip parse') - return - } - bitbakeSanity = true - - if (bitbakeESDKMode) { - return - } - - // We have to use tasks instead of BitbakeTerminal because we want the problemMatchers to detect parsing errors - const parseAllRecipesTask = new vscode.Task( - { type: 'bitbake', options: { parseOnly: true } }, - vscode.TaskScope.Workspace, - 'Bitbake: Parse', - 'bitbake' - ) - const runningTasks = vscode.tasks.taskExecutions - if (runningTasks.some((execution) => execution.task.name === parseAllRecipesTask.name)) { - logger.debug('Bitbake parsing task is already running') - parsingPending = true - return - } - - // Temporarily disable task.saveBeforeRun - // This request happens on bitbake document save. We don't want to save all files when any bitbake file is saved. - const saveBeforeRun = await vscode.workspace.getConfiguration('task').get('saveBeforeRun') - await vscode.workspace.getConfiguration('task').update('saveBeforeRun', 'never', undefined, true) - await runBitbakeTask(parseAllRecipesTask, taskProvider) - await vscode.workspace.getConfiguration('task').update('saveBeforeRun', saveBeforeRun, undefined, true) -} +// async function parseAllrecipes (bitbakeWorkspace: BitbakeWorkspace, taskProvider: BitbakeTaskProvider): Promise { +// logger.debug('Command: parse-recipes') +// +// if (!bitbakeSanity && !(await taskProvider.bitbakeDriver?.checkBitbakeSettingsSanity())) { +// logger.warn('bitbake settings are not sane, skip parse') +// return +// } +// bitbakeSanity = true +// +// if (bitbakeESDKMode) { +// return +// } +// +// // We have to use tasks instead of BitbakeTerminal because we want the problemMatchers to detect parsing errors +// // const parseAllRecipesTask = new vscode.Task( +// // { type: 'bitbake', options: { parseOnly: true } }, +// // vscode.TaskScope.Workspace, +// // 'Bitbake: Parse', +// // 'bitbake' +// // ) +// // const runningTasks = vscode.tasks.taskExecutions +// // if (runningTasks.some((execution) => execution.task.name === parseAllRecipesTask.name)) { +// // logger.debug('Bitbake parsing task is already running') +// // parsingPending = true +// // return +// // } +// // +// // // Temporarily disable task.saveBeforeRun +// // // This request happens on bitbake document save. We don't want to save all files when any bitbake file is saved. +// // const saveBeforeRun = await vscode.workspace.getConfiguration('task').get('saveBeforeRun') +// // await vscode.workspace.getConfiguration('task').update('saveBeforeRun', 'never', undefined, true) +// // await runBitbakeTask(parseAllRecipesTask, taskProvider) +// // await vscode.workspace.getConfiguration('task').update('saveBeforeRun', saveBeforeRun, undefined, true) +// } async function buildRecipeCommand (bitbakeWorkspace: BitbakeWorkspace, bitBakeProjectScanner: BitBakeProjectScanner, uri?: any): Promise { const chosenRecipe = await selectRecipe(bitbakeWorkspace, bitBakeProjectScanner, uri) if (chosenRecipe !== undefined) { logger.debug(`Command: build-recipe: ${chosenRecipe}`) - await runBitbakeTerminal( - bitBakeProjectScanner.bitbakeDriver, - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - { - recipes: [chosenRecipe] - } as BitbakeTaskDefinition, - `Bitbake: Build: ${chosenRecipe}`) + // await runBitbakeTerminal( + // bitBakeProjectScanner.bitbakeDriver, + // // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + // { + // recipes: [chosenRecipe] + // } as BitbakeTaskDefinition, + // `Bitbake: Build: ${chosenRecipe}`) } } @@ -126,45 +126,45 @@ async function cleanRecipeCommand (bitbakeWorkspace: BitbakeWorkspace, bitBakePr const chosenRecipe = await selectRecipe(bitbakeWorkspace, bitBakeProjectScanner, uri) if (chosenRecipe !== undefined) { logger.debug(`Command: clean-recipe: ${chosenRecipe}`) - await runBitbakeTerminal( - bitBakeProjectScanner.bitbakeDriver, - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - { - recipes: [chosenRecipe], - task: 'clean' - } as BitbakeTaskDefinition, - `Bitbake: Clean: ${chosenRecipe}`) + // await runBitbakeTerminal( + // bitBakeProjectScanner.bitbakeDriver, + // // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + // { + // recipes: [chosenRecipe], + // task: 'clean' + // } as BitbakeTaskDefinition, + // `Bitbake: Clean: ${chosenRecipe}`) } } -async function scanRecipeCommand (bitbakeWorkspace: BitbakeWorkspace, taskProvider: BitbakeTaskProvider, bitBakeProjectScanner: BitBakeProjectScanner, uri?: any): Promise { - const chosenRecipe = await selectRecipe(bitbakeWorkspace, bitBakeProjectScanner, uri, false) - - if (chosenRecipe === undefined) { - logger.debug('Command: scan-recipe-env: chosen recipe is undefined. Abort command') - return - } - - logger.debug('Command: scan-recipe-env') - - if (!bitbakeSanity && !(await taskProvider.bitbakeDriver?.checkBitbakeSettingsSanity())) { - logger.warn('bitbake settings are not sane, Abort scan') - return - } - - bitbakeSanity = true - - if (bitbakeESDKMode) { - return - } - - // Temporarily disable task.saveBeforeRun - // This request happens on bitbake document save. We don't want to save all files when any bitbake file is saved. - const saveBeforeRun = await vscode.workspace.getConfiguration('task').get('saveBeforeRun') - await vscode.workspace.getConfiguration('task').update('saveBeforeRun', 'never', undefined, true) - await bitbakeRecipeScanner.scan(chosenRecipe, taskProvider, uri) - await vscode.workspace.getConfiguration('task').update('saveBeforeRun', saveBeforeRun, undefined, true) -} +// async function scanRecipeCommand (bitbakeWorkspace: BitbakeWorkspace, taskProvider: BitbakeTaskProvider, bitBakeProjectScanner: BitBakeProjectScanner, uri?: any): Promise { +// const chosenRecipe = await selectRecipe(bitbakeWorkspace, bitBakeProjectScanner, uri, false) +// +// if (chosenRecipe === undefined) { +// logger.debug('Command: scan-recipe-env: chosen recipe is undefined. Abort command') +// return +// } +// +// logger.debug('Command: scan-recipe-env') +// +// if (!bitbakeSanity && !(await taskProvider.bitbakeDriver?.checkBitbakeSettingsSanity())) { +// logger.warn('bitbake settings are not sane, Abort scan') +// return +// } +// +// bitbakeSanity = true +// +// if (bitbakeESDKMode) { +// return +// } +// +// // Temporarily disable task.saveBeforeRun +// // This request happens on bitbake document save. We don't want to save all files when any bitbake file is saved. +// // const saveBeforeRun = await vscode.workspace.getConfiguration('task').get('saveBeforeRun') +// // await vscode.workspace.getConfiguration('task').update('saveBeforeRun', 'never', undefined, true) +// // await bitbakeRecipeScanner.scan(chosenRecipe, taskProvider, uri) +// // await vscode.workspace.getConfiguration('task').update('saveBeforeRun', saveBeforeRun, undefined, true) +// } async function runTaskCommand (bitbakeWorkspace: BitbakeWorkspace, bitBakeProjectScanner: BitBakeProjectScanner, client: LanguageClient, uri?: any, task?: any): Promise { const chosenRecipe = await selectRecipe(bitbakeWorkspace, bitBakeProjectScanner, uri) @@ -177,13 +177,13 @@ async function runTaskCommand (bitbakeWorkspace: BitbakeWorkspace, bitBakeProjec } if (chosenTask !== undefined) { logger.debug(`Command: run-task: ${chosenRecipe}, ${chosenTask}`) - await runBitbakeTerminal(bitBakeProjectScanner.bitbakeDriver, - // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - { - recipes: [chosenRecipe], - task: chosenTask - } as BitbakeTaskDefinition, - `Bitbake: Task: ${chosenTask}: ${chosenRecipe}`) + // await runBitbakeTerminal(bitBakeProjectScanner.bitbakeDriver, + // // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + // { + // recipes: [chosenRecipe], + // task: chosenTask + // } as BitbakeTaskDefinition, + // `Bitbake: Task: ${chosenTask}: ${chosenRecipe}`) } } } @@ -199,10 +199,10 @@ async function selectTask (client: LanguageClient, recipe: string): Promise recipe.name) let chosenRecipe: string | undefined if (recipeNames.length !== 0) { - chosenRecipe = await vscode.window.showQuickPick(recipeNames, { placeHolder: 'Select recipe to add' }) + // chosenRecipe = await vscode.window.showQuickPick(recipeNames, { placeHolder: 'Select recipe to add' }) } else { - chosenRecipe = await vscode.window.showInputBox({ placeHolder: "Type the recipe's name to add. (Bitbake scan not complete yet)" }) + // chosenRecipe = await vscode.window.showInputBox({ placeHolder: "Type the recipe's name to add. (Bitbake scan not complete yet)" }) } if (chosenRecipe !== undefined) { chosenRecipe = sanitizeForShell(extractRecipeName(chosenRecipe)) as string @@ -280,17 +280,17 @@ async function dropAllRecipes (bitbakeWorkspace: BitbakeWorkspace): Promise { - let resolvedTask = taskProvider.resolveTask(task, new vscode.CancellationTokenSource().token) - if (resolvedTask instanceof Promise) { - resolvedTask = await resolvedTask - } - if (resolvedTask instanceof vscode.Task) { - await vscode.tasks.executeTask(resolvedTask) - } else { - throw new Error(`Failed to resolve task for recipe ${task.definition.recipes[0]}`) - } -} +// export async function runBitbakeTask (task: vscode.Task, taskProvider: vscode.TaskProvider): Promise { +// let resolvedTask = taskProvider.resolveTask(task, new vscode.CancellationTokenSource().token) +// if (resolvedTask instanceof Promise) { +// resolvedTask = await resolvedTask +// } +// if (resolvedTask instanceof vscode.Task) { +// await vscode.tasks.executeTask(resolvedTask) +// } else { +// throw new Error(`Failed to resolve task for recipe ${task.definition.recipes[0]}`) +// } +// } async function rescanProject (bitBakeProjectScanner: BitBakeProjectScanner): Promise { bitbakeSanity = false @@ -308,17 +308,17 @@ async function devtoolModifyCommand (bitbakeWorkspace: BitbakeWorkspace, bitBake if (chosenRecipe !== undefined) { logger.debug(`Command: devtool-modify: ${chosenRecipe}`) const command = `devtool modify ${chosenRecipe}` - const process = await runBitbakeTerminalCustomCommand(bitBakeProjectScanner.bitbakeDriver, command, `Bitbake: Devtool Modify: ${chosenRecipe}`) - process.onExit((event) => { - if (event.exitCode === 0) { - void bitBakeProjectScanner.rescanDevtoolWorkspaces().then(() => { - // Running devtool-ide-sdk is very slow. Users may not want to start it all the time so we suggest it here. - // For instance, if they only need to make a quick patch to a recipe, they may not want to wait for the SDK to be built. - clientNotificationManager.showSDKSuggestion(chosenRecipe) - void bitBakeProjectScanner.rescanProject() - }) - } - }) + // const process = await runBitbakeTerminalCustomCommand(bitBakeProjectScanner.bitbakeDriver, command, `Bitbake: Devtool Modify: ${chosenRecipe}`) + // process.onExit((event) => { + // if (event.exitCode === 0) { + // void bitBakeProjectScanner.rescanDevtoolWorkspaces().then(() => { + // // Running devtool-ide-sdk is very slow. Users may not want to start it all the time so we suggest it here. + // // For instance, if they only need to make a quick patch to a recipe, they may not want to wait for the SDK to be built. + // clientNotificationManager.showSDKSuggestion(chosenRecipe) + // void bitBakeProjectScanner.rescanProject() + // }) + // } + // }) } } @@ -362,7 +362,7 @@ async function devtoolIdeSDKCommand (bitbakeWorkspace: BitbakeWorkspace, bitBake return } const command = bitbakeDriver.composeDevtoolIDECommand(chosenRecipe) - await runBitbakeTerminalCustomCommand(bitbakeDriver, command, `Bitbake: Devtool ide-sdk: ${chosenRecipe}`) + // await runBitbakeTerminalCustomCommand(bitbakeDriver, command, `Bitbake: Devtool ide-sdk: ${chosenRecipe}`) showSDKConfigurationDone(chosenRecipe) } @@ -370,9 +370,10 @@ async function devtoolIdeSDKCommand (bitbakeWorkspace: BitbakeWorkspace, bitBake async function checkIdeSdkAvailable (bitbakeDriver: BitbakeDriver): Promise { const command = "devtool --help | grep 'ide-sdk'" - const process = runBitbakeTerminalCustomCommand(bitbakeDriver, command, 'Bitbake: Devtool ide-sdk: check') - const res = await finishProcessExecution(process) - return res.status === 0 + // const process = runBitbakeTerminalCustomCommand(bitbakeDriver, command, 'Bitbake: Devtool ide-sdk: check') + // const res = await finishProcessExecution(process) + // return res.status === 0 + return true } function checkIdeSdkConfiguration (bitbakeDriver: BitbakeDriver): boolean { @@ -382,14 +383,15 @@ function checkIdeSdkConfiguration (bitbakeDriver: BitbakeDriver): boolean { async function pickLayer (extraOption: string, bitBakeProjectScanner: BitBakeProjectScanner): Promise { const layers = bitBakeProjectScanner.scanResult._layers - const chosenLayer = await vscode.window.showQuickPick([...layers.map(layer => layer.name), extraOption], { placeHolder: 'Choose target BitBake layer' }) - if (chosenLayer === undefined) { return } - - if (chosenLayer === extraOption) { - return { name: extraOption, path: '', priority: 0 } - } else { - return layers.find(layer => layer.name === chosenLayer) - } + // const chosenLayer = await vscode.window.showQuickPick([...layers.map(layer => layer.name), extraOption], { placeHolder: 'Choose target BitBake layer' }) + // if (chosenLayer === undefined) { return } + // + // if (chosenLayer === extraOption) { + // return { name: extraOption, path: '', priority: 0 } + // } else { + // return layers.find(layer => layer.name === chosenLayer) + // } + return } async function devtoolUpdateCommand (bitbakeWorkspace: BitbakeWorkspace, bitBakeProjectScanner: BitBakeProjectScanner, uri?: any): Promise { @@ -408,12 +410,12 @@ async function devtoolUpdateCommand (bitbakeWorkspace: BitbakeWorkspace, bitBake } logger.debug(`Command: devtool-update: ${chosenRecipe}`) - const process = runBitbakeTerminalCustomCommand(bitBakeProjectScanner.bitbakeDriver, command, `Bitbake: Devtool Update: ${chosenRecipe}`) - const res = await finishProcessExecution(process, async () => { await bitBakeProjectScanner.bitbakeDriver.killBitbake() }) - if (res.status === 0 && chosenLayer?.name !== originalRecipeChoice) { - await openDevtoolUpdateBBAppend(res, bitBakeProjectScanner) - void bitBakeProjectScanner.rescanProject() - } + // const process = runBitbakeTerminalCustomCommand(bitBakeProjectScanner.bitbakeDriver, command, `Bitbake: Devtool Update: ${chosenRecipe}`) + // const res = await finishProcessExecution(process, async () => { await bitBakeProjectScanner.bitbakeDriver.killBitbake() }) + // if (res.status === 0 && chosenLayer?.name !== originalRecipeChoice) { + // await openDevtoolUpdateBBAppend(res, bitBakeProjectScanner) + // void bitBakeProjectScanner.rescanProject() + // } } async function openDevtoolUpdateBBAppend (res: SpawnSyncReturns, bitBakeProjectScanner: BitBakeProjectScanner): Promise { @@ -437,14 +439,14 @@ async function devtoolResetCommand (bitbakeWorkspace: BitbakeWorkspace, bitBakeP if (chosenRecipe !== undefined) { logger.debug(`Command: devtool-reset: ${chosenRecipe}`) const command = `devtool reset ${chosenRecipe}` - const process = await runBitbakeTerminalCustomCommand(bitBakeProjectScanner.bitbakeDriver, command, `Bitbake: Devtool Reset: ${chosenRecipe}`) - process.onExit((event) => { - if (event.exitCode === 0) { - void bitBakeProjectScanner.rescanDevtoolWorkspaces().then(() => { - void bitBakeProjectScanner.rescanProject() - }) - } - }) + // const process = await runBitbakeTerminalCustomCommand(bitBakeProjectScanner.bitbakeDriver, command, `Bitbake: Devtool Reset: ${chosenRecipe}`) + // process.onExit((event) => { + // if (event.exitCode === 0) { + // void bitBakeProjectScanner.rescanDevtoolWorkspaces().then(() => { + // void bitBakeProjectScanner.rescanProject() + // }) + // } + // }) } } @@ -481,36 +483,36 @@ async function openRecipeWorkdirCommand (bitbakeWorkspace: BitbakeWorkspace, bit recipeWorkdir = await bitBakeProjectScanner.resolveContainerPath(recipeWorkdir, true) as string if (!fs.existsSync(recipeWorkdir)) { await vscode.window.showErrorMessage(`WORKDIR for ${chosenRecipe} was not found. Make sure you have built the recipe.`, - { modal: true, detail: `${recipeWorkdir} does not exist` }) + /* { modal: true, detail: `${recipeWorkdir} does not exist` } */) return } const recipeWorkdirURI = vscode.Uri.file(recipeWorkdir) await vscode.commands.executeCommand('vscode.openFolder', recipeWorkdirURI, { forceNewWindow: true }) } -async function openBitbakeDevshell (terminalProvider: BitbakeTerminalProfileProvider, bitbakeWorkspace: BitbakeWorkspace, bitBakeProjectScanner: BitBakeProjectScanner, uri?: any): Promise { - const chosenRecipe = await selectRecipe(bitbakeWorkspace, bitBakeProjectScanner, uri) - if (chosenRecipe === undefined) return - console.log(`Command: recipe-devshell: ${chosenRecipe}`) - - const terminal = await openBitbakeTerminalProfile(terminalProvider) - const command = bitBakeProjectScanner.bitbakeDriver.composeDevshellCommand(chosenRecipe) - terminal.sendText(command + ' && exit') - - return terminal -} +// async function openBitbakeDevshell (terminalProvider: BitbakeTerminalProfileProvider, bitbakeWorkspace: BitbakeWorkspace, bitBakeProjectScanner: BitBakeProjectScanner, uri?: any): Promise { +// const chosenRecipe = await selectRecipe(bitbakeWorkspace, bitBakeProjectScanner, uri) +// if (chosenRecipe === undefined) return +// console.log(`Command: recipe-devshell: ${chosenRecipe}`) +// +// const terminal = await openBitbakeTerminalProfile(terminalProvider) +// const command = bitBakeProjectScanner.bitbakeDriver.composeDevshellCommand(chosenRecipe) +// terminal.sendText(command + ' && exit') +// +// return terminal +// } async function devtoolBuildCommand (bitbakeWorkspace: BitbakeWorkspace, bitBakeProjectScanner: BitBakeProjectScanner, uri?: any): Promise { const chosenRecipe = await selectRecipe(bitbakeWorkspace, bitBakeProjectScanner, uri) if (chosenRecipe !== undefined) { logger.debug(`Command: devtool-build: ${chosenRecipe}`) - await runBitbakeTerminal( - bitBakeProjectScanner.bitbakeDriver, - { - specialCommand: `devtool build ${chosenRecipe}`, - type: 'bitbake' - } satisfies BitbakeTaskDefinition, - `Bitbake: Devtool Build: ${chosenRecipe}`) + // await runBitbakeTerminal( + // bitBakeProjectScanner.bitbakeDriver, + // { + // specialCommand: `devtool build ${chosenRecipe}`, + // type: 'bitbake' + // } satisfies BitbakeTaskDefinition, + // `Bitbake: Devtool Build: ${chosenRecipe}`) } } @@ -524,13 +526,13 @@ async function devtoolDeployCommand (bitbakeWorkspace: BitbakeWorkspace, bitBake clientNotificationManager.showSDKConfigurationError() return } - await runBitbakeTerminal( - bitbakeDriver, - { - specialCommand: `devtool deploy-target ${chosenRecipe} ${sshTarget}`, - type: 'bitbake' - } satisfies BitbakeTaskDefinition, - `Bitbake: Devtool Deploy: ${chosenRecipe}`) + // await runBitbakeTerminal( + // bitbakeDriver, + // { + // specialCommand: `devtool deploy-target ${chosenRecipe} ${sshTarget}`, + // type: 'bitbake' + // } satisfies BitbakeTaskDefinition, + // `Bitbake: Devtool Deploy: ${chosenRecipe}`) } } @@ -538,16 +540,16 @@ async function devtoolCleanCommand (bitbakeWorkspace: BitbakeWorkspace, bitBakeP const chosenRecipe = await selectRecipe(bitbakeWorkspace, bitBakeProjectScanner, uri) if (chosenRecipe !== undefined) { logger.debug(`Command: devtool-clean: ${chosenRecipe}`) - await runBitbakeTerminal( - bitBakeProjectScanner.bitbakeDriver, - { - specialCommand: `devtool build -c ${chosenRecipe}`, - type: 'bitbake' - } satisfies BitbakeTaskDefinition, - `Bitbake: Devtool Clean: ${chosenRecipe}`) + // await runBitbakeTerminal( + // bitBakeProjectScanner.bitbakeDriver, + // { + // specialCommand: `devtool build -c ${chosenRecipe}`, + // type: 'bitbake' + // } satisfies BitbakeTaskDefinition, + // `Bitbake: Devtool Clean: ${chosenRecipe}`) } } async function collapseActiveList (): Promise { - await vscode.commands.executeCommand('list.collapseAll') + // await vscode.commands.executeCommand('list.collapseAll') } diff --git a/client/src/ui/BitbakeConfigPicker.ts b/client/src/ui/BitbakeConfigPicker.ts index 571a349b4..8d904b085 100644 --- a/client/src/ui/BitbakeConfigPicker.ts +++ b/client/src/ui/BitbakeConfigPicker.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import * as vscode from 'vscode' +import * as vscode from 'coc.nvim' import { type BitbakeSettings } from '../lib/src/BitbakeSettings' import assert from 'assert' @@ -12,7 +12,7 @@ export class BitbakeConfigPicker { private bitbakeSettings: BitbakeSettings private readonly memento: vscode.Memento | undefined private _activeBuildConfiguration: string = 'No BitBake configuration' - public readonly onActiveConfigChanged: vscode.EventEmitter = new vscode.EventEmitter() + // public readonly onActiveConfigChanged: vscode.EventEmitter = new vscode.EventEmitter() public get activeBuildConfiguration (): string { return this._activeBuildConfiguration @@ -20,18 +20,18 @@ export class BitbakeConfigPicker { private set activeBuildConfiguration (value: string) { this._activeBuildConfiguration = value - this.onActiveConfigChanged.fire(value) + // this.onActiveConfigChanged.fire(value) void this.memento?.update('BitbakeConfigPicker.activeBuildConfiguration', value) } constructor (bitbakeSettings: BitbakeSettings, context: vscode.ExtensionContext) { this.bitbakeSettings = bitbakeSettings - this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 0) + this.statusBarItem = vscode.window.createStatusBarItem(/* vscode.StatusBarAlignment.Right, */0) this.memento = context.workspaceState this.activeBuildConfiguration = this.memento?.get('BitbakeConfigPicker.activeBuildConfiguration', 'No BitBake configuration') as string - this.statusBarItem.command = 'bitbake.pick-configuration' - this.statusBarItem.tooltip = 'Select BitBake buildConfiguration' + // this.statusBarItem.command = 'bitbake.pick-configuration' + // this.statusBarItem.tooltip = 'Select BitBake buildConfiguration' context.subscriptions.push(vscode.commands.registerCommand('bitbake.pick-configuration', this.pickConfiguration, this)) this.updateStatusBar(bitbakeSettings) } @@ -59,11 +59,11 @@ export class BitbakeConfigPicker { } else { const options = this.bitbakeSettings.buildConfigurations.map((config) => config.name) const filteredOptions = options.filter((option) => typeof option === 'string') as string[] // Always all according to the definition in client/package.json - const selection = await vscode.window.showQuickPick(filteredOptions, { placeHolder: 'Select a BitBake configuration' }) - if (selection !== undefined) { - this.activeBuildConfiguration = selection + // const selection = await vscode.window.showQuickPick(filteredOptions, { placeHolder: 'Select a BitBake configuration' }) + // if (selection !== undefined) { + // this.activeBuildConfiguration = selection this.updateStatusBar(this.bitbakeSettings) - } + // } } } } diff --git a/client/src/ui/BitbakeRecipesView.ts b/client/src/ui/BitbakeRecipesView.ts index 45c4a185c..d8e0d7720 100644 --- a/client/src/ui/BitbakeRecipesView.ts +++ b/client/src/ui/BitbakeRecipesView.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import * as vscode from 'vscode' +import * as vscode from 'coc.nvim' import { type BitbakeWorkspace } from './BitbakeWorkspace' import { type ElementInfo, type BitbakeScanResult, type PathInfo, scanContainsData, scanContainsRecipes } from '../lib/src/types/BitbakeScanResult' import path from 'path' @@ -18,17 +18,17 @@ export class BitbakeRecipesView { } registerView (context: vscode.ExtensionContext): void { - const view = vscode.window.createTreeView('bitbakeRecipes', { treeDataProvider: this.bitbakeTreeProvider, showCollapseAll: true }) + const view = vscode.window.createTreeView('bitbakeRecipes', { treeDataProvider: this.bitbakeTreeProvider, /* showCollapseAll: true */ }) context.subscriptions.push(view) - vscode.window.registerTreeDataProvider('bitbakeRecipes', this.bitbakeTreeProvider) + // vscode.window.registerTreeDataProvider('bitbakeRecipes', this.bitbakeTreeProvider) } } export class BitbakeRecipeTreeItem extends vscode.TreeItem { constructor (public readonly label: string, public readonly collapsibleState: vscode.TreeItemCollapsibleState) { super(label, collapsibleState) - this.contextValue = 'bitbakeRecipeCtx' - this.iconPath = new vscode.ThemeIcon('library') + // this.contextValue = 'bitbakeRecipeCtx' + // this.iconPath = new vscode.ThemeIcon('library') } } @@ -36,8 +36,8 @@ class BitbakeFileTreeItem extends BitbakeRecipeTreeItem { constructor (public readonly pathInfo: PathInfo, public readonly collapsibleState: vscode.TreeItemCollapsibleState) { const resolvedPath = path.resolve(pathInfo.dir + '/' + pathInfo.base) super(pathInfo.base, collapsibleState) - this.contextValue = 'bitbakeFileCtx' - this.iconPath = new vscode.ThemeIcon('book') + // this.contextValue = 'bitbakeFileCtx' + // this.iconPath = new vscode.ThemeIcon('book') const uri: vscode.Uri = vscode.Uri.file(resolvedPath) this.command = { command: 'vscode.open', title: 'Open file', arguments: [uri] } this.description = vscode.workspace.asRelativePath(resolvedPath, false) @@ -48,8 +48,8 @@ class BitbakeFileTreeItem extends BitbakeRecipeTreeItem { class BitbakeTreeDataProvider implements vscode.TreeDataProvider { readonly bitbakeWorkspace: BitbakeWorkspace - private readonly _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter() - readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event + // private readonly _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter() + // readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event private readonly bitbakeProjectScanner: BitBakeProjectScanner private bitbakeScanResults: BitbakeScanResult | undefined @@ -58,21 +58,21 @@ class BitbakeTreeDataProvider implements vscode.TreeDataProvider { - this._onDidChangeTreeData.fire(undefined) + // this._onDidChangeTreeData.fire(undefined) }) bitbakeWorkspace.onChange.on('recipeDropped', (recipe: string) => { - this._onDidChangeTreeData.fire(undefined) + // this._onDidChangeTreeData.fire(undefined) }) bitbakeProjectScanner.onChange.on('scanReady', (scanResults: BitbakeScanResult) => { // In case a parsing error was just introduced, we keep the previous results to keep navigation functional if (this.bitbakeScanResults === undefined || !scanContainsRecipes(this.bitbakeScanResults) || scanContainsRecipes(scanResults)) { this.bitbakeScanResults = scanResults } - this._onDidChangeTreeData.fire(undefined) + // this._onDidChangeTreeData.fire(undefined) }) } - getTreeItem (element: BitbakeRecipeTreeItem): vscode.TreeItem | Thenable { + getTreeItem (element: BitbakeRecipeTreeItem): vscode.TreeItem | Promise { return element } @@ -112,8 +112,8 @@ class BitbakeTreeDataProvider implements vscode.TreeDataProvider { - if (e.execution.task.source !== 'bitbake') { - return - } - - const taskName = e.execution.task.name - - if (taskName === 'Bitbake: Parse') { - this.parsingInProgress = true - } else if (taskName === BitbakeRecipeScanner.taskName) { - this.recipeScanInProgress = true - } - - this.updateStatusBar() - }) - vscode.tasks.onDidEndTask((e: vscode.TaskEndEvent) => { - if (e.execution.task.source !== 'bitbake') { - return - } - - const taskName = e.execution.task.name - this.scanExitCode = (e.execution.task.execution as BitbakeCustomExecution).pty?.lastExitCode ?? -1 - - if (taskName === 'Bitbake: Parse') { - this.parsingInProgress = false - } else if (taskName === BitbakeRecipeScanner.taskName) { - this.recipeScanInProgress = false - } - - this.updateStatusBar() - }) + // vscode.tasks.onDidStartTask((e: vscode.TaskStartEvent) => { + // if (e.execution.task.source !== 'bitbake') { + // return + // } + // + // const taskName = e.execution.task.name + // + // if (taskName === 'Bitbake: Parse') { + // this.parsingInProgress = true + // } else if (taskName === BitbakeRecipeScanner.taskName) { + // this.recipeScanInProgress = true + // } + // + // this.updateStatusBar() + // }) + // vscode.tasks.onDidEndTask((e: vscode.TaskEndEvent) => { + // if (e.execution.task.source !== 'bitbake') { + // return + // } + // + // const taskName = e.execution.task.name + // this.scanExitCode = (e.execution.task.execution as BitbakeCustomExecution).pty?.lastExitCode ?? -1 + // + // if (taskName === 'Bitbake: Parse') { + // this.parsingInProgress = false + // } else if (taskName === BitbakeRecipeScanner.taskName) { + // this.recipeScanInProgress = false + // } + // + // this.updateStatusBar() + // }) } updateStatusBar (): void { if (this.scanInProgress || this.parsingInProgress || this.recipeScanInProgress) { if (this.scanInProgress) { this.statusBarItem.text = '$(loading~spin) BitBake: Scanning...' - this.statusBarItem.tooltip = 'BitBake: Scanning...' + // this.statusBarItem.tooltip = 'BitBake: Scanning...' } else { this.statusBarItem.text = '$(loading~spin) BitBake: Parsing...' - this.statusBarItem.tooltip = 'BitBake: Parsing...' + // this.statusBarItem.tooltip = 'BitBake: Parsing...' } - this.statusBarItem.command = undefined - this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.prominentBackground') + // this.statusBarItem.command = undefined + // this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.prominentBackground') return } if (this.commandInProgress !== undefined) { @@ -96,21 +96,21 @@ export class BitbakeStatusBar { if (this.commandInProgress.includes('devtool')) displayText = 'Devtool...' if (this.commandInProgress.includes('which devtool')) displayText = 'Scanning...' this.statusBarItem.text = '$(loading~spin) BitBake: ' + displayText - this.statusBarItem.tooltip = 'BitBake: ' + displayText - this.statusBarItem.command = undefined - this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.prominentBackground') + // this.statusBarItem.tooltip = 'BitBake: ' + displayText + // this.statusBarItem.command = undefined + // this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.prominentBackground') return } if (this.scanExitCode !== 0) { this.statusBarItem.text = '$(error) BitBake: Parsing error' - this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.errorBackground') - this.statusBarItem.command = 'workbench.action.problems.focus' - this.statusBarItem.tooltip = 'Open problems view for more details' + // this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.errorBackground') + // this.statusBarItem.command = 'workbench.action.problems.focus' + // this.statusBarItem.tooltip = 'Open problems view for more details' } else { this.statusBarItem.text = '$(library) BitBake: ' + this.bitbakeScanResults._recipes.length + ' recipes scanned' - this.statusBarItem.command = 'bitbake.rescan-project' - this.statusBarItem.tooltip = 'BitBake: Scan project for recipes' - this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.prominentBackground') + // this.statusBarItem.command = 'bitbake.rescan-project' + // this.statusBarItem.tooltip = 'BitBake: Scan project for recipes' + // this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.prominentBackground') } } } diff --git a/client/src/ui/BitbakeTaskProvider.ts b/client/src/ui/BitbakeTaskProvider.ts deleted file mode 100644 index d25dec5a4..000000000 --- a/client/src/ui/BitbakeTaskProvider.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import * as vscode from 'vscode' -import { type BitbakeDriver } from '../driver/BitbakeDriver' -import { BitbakePseudoTerminal } from './BitbakeTerminal' - -/// Reflects the task definition in package.json -export interface BitbakeTaskDefinition extends vscode.TaskDefinition { - recipes?: string[] - task?: string - options?: { - continue?: boolean - force?: boolean - parseOnly?: boolean - env?: boolean // Recipe environment - } - specialCommand?: string -} - -export class BitbakeCustomExecution extends vscode.CustomExecution { - pty: BitbakePseudoTerminal | undefined -} - -export class BitbakeTaskProvider implements vscode.TaskProvider { - readonly bitbakeDriver: BitbakeDriver - - constructor (bitbakeDriver: BitbakeDriver) { - this.bitbakeDriver = bitbakeDriver - } - - provideTasks (token: vscode.CancellationToken): vscode.ProviderResult { - return [] - } - - resolveTask (task: vscode.Task, token: vscode.CancellationToken): vscode.ProviderResult | undefined { - const bitbakeTaskDefinition: BitbakeTaskDefinition = task.definition as any - - const canResolveTask = (bitbakeTaskDefinition.recipes?.[0] !== undefined || - bitbakeTaskDefinition.options?.parseOnly === true || - bitbakeTaskDefinition.options?.env === true || - bitbakeTaskDefinition.specialCommand !== undefined) - - if (canResolveTask) { - const bitbakeCommand = this.bitbakeDriver.composeBitbakeCommand(bitbakeTaskDefinition) - const problemMatchers = ['$bitbake-ParseError', '$bitbake-Variable', '$bitbake-generic', '$bitbake-task-error', '$bitbake-UnableToParse', '$bitbake-non-existent-uri'] - - const resolvedTask = new vscode.Task( - task.definition, - task.scope ?? vscode.TaskScope.Workspace, - task.name, - task.source ?? 'bitbake', - new BitbakeCustomExecution(async (resolvedDefinition: vscode.TaskDefinition): Promise => { - const pty = new BitbakePseudoTerminal(this.bitbakeDriver); - (resolvedTask.execution as BitbakeCustomExecution).pty = pty - void pty.runProcess( - this.bitbakeDriver.spawnBitbakeProcess(bitbakeCommand), - this.bitbakeDriver.composeBitbakeScript(bitbakeCommand)) - return pty - }), - problemMatchers - ) - if ((bitbakeTaskDefinition.task === undefined || bitbakeTaskDefinition.task.includes('build')) && - bitbakeTaskDefinition.options?.parseOnly !== true) { - resolvedTask.group = vscode.TaskGroup.Build - } - if (bitbakeTaskDefinition.task !== undefined && bitbakeTaskDefinition.task.includes('clean')) { - resolvedTask.group = vscode.TaskGroup.Clean - } - if (bitbakeTaskDefinition.options?.parseOnly === true) { - resolvedTask.presentationOptions.reveal = vscode.TaskRevealKind.Silent - resolvedTask.presentationOptions.focus = false - } - return resolvedTask - } - return undefined - } -} diff --git a/client/src/ui/BitbakeTerminal.ts b/client/src/ui/BitbakeTerminal.ts deleted file mode 100644 index 984a210ee..000000000 --- a/client/src/ui/BitbakeTerminal.ts +++ /dev/null @@ -1,194 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import { type IPty } from 'node-pty' -import * as vscode from 'vscode' -import { logger } from '../lib/src/utils/OutputLogger' -import path from 'path' -import { type BitbakeDriver } from '../driver/BitbakeDriver' -import { type BitbakeTaskDefinition } from './BitbakeTaskProvider' - -const endOfLine: string = '\r\n' -const emphasisedAsterisk: string = '\x1b[7m * \x1b[0m' - -/// Spawn a bitbake process in a dedicated terminal and wait for it to finish -export async function runBitbakeTerminal (bitbakeDriver: BitbakeDriver, bitbakeTaskDefinition: BitbakeTaskDefinition, terminalName: string, isBackground: boolean = false): Promise { - const command = bitbakeDriver.composeBitbakeCommand(bitbakeTaskDefinition) - const script = bitbakeDriver.composeBitbakeScript(command) - return await runBitbakeTerminalScript(command, bitbakeDriver, terminalName, script, isBackground) -} - -/// Spawn a bitbake process in a dedicated terminal and wait for it to finish -export async function runBitbakeTerminalCustomCommand (bitbakeDriver: BitbakeDriver, command: string, terminalName: string, isBackground: boolean = false): Promise { - const script = bitbakeDriver.composeBitbakeScript(command) - return await runBitbakeTerminalScript(command, bitbakeDriver, terminalName, script, isBackground) -} - -const bitbakeTerminals: BitbakeTerminal[] = [] -async function runBitbakeTerminalScript (command: string, bitbakeDriver: BitbakeDriver, terminalName: string, bitbakeScript: string, isBackground: boolean): Promise { - let terminal: BitbakeTerminal | undefined - for (const t of bitbakeTerminals) { - if (!t.pty.isBusy()) { - terminal = t - terminal.pty.changeNameEmitter.fire(terminalName) - break - } - } - if (terminal === undefined) { - // All bitbake calls are serialized under one big lock to prevent bitbake server container issues - // We want to open another terminal right away to show the user that the command is queued - // But the process will have to wait for the previous one to finish (await process) - terminal = new BitbakeTerminal(terminalName, bitbakeDriver) - // Wait for the terminal to be ready to receive input before spawning the process - // Otherwise it might miss the first input, or the whole process! - await new Promise(resolve => terminal?.pty.onDidOpen.event(resolve)) - } - - if (!isBackground) { - terminal.terminal.show() - } - const process = bitbakeDriver.spawnBitbakeProcess(command) - await terminal.pty.runProcess(process, bitbakeScript, terminalName) - return await process -} - -export class BitbakePseudoTerminal implements vscode.Pseudoterminal { - private readonly writeEmitter = new vscode.EventEmitter() - private readonly closeEmitter = new vscode.EventEmitter() - readonly changeNameEmitter = new vscode.EventEmitter() - onDidWrite = this.writeEmitter.event - onDidClose = this.closeEmitter.event - onDidChangeName = this.changeNameEmitter.event - readonly onDidOpen = new vscode.EventEmitter() - lastExitCode: number = 0 - outputDataString: string = '' - private dimensions: vscode.TerminalDimensions | undefined - - readonly parentTerminal: BitbakeTerminal | undefined - bitbakeDriver: BitbakeDriver - - private isTaskTerminal (): boolean { - // If parentTerminal is undefined, we are running in a task terminal which handles some events itself - return this.parentTerminal === undefined - } - - open (initialDimensions: vscode.TerminalDimensions | undefined): void { - if (!this.isTaskTerminal()) { bitbakeTerminals.push(this.parentTerminal as BitbakeTerminal) } - this.onDidOpen.fire() - this.dimensions = initialDimensions - this.resizePty() - } - - setDimensions (dimensions: vscode.TerminalDimensions): void { - this.dimensions = dimensions - this.resizePty() - } - - private resizePty (): void { - void this.process?.then((process) => { - if (this.dimensions === undefined) { return } - process?.resize(this.dimensions.columns, this.dimensions.rows) - }) - } - - async close (): Promise { - if (!this.isTaskTerminal()) { bitbakeTerminals.splice(bitbakeTerminals.indexOf(this.parentTerminal as BitbakeTerminal), 1) } - if (this.isBusy()) { - // Wait for this process to be the one executed by bitbakeDriver - await this.process - void this.bitbakeDriver.killBitbake() - } - } - - handleInput (data: string): void { - if (this.process === undefined) { - this.closeEmitter.fire(0) - if (!this.isTaskTerminal()) { bitbakeTerminals.splice(bitbakeTerminals.indexOf(this.parentTerminal as BitbakeTerminal), 1) } - } else { - if (!this.isTaskTerminal()) { - if (data === '\x03') { - logger.info('Bitbake process killed by user') - void this.bitbakeDriver.killBitbake() - } - } - } - } - - private process: Promise | undefined - - isBusy (): boolean { - return this.process !== undefined - } - - constructor (bitbakeDriver: BitbakeDriver, parentTerminal?: BitbakeTerminal) { - this.parentTerminal = parentTerminal - this.bitbakeDriver = bitbakeDriver - } - - output (line: string): void { - this.writeEmitter.fire(line) - } - - public async runProcess (process: Promise, bitbakeScript: string, terminalName?: string): Promise { - if (this.process !== undefined) { - throw new Error('Bitbake process already running') - } - - this.process = process - const processResolved = await this.process - this.resizePty() - - processResolved.onData((data) => { - this.output(data.toString()) - logger.debug(data.toString()) - if (this.isTaskTerminal()) { - this.outputDataString += data.toString() - } - }) - const listener = processResolved.onData(() => { - // I wanted to use appropriate events like process.on('spawn') or terminal.open() but they are not triggered at the right time for - // the terminal to be ready to receive input - this.output(emphasisedAsterisk + ' Executing script: ' + bitbakeScript + endOfLine) - listener.dispose() - }) - - processResolved.onExit((event) => { - this.lastExitCode = event.exitCode ?? -1 - this.process = undefined - if (event.exitCode !== 0) { - this.output(emphasisedAsterisk + ' Bitbake process failed with code ' + event.exitCode + endOfLine) - if (!this.isTaskTerminal()) { - this.changeNameEmitter.fire('✖ ' + terminalName) - this.parentTerminal?.terminal.show() - } - } else { - this.output(emphasisedAsterisk + ' Bitbake process exited successfully' + endOfLine) - if (!this.isTaskTerminal()) { this.changeNameEmitter.fire('✔ ' + terminalName) } - } - if (!this.isTaskTerminal()) { this.output(emphasisedAsterisk + ' Terminal will be reused by BitBake, press any key to close it.' + endOfLine) } - if (this.isTaskTerminal()) { this.closeEmitter.fire(event.exitCode ?? -1) } - }) - - return processResolved - } -} - -class BitbakeTerminal { - readonly terminal: vscode.Terminal - readonly pty: BitbakePseudoTerminal - - constructor (terminalName: string, bitbakeDriver: BitbakeDriver) { - this.pty = new BitbakePseudoTerminal(bitbakeDriver, this) - const extensionTerminalOptions: vscode.ExtensionTerminalOptions = { - name: terminalName, - pty: this.pty, - iconPath: { - light: vscode.Uri.file(path.join(__dirname, '/../../images/yocto-light-icon.svg')), - dark: vscode.Uri.file(path.join(__dirname, '/../../images/yocto-view-icon.svg')) - } - } - this.terminal = vscode.window.createTerminal(extensionTerminalOptions) - } -} diff --git a/client/src/ui/BitbakeTerminalLinkProvider.ts b/client/src/ui/BitbakeTerminalLinkProvider.ts deleted file mode 100644 index 402df0f95..000000000 --- a/client/src/ui/BitbakeTerminalLinkProvider.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import * as vscode from 'vscode' -import { type BitBakeProjectScanner } from '../driver/BitBakeProjectScanner' -import * as fs from 'fs' - -export class BitbakeTerminalLinkProvider implements vscode.TerminalLinkProvider { - bitBakeProjectScanner: BitBakeProjectScanner - - constructor (bitBakeProjectScanner: BitBakeProjectScanner) { - this.bitBakeProjectScanner = bitBakeProjectScanner - } - - async provideTerminalLinks (context: vscode.TerminalLinkContext, token: vscode.CancellationToken): Promise { - const links: vscode.TerminalLink[] = [] - // We only have additional links to provide if we need to resolve container paths - if (!this.bitBakeProjectScanner.needsContainerPathsResolution()) { return links } - - // Match any string that starts with a slash enclosed in spaces or special characters - const regex = /(^|[^a-zA-Z0-9_/.-])(\/[a-zA-Z0-9_/.-]+)(?=$|[^a-zA-Z0-9_/.-])/g - const matches = context.line.matchAll(regex) - for (const match of matches) { - if (match.index === undefined) continue - const link = new vscode.TerminalLink( - match.index + match[1].length, - match[2].length, - // We pass the link's URI in the tooltip. There's no other way to pass data to the handleTerminalLink method. - // It's easier than storing and managing a map of links to URIs. - await this.bitBakeProjectScanner.resolveContainerPath(match[2], true) ?? match[2] - ) - links.push(link) - } - return links - } - - handleTerminalLink (link: vscode.TerminalLink): vscode.ProviderResult { - const path = link.tooltip as string - const uri = vscode.Uri.file(path) - if (fs.existsSync(path) && fs.lstatSync(path).isDirectory()) { // TODO test folder - void vscode.commands.executeCommand('revealInExplorer', uri) - } else { - void vscode.commands.executeCommand('vscode.open', uri) - } - } -} diff --git a/client/src/ui/BitbakeTerminalProfile.ts b/client/src/ui/BitbakeTerminalProfile.ts deleted file mode 100644 index 9757dcc5b..000000000 --- a/client/src/ui/BitbakeTerminalProfile.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import * as vscode from 'vscode' -import { type BitbakeDriver } from '../driver/BitbakeDriver' -import path from 'path' -import { logger } from '../lib/src/utils/OutputLogger' - -export class BitbakeTerminalProfileProvider implements vscode.TerminalProfileProvider { - private readonly bitbakeDriver: BitbakeDriver - - constructor (bitbakeDriver: BitbakeDriver) { - this.bitbakeDriver = bitbakeDriver - } - - provideTerminalProfile (token?: vscode.CancellationToken): vscode.ProviderResult { - // This does not take the lock of bitbakeDriver.bitbakeProcess - // which means pipe errors if using docker containers in parallel to commands. - // However it's also expected an interactive terminal can stay open on the side. - // We can't use BitbakeTerminal either because VSCode won't allow it to be interactive. - const command = this.bitbakeDriver.composeInteractiveCommand() - const { shell, script } = this.bitbakeDriver.prepareCommand(command) - logger.info(`Spawning Bitbake terminal with ${shell} -c ${script}`) - return { - options: { - name: script, - shellPath: shell, - shellArgs: ['-c', script], - env: { ...process.env, ...this.bitbakeDriver.bitbakeSettings.shellEnv }, - cwd: this.bitbakeDriver.bitbakeSettings.workingDirectory, - iconPath: vscode.Uri.file(path.resolve(__dirname, '../../images/yocto-view-icon.svg')) - } satisfies vscode.TerminalOptions - } - } -} - -export async function openBitbakeTerminalProfile (terminalProvider: BitbakeTerminalProfileProvider): Promise { - // This doesn't take the bitbake driver lock. If the user opens a terminal while a command is running, - // broken pipe errors to the bitbake server can occur. This is docummented in TROUBLESHOOTING.md. - const profile = await terminalProvider.provideTerminalProfile() as vscode.TerminalProfile - const terminal = vscode.window.createTerminal(profile.options) - terminal.show() - return terminal -} diff --git a/client/src/ui/BitbakeWorkspace.ts b/client/src/ui/BitbakeWorkspace.ts index 83f2a57b0..830ffcefc 100644 --- a/client/src/ui/BitbakeWorkspace.ts +++ b/client/src/ui/BitbakeWorkspace.ts @@ -4,7 +4,7 @@ * ------------------------------------------------------------------------------------------ */ import { EventEmitter } from 'events' -import type * as vscode from 'vscode' +import type * as vscode from 'coc.nvim' /// Class representing active bitbake recipes for a bitbake project export class BitbakeWorkspace { diff --git a/client/src/ui/ClientNotificationManager.ts b/client/src/ui/ClientNotificationManager.ts index 9e77e6917..edfdd0f43 100644 --- a/client/src/ui/ClientNotificationManager.ts +++ b/client/src/ui/ClientNotificationManager.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ -import { type Memento, commands, window } from 'vscode' +import { type Memento, commands, window } from 'coc.nvim' import { logger } from '../lib/src/utils/OutputLogger' export class ClientNotificationManager { @@ -87,7 +87,7 @@ You can configure the sources' workspace to use the Yocto SDK for cross-compilat }) } - private neverShowAgain (method: string): Thenable { + private neverShowAgain (method: string): Promise { if (this._memento === undefined) { throw new Error('ClientNotificationManager Memento not set') } diff --git a/client/src/ui/DevtoolWorkspacesView.ts b/client/src/ui/DevtoolWorkspacesView.ts deleted file mode 100644 index 8f9f7ffd3..000000000 --- a/client/src/ui/DevtoolWorkspacesView.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import * as vscode from 'vscode' -import { scanContainsData, type BitbakeScanResult, type DevtoolWorkspaceInfo } from '../lib/src/types/BitbakeScanResult' -import { type BitBakeProjectScanner } from '../driver/BitBakeProjectScanner' - -export class DevtoolWorkspacesView { - private readonly devtoolTreeProvider: DevtoolTreeDataProvider - - constructor (bitbakeProjectScanner: BitBakeProjectScanner) { - this.devtoolTreeProvider = new DevtoolTreeDataProvider(bitbakeProjectScanner) - } - - registerView (context: vscode.ExtensionContext): void { - const view = vscode.window.createTreeView('devtoolWorkspaces', { treeDataProvider: this.devtoolTreeProvider, showCollapseAll: true }) - context.subscriptions.push(view) - vscode.window.registerTreeDataProvider('devtoolWorkspaces', this.devtoolTreeProvider) - } -} - -class DevtoolTreeDataProvider implements vscode.TreeDataProvider { - private readonly _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter() - readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event - private bitbakeScanResults: BitbakeScanResult | undefined - - constructor (bitbakeProjectScanner: BitBakeProjectScanner) { - bitbakeProjectScanner.onChange.on('scanReady', (scanResults: BitbakeScanResult) => { - // In case a parsing error was just introduced, we keep the previous results to keep navigation functional - if (this.bitbakeScanResults === undefined || !scanContainsData(this.bitbakeScanResults) || scanContainsData(scanResults)) { - this.bitbakeScanResults = scanResults - } - this._onDidChangeTreeData.fire(undefined) - }) - } - - getTreeItem (element: DevtoolWorkspaceTreeItem): vscode.TreeItem | Thenable { - return element - } - - async getChildren (element?: DevtoolWorkspaceTreeItem | undefined): Promise { - if (element === undefined) { - while (this.bitbakeScanResults === undefined) { - await new Promise(resolve => setTimeout(resolve, 300)) - } - const items = this.getDevtoolWorkspaces() - items.push(this.getAddWorkspaceItem()) - return items - } - - // No children for devtool workspaces - return [] - } - - private getDevtoolWorkspaces (): DevtoolWorkspaceTreeItem[] { - if (this.bitbakeScanResults === undefined) { - return [] - } - return this.bitbakeScanResults._workspaces.map((workspace: DevtoolWorkspaceInfo) => { - return new DevtoolWorkspaceTreeItem(workspace) - }) - } - - private getAddWorkspaceItem (): DevtoolWorkspaceTreeItem { - const item = new DevtoolWorkspaceTreeItem({ name: 'New devtool workspace', path: '' }) - item.command = { command: 'bitbake.devtool-modify', title: 'Open a new devtool workspace to modify a recipe\'s sources', arguments: [undefined] } - item.iconPath = new vscode.ThemeIcon('edit') - item.contextValue = undefined - item.tooltip = 'Open a new devtool workspace to modify a recipe\'s sources' - return item - } -} - -export class DevtoolWorkspaceTreeItem extends vscode.TreeItem { - constructor (public readonly workspace: DevtoolWorkspaceInfo) { - super(workspace.name, vscode.TreeItemCollapsibleState.None) - this.contextValue = 'devtoolWorskpaceCtx' - this.iconPath = new vscode.ThemeIcon('folder') - this.command = { - command: 'bitbake.devtool-open-workspace', - title: 'Open sources workspace in a new window', - arguments: [ - workspace.name - ] - } - this.tooltip = "Open the workspace's sources in a new window" - } -} diff --git a/client/src/utils/ProcessUtils.ts b/client/src/utils/ProcessUtils.ts deleted file mode 100644 index 4382a22ac..000000000 --- a/client/src/utils/ProcessUtils.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) 2023 Savoir-faire Linux. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ - -import * as vscode from 'vscode' -import type childProcess from 'child_process' -import { logger } from '../lib/src/utils/OutputLogger' -import type * as nodepty from 'node-pty' - -function importFromVSCode (id: string): NodeRequire { - /* Inspired by https://github.com/microsoft/vscode/issues/658#issuecomment-982842847 - * VSCode uses electron with a custom NODE_MODULE_VERSION and it's own node-pty version - * We need to use the same node-pty version as VSCode to avoid compatibility issues - * Meanwhile, under jest, we need to use the regular node-pty version - * Types still need to be imported normally at compile time - */ - try { - return require(`${vscode.env.appRoot}/node_modules.asar/${id}`) - } catch (err) { - // ignore - } - try { - return require(`${vscode.env.appRoot}/node_modules/${id}`) - } catch (err) { - // ignore - } - return require(id) -} - -// The conversion allows the linter to understand the type of the imported module -export const pty = importFromVSCode('node-pty') as unknown as typeof nodepty - -export const BITBAKE_TIMEOUT = 300000 -export const BITBAKE_EXIT_TIMEOUT = 30000 - -export type KillProcessFunction = (child: nodepty.IPty) => Promise - -/// Wait for an asynchronous process to finish and return its output -export async function finishProcessExecution (process: Promise, timeoutCallback: KillProcessFunction = async (child) => { child.kill() }, timeout = BITBAKE_TIMEOUT): Promise> { - return await new Promise>((resolve, reject) => { - process.then((child) => { - let stdout = '' - const stderr = '' - child.onData((data) => { - stdout += data - }) - child.onExit((event) => { - clearTimeout(timer) - const stdoutBuffer = Buffer.from(stdout) - const stderrBuffer = Buffer.from(stderr) - resolve({ - pid: child.pid ?? -1, - output: [stdoutBuffer, stderrBuffer], - stdout: stdoutBuffer, - stderr: stderrBuffer, - status: event.exitCode, - signal: null - }) - }) - const timer = setTimeout(() => { - void timeoutCallback(child) - logger.error(`Process ${child.pid} timed out after ${timeout}ms`) - // TODO If we can't terminate, just resolve with the current output - }, timeout) - }, - (error) => { - reject(error) - }) - }) -}