Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

keyboard: Use parser for key sequences #2051

Merged
merged 44 commits into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
1bc2b31
Use parser for key sequences
pokey Nov 24, 2023
5d4ae88
cleanup grammar
pokey Nov 24, 2023
f5953e3
More tweaks
pokey Nov 24, 2023
f5e3bf9
More tweaks#
pokey Nov 24, 2023
c086d77
More tweaks
pokey Nov 24, 2023
c7efc82
Again
pokey Nov 24, 2023
4c89400
More cleanup
pokey Nov 24, 2023
774cab8
whoops
pokey Nov 24, 2023
48ab4e9
Improve naming
pokey Nov 24, 2023
a44b2f9
Merge branch 'main' into pokey/keyboard-parser
pokey Dec 1, 2023
11b87f6
PR feedback
pokey Dec 1, 2023
9292dc4
tweak
pokey Dec 1, 2023
9e9ce0a
Add example config and use it for tests
pokey Dec 1, 2023
877b806
docs
pokey Dec 1, 2023
54c71d1
more PR feedback
pokey Dec 2, 2023
dd25e8d
cleanup
pokey Dec 2, 2023
75cd229
more
pokey Dec 2, 2023
8860978
Show keys pressed
pokey Dec 2, 2023
7539276
Use trie
pokey Dec 3, 2023
8b51ad2
Add railroad to website
pokey Dec 4, 2023
5b53394
tweak
pokey Dec 4, 2023
4cc6725
rename
pokey Dec 4, 2023
47cca49
improve WorkQueue
pokey Dec 4, 2023
84b1140
Use uniqWithHash
pokey Dec 4, 2023
9601b92
use `|`
pokey Dec 4, 2023
6e6698e
relative => nextPrev
pokey Dec 4, 2023
b6042c2
Use proper sentinel values
pokey Dec 4, 2023
0a829d5
docs
pokey Dec 4, 2023
dec3998
more cleanup
pokey Dec 4, 2023
a16dcc1
lexer => keyboardLexer
pokey Dec 4, 2023
0f0aa79
Remove defaultKeyMap as we have no current use case
pokey Dec 4, 2023
467469b
improve clarity
pokey Dec 4, 2023
4137211
Remove `getSingularSectionEntry`
pokey Dec 4, 2023
eec992e
Make config sections singular
pokey Dec 4, 2023
aa1aa0c
Fix dependency spec
pokey Dec 4, 2023
8be7fa8
Tweaks
pokey Dec 4, 2023
f8fff04
Cache layers
pokey Dec 4, 2023
845f3d8
Finish plural => singular
pokey Dec 4, 2023
7b5fadf
Update doc
pokey Dec 4, 2023
6b39ea1
One more test
pokey Dec 4, 2023
c96370f
Merge branch 'main' into pokey/keyboard-parser
pokey Dec 5, 2023
843d774
one more test for good measure
pokey Dec 5, 2023
eda5c6f
Rename
pokey Dec 5, 2023
bae5514
rename
pokey Dec 5, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ trim_trailing_whitespace = false
[Makefile]
indent_style = tab

[**/vendor/**]
[**/{vendor,generated}/**]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We keep the parser generator output in source control because it's quite short, and includes types so we can type check it, and then imports work without needing a preprocessing step. We have a step in CI that ensures it's up to date, and it auto-updates when you run extension as it's quite quick to generate

charset = unset
end_of_line = unset
indent_size = unset
Expand Down
7 changes: 6 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,10 @@
}
}
},
"ignorePatterns": ["**/vendor/**/*.ts", "**/vendor/**/*.js", "**/out/**"]
"ignorePatterns": [
"**/vendor/**/*.ts",
"**/vendor/**/*.js",
"**/out/**",
"**/generated/**"
]
}
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ repos:
# tests use strings with trailing white space to represent the final
# document contents. For example
# packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/languages/ruby/changeCondition.yml
exclude: ^packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/.*/[^/]*\.yml$
exclude: ^packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/.*/[^/]*\.yml$|/generated/|^patches/
pokey marked this conversation as resolved.
Show resolved Hide resolved
- repo: local
hooks:
- id: eslint
Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
**/vendor
**/generated

# We use our own format for our recorded yaml tests to keep them compact
/packages/cursorless-vscode-e2e/src/suite/fixtures/recorded/**/*.yml
Expand Down
11 changes: 11 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"type": "npm",
"script": "esbuild",
"path": "packages/cursorless-vscode",
"dependsOn": ["Generate grammar"],
"presentation": {
"reveal": "silent"
},
Expand Down Expand Up @@ -61,6 +62,16 @@
},
"group": "build"
},
{
"label": "Generate grammar",
"type": "npm",
"script": "generate-grammar",
"path": "packages/cursorless-vscode",
"presentation": {
"reveal": "silent"
},
"group": "build"
},
{
"label": "Ensure test subset file exists",
"type": "npm",
Expand Down
10 changes: 5 additions & 5 deletions docs/user/experimental/keyboard/modal.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ The above allows you to press `ctrl-c` to switch to Cursorless mode, `escape` to
To bind keys that do not have modifiers (eg just pressing `a`), add entries like the following to your [VSCode `settings.json`](https://code.visualstudio.com/docs/getstarted/settings#_settingsjson) (or edit these settings in the VSCode settings gui by saying `"cursorless settings"`):

```json
"cursorless.experimental.keyboard.modal.keybindings.scopes": {
"cursorless.experimental.keyboard.modal.keybindings.scope": {
"i": "line",
"p": "paragraph",
";": "statement",
Expand All @@ -60,7 +60,7 @@ To bind keys that do not have modifiers (eg just pressing `a`), add entries like
"sa": "argumentOrParameter",
"sl": "url",
},
"cursorless.experimental.keyboard.modal.keybindings.actions": {
"cursorless.experimental.keyboard.modal.keybindings.action": {
"t": "setSelection",
"h": "setSelectionBefore",
"l": "setSelectionAfter",
Expand All @@ -81,13 +81,13 @@ To bind keys that do not have modifiers (eg just pressing `a`), add entries like
"ap": "pasteFromClipboard",
"ad": "followLink"
},
"cursorless.experimental.keyboard.modal.keybindings.colors": {
"cursorless.experimental.keyboard.modal.keybindings.color": {
"d": "default",
"b": "blue",
"g": "yellow",
"r": "red"
},
"cursorless.experimental.keyboard.modal.keybindings.shapes": {
"cursorless.experimental.keyboard.modal.keybindings.shape": {
"x": "ex",
"f": "fox",
"q": "frame",
Expand All @@ -97,7 +97,7 @@ To bind keys that do not have modifiers (eg just pressing `a`), add entries like
"z": "bolt",
"w": "crosshairs"
},
"cursorless.experimental.keyboard.modal.keybindings.vscodeCommands": {
"cursorless.experimental.keyboard.modal.keybindings.vscodeCommand": {
// For simple commands, just use the command name
// "aa": "workbench.action.editor.changeLanguageMode",

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
},
"pnpm": {
"patchedDependencies": {
"@docusaurus/[email protected]": "patches/@[email protected]"
"@docusaurus/[email protected]": "patches/@[email protected]",
"@types/[email protected]": "patches/@[email protected]",
josharian marked this conversation as resolved.
Show resolved Hide resolved
"[email protected]": "patches/[email protected]"
},
"peerDependencyRules": {
"ignoreMissing": [
Expand Down
1 change: 1 addition & 0 deletions packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@types/mocha": "^10.0.3",
"@types/sinon": "^10.0.2",
"cross-spawn": "7.0.3",
"fast-check": "3.12.0",
"js-yaml": "^4.1.0",
"mocha": "^10.2.0",
"sinon": "^11.1.1"
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export * from "./types/GeneralizedRange";
export * from "./types/RangeOffsets";
export * from "./util/omitByDeep";
export * from "./util/range";
export * from "./util/uniqWithHash";
export * from "./testUtil/isTesting";
export * from "./testUtil/testConstants";
export * from "./testUtil/getFixturePaths";
Expand Down
5 changes: 5 additions & 0 deletions packages/common/src/util/CompositeKeyMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,9 @@ export class CompositeKeyMap<K, V> {
delete this.map[this.hash(key)];
return this;
}

clear(): this {
this.map = {};
return this;
}
}
1 change: 0 additions & 1 deletion packages/cursorless-engine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
"@types/mocha": "^10.0.3",
"@types/sbd": "^1.0.3",
"@types/sinon": "^10.0.2",
"fast-check": "3.12.0",
"js-yaml": "^4.1.0",
"mocha": "^10.2.0",
"sinon": "^11.1.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Modifier,
Range,
ScopeType,
uniqWithHash,
} from "@cursorless/common";
import { zip } from "lodash";
import {
Expand All @@ -15,11 +16,10 @@ import { Target } from "../typings/target.types";
import { MarkStageFactory } from "./MarkStageFactory";
import { ModifierStageFactory } from "./ModifierStageFactory";
import { MarkStage, ModifierStage } from "./PipelineStages.types";
import { createContinuousRangeTarget } from "./createContinuousRangeTarget";
import { ImplicitStage } from "./marks/ImplicitStage";
import { ContainingTokenIfUntypedEmptyStage } from "./modifiers/ConditionalModifierStages";
import { PlainTarget } from "./targets";
import { uniqWithHash } from "../util/uniqWithHash";
import { createContinuousRangeTarget } from "./createContinuousRangeTarget";

export class TargetPipelineRunner {
constructor(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { EditableTextEditor, Selection } from "@cursorless/common";

import { uniqWithHash } from "./uniqWithHash";
import {
EditableTextEditor,
Selection,
uniqWithHash,
} from "@cursorless/common";

export async function setSelectionsAndFocusEditor(
editor: EditableTextEditor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@ import { getCursorlessApi, openNewEditor } from "@cursorless/vscode-common";
import { assert } from "chai";
import * as vscode from "vscode";
import { endToEndTestSetup, sleepWithBackoff } from "../../endToEndTestSetup";
import sinon from "sinon";
import path from "path";
import { getCursorlessRepoRoot } from "@cursorless/common";
import { readFile } from "node:fs/promises";

suite("Basic keyboard test", async function () {
endToEndTestSetup(this);

this.beforeEach(async () => {
await injectFakes();
});

this.afterEach(async () => {
await vscode.commands.executeCommand("cursorless.keyboard.modal.modeOff");
});
Expand Down Expand Up @@ -46,7 +54,7 @@ async function basic() {
await typeText("sf");

// Select target
await typeText("t");
await typeText("at");

assert.isTrue(editor.selection.isEqual(new vscode.Selection(0, 0, 0, 17)));

Expand All @@ -73,16 +81,16 @@ async function vscodeCommand() {
await typeText("db");

// Comment line containing *selection*
await typeText("c");
await typeText("va");
assert.equal(editor.document.getText(), "// aaa;\nbbb;\nccc;\n");

// Comment line containing *target*
await typeText("mc");
await typeText("vb");
assert.equal(editor.document.getText(), "// aaa;\n// bbb;\nccc;\n");

// Comment line containing *target*, keeping changed selection and exiting
// cursorless mode
await typeText("dcmma");
await typeText("dcvca");
assert.equal(editor.document.getText(), "// aaa;\n// bbb;\n// a;\n");

await vscode.commands.executeCommand("cursorless.keyboard.modal.modeOff");
Expand Down Expand Up @@ -111,3 +119,38 @@ async function typeText(text: string) {
await sleepWithBackoff(100);
}
}

async function injectFakes(): Promise<void> {
const { vscodeApi } = (await getCursorlessApi()).testHelpers!;

const keyboardConfigPath = path.join(
getCursorlessRepoRoot(),
"packages/cursorless-vscode/src/keyboard/keyboard-config.fixture.json",
);

const keyboardConfig = JSON.parse(await readFile(keyboardConfigPath, "utf8"));

const getConfigurationValue = sinon.fake((sectionName) => {
return keyboardConfig[
`cursorless.experimental.keyboard.modal.keybindings.${sectionName}`
];
});

sinon.replace(
vscodeApi.workspace,
"getConfiguration",
sinon.fake((section) => {
if (
!section?.startsWith(
"cursorless.experimental.keyboard.modal.keybindings",
)
) {
return vscode.workspace.getConfiguration(section);
}

return {
get: getConfigurationValue,
} as unknown as vscode.WorkspaceConfiguration;
}),
);
}
20 changes: 14 additions & 6 deletions packages/cursorless-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,7 @@
"description": "Directory containing snippets for use in Cursorless",
"type": "string"
},
"cursorless.experimental.keyboard.modal.keybindings.actions": {
"cursorless.experimental.keyboard.modal.keybindings.action": {
"description": "Define modal keybindings for actions",
"type": "object",
"additionalProperties": {
Expand Down Expand Up @@ -909,7 +909,7 @@
]
}
},
"cursorless.experimental.keyboard.modal.keybindings.vscodeCommands": {
"cursorless.experimental.keyboard.modal.keybindings.vscodeCommand": {
"description": "Define modal keybindings for running vscode commands",
"type": "object",
"additionalProperties": {
Expand Down Expand Up @@ -944,7 +944,7 @@
]
}
},
"cursorless.experimental.keyboard.modal.keybindings.colors": {
"cursorless.experimental.keyboard.modal.keybindings.color": {
"description": "Define modal keybindings for colors",
"type": "object",
"additionalProperties": {
Expand All @@ -961,7 +961,7 @@
]
}
},
"cursorless.experimental.keyboard.modal.keybindings.shapes": {
"cursorless.experimental.keyboard.modal.keybindings.shape": {
pokey marked this conversation as resolved.
Show resolved Hide resolved
"description": "Define modal keybindings for shapes",
"type": "object",
"additionalProperties": {
Expand All @@ -980,7 +980,7 @@
]
}
},
"cursorless.experimental.keyboard.modal.keybindings.scopes": {
"cursorless.experimental.keyboard.modal.keybindings.scope": {
"description": "Define modal keybindings for scopes",
"type": "object",
"additionalProperties": {
Expand Down Expand Up @@ -1091,7 +1091,7 @@
"funding": "https://github.com/sponsors/pokey",
"scripts": {
"build": "pnpm run esbuild:prod && pnpm -F cheatsheet-local build:prod && pnpm run populate-dist",
"build:dev": "pnpm run esbuild && pnpm -F cheatsheet-local build && pnpm run populate-dist",
"build:dev": "pnpm generate-grammar && pnpm run esbuild && pnpm -F cheatsheet-local build && pnpm run populate-dist",
"esbuild:base": "esbuild ./src/extension.ts --conditions=cursorless:bundler --bundle --outfile=dist/extension.cjs --external:vscode --format=cjs --platform=node",
"install-local": "bash ./scripts/install-local.sh",
"install-from-pr": "bash ./scripts/install-from-pr.sh",
Expand All @@ -1104,6 +1104,11 @@
"preprocess-svg-hats": "my-ts-node src/scripts/preprocessSvgHats.ts",
"hat-adjustment-add": "my-ts-node src/scripts/hatAdjustments/add.ts",
"hat-adjustment-average": "my-ts-node src/scripts/hatAdjustments/average.ts",
"generate-grammar:base": "nearleyc src/keyboard/grammar/grammar.ne",
"ensure-grammar-up-to-date": "pnpm -s generate-grammar:base | diff -u src/keyboard/grammar/generated/grammar.ts -",
"generate-grammar": "pnpm generate-grammar:base -o src/keyboard/grammar/generated/grammar.ts",
"generate-railroad": "nearley-railroad src/keyboard/grammar/grammar.ne -o out/railroad.html",
josharian marked this conversation as resolved.
Show resolved Hide resolved
"test": "pnpm ensure-grammar-up-to-date",
"compile": "tsc --build",
"watch": "tsc --build --watch",
"clean": "rm -rf ./out tsconfig.tsbuildinfo ./dist ./build"
Expand All @@ -1115,6 +1120,7 @@
"@types/js-yaml": "^4.0.2",
"@types/lodash": "4.14.181",
"@types/mocha": "^10.0.3",
"@types/nearley": "2.11.5",
"@types/node": "^18.18.2",
"@types/semver": "^7.3.9",
"@types/sinon": "^10.0.2",
Expand All @@ -1135,8 +1141,10 @@
"@cursorless/vscode-common": "workspace:*",
"itertools": "^2.1.1",
"lodash": "^4.17.21",
"nearley": "2.20.1",
"semver": "^7.5.2",
"tinycolor2": "1.6.0",
"trie-search": "2.0.0",
"uuid": "^9.0.0",
"vscode-uri": "^3.0.6"
},
Expand Down
6 changes: 5 additions & 1 deletion packages/cursorless-vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,11 @@ export async function activate(
addCommandRunnerDecorator(testCaseRecorder);

const statusBarItem = StatusBarItem.create("cursorless.showQuickPick");
const keyboardCommands = KeyboardCommands.create(context, statusBarItem);
const keyboardCommands = KeyboardCommands.create(
context,
vscodeApi,
statusBarItem,
);
const scopeVisualizer = createScopeVisualizer(normalizedIde, scopeProvider);
context.subscriptions.push(
revisualizeOnCustomRegexChange(scopeVisualizer, scopeProvider),
Expand Down
Loading