Skip to content

Commit

Permalink
Use Talon rpc library (#34)
Browse files Browse the repository at this point in the history
Use the Talon rpc library as the single source of truth for the rpc
server protocol. Is also used by:
https://github.com/AndreasArvidsson/clippy
https://github.com/AndreasArvidsson/talon-browser
  • Loading branch information
AndreasArvidsson authored Jan 19, 2025
1 parent c94f885 commit 0ea02a2
Show file tree
Hide file tree
Showing 10 changed files with 37 additions and 317 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"type": "git",
"url": "https://github.com/cursorless-dev/command-server"
},
"version": "0.10.1",
"version": "0.11.0",
"engines": {
"vscode": "^1.53.0"
},
Expand Down Expand Up @@ -138,6 +138,7 @@
},
"dependencies": {
"minimatch": "^3.0.4",
"rimraf": "^3.0.2"
"rimraf": "^3.0.2",
"talon-rpc": "2.1.0"
}
}
88 changes: 16 additions & 72 deletions src/commandRunner.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
import { Minimatch } from "minimatch";
import type { RequestCallbackOptions } from "talon-rpc";
import * as vscode from "vscode";

import { any } from "./regex";
import { Request } from "./types";
import { Io } from "./io";

export default class CommandRunner {
private allowRegex!: RegExp;
private denyRegex!: RegExp | null;
private backgroundWindowProtection!: boolean;

constructor(private io: Io) {
constructor() {
this.reloadConfiguration = this.reloadConfiguration.bind(this);
this.runCommand = this.runCommand.bind(this);

this.reloadConfiguration();
vscode.workspace.onDidChangeConfiguration(this.reloadConfiguration);
}

reloadConfiguration() {
private reloadConfiguration() {
const allowList = vscode.workspace
.getConfiguration("command-server")
.get<string[]>("allowList")!;
Expand All @@ -41,77 +39,23 @@ export default class CommandRunner {
.get<boolean>("backgroundWindowProtection")!;
}

/**
* Reads a command from the request file and executes it. Writes information
* about command execution to the result of the command to the response file,
* If requested, will wait for command to finish, and can also write command
* output to response file. See also documentation for Request / Response
* types.
*/
async runCommand() {
await this.io.prepareResponse();

let request: Request;

try {
request = await this.io.readRequest();
} catch (err) {
await this.io.closeResponse();
throw err;
}

const { commandId, args, uuid, returnCommandOutput, waitForFinish } =
request;

const warnings = [];

let commandPromise: Thenable<unknown> | undefined;

try {
if (!vscode.window.state.focused) {
if (this.backgroundWindowProtection) {
throw new Error("This editor is not active");
} else {
warnings.push("This editor is not active");
}
}

if (!commandId.match(this.allowRegex)) {
throw new Error("Command not in allowList");
runCommand(commandId: string, args: any[], options: RequestCallbackOptions) {
if (!vscode.window.state.focused) {
if (this.backgroundWindowProtection) {
throw new Error("This editor is not active");
} else {
options.warn("This editor is not active");
}

if (this.denyRegex != null && commandId.match(this.denyRegex)) {
throw new Error("Command in denyList");
}

commandPromise = vscode.commands.executeCommand(commandId, ...args);

let commandReturnValue = null;

if (returnCommandOutput) {
commandReturnValue = await commandPromise;
} else if (waitForFinish) {
await commandPromise;
}

await this.io.writeResponse({
error: null,
uuid,
returnValue: commandReturnValue,
warnings,
});
} catch (err) {
await this.io.writeResponse({
error: (err as Error).message,
uuid,
warnings,
});
}

await this.io.closeResponse();
if (!commandId.match(this.allowRegex)) {
throw new Error("Command not in allowList");
}

if (commandPromise != null) {
await commandPromise;
if (this.denyRegex != null && commandId.match(this.denyRegex)) {
throw new Error("Command in denyList");
}

return vscode.commands.executeCommand(commandId, ...args);
}
}
8 changes: 1 addition & 7 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1 @@
// How old a request file needs to be before we declare it stale and are willing
// to remove it
export const STALE_TIMEOUT_MS = 60000;

// The amount of time that client is expected to wait for VSCode to perform a
// command, in seconds
export const VSCODE_COMMAND_TIMEOUT_MS = 3000;
export const RPC_DIR_NAME = "vscode-command-server";
13 changes: 8 additions & 5 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import { NodeIo, TalonRpcServer } from "talon-rpc";
import * as vscode from "vscode";

import { NativeIo } from "./nativeIo";
import CommandRunner from "./commandRunner";
import { RPC_DIR_NAME } from "./constants";
import { FocusedElementType } from "./types";

export async function activate(context: vscode.ExtensionContext) {
const io = new NativeIo();
const commandRunner = new CommandRunner();
const io = new NodeIo(RPC_DIR_NAME);
const rpc = new TalonRpcServer(io, commandRunner.runCommand);

await io.initialize();

const commandRunner = new CommandRunner(io);
let focusedElementType: FocusedElementType | undefined;

context.subscriptions.push(
vscode.commands.registerCommand(
"command-server.runCommand",
async (focusedElementType_: FocusedElementType) => {
focusedElementType = focusedElementType_;
await commandRunner.runCommand();
await rpc.executeRequest();
focusedElementType = undefined;
}
),

vscode.commands.registerCommand(
"command-server.getFocusedElementType",
() => focusedElementType
Expand Down
29 changes: 0 additions & 29 deletions src/io.ts

This file was deleted.

122 changes: 0 additions & 122 deletions src/nativeIo.ts

This file was deleted.

24 changes: 0 additions & 24 deletions src/paths.ts

This file was deleted.

Loading

0 comments on commit 0ea02a2

Please sign in to comment.