Skip to content

Commit

Permalink
Show document with server debug info (#694)
Browse files Browse the repository at this point in the history
## Summary

This PR is inspired by `rust-analyzer/status` request to show the debug
information in a separate window.

Reference:
https://github.com/rust-lang/rust-analyzer/blob/e865b249e63a9c73e4741b32fd1c977a98d3c556/editors/code/src/commands.ts#L37-L71

It has been adopted to fit out needs:
* The language client could be `undefined`
* When not using the native server
* Avoid showing the document if it's empty
* Return an empty string for older Ruff version which doesn't return the
information

## Test Plan



https://github.com/user-attachments/assets/c104e211-631c-43a9-b289-394c7207a92e
  • Loading branch information
dhruvmanila authored Feb 18, 2025
1 parent b4e0698 commit 01f76c1
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 22 deletions.
85 changes: 85 additions & 0 deletions src/common/commands.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as vscode from "vscode";
import { ExecuteCommandRequest, LanguageClient } from "vscode-languageclient/node";
import { getConfiguration } from "./vscodeapi";
import { ISettings } from "./settings";

const ISSUE_TRACKER = "https://github.com/astral-sh/ruff/issues";

Expand Down Expand Up @@ -36,3 +38,86 @@ async function executeCommand(lsClient: LanguageClient, command: string) {
);
});
}

/**
* Creates a debug information provider for the `ruff.printDebugInformation` command.
*
* This will open a new editor window with the debug information considering the active editor.
*/
export function createDebugInformationProvider(
getClient: () => LanguageClient | undefined,
serverId: string,
context: vscode.ExtensionContext,
) {
let configuration = getConfiguration(serverId) as unknown as ISettings;
if (configuration.nativeServer === false || configuration.nativeServer === "off") {
return async () => {
vscode.window.showInformationMessage(
"Debug information is only available when using the native server",
);
};
}

const contentProvider = new (class implements vscode.TextDocumentContentProvider {
readonly uri = vscode.Uri.parse("ruff-server-debug://debug");
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();

async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
const lsClient = getClient();
if (!lsClient) {
return "";
}
const textEditor = vscode.window.activeTextEditor;
const notebookEditor = vscode.window.activeNotebookEditor;
const params = {
command: `${serverId}.printDebugInformation`,
arguments: [
{
textDocument: notebookEditor
? { uri: notebookEditor.notebook.uri.toString() }
: textEditor
? { uri: textEditor.document.uri.toString() }
: undefined,
},
],
};
return await lsClient.sendRequest(ExecuteCommandRequest.type, params).then(
(result) => {
if (typeof result === "string") {
return result;
}
// For older Ruff version, we don't return a string but log the information.
return "";
},
async () => {
vscode.window.showErrorMessage(
`Failed to print debug information. Please consider opening an issue at ${ISSUE_TRACKER} with steps to reproduce.`,
);
return "";
},
);
}

get onDidChange(): vscode.Event<vscode.Uri> {
return this.eventEmitter.event;
}
})();

context.subscriptions.push(
vscode.workspace.registerTextDocumentContentProvider("ruff-server-debug", contentProvider),
);

return async () => {
contentProvider.eventEmitter.fire(contentProvider.uri);
const document = await vscode.workspace.openTextDocument(contentProvider.uri);
const content = document.getText();

// Show the document only if it has content.
if (content.length > 0) {
void (await vscode.window.showTextDocument(document, {
viewColumn: vscode.ViewColumn.Two,
preserveFocus: true,
}));
}
};
}
37 changes: 15 additions & 22 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as vscode from "vscode";
import { ExecuteCommandRequest, LanguageClient } from "vscode-languageclient/node";
import { LanguageClient } from "vscode-languageclient/node";
import { LazyOutputChannel, logger } from "./common/logger";
import {
checkVersion,
Expand All @@ -24,12 +24,21 @@ import {
registerCommand,
} from "./common/vscodeapi";
import { getProjectRoot } from "./common/utilities";
import { executeAutofix, executeFormat, executeOrganizeImports } from "./common/commands";
import {
executeAutofix,
executeFormat,
executeOrganizeImports,
createDebugInformationProvider,
} from "./common/commands";

let lsClient: LanguageClient | undefined;
let restartInProgress = false;
let restartQueued = false;

function getClient(): LanguageClient | undefined {
return lsClient;
}

export async function activate(context: vscode.ExtensionContext): Promise<void> {
// This is required to get server name and module. This should be
// the first thing that we do in this extension.
Expand Down Expand Up @@ -188,26 +197,10 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
await executeOrganizeImports(lsClient, serverId);
}
}),
registerCommand(`${serverId}.debugInformation`, async () => {
let configuration = getConfiguration(serverId) as unknown as ISettings;
if (!lsClient || !configuration.nativeServer) {
return;
}

const editor = vscode.window.activeTextEditor;
const params = {
command: `${serverId}.printDebugInformation`,
arguments: [
{
textDocument: editor ? { uri: editor.document.uri.toString() } : null,
},
],
};

await lsClient.sendRequest(ExecuteCommandRequest.type, params).then(undefined, async () => {
vscode.window.showErrorMessage("Failed to print debug information.");
});
}),
registerCommand(
`${serverId}.debugInformation`,
createDebugInformationProvider(getClient, serverId, context),
),
registerLanguageStatusItem(serverId, serverName, `${serverId}.showLogs`),
);

Expand Down

0 comments on commit 01f76c1

Please sign in to comment.