Skip to content

Commit

Permalink
Add ability to repeat last cursorless command
Browse files Browse the repository at this point in the history
  • Loading branch information
pokey committed Jun 17, 2024
1 parent 663c5d3 commit f41fd68
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 36 deletions.
4 changes: 4 additions & 0 deletions packages/common/src/cursorlessCommandIds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class VisibleCommand extends Command implements CommandDescription {

export const cursorlessCommandIds = [
"cursorless.command",
"cursorless.repeatPreviousCommand",
"cursorless.internal.updateCheatsheetDefaults",
"cursorless.private.logQuickActions",
"cursorless.keyboard.escape",
Expand Down Expand Up @@ -90,6 +91,9 @@ export const cursorlessCommandDescriptions: Record<
),

["cursorless.command"]: new HiddenCommand("The core cursorless command"),
["cursorless.repeatPreviousCommand"]: new VisibleCommand(
"Repeat the previous Cursorless command",
),
["cursorless.showQuickPick"]: new HiddenCommand(
"Pop up a quick pick of all cursorless commands",
),
Expand Down
5 changes: 5 additions & 0 deletions packages/cursorless-engine/src/api/CursorlessEngineApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ export interface CommandApi {
* the command args are of the correct shape.
*/
runCommandSafe(...args: unknown[]): Promise<CommandResponse | unknown>;

/**
* Repeats the previous command.
*/
repeatPreviousCommand(): Promise<CommandResponse | unknown>;
}

export interface CommandRunnerDecorator {
Expand Down
54 changes: 29 additions & 25 deletions packages/cursorless-engine/src/cursorlessEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,36 +70,40 @@ export async function createCursorlessEngine(

const commandRunnerDecorators: CommandRunnerDecorator[] = [];

let previousCommand: Command | undefined = undefined;

const runCommandClosure = (command: Command) => {
previousCommand = command;
return runCommand(
treeSitter,
commandServerApi,
debug,
hatTokenMap,
snippets,
storedTargets,
languageDefinitions,
rangeUpdater,
commandRunnerDecorators,
command,
);
};

return {
commandApi: {
runCommand(command: Command) {
return runCommand(
treeSitter,
commandServerApi,
debug,
hatTokenMap,
snippets,
storedTargets,
languageDefinitions,
rangeUpdater,
commandRunnerDecorators,
command,
);
return runCommandClosure(command);
},

async runCommandSafe(...args: unknown[]) {
return runCommand(
treeSitter,
commandServerApi,
debug,
hatTokenMap,
snippets,
storedTargets,
languageDefinitions,
rangeUpdater,
commandRunnerDecorators,
ensureCommandShape(args),
);
runCommandSafe(...args: unknown[]) {
return runCommandClosure(ensureCommandShape(args));
},

repeatPreviousCommand() {
if (previousCommand == null) {
throw new Error("No previous command");
}

return runCommandClosure(previousCommand);
},
},
scopeProvider: createScopeProvider(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ const testCases: TestCase[] = [
keySequence: ["db", "fa", "2", "n", "st", "c"],
finalContent: "aaa ccc ",
},
{
name: "repeat command",
initialContent: "aaa bbb ccc ddd",
// keyboard air
// keyboard next token twice
// clear keyboard
keySequence: ["da", "nst", " ", "c"],
finalContent: "aaa bbb ddd",
},
];

suite("Basic keyboard test", async function () {
Expand Down
4 changes: 4 additions & 0 deletions packages/cursorless-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@
"title": "Cursorless: The core cursorless command",
"enablement": "false"
},
{
"command": "cursorless.repeatPreviousCommand",
"title": "Cursorless: Repeat the previous Cursorless command"
},
{
"command": "cursorless.showQuickPick",
"title": "Cursorless: Pop up a quick pick of all cursorless commands",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@
"executeAtTarget": true,
"keepChangedSelection": true,
"exitCursorlessMode": true
}
},
" ": "cursorless.repeatPreviousCommand"
},
"cursorless.experimental.keyboard.modal.keybindings.pairedDelimiter": {
"wl": "angleBrackets",
Expand Down
28 changes: 18 additions & 10 deletions packages/cursorless-vscode/src/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,27 @@ export function registerCommands(
keyboardCommands: KeyboardCommands,
hats: VscodeHats,
): void {
const runCommandWrapper = async (run: () => Promise<unknown>) => {
try {
return await run();
} catch (e) {
if (!isTesting()) {
const err = e as Error;
console.error(err.stack);
vscodeIde.handleCommandError(err);
}
throw e;
}
};

const commands: Record<CursorlessCommandId, (...args: any[]) => any> = {
// The core Cursorless command
[CURSORLESS_COMMAND_ID]: async (...args: unknown[]) => {
try {
return await commandApi.runCommandSafe(...args);
} catch (e) {
if (!isTesting()) {
const err = e as Error;
console.error(err.stack);
vscodeIde.handleCommandError(err);
}
throw e;
}
return runCommandWrapper(() => commandApi.runCommandSafe(...args));
},

["cursorless.repeatPreviousCommand"]: async () => {
return runCommandWrapper(() => commandApi.repeatPreviousCommand());
},

// Cheatsheet commands
Expand Down

0 comments on commit f41fd68

Please sign in to comment.