diff --git a/verilog/tools/ls/vscode/.gitignore b/verilog/tools/ls/vscode/.gitignore index 7a191ee42..01d822585 100644 --- a/verilog/tools/ls/vscode/.gitignore +++ b/verilog/tools/ls/vscode/.gitignore @@ -3,3 +3,5 @@ node_modules package-lock.json README.html dist/ +bin/ +.vscode/ diff --git a/verilog/tools/ls/vscode/README.md b/verilog/tools/ls/vscode/README.md index 8d6b291dc..d4fbb6e7e 100644 --- a/verilog/tools/ls/vscode/README.md +++ b/verilog/tools/ls/vscode/README.md @@ -1,5 +1,15 @@ # Verible Language Server Extension +## Quick Start +The extension provides support for Verible Language Serve in Visual Studio Code. + +Before enjoying the privilige of modern language server features, you need to take the following instructions. + +1. Install the Verible Language Server. This is described in the `Prerequisite on your machine` section below. +2. Generate the `verible.filelist` at the root directory. You can execute the `Verible: Generate File List` command in VSCode to achive it. +3. If you add new source files into your project, you'll need to generate the `verible.filelist` again to include them. +> New to VSCode and have no idea how to execute a VSCode command? Try hitting `Ctrl+Shift+P` (for Windows) or `Command+Shift+P` (for MacOS) and type `Verible: Generate File List`, then press `Enter`. + ## Features The language server provides a couple of features from the [Verible SystemVerilog productivity suite](https://github.com/chipsalliance/verible) right in the editor. diff --git a/verilog/tools/ls/vscode/package.json b/verilog/tools/ls/vscode/package.json index 3c234f235..39003a17e 100644 --- a/verilog/tools/ls/vscode/package.json +++ b/verilog/tools/ls/vscode/package.json @@ -28,6 +28,12 @@ ] } ], + "commands": [ + { + "command": "verible.generateFileList", + "title": "Verible: Generate File List" + } + ], "configuration": { "type": "object", "title": "verible", @@ -45,6 +51,14 @@ "type": "string" }, "description": "Arguments for verible-verilog-ls server." + }, + "verible.includedFileExts": { + "type": "array", + "default": [".v", ".sv", ".vh", ".svh"], + "items": { + "type": "string" + }, + "description": "Included files when generating verible.filelist." } } } @@ -72,12 +86,12 @@ "vsix": "vsce package -o verible.vsix" }, "devDependencies": { + "@types/decompress": "^4.2.4", + "@types/follow-redirects": "^1.14.1", "@types/glob": "^7.1.4", "@types/mocha": "^9.0.0", "@types/node": "14.x", "@types/vscode": "^1.61.0", - "@types/decompress": "^4.2.4", - "@types/follow-redirects": "^1.14.1", "@typescript-eslint/eslint-plugin": "^4.31.1", "@typescript-eslint/parser": "^4.31.1", "@vscode/test-electron": "^1.6.2", @@ -87,7 +101,7 @@ "ts-loader": "^9.2.5", "typescript": "^4.4.3", "vsce": "^1.100.1", - "webpack": "^5.52.1", + "webpack": "^5.95.0", "webpack-cli": "^4.10.0" }, "dependencies": { diff --git a/verilog/tools/ls/vscode/src/download-ls.js b/verilog/tools/ls/vscode/src/download-ls.js new file mode 100644 index 000000000..456ac91de --- /dev/null +++ b/verilog/tools/ls/vscode/src/download-ls.js @@ -0,0 +1,113 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.checkAndDownloadBinaries = void 0; +const os_1 = require("os"); +const fs = require("fs"); +const path = require("path"); +const follow_redirects_1 = require("follow-redirects"); +const child_process_1 = require("child_process"); +const decompress = require("decompress"); +const decompressTargz = require("decompress-targz"); +const decompressUnzip = require("decompress-unzip"); +const TAG = require("../package.json").repository.tag; +function checkIfBinaryExists(binaryPath) { + let whichCommand; + let binaryExists; + if ((0, os_1.platform)() == "win32") { + let parsedBinPath = path.parse(binaryPath); + whichCommand = `where "${parsedBinPath.dir}:${parsedBinPath.base}"`; + } + else { + whichCommand = `command -v ${binaryPath}`; + } + binaryExists = true; + try { + (0, child_process_1.execSync)(whichCommand, { windowsHide: true }); + } + catch { + binaryExists = false; + } + return binaryExists; +} +async function checkAndDownloadBinaries(binaryPath, output) { + output.appendLine("Platform: '" + (0, os_1.platform)() + "'"); + // Update home paths to an absolute path + if ((0, os_1.platform)() != "win32" && binaryPath.startsWith("~/")) { + binaryPath = binaryPath.replace("~", ""); + binaryPath = path.join((0, os_1.homedir)(), binaryPath); + output.appendLine(`Adjusted server path: ${binaryPath}`); + } + if (checkIfBinaryExists(binaryPath)) { + // Language server binary exists -- nothing to do + return binaryPath; + } + output.appendLine(`Set language server executable (${binaryPath}) doesn't exist or cannot be accessed`); + if ((0, os_1.platform)() === "darwin") { + // There is no static binaries for MacOS -- aborting + output.appendLine("GitHub release is not available for MacOS. Language server can be installed with:"); + output.appendLine("\tbrew tap chipsalliance/verible"); + output.appendLine("\tbrew install verible"); + return binaryPath; + } + const pluginDir = path.join(__dirname, ".."); + const binDir = path.join(pluginDir, "bin"); + const pluginBinaryPath = path.join(binDir, "verible-verilog-ls" + ((0, os_1.platform)() === "win32" ? ".exe" : "")); + if (checkIfBinaryExists(pluginBinaryPath)) { + output.appendLine("Language server binary already downloaded"); + return pluginBinaryPath; + } + // Retreving tag based on plugin's version + if (TAG === undefined || TAG === null) { + // No tag found -- aborting + return binaryPath; + } + output.appendLine(`Extension will attempt to download executables (${TAG}) from GitHub Release page`); + // Preparing URL + let platformName, extension, archName = ""; + if ((0, os_1.platform)() === "win32") { + platformName = "win64"; + extension = "zip"; + } + else { + platformName = "linux-static"; + archName = (0, os_1.arch)() === "x64" ? "-x86_64" : "-aarch64"; + extension = "tar.gz"; + } + const releaseUrl = `https://github.com/chipsalliance/verible/releases/download/${TAG}/verible-${TAG}-${platformName}${archName}.${extension}`; + // Creating bin directory + fs.mkdirSync(binDir, { recursive: true }); + // Downloading release + const archivePath = path.join(pluginDir, `verible.${extension}`); + const archive = fs.createWriteStream(archivePath); + await new Promise((resolve, reject) => follow_redirects_1.https.get(releaseUrl, (response) => { + if (response.statusCode !== 200) { + output.appendLine("Download failed with status code " + response.statusCode); + reject("Status code " + response.statusCode); + } + response.pipe(archive); + archive.on("finish", () => { + archive.close(); + resolve(); + }); + }).on("error", (_err) => { + output.appendLine("Failed to start download"); + return binaryPath; + })); + // Unpacking and removing downloaded archive + await decompress(archivePath, binDir, { + filter: (file) => path.basename(file.path).startsWith("verible-verilog-ls"), + map: (file) => { + file.path = path.basename(file.path); + return file; + }, + plugins: (0, os_1.platform)() === "win32" ? [decompressUnzip()] : [decompressTargz()], + }).catch((_err) => { + return binaryPath; + }) + .finally(() => { + fs.rm(archivePath, () => null); + }); + return pluginBinaryPath; +} +exports.checkAndDownloadBinaries = checkAndDownloadBinaries; +//# sourceMappingURL=download-ls.js.map \ No newline at end of file diff --git a/verilog/tools/ls/vscode/src/download-ls.js.map b/verilog/tools/ls/vscode/src/download-ls.js.map new file mode 100644 index 000000000..eea28e3b6 --- /dev/null +++ b/verilog/tools/ls/vscode/src/download-ls.js.map @@ -0,0 +1 @@ +{"version":3,"file":"download-ls.js","sourceRoot":"","sources":["download-ls.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/verilog/tools/ls/vscode/src/extension.js b/verilog/tools/ls/vscode/src/extension.js new file mode 100644 index 000000000..aff6337dc --- /dev/null +++ b/verilog/tools/ls/vscode/src/extension.js @@ -0,0 +1,98 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.deactivate = exports.activate = void 0; +const vscode = require("vscode"); +const vscodelc = require("vscode-languageclient/node"); +const download_ls_1 = require("./download-ls"); +const util_1 = require("util"); +// Global object to dispose of previous language clients. +let client = undefined; +async function initLanguageClient() { + const output = vscode.window.createOutputChannel("Verible Language Server"); + const config = vscode.workspace.getConfiguration("verible"); + const binary_path = await (0, download_ls_1.checkAndDownloadBinaries)(config.get("path"), output); + output.appendLine(`Using executable from path: ${binary_path}`); + const verible_ls = { + command: binary_path, + args: await config.get("arguments"), + }; + const serverOptions = verible_ls; + // Options to control the language client + const clientOptions = { + // Register the server for (System)Verilog documents + documentSelector: [ + { scheme: "file", language: "systemverilog" }, + { scheme: "file", language: "verilog" }, + ], + outputChannel: output, + }; + // Create the language client and start the client. + output.appendLine("Starting Language Server"); + client = new vscodelc.LanguageClient("verible", "Verible Language Server", serverOptions, clientOptions); + client.start(); +} +function restartLanguageClient() { + if (!client) { + return initLanguageClient(); + } + return client.stop().finally(() => { + initLanguageClient(); + }); +} +function bindGenerateFileListCommand(ctx) { + const cmd = "verible.generateFileList"; + const encoder = new util_1.TextEncoder(); + const cmdHandler = () => { + const fs = vscode.workspace.fs; + vscode.workspace.workspaceFolders?.forEach(async (folder) => { + var folders = ["."]; + var fileList = []; + while (folders.length > 0) { + var cur = folders.pop(); + var files = await fs.readDirectory(vscode.Uri.joinPath(folder.uri, cur)); + files.forEach(([fileName, type]) => { + switch (type) { + case vscode.FileType.File: + if (fileName.endsWith(".sv") || + fileName.endsWith(".v") || + fileName.endsWith(".vh")) { + fileList.push(cur + "/" + fileName); + } + break; + case vscode.FileType.Directory: + // console.log(cur + "/" + fileName); + folders.push(cur + "/" + fileName); + break; + } + }); + } + fs.writeFile(vscode.Uri.joinPath(folder.uri, "verible.filelist"), encoder.encode(fileList.join("\n"))); + }); + return restartLanguageClient(); + }; + ctx.subscriptions.push(vscode.commands.registerCommand(cmd, cmdHandler)); +} +// VSCode entrypoint to bootstrap an extension +function activate(context) { + // Bind Commands + bindGenerateFileListCommand(context); + // If a configuration change even it fired, let's dispose + // of the previous client and create a new one. + vscode.workspace.onDidChangeConfiguration(async (event) => { + if (!event.affectsConfiguration("verible")) { + return; + } + restartLanguageClient(); + }); + return initLanguageClient(); +} +exports.activate = activate; +// Entrypoint to tear it down. +function deactivate() { + if (!client) { + return undefined; + } + return client.stop(); +} +exports.deactivate = deactivate; +//# sourceMappingURL=extension.js.map \ No newline at end of file diff --git a/verilog/tools/ls/vscode/src/extension.js.map b/verilog/tools/ls/vscode/src/extension.js.map new file mode 100644 index 000000000..935c7b282 --- /dev/null +++ b/verilog/tools/ls/vscode/src/extension.js.map @@ -0,0 +1 @@ +{"version":3,"file":"extension.js","sourceRoot":"","sources":["extension.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/verilog/tools/ls/vscode/src/extension.ts b/verilog/tools/ls/vscode/src/extension.ts index ac0a4b1c9..d3ce8d54d 100644 --- a/verilog/tools/ls/vscode/src/extension.ts +++ b/verilog/tools/ls/vscode/src/extension.ts @@ -1,65 +1,128 @@ -import * as vscode from 'vscode'; -import * as vscodelc from 'vscode-languageclient/node'; -import { checkAndDownloadBinaries } from './download-ls'; +import * as vscode from "vscode"; +import * as vscodelc from "vscode-languageclient/node"; +import { checkAndDownloadBinaries } from "./download-ls"; +import { TextEncoder } from "util"; // Global object to dispose of previous language clients. let client: undefined | vscodelc.LanguageClient = undefined; async function initLanguageClient() { - const output = vscode.window.createOutputChannel('Verible Language Server'); - const config = vscode.workspace.getConfiguration('verible'); - const binary_path: string = await checkAndDownloadBinaries(config.get('path') as string, output); + const output = vscode.window.createOutputChannel("Verible Language Server"); + const config = vscode.workspace.getConfiguration("verible"); + const binary_path: string = await checkAndDownloadBinaries( + config.get("path") as string, + output + ); - output.appendLine(`Using executable from path: ${binary_path}`); + output.appendLine(`Using executable from path: ${binary_path}`); - const verible_ls: vscodelc.Executable = { - command: binary_path, - args: await config.get('arguments') - }; + const verible_ls: vscodelc.Executable = { + command: binary_path, + args: await config.get("arguments"), + }; - const serverOptions: vscodelc.ServerOptions = verible_ls; + const serverOptions: vscodelc.ServerOptions = verible_ls; - // Options to control the language client - const clientOptions: vscodelc.LanguageClientOptions = { - // Register the server for (System)Verilog documents - documentSelector: [{ scheme: 'file', language: 'systemverilog' }, - { scheme: 'file', language: 'verilog' }], - outputChannel: output - }; + // Options to control the language client + const clientOptions: vscodelc.LanguageClientOptions = { + // Register the server for (System)Verilog documents + documentSelector: [ + { scheme: "file", language: "systemverilog" }, + { scheme: "file", language: "verilog" }, + ], + outputChannel: output, + }; - // Create the language client and start the client. - output.appendLine("Starting Language Server"); - client = new vscodelc.LanguageClient( - 'verible', - 'Verible Language Server', - serverOptions, - clientOptions - ); - client.start(); + // Create the language client and start the client. + output.appendLine("Starting Language Server"); + client = new vscodelc.LanguageClient( + "verible", + "Verible Language Server", + serverOptions, + clientOptions + ); + client.start(); } -// VSCode entrypoint to bootstrap an extension -export function activate(_: vscode.ExtensionContext) { - // If a configuration change even it fired, let's dispose - // of the previous client and create a new one. - vscode.workspace.onDidChangeConfiguration(async (event) => { - if (!event.affectsConfiguration('verible')) { - return; - } - if (!client) { - return initLanguageClient(); - } - client.stop().finally(() => { - initLanguageClient(); +function restartLanguageClient() { + if (!client) { + return initLanguageClient(); + } + return client.stop().finally(() => { + initLanguageClient(); + }); +} + +function bindGenerateFileListCommand(ctx: vscode.ExtensionContext) { + const cmd = "verible.generateFileList"; + const includedExts = vscode.workspace + .getConfiguration("verible") + .get("includedFileExts")!; + const encoder = new TextEncoder(); + + console.log(includedExts); + + const cmdHandler = () => { + const fs = vscode.workspace.fs; + vscode.workspace.workspaceFolders?.forEach(async (folder) => { + var folders = ["."]; + var fileList: string[] = []; + while (folders.length > 0) { + var cur = folders.pop()!; + var files = await fs.readDirectory( + vscode.Uri.joinPath(folder.uri, cur) + ); + files.forEach(([fileName, type]) => { + switch (type) { + case vscode.FileType.File: + var dot = fileName.lastIndexOf("."); + if ( + dot >= 0 && + includedExts.includes( + fileName.substring(dot, fileName.length) + ) + ) { + fileList.push(cur + "/" + fileName); + } + break; + case vscode.FileType.Directory: + // console.log(cur + "/" + fileName); + folders.push(cur + "/" + fileName); + break; + } }); + } + fs.writeFile( + vscode.Uri.joinPath(folder.uri, "verible.filelist"), + encoder.encode(fileList.join("\n")) + ); }); - return initLanguageClient(); + return restartLanguageClient(); + }; + ctx.subscriptions.push(vscode.commands.registerCommand(cmd, cmdHandler)); +} + +// VSCode entrypoint to bootstrap an extension +export function activate(context: vscode.ExtensionContext) { + // Bind Commands + bindGenerateFileListCommand(context); + + // If a configuration change even it fired, let's dispose + // of the previous client and create a new one. + vscode.workspace.onDidChangeConfiguration(async (event) => { + if (!event.affectsConfiguration("verible")) { + return; + } + + restartLanguageClient(); + }); + return initLanguageClient(); } // Entrypoint to tear it down. export function deactivate(): Thenable | undefined { - if (!client) { - return undefined; - } - return client.stop(); + if (!client) { + return undefined; + } + return client.stop(); }