diff --git a/src/client.ts b/src/client.ts index c44a609..132c38c 100644 --- a/src/client.ts +++ b/src/client.ts @@ -9,7 +9,6 @@ import { TestItem, TestMessage, TestController, - OutputChannel, CancellationToken, TestRunRequest, } from 'vscode'; @@ -101,19 +100,14 @@ function getLspCommand(uri: Uri) { } export default class Client extends LanguageClient { - #uri: Uri; #command: string; - #args: string[]; - #output: OutputChannel; profileRunResult: NargoProfileRunResult; // This function wasn't added until vscode 1.81.0 so fake the type #testController: TestController & { invalidateTestResults?: (item: TestItem) => void; }; - constructor(uri: Uri, workspaceFolder?: WorkspaceFolder) { - const outputChannel = window.createOutputChannel(extensionName, languageId); - + constructor(uri: Uri, workspaceFolder?: WorkspaceFolder, file?: string) { const [command, args] = getLspCommand(uri); const documentSelector: TextDocumentFilter[] = []; @@ -139,12 +133,12 @@ export default class Client extends LanguageClient { const clientOptions: LanguageClientOptions = { documentSelector, workspaceFolder, - outputChannel, initializationOptions: { enableCodeLens, }, + outputChannelName: file ? `${extensionName} (${file})` : `${extensionName}`, + traceOutputChannel: file ? null : window.createOutputChannel(`${extensionName} Trace`), }; - const serverOptions: ServerOptions = { command, args, @@ -152,10 +146,7 @@ export default class Client extends LanguageClient { super(languageId, extensionName, serverOptions, clientOptions); - this.#uri = uri; this.#command = command; - this.#args = args; - this.#output = outputChannel; // TODO: Figure out how to do type-safe onNotification this.onNotification('nargo/tests/update', (testData: NargoTests) => { diff --git a/src/extension.ts b/src/extension.ts index 9afc1dd..f72f229 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -240,7 +240,7 @@ async function addFileClient(uri: Uri) { const file = uri.toString(); if (!lspClients.has(file)) { // Start the client. This will also launch the server - const client = new Client(uri); + const client = new Client(uri, undefined, file); lspClients.set(file, client); await client.start(); } @@ -290,8 +290,13 @@ async function runNargoExpand() { if (!editor) return 'Not available'; const document = editor.document; - const workspaceFolder = workspace.getWorkspaceFolder(document.uri).uri.toString(); - const client = lspClients.get(workspaceFolder); + const workspaceFolder = workspace.getWorkspaceFolder(document.uri); + let client: Client; + if (workspaceFolder) { + client = lspClients.get(workspaceFolder.uri.toString()); + } else { + client = lspClients.get(document.uri.toString()); + } if (!client) return 'Not available'; const position = editor.selection.active; @@ -365,12 +370,17 @@ async function didOpenTextDocument(document: TextDocument): Promise } else { // We only want to handle `file:` and `untitled:` schemes because // vscode sends `output:` schemes for markdown responses from our LSP - if (uri.scheme !== 'file' && uri.scheme !== 'untitled') { + if (uri.scheme !== 'file' && uri.scheme !== 'untitled' && uri.scheme !== 'noir-std') { return Disposable.from(); } // Each file outside of a workspace gets it's own client await addFileClient(uri); + + if (uri.scheme === 'noir-std') { + return Disposable.from(); + } + registerFileCommands(uri); configHandler = mutex(uri.toString(), async (e: ConfigurationChangeEvent) => { @@ -401,6 +411,18 @@ async function didOpenTextDocument(document: TextDocument): Promise } } +async function didCloseTextDocument(document: TextDocument): Promise { + // We are only interested in language mode text + if (document.languageId !== languageId) { + return Disposable.from(); + } + + const uri = document.uri; + if (uri.scheme === 'noir-std') { + await removeFileClient(uri); + } +} + async function didChangeWorkspaceFolders(event: WorkspaceFoldersChangeEvent) { // Reset the workspace folders so it'll sort them again workspaceFolders = []; @@ -415,12 +437,21 @@ async function didChangeWorkspaceFolders(event: WorkspaceFoldersChangeEvent) { } export async function activate(context: ExtensionContext): Promise { + registerNoirStdContentProvider(); + const didOpenTextDocument$ = workspace.onDidOpenTextDocument(didOpenTextDocument); + const didCloseTextDocument$ = workspace.onDidCloseTextDocument(didCloseTextDocument); const didChangeWorkspaceFolders$ = workspace.onDidChangeWorkspaceFolders(didChangeWorkspaceFolders); const restart$ = commands.registerCommand('noir.restart', restartAllClients); const expand$ = commands.registerCommand('nargo.expand', runNargoExpand); - context.subscriptions.push(didOpenTextDocument$, didChangeWorkspaceFolders$, restart$, expand$); + context.subscriptions.push( + didOpenTextDocument$, + didCloseTextDocument$, + didChangeWorkspaceFolders$, + restart$, + expand$, + ); for (const doc of workspace.textDocuments) { const disposable = await didOpenTextDocument(doc); @@ -439,3 +470,17 @@ export async function deactivate(): Promise { await commands.executeCommand('setContext', NOIR_PROJECT_CONTEXT_NAME, undefined); } + +function registerNoirStdContentProvider() { + const noir_std_provider = new (class implements TextDocumentContentProvider { + async provideTextDocumentContent(uri: Uri): Promise { + if (lspClients.size == 0) { + return 'Not available'; + } + // Any client can answer this request + const client: Client = lspClients.values().next().value; + return await client.sendRequest('nargo/std-source-code', { uri: uri.toString() }); + } + })(); + workspace.registerTextDocumentContentProvider('noir-std', noir_std_provider); +}