diff --git a/packages/databricks-vscode/package.json b/packages/databricks-vscode/package.json index 52b6166a3..b7918d7c0 100644 --- a/packages/databricks-vscode/package.json +++ b/packages/databricks-vscode/package.json @@ -1201,6 +1201,7 @@ "minimatch": "^10.0.1", "shell-quote": "^1.8.1", "triple-beam": "^1.4.1", + "vscode-languageclient": "^9.0.1", "winston": "^3.11.0", "yaml": "^2.3.4" }, diff --git a/packages/databricks-vscode/src/bundle/BundleLSPClient.ts b/packages/databricks-vscode/src/bundle/BundleLSPClient.ts new file mode 100644 index 000000000..82988b9bf --- /dev/null +++ b/packages/databricks-vscode/src/bundle/BundleLSPClient.ts @@ -0,0 +1,93 @@ +import { + LanguageClient, + LanguageClientOptions, + ServerOptions, +} from "vscode-languageclient/node"; +import {Disposable, Uri, workspace} from "vscode"; +import {CliWrapper} from "../cli/CliWrapper"; + +/** + * Manages the lifecycle of the DABs Language Server Protocol client. + * Spawns `databricks experimental bundle-lsp` and connects via stdio to provide + * deployment-aware features (document links, hover) for bundle YAML files. + */ +export class BundleLSPClient implements Disposable { + private client: LanguageClient | undefined; + private readonly cli: CliWrapper; + + constructor(cli: CliWrapper) { + this.cli = cli; + } + + async start(workspaceFolder: Uri, target?: string): Promise { + // Stop existing client if running. + await this.stop(); + + const args = ["experimental", "bundle-lsp"]; + if (target) { + args.push("--target", target); + } + + const serverOptions: ServerOptions = { + command: this.cli.cliPath, + args: args, + options: { + cwd: workspaceFolder.fsPath, + }, + }; + + const clientOptions: LanguageClientOptions = { + documentSelector: [ + { + scheme: "file", + language: "yaml", + pattern: "**/databricks.yml", + }, + { + scheme: "file", + language: "yaml", + pattern: "**/databricks.yaml", + }, + { + scheme: "file", + language: "yaml", + pattern: "**/bundle.yml", + }, + { + scheme: "file", + language: "yaml", + pattern: "**/bundle.yaml", + }, + ], + workspaceFolder: { + uri: workspaceFolder, + name: workspace.name ?? "workspace", + index: 0, + }, + }; + + this.client = new LanguageClient( + "databricks-bundle-lsp", + "Databricks Experimental Bundle LSP", + serverOptions, + clientOptions + ); + + await this.client.start(); + } + + async stop(): Promise { + if (this.client) { + try { + await this.client.stop(); + } catch { + // Client may already be stopped. + } + this.client = undefined; + } + } + + dispose(): void { + this.stop(); + } +} diff --git a/packages/databricks-vscode/src/extension.ts b/packages/databricks-vscode/src/extension.ts index 4713b02eb..5cc701869 100644 --- a/packages/databricks-vscode/src/extension.ts +++ b/packages/databricks-vscode/src/extension.ts @@ -50,6 +50,7 @@ import { BundleFileSet, registerBundleAutocompleteProvider, } from "./bundle"; +import {BundleLSPClient} from "./bundle/BundleLSPClient"; import {showWhatsNewPopup} from "./whatsNewPopup"; import {BundleValidateModel} from "./bundle/models/BundleValidateModel"; import {ConfigModel} from "./configuration/models/ConfigModel"; @@ -890,6 +891,20 @@ export async function activate( ); }); + // Start the DABs LSP client for deployment-aware features (document links, hover). + const bundleLSPClient = new BundleLSPClient(cli); + context.subscriptions.push(bundleLSPClient); + + const workspaceFolder = workspace.workspaceFolders?.[0]?.uri; + if (workspaceFolder) { + bundleLSPClient.start(workspaceFolder).catch((e) => { + logging.NamedLogger.getOrCreate(Loggers.Extension).error( + "Failed to start bundle LSP: ", + e + ); + }); + } + setDbnbCellLimits(workspaceFolderManager, connectionManager).catch((e) => { logging.NamedLogger.getOrCreate(Loggers.Extension).error( "Error while setting jupyter configs for parsing databricks notebooks", diff --git a/yarn.lock b/yarn.lock index bff6cb6c3..0189ec28c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3799,6 +3799,7 @@ __metadata: ts-node: ^10.9.2 typescript: ^5.3.3 vsce: ^2.15.0 + vscode-languageclient: ^9.0.1 wdio-video-reporter: ^5.1.4 wdio-vscode-service: ^6.0.2 winston: ^3.11.0 @@ -9520,6 +9521,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.3.7": + version: 7.7.4 + resolution: "semver@npm:7.7.4" + bin: + semver: bin/semver.js + checksum: 9b4a6a58e98b9723fafcafa393c9d4e8edefaa60b8dfbe39e30892a3604cf1f45f52df9cfb1ae1a22b44c8b3d57fec8a9bb7b3e1645431587cb272399ede152e + languageName: node + linkType: hard + "semver@npm:^7.5.2, semver@npm:^7.5.4": version: 7.5.4 resolution: "semver@npm:7.5.4" @@ -10840,6 +10850,41 @@ __metadata: languageName: node linkType: hard +"vscode-jsonrpc@npm:8.2.0": + version: 8.2.0 + resolution: "vscode-jsonrpc@npm:8.2.0" + checksum: f302a01e59272adc1ae6494581fa31c15499f9278df76366e3b97b2236c7c53ebfc71efbace9041cfd2caa7f91675b9e56f2407871a1b3c7f760a2e2ee61484a + languageName: node + linkType: hard + +"vscode-languageclient@npm:^9.0.1": + version: 9.0.1 + resolution: "vscode-languageclient@npm:9.0.1" + dependencies: + minimatch: ^5.1.0 + semver: ^7.3.7 + vscode-languageserver-protocol: 3.17.5 + checksum: ff30e5a9aac6726a88fe443fd631fe7e6130225299667c13162547f0a13ca2548d3f277d68cfb3ef6dc1810c048b2cf0e05024e1bcbd11982cd8acf681a67873 + languageName: node + linkType: hard + +"vscode-languageserver-protocol@npm:3.17.5": + version: 3.17.5 + resolution: "vscode-languageserver-protocol@npm:3.17.5" + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + checksum: dfb42d276df5dfea728267885b99872ecff62f6c20448b8539fae71bb196b420f5351c5aca7c1047bf8fb1f89fa94a961dce2bc5bf7e726198f4be0bb86a1e71 + languageName: node + linkType: hard + +"vscode-languageserver-types@npm:3.17.5": + version: 3.17.5 + resolution: "vscode-languageserver-types@npm:3.17.5" + checksum: 79b420e7576398d396579ca3a461c9ed70e78db4403cd28bbdf4d3ed2b66a2b4114031172e51fad49f0baa60a2180132d7cb2ea35aa3157d7af3c325528210ac + languageName: node + linkType: hard + "vscode-uri@npm:^3.0.8": version: 3.0.8 resolution: "vscode-uri@npm:3.0.8"