mirror of
https://github.com/cursorless-dev/cursorless.git
synced 2024-10-03 20:37:50 +03:00
Merge branch 'main' into pokey/add-shell-check-pre-commit-hook
This commit is contained in:
commit
57368e7848
@ -4,12 +4,15 @@
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
// We want to enable this in the long run. For now there are a lot of errors that needs to be handled.
|
||||
// "plugin:@typescript-eslint/recommended-requiring-type-checking",
|
||||
"plugin:import/typescript",
|
||||
"prettier"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module"
|
||||
"sourceType": "module",
|
||||
"project": true
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint",
|
||||
@ -20,6 +23,7 @@
|
||||
],
|
||||
"rules": {
|
||||
"import/no-relative-packages": "error",
|
||||
"@typescript-eslint/consistent-type-imports": "error",
|
||||
"@typescript-eslint/consistent-type-assertions": [
|
||||
"error",
|
||||
{
|
||||
@ -37,21 +41,22 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-inferrable-types": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
"error",
|
||||
{
|
||||
"argsIgnorePattern": "^_",
|
||||
"varsIgnorePattern": "^_",
|
||||
"ignoreRestSiblings": true
|
||||
}
|
||||
],
|
||||
"curly": "warn",
|
||||
"curly": "error",
|
||||
"eqeqeq": [
|
||||
"warn",
|
||||
"error",
|
||||
"always",
|
||||
{
|
||||
"null": "never"
|
||||
@ -67,7 +72,7 @@
|
||||
"error",
|
||||
"MemberExpression[object.property.name='constructor'][property.name='name']"
|
||||
],
|
||||
"no-throw-literal": "warn",
|
||||
"no-throw-literal": "error",
|
||||
"semi": "off",
|
||||
"unicorn/prefer-module": "error",
|
||||
"mocha/no-skipped-tests": "error",
|
||||
@ -85,21 +90,30 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"jest.config.ts",
|
||||
"docusaurus.config.mts",
|
||||
"mdx-components.tsx",
|
||||
"typings/**"
|
||||
],
|
||||
"extends": ["plugin:@typescript-eslint/disable-type-checked"]
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
"typescript": {
|
||||
"alwaysTryTypes": true, // always try to resolve types under `<root>@types` directory even it doesn't contain any source code, like `@types/unist`
|
||||
|
||||
"project": ["tsconfig.json", "packages/*/tsconfig.json"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"**/vendor/**/*.ts",
|
||||
"**/vendor/**/*.js",
|
||||
"**/generated/**",
|
||||
"**/out/**",
|
||||
"**/generated/**"
|
||||
"**/vendor/**/*.js",
|
||||
"**/vendor/**/*.ts",
|
||||
"/data/playground/**"
|
||||
]
|
||||
}
|
||||
|
11
.github/CODEOWNERS
vendored
11
.github/CODEOWNERS
vendored
@ -1,4 +1,9 @@
|
||||
* @pokey @AndreasArvidsson @phillco
|
||||
* @cursorless-dev/code-owners
|
||||
|
||||
*keyboard* @pokey @AndreasArvidsson @phillco @josharian
|
||||
*Keyboard* @pokey @AndreasArvidsson @phillco @josharian
|
||||
*keyboard* @cursorless-dev/code-owners @josharian
|
||||
*Keyboard* @cursorless-dev/code-owners @josharian
|
||||
|
||||
*neovim* @cursorless-dev/code-owners @saidelike @fidgetingbits
|
||||
*Neovim* @cursorless-dev/code-owners @saidelike @fidgetingbits
|
||||
*nvim* @cursorless-dev/code-owners @saidelike @fidgetingbits
|
||||
*Nvim* @cursorless-dev/code-owners @saidelike @fidgetingbits
|
||||
|
13
.github/actions/lint-lua-ls/action.yml
vendored
Normal file
13
.github/actions/lint-lua-ls/action.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
name: "Lua Language Server Lint"
|
||||
description: "Lints all lua files with lua-language-server"
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: cachix/install-nix-action@v27
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-unstable
|
||||
- uses: DeterminateSystems/magic-nix-cache-action@v2
|
||||
- run: nix profile install --accept-flake-config .#lua-language-server
|
||||
shell: bash
|
||||
- run: scripts/lint-lua-ls.sh
|
||||
shell: bash
|
17
.github/actions/test-neovim-lua/action.yml
vendored
Normal file
17
.github/actions/test-neovim-lua/action.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
name: "Neovim Lua Tests"
|
||||
description: "Set up Neovim Lua environment and run Busted tests"
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: leafo/gh-actions-lua@v9
|
||||
with:
|
||||
luaVersion: "luajit-2.1.0-beta3"
|
||||
- uses: leafo/gh-actions-luarocks@v4
|
||||
- shell: bash
|
||||
run: |
|
||||
luarocks install busted
|
||||
luarocks install luafilesystem
|
||||
- shell: bash
|
||||
run: |
|
||||
cd cursorless.nvim
|
||||
busted --run unit
|
40
.github/workflows/deploy.yaml
vendored
40
.github/workflows/deploy.yaml
vendored
@ -40,6 +40,46 @@ jobs:
|
||||
registryUrl: https://marketplace.visualstudio.com
|
||||
extensionFile: ${{ steps.publishToOpenVSX.outputs.vsixPath }}
|
||||
|
||||
publish-neovim-extension:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
environment: production
|
||||
env:
|
||||
CURSORLESS_REPO_ROOT: ${{ github.workspace }}
|
||||
STAGING_DIRECTORY: ${{ github.workspace }}/cursorless.nvim-staging
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: corepack enable
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
cache: pnpm
|
||||
- run: pnpm --color install
|
||||
- run: pnpm --color compile
|
||||
- run: pnpm --color --filter '!cursorless-org' --filter '!cursorless-org-*' build
|
||||
env:
|
||||
CURSORLESS_DEPLOY: true
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.CURSORLESS_BOT_TOKEN }}
|
||||
repository: hands-free-vim/cursorless.nvim
|
||||
path: ${{ env.STAGING_DIRECTORY }}
|
||||
- name: Configure GPG Key
|
||||
working-directory: ${{ env.STAGING_DIRECTORY }}
|
||||
run: |
|
||||
echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import
|
||||
env:
|
||||
GPG_SIGNING_KEY: ${{ secrets.CURSORLESS_BOT_GPG_SIGNING_KEY }}
|
||||
- name: git config
|
||||
working-directory: ${{ env.STAGING_DIRECTORY }}
|
||||
run: |
|
||||
git config user.name cursorless-bot
|
||||
git config user.email 98099035+cursorless-bot@users.noreply.github.com
|
||||
git config user.signingkey A9387720AFC62221
|
||||
git config commit.gpgsign true
|
||||
- name: Push compiled files to cursorless.nvim plugin repo
|
||||
run: bash -x scripts/deploy-cursorless-nvim.sh ${{ env.STAGING_DIRECTORY }}
|
||||
|
||||
push-cursorless-talon:
|
||||
name: Push cursorless-talon subrepo
|
||||
runs-on: ubuntu-latest
|
||||
|
5
.github/workflows/pre-commit.yml
vendored
5
.github/workflows/pre-commit.yml
vendored
@ -8,11 +8,14 @@ on:
|
||||
types: [opened, synchronize, reopened]
|
||||
merge_group:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
name: Pre-commit
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CURSORLESS_REPO_ROOT: ${{ github.workspace }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
@ -24,6 +27,8 @@ jobs:
|
||||
node-version-file: .nvmrc
|
||||
cache: pnpm
|
||||
- run: pnpm --color install
|
||||
- uses: leafo/gh-actions-lua@v9
|
||||
- uses: leafo/gh-actions-luarocks@v4
|
||||
- uses: pre-commit/action@v3.0.1
|
||||
- uses: pre-commit-ci/lite-action@v1.0.2
|
||||
if: always()
|
||||
|
40
.github/workflows/test.yml
vendored
40
.github/workflows/test.yml
vendored
@ -17,16 +17,19 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
vscode_version: [stable]
|
||||
app_version: [stable]
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
vscode_version: legacy
|
||||
app_version: legacy
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
VSCODE_VERSION: ${{ matrix.vscode_version }}
|
||||
APP_VERSION: ${{ matrix.app_version }}
|
||||
NEOVIM_VERSION: ${{ matrix.app_version == 'stable' && 'stable' || 'v0.10.0' }}
|
||||
VSCODE_CRASH_DIR: ${{ github.workspace }}/artifacts/dumps
|
||||
VSCODE_LOGS_DIR: ${{ github.workspace }}/artifacts/logs
|
||||
CURSORLESS_REPO_ROOT: ${{ github.workspace }}
|
||||
TEMP_DIR: ${{ github.workspace }}/temp
|
||||
NODE_OPTIONS: "--max-old-space-size=4096"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: corepack enable
|
||||
@ -34,7 +37,7 @@ jobs:
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
cache: pnpm
|
||||
- run: mkdir -p "${{ env.VSCODE_CRASH_DIR }}" "${{ env.VSCODE_LOGS_DIR }}"
|
||||
- run: mkdir -p "${{ env.VSCODE_CRASH_DIR }}" "${{ env.VSCODE_LOGS_DIR }}" "${{ env.TEMP_DIR }}"
|
||||
shell: bash
|
||||
- run: pnpm --color install
|
||||
- run: pnpm --color compile
|
||||
@ -43,9 +46,32 @@ jobs:
|
||||
if: runner.os == 'Linux'
|
||||
- run: pnpm --color test
|
||||
if: runner.os != 'Linux'
|
||||
- run: xvfb-run -a pnpm -F @cursorless/test-harness test:talonJs
|
||||
if: runner.os == 'Linux' && matrix.vscode_version == 'stable'
|
||||
- run: pnpm -F @cursorless/test-harness test:talonJs
|
||||
if: runner.os != 'Linux' && matrix.vscode_version == 'stable'
|
||||
- run: xvfb-run -a pnpm -F @cursorless/cursorless-everywhere-talon-e2e test:quickjs
|
||||
if: runner.os == 'Linux' && matrix.vscode_version == 'stable'
|
||||
- run: pnpm -F @cursorless/cursorless-everywhere-talon-e2e test:quickjs
|
||||
if: runner.os != 'Linux' && matrix.vscode_version == 'stable'
|
||||
- run: bash -x scripts/install-neovim-dependencies.sh
|
||||
- uses: rhysd/action-setup-vim@v1
|
||||
id: vim
|
||||
with:
|
||||
version: ${{ env.NEOVIM_VERSION }}
|
||||
neovim: true
|
||||
- name: Run neovim tests
|
||||
run: xvfb-run -a pnpm -F @cursorless/test-harness test:neovim
|
||||
if: runner.os == 'Linux'
|
||||
env:
|
||||
NEOVIM_PATH: ${{ steps.vim.outputs.executable }}
|
||||
- uses: ./.github/actions/test-neovim-lua/
|
||||
if: runner.os == 'Linux' && matrix.app_version == 'stable'
|
||||
- uses: ./.github/actions/lint-lua-ls/
|
||||
if: runner.os == 'Linux' && matrix.app_version == 'stable'
|
||||
- name: Create vscode dist that can be installed locally
|
||||
run: pnpm -F @cursorless/cursorless-vscode populate-dist --local-install
|
||||
if: runner.os == 'Linux' && matrix.vscode_version == 'stable'
|
||||
if: runner.os == 'Linux' && matrix.app_version == 'stable'
|
||||
- name: Test create vsix
|
||||
id: createVsix
|
||||
uses: HaaLeo/publish-vscode-extension@v1
|
||||
@ -54,10 +80,10 @@ jobs:
|
||||
packagePath: packages/cursorless-vscode/dist
|
||||
dryRun: true
|
||||
- run: mv ${{ steps.createVsix.outputs.vsixPath }} cursorless-development.vsix
|
||||
if: runner.os == 'Linux' && matrix.vscode_version == 'stable'
|
||||
if: runner.os == 'Linux' && matrix.app_version == 'stable'
|
||||
- name: Upload vsix
|
||||
uses: actions/upload-artifact@v4
|
||||
if: runner.os == 'Linux' && matrix.vscode_version == 'stable'
|
||||
if: runner.os == 'Linux' && matrix.app_version == 'stable'
|
||||
with:
|
||||
name: vsix
|
||||
path: cursorless-development.vsix
|
||||
|
7
.gitignore
vendored
7
.gitignore
vendored
@ -1,10 +1,13 @@
|
||||
out
|
||||
dist
|
||||
testOut
|
||||
node_modules
|
||||
.vscode-test/
|
||||
*.vsix
|
||||
/package-lock.json
|
||||
*.DS_Store
|
||||
meta.json
|
||||
.luacheckcache
|
||||
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
@ -43,5 +46,9 @@ next-env.d.ts
|
||||
# test subset config
|
||||
packages/test-harness/testSubsetGrep.properties
|
||||
|
||||
# cursorless-neovim
|
||||
cursorless.nvim/node/cursorless-neovim
|
||||
cursorless.nvim/node/test-harness
|
||||
|
||||
# nix
|
||||
.direnv/
|
||||
|
8
.luacheckrc
Normal file
8
.luacheckrc
Normal file
@ -0,0 +1,8 @@
|
||||
std = luajit
|
||||
cache = true
|
||||
codes = true
|
||||
ignore = { "432" }
|
||||
|
||||
globals = {
|
||||
"vim",
|
||||
}
|
6
.luarc.json
Normal file
6
.luarc.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"runtime.version": "Lua 5.1",
|
||||
"diagnostics.ignoredFiles": "Disable",
|
||||
"diagnostics.globals": ["vim", "talon", "it", "describe"],
|
||||
"workspace.ignoreDir": ["data/playground/lua/", ".luarocks", ".lua"]
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
minimum_pre_commit_version: "2.9.0"
|
||||
ci:
|
||||
autoupdate_schedule: monthly
|
||||
exclude: /vendor/
|
||||
exclude: /vendor/|^data/playground/
|
||||
repos:
|
||||
- repo: meta
|
||||
hooks:
|
||||
@ -81,6 +81,14 @@ repos:
|
||||
- id: ruff
|
||||
args: [--fix, --exit-non-zero-on-fix]
|
||||
- id: ruff-format
|
||||
- repo: https://github.com/lunarmodules/luacheck
|
||||
rev: v1.2.0
|
||||
hooks:
|
||||
- id: luacheck
|
||||
- repo: https://github.com/JohnnyMorganz/StyLua
|
||||
rev: v0.20.0
|
||||
hooks:
|
||||
- id: stylua
|
||||
- repo: https://github.com/koalaman/shellcheck-precommit
|
||||
rev: v0.10.0
|
||||
hooks:
|
||||
|
6
.vscode/extensions.json
vendored
6
.vscode/extensions.json
vendored
@ -7,7 +7,9 @@
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"jrieken.vscode-tree-sitter-query",
|
||||
"wenkokke.tree-sitter-talon",
|
||||
"usernamehw.commands"
|
||||
"wenkokke.talonfmt-vscode",
|
||||
"usernamehw.commands",
|
||||
"sumneko.lua",
|
||||
"JohnnyMorganz.stylua"
|
||||
]
|
||||
}
|
||||
|
57
.vscode/launch.json
vendored
57
.vscode/launch.json
vendored
@ -110,9 +110,27 @@
|
||||
]
|
||||
},
|
||||
|
||||
// Neovim launch configs
|
||||
{
|
||||
"name": "Neovim: Run",
|
||||
"request": "attach",
|
||||
"continueOnAttach": true,
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
"preLaunchTask": "Neovim: Build extension",
|
||||
"type": "node"
|
||||
},
|
||||
{
|
||||
"name": "Neovim: Test",
|
||||
"request": "attach",
|
||||
"continueOnAttach": true,
|
||||
"skipFiles": ["<node_internals>/**"],
|
||||
"preLaunchTask": "Neovim: Build extension and tests",
|
||||
"type": "node"
|
||||
},
|
||||
|
||||
// Talon launch configs
|
||||
{
|
||||
"name": "Talon: Test",
|
||||
"name": "Talon: Test grammar",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/packages/test-harness/dist/runTalonTests.cjs",
|
||||
@ -128,7 +146,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Talon: Test (subset)",
|
||||
"name": "Talon: Test grammar (subset)",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/packages/test-harness/dist/runTalonTests.cjs",
|
||||
@ -145,6 +163,41 @@
|
||||
]
|
||||
},
|
||||
|
||||
// Talon everywhere/JS launch configs
|
||||
{
|
||||
"name": "TalonJS: Test",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/packages/test-harness/dist/runTalonJsTests.cjs",
|
||||
"env": {
|
||||
"CURSORLESS_MODE": "test",
|
||||
"CURSORLESS_REPO_ROOT": "${workspaceFolder}"
|
||||
},
|
||||
"outFiles": ["${workspaceFolder}/**/out/**/*.js"],
|
||||
"preLaunchTask": "VSCode: Build extension and tests",
|
||||
"resolveSourceMapLocations": [
|
||||
"${workspaceFolder}/**",
|
||||
"!**/node_modules/**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "TalonJS: Test (subset)",
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/packages/test-harness/dist/runTalonJsTests.cjs",
|
||||
"env": {
|
||||
"CURSORLESS_MODE": "test",
|
||||
"CURSORLESS_RUN_TEST_SUBSET": "true",
|
||||
"CURSORLESS_REPO_ROOT": "${workspaceFolder}"
|
||||
},
|
||||
"outFiles": ["${workspaceFolder}/**/out/**/*.js"],
|
||||
"preLaunchTask": "VSCode: Build extension and tests",
|
||||
"resolveSourceMapLocations": [
|
||||
"${workspaceFolder}/**",
|
||||
"!**/node_modules/**"
|
||||
]
|
||||
},
|
||||
|
||||
// Unit tests launch configs
|
||||
{
|
||||
"name": "Unit tests: Test",
|
||||
|
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
@ -25,5 +25,11 @@
|
||||
"files.eol": "\n",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"eslint.workingDirectories": [{ "pattern": "packages/*/" }]
|
||||
"eslint.workingDirectories": [{ "pattern": "packages/*/" }],
|
||||
"[lua]": {
|
||||
"editor.defaultFormatter": "JohnnyMorganz.stylua"
|
||||
},
|
||||
"files.associations": {
|
||||
".busted": "lua"
|
||||
}
|
||||
}
|
||||
|
146
.vscode/tasks.json
vendored
146
.vscode/tasks.json
vendored
@ -152,6 +152,152 @@
|
||||
"group": "test"
|
||||
},
|
||||
|
||||
// Neovim tasks
|
||||
{
|
||||
"label": "Neovim: Build extension",
|
||||
"dependsOn": [
|
||||
"Neovim: Launch neovim",
|
||||
"Neovim: ESBuild",
|
||||
"Neovim: Populate dist"
|
||||
],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "Neovim: Build extension and tests",
|
||||
"dependsOn": [
|
||||
"Neovim: Launch neovim (test)",
|
||||
"Neovim: ESBuild",
|
||||
"Neovim: Populate dist",
|
||||
"TSBuild",
|
||||
"Build test harness"
|
||||
],
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "Neovim: ESBuild",
|
||||
"type": "npm",
|
||||
"script": "esbuild",
|
||||
"path": "packages/cursorless-neovim",
|
||||
"dependsOn": ["Generate grammar"],
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
},
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "Neovim: Populate dist",
|
||||
"type": "npm",
|
||||
"script": "populate-dist",
|
||||
"path": "packages/cursorless-neovim",
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
},
|
||||
"options": {
|
||||
"env": {
|
||||
"CURSORLESS_REPO_ROOT": "${workspaceFolder}"
|
||||
}
|
||||
},
|
||||
"group": "build"
|
||||
},
|
||||
{
|
||||
"label": "Neovim: Launch neovim",
|
||||
"type": "process",
|
||||
"command": "packages/cursorless-neovim/scripts/linux-terminal.sh",
|
||||
"args": [
|
||||
"${workspaceFolder}/packages/cursorless-neovim/scripts/debug-neovim.sh ${workspaceFolder} development"
|
||||
],
|
||||
"osx": {
|
||||
"command": "osascript",
|
||||
"args": [
|
||||
"-e",
|
||||
"tell app \"Terminal\" to do script \"${workspaceFolder}/packages/cursorless-neovim/scripts/debug-neovim.sh ${workspaceFolder} development\" activate"
|
||||
]
|
||||
},
|
||||
"windows": {
|
||||
"command": "powershell",
|
||||
"args": [
|
||||
"(New-Object -ComObject WScript.Shell).Run(\"\"\"${workspaceFolder}/packages/cursorless-neovim/scripts/debug-neovim.bat\"\"\", 1, $false)"
|
||||
]
|
||||
},
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
},
|
||||
"options": {
|
||||
"env": {
|
||||
"CURSORLESS_REPO_ROOT": "${workspaceFolder}",
|
||||
"NVIM_NODE_HOST_DEBUG": "1",
|
||||
"NVIM_NODE_LOG_FILE": "${workspaceFolder}/packages/cursorless-neovim/out/nvim_node.log",
|
||||
"NVIM_NODE_LOG_LEVEL": "info",
|
||||
"CURSORLESS_MODE": "development"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Neovim: Launch neovim (test)",
|
||||
"type": "process",
|
||||
"command": "packages/cursorless-neovim/scripts/linux-terminal.sh",
|
||||
"args": [
|
||||
"${workspaceFolder}/packages/cursorless-neovim/scripts/debug-neovim.sh ${workspaceFolder} test"
|
||||
],
|
||||
"osx": {
|
||||
"command": "osascript",
|
||||
"args": [
|
||||
"-e",
|
||||
"tell app \"Terminal\" to do script \"${workspaceFolder}/packages/cursorless-neovim/scripts/debug-neovim.sh ${workspaceFolder} test\" activate"
|
||||
]
|
||||
},
|
||||
"windows": {
|
||||
"command": "powershell",
|
||||
"args": [
|
||||
"(New-Object -ComObject WScript.Shell).Run(\"\"\"${workspaceFolder}/packages/cursorless-neovim/scripts/debug-neovim.bat\"\"\", 1, $false)"
|
||||
]
|
||||
},
|
||||
"group": "build",
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
},
|
||||
"options": {
|
||||
"env": {
|
||||
"CURSORLESS_REPO_ROOT": "${workspaceFolder}",
|
||||
"NVIM_NODE_HOST_DEBUG": "1",
|
||||
"NVIM_NODE_LOG_FILE": "${workspaceFolder}/packages/cursorless-neovim/out/nvim_node.log",
|
||||
"NVIM_NODE_LOG_LEVEL": "info",
|
||||
"CURSORLESS_MODE": "test"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "Neovim: Show logs",
|
||||
"type": "shell",
|
||||
"command": "packages/cursorless-neovim/scripts/show-logs.sh",
|
||||
"problemMatcher": [],
|
||||
"isBackground": true,
|
||||
"presentation": {
|
||||
"echo": false,
|
||||
"reveal": "always",
|
||||
"focus": false,
|
||||
"panel": "dedicated",
|
||||
"showReuseMessage": false,
|
||||
"clear": true
|
||||
},
|
||||
"options": {
|
||||
"env": {
|
||||
"CURSORLESS_REPO_ROOT": "${workspaceFolder}"
|
||||
}
|
||||
}
|
||||
// NOTE: We don't have a way on Windows atm due to command with argument inside Run() not working
|
||||
// so we need to show logs outside of vscode (see #2454)
|
||||
},
|
||||
{
|
||||
"label": "Neovim: Launch neovim (lua test)",
|
||||
"type": "shell",
|
||||
"command": "busted --run unit",
|
||||
"options": {
|
||||
"cwd": "cursorless.nvim"
|
||||
}
|
||||
},
|
||||
|
||||
// cursorless.org
|
||||
{
|
||||
"label": "Serve cursorless.org",
|
||||
|
50
cursorless-everywhere-talon/cursorless_everywhere_talon.py
Normal file
50
cursorless-everywhere-talon/cursorless_everywhere_talon.py
Normal file
@ -0,0 +1,50 @@
|
||||
from typing import TypedDict
|
||||
|
||||
from talon import Module
|
||||
|
||||
|
||||
class SelectionOffsets(TypedDict):
|
||||
anchor: int
|
||||
active: int
|
||||
|
||||
|
||||
class EditorState(TypedDict):
|
||||
text: str
|
||||
selections: list[SelectionOffsets]
|
||||
|
||||
|
||||
class EditorChange(TypedDict):
|
||||
text: str
|
||||
rangeOffset: int
|
||||
rangeLength: int
|
||||
|
||||
|
||||
class EditorEdit(TypedDict):
|
||||
# The new document content after the edit
|
||||
text: str
|
||||
|
||||
# A list of changes that were made to the document. If you can not handle
|
||||
# this, you can ignore it and just replace the entire document with the
|
||||
# value of the `text` field above.
|
||||
changes: list[EditorChange]
|
||||
|
||||
|
||||
mod = Module()
|
||||
|
||||
mod.tag("cursorless_everywhere_talon", desc="Enable cursorless everywhere in Talon")
|
||||
|
||||
|
||||
@mod.action_class
|
||||
class Actions:
|
||||
def cursorless_everywhere_get_editor_state() -> EditorState: # pyright: ignore [reportReturnType]
|
||||
"""Get the focused editor element state"""
|
||||
|
||||
def cursorless_everywhere_set_selections(
|
||||
selections: list[SelectionOffsets], # pyright: ignore [reportGeneralTypeIssues]
|
||||
):
|
||||
"""Set focused element selections"""
|
||||
|
||||
def cursorless_everywhere_edit_text(
|
||||
edit: EditorEdit, # pyright: ignore [reportGeneralTypeIssues]
|
||||
):
|
||||
"""Edit focused element text"""
|
129
cursorless-everywhere-talon/cursorless_everywhere_talon_win.py
Normal file
129
cursorless-everywhere-talon/cursorless_everywhere_talon_win.py
Normal file
@ -0,0 +1,129 @@
|
||||
from talon import Context, app, ui
|
||||
|
||||
from .cursorless_everywhere_talon import (
|
||||
EditorEdit,
|
||||
EditorState,
|
||||
SelectionOffsets,
|
||||
)
|
||||
|
||||
if app.platform == "windows":
|
||||
from talon.windows.ax import TextRange
|
||||
|
||||
|
||||
# https://learn.microsoft.com/en-us/dotnet/api/system.windows.automation.text.textpatternrange?view=windowsdesktop-8.0
|
||||
|
||||
ctx = Context()
|
||||
|
||||
ctx.matches = r"""
|
||||
os: windows
|
||||
"""
|
||||
|
||||
|
||||
@ctx.action_class("user")
|
||||
class Actions:
|
||||
def cursorless_everywhere_get_editor_state() -> EditorState:
|
||||
el = ui.focused_element()
|
||||
|
||||
if "Text2" not in el.patterns:
|
||||
raise ValueError("Focused element is not a text element")
|
||||
|
||||
text_pattern = el.text_pattern2
|
||||
document_range = text_pattern.document_range
|
||||
caret_range = text_pattern.caret_range
|
||||
selection_ranges = text_pattern.selection
|
||||
selections: list[SelectionOffsets] = []
|
||||
|
||||
for selection_range in selection_ranges:
|
||||
anchor, active = get_selection(document_range, selection_range, caret_range)
|
||||
selections.append(
|
||||
{
|
||||
"anchor": anchor,
|
||||
"active": active,
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
"text": document_range.text,
|
||||
"selections": selections,
|
||||
}
|
||||
|
||||
def cursorless_everywhere_set_selections(
|
||||
selections: list[SelectionOffsets], # pyright: ignore [reportGeneralTypeIssues]
|
||||
):
|
||||
if selections.length != 1: # pyright: ignore [reportAttributeAccessIssue]
|
||||
raise ValueError("Only single selection supported")
|
||||
|
||||
selection = selections[0]
|
||||
anchor = selection["anchor"]
|
||||
active = selection["active"]
|
||||
|
||||
el = ui.focused_element()
|
||||
|
||||
if "Text2" not in el.patterns:
|
||||
raise ValueError("Focused element is not a text element")
|
||||
|
||||
text_pattern = el.text_pattern2
|
||||
document_range = text_pattern.document_range
|
||||
|
||||
set_selection(document_range, anchor, active)
|
||||
|
||||
def cursorless_everywhere_edit_text(
|
||||
edit: EditorEdit, # pyright: ignore [reportGeneralTypeIssues]
|
||||
):
|
||||
text = edit["text"]
|
||||
|
||||
el = ui.focused_element()
|
||||
|
||||
if "Value" not in el.patterns:
|
||||
raise ValueError("Focused element is not a text element")
|
||||
|
||||
el.value_pattern.value = text
|
||||
|
||||
|
||||
def set_selection(document_range: TextRange, anchor: int, active: int):
|
||||
# This happens in slack, for example. The document range starts with a
|
||||
# newline and selecting first character we'll make the selection go outside
|
||||
# of the edit box.
|
||||
if document_range.text.startswith("\n") and anchor == 0 and active == 0:
|
||||
anchor = 1
|
||||
active = 1
|
||||
|
||||
start = min(anchor, active)
|
||||
end = max(anchor, active)
|
||||
range = document_range.clone()
|
||||
range.move_endpoint_by_range("End", "Start", target=document_range)
|
||||
range.move_endpoint_by_unit("End", "Character", end)
|
||||
range.move_endpoint_by_unit("Start", "Character", start)
|
||||
range.select()
|
||||
|
||||
|
||||
def get_selection(
|
||||
document_range: TextRange, selection_range: TextRange, caret_range: TextRange
|
||||
) -> tuple[int, int]:
|
||||
# Make copy of the document range to avoid modifying the original
|
||||
range_before_selection = document_range.clone()
|
||||
# Move the end of the copy to the start of the selection
|
||||
# range_before_selection.end = selection_range.start
|
||||
range_before_selection.move_endpoint_by_range(
|
||||
"End",
|
||||
"Start",
|
||||
target=selection_range,
|
||||
)
|
||||
# The selection start offset is the length of the text before the selection
|
||||
start = len(range_before_selection.text)
|
||||
|
||||
range_after_selection = document_range.clone()
|
||||
range_after_selection.move_endpoint_by_range(
|
||||
"Start",
|
||||
"End",
|
||||
target=selection_range,
|
||||
)
|
||||
end = len(document_range.text) - len(range_after_selection.text)
|
||||
|
||||
# The selection is reversed if the caret is at the start of the selection
|
||||
is_reversed = (
|
||||
caret_range.compare_endpoints("Start", "Start", target=selection_range) == 0
|
||||
)
|
||||
|
||||
# Return as (anchor, active)
|
||||
return (end, start) if is_reversed else (start, end)
|
@ -23,3 +23,12 @@ debug edit subset:
|
||||
debug {user.cursorless_launch_configuration}:
|
||||
user.run_rpc_command("commands.startDebugging", cursorless_launch_configuration)
|
||||
user.run_rpc_command("workbench.debug.action.focusRepl")
|
||||
|
||||
neovim log:
|
||||
user.run_rpc_command("workbench.action.tasks.runTask", "Neovim: Show logs")
|
||||
debug neovim:
|
||||
user.run_rpc_command("commands.startDebugging", "Neovim: Run")
|
||||
user.run_rpc_command("workbench.action.tasks.showTasks")
|
||||
debug test neovim:
|
||||
user.run_rpc_command("commands.startDebugging", "Neovim: Test")
|
||||
user.run_rpc_command("workbench.action.tasks.showTasks")
|
||||
|
@ -27,7 +27,7 @@ head_tail_swallowed_modifiers = [
|
||||
"<user.cursorless_simple_scope_modifier>", # funk, state, class, every funk
|
||||
"<user.cursorless_ordinal_scope>", # first past second word
|
||||
"<user.cursorless_relative_scope>", # next funk, 3 funks
|
||||
"<user.cursorless_surrounding_pair>", # matching/pair [curly, round]
|
||||
"<user.cursorless_surrounding_pair_force_direction>", # DEPRECATED "left quad" / "right quad"
|
||||
]
|
||||
|
||||
modifiers = [
|
||||
|
@ -15,7 +15,10 @@ mod.list(
|
||||
|
||||
|
||||
@mod.capture(
|
||||
rule="{user.cursorless_scope_type} | <user.cursorless_glyph_scope_type> | {user.cursorless_custom_regex_scope_type}"
|
||||
rule="{user.cursorless_scope_type}"
|
||||
" | <user.cursorless_surrounding_pair_scope_type>"
|
||||
" | <user.cursorless_glyph_scope_type>"
|
||||
" | {user.cursorless_custom_regex_scope_type}"
|
||||
)
|
||||
def cursorless_scope_type(m) -> dict[str, str]:
|
||||
"""Cursorless scope type singular"""
|
||||
@ -24,16 +27,27 @@ def cursorless_scope_type(m) -> dict[str, str]:
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
return m.cursorless_surrounding_pair_scope_type
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
return m.cursorless_glyph_scope_type
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
return {"type": "customRegex", "regex": m.cursorless_custom_regex_scope_type}
|
||||
return {
|
||||
"type": "customRegex",
|
||||
"regex": m.cursorless_custom_regex_scope_type,
|
||||
}
|
||||
|
||||
|
||||
@mod.capture(
|
||||
rule="{user.cursorless_scope_type_plural} | <user.cursorless_glyph_scope_type_plural> | {user.cursorless_custom_regex_scope_type_plural}"
|
||||
rule="{user.cursorless_scope_type_plural}"
|
||||
" | <user.cursorless_surrounding_pair_scope_type_plural>"
|
||||
" | <user.cursorless_glyph_scope_type_plural>"
|
||||
" | {user.cursorless_custom_regex_scope_type_plural}"
|
||||
)
|
||||
def cursorless_scope_type_plural(m) -> dict[str, str]:
|
||||
"""Cursorless scope type plural"""
|
||||
@ -42,6 +56,11 @@ def cursorless_scope_type_plural(m) -> dict[str, str]:
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
return m.cursorless_surrounding_pair_scope_type_plural
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
return m.cursorless_glyph_scope_type_plural
|
||||
except AttributeError:
|
||||
|
@ -22,6 +22,10 @@ mod.list(
|
||||
"cursorless_surrounding_pair_scope_type",
|
||||
desc="Scope types that can function as surrounding pairs",
|
||||
)
|
||||
mod.list(
|
||||
"cursorless_surrounding_pair_scope_type_plural",
|
||||
desc="Plural form of scope types that can function as surrounding pairs",
|
||||
)
|
||||
|
||||
|
||||
@mod.capture(
|
||||
@ -30,29 +34,43 @@ mod.list(
|
||||
"{user.cursorless_surrounding_pair_scope_type}"
|
||||
)
|
||||
)
|
||||
def cursorless_surrounding_pair_scope_type(m) -> str:
|
||||
def cursorless_surrounding_pair_scope_type(m) -> dict[str, str]:
|
||||
"""Surrounding pair scope type"""
|
||||
try:
|
||||
return m.cursorless_surrounding_pair_scope_type
|
||||
delimiter = m.cursorless_surrounding_pair_scope_type
|
||||
except AttributeError:
|
||||
return m.cursorless_selectable_paired_delimiter
|
||||
delimiter = m.cursorless_selectable_paired_delimiter
|
||||
return {
|
||||
"type": "surroundingPair",
|
||||
"delimiter": delimiter,
|
||||
}
|
||||
|
||||
|
||||
@mod.capture(
|
||||
rule="[{user.cursorless_delimiter_force_direction}] <user.cursorless_surrounding_pair_scope_type>"
|
||||
rule=(
|
||||
"<user.cursorless_selectable_paired_delimiter_plural> |"
|
||||
"{user.cursorless_surrounding_pair_scope_type_plural}"
|
||||
)
|
||||
)
|
||||
def cursorless_surrounding_pair(m) -> dict[str, Any]:
|
||||
"""Expand to containing surrounding pair"""
|
||||
def cursorless_surrounding_pair_scope_type_plural(m) -> dict[str, str]:
|
||||
"""Plural surrounding pair scope type"""
|
||||
try:
|
||||
surrounding_pair_scope_type = m.cursorless_surrounding_pair_scope_type
|
||||
delimiter = m.cursorless_surrounding_pair_scope_type_plural
|
||||
except AttributeError:
|
||||
surrounding_pair_scope_type = "any"
|
||||
|
||||
scope_type = {
|
||||
delimiter = m.cursorless_selectable_paired_delimiter_plural
|
||||
return {
|
||||
"type": "surroundingPair",
|
||||
"delimiter": surrounding_pair_scope_type,
|
||||
"delimiter": delimiter,
|
||||
}
|
||||
|
||||
|
||||
@mod.capture(
|
||||
rule="{user.cursorless_delimiter_force_direction} <user.cursorless_surrounding_pair_scope_type>"
|
||||
)
|
||||
def cursorless_surrounding_pair_force_direction(m) -> dict[str, Any]:
|
||||
"""DEPRECATED: Expand to containing surrounding pair"""
|
||||
scope_type = m.cursorless_surrounding_pair_scope_type
|
||||
|
||||
with suppress(AttributeError):
|
||||
scope_type["forceDirection"] = m.cursorless_delimiter_force_direction
|
||||
|
||||
|
@ -15,6 +15,15 @@ mod.list(
|
||||
desc="A paired delimiter that can be used as a scope type and as a wrapper",
|
||||
)
|
||||
|
||||
mod.list(
|
||||
"cursorless_selectable_only_paired_delimiter_plural",
|
||||
desc="Plural form of a paired delimiter that can only be used as a scope type",
|
||||
)
|
||||
mod.list(
|
||||
"cursorless_wrapper_selectable_paired_delimiter_plural",
|
||||
desc="Plural form of a paired delimiter that can be used as a scope type and as a wrapper",
|
||||
)
|
||||
|
||||
# Maps from the id we use in the spoken form csv to the delimiter strings
|
||||
paired_delimiters = {
|
||||
"curlyBrackets": ["{", "}"],
|
||||
@ -58,3 +67,16 @@ def cursorless_selectable_paired_delimiter(m) -> str:
|
||||
return m.cursorless_selectable_only_paired_delimiter
|
||||
except AttributeError:
|
||||
return m.cursorless_wrapper_selectable_paired_delimiter
|
||||
|
||||
|
||||
@mod.capture(
|
||||
rule=(
|
||||
"{user.cursorless_selectable_only_paired_delimiter_plural} |"
|
||||
"{user.cursorless_wrapper_selectable_paired_delimiter_plural}"
|
||||
)
|
||||
)
|
||||
def cursorless_selectable_paired_delimiter_plural(m) -> str:
|
||||
try:
|
||||
return m.cursorless_selectable_only_paired_delimiter_plural
|
||||
except AttributeError:
|
||||
return m.cursorless_wrapper_selectable_paired_delimiter_plural
|
||||
|
@ -170,6 +170,7 @@
|
||||
"file": "document",
|
||||
"paint": "nonWhitespaceSequence",
|
||||
"short paint": "boundedNonWhitespaceSequence",
|
||||
"short block": "boundedParagraph",
|
||||
"link": "url",
|
||||
"cell": "notebookCell"
|
||||
},
|
||||
|
@ -133,18 +133,29 @@ def update():
|
||||
handle_csv("target_connectives.csv"),
|
||||
handle_csv("modifiers.csv"),
|
||||
handle_csv("positions.csv"),
|
||||
handle_csv("paired_delimiters.csv"),
|
||||
handle_csv(
|
||||
"paired_delimiters.csv",
|
||||
pluralize_lists=[
|
||||
"selectable_only_paired_delimiter",
|
||||
"wrapper_selectable_paired_delimiter",
|
||||
],
|
||||
),
|
||||
handle_csv("special_marks.csv"),
|
||||
handle_csv("scope_visualizer.csv"),
|
||||
handle_csv("experimental/experimental_actions.csv"),
|
||||
handle_csv("experimental/miscellaneous.csv"),
|
||||
handle_csv(
|
||||
"modifier_scope_types.csv",
|
||||
pluralize_lists=["scope_type", "glyph_scope_type"],
|
||||
pluralize_lists=[
|
||||
"scope_type",
|
||||
"glyph_scope_type",
|
||||
"surrounding_pair_scope_type",
|
||||
],
|
||||
extra_allowed_values=[
|
||||
"private.fieldAccess",
|
||||
"private.switchStatementSubject",
|
||||
"textFragment",
|
||||
"disqualifyDelimiter",
|
||||
],
|
||||
default_list_name="scope_type",
|
||||
),
|
||||
|
10
cursorless.nvim/.busted
Normal file
10
cursorless.nvim/.busted
Normal file
@ -0,0 +1,10 @@
|
||||
return {
|
||||
_all = {
|
||||
lua = './test/nvim-shim.sh',
|
||||
output = "TAP",
|
||||
["defer-print"] = false,
|
||||
},
|
||||
unit = {
|
||||
ROOT = {'./test/unit/'},
|
||||
},
|
||||
}
|
5
cursorless.nvim/.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
cursorless.nvim/.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Create issue on cursorless-dev/cursorless
|
||||
url: https://github.com/cursorless-dev/cursorless/issues/new
|
||||
about: Please file issues on the main Cursorless repository
|
7
cursorless.nvim/CONTRIBUTING.md
Normal file
7
cursorless.nvim/CONTRIBUTING.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Contributing
|
||||
|
||||
Welcome! So glad you've decided to help make Cursorless in Neovim better.
|
||||
|
||||
Note that Cursorless is maintained as a monorepo, hosted at [`cursorless`](https://github.com/cursorless-dev/cursorless), and the source of truth for all of the files here lives there, so that's where you'll want to file a PR. We automatically deploy from our monorepo to the [cursorless.nvim repo](https://github.com/hands-free-vim/cursorless.nvim) in CI.
|
||||
|
||||
See [the Cursorless neovim contributor docs](https://www.cursorless.org/docs/contributing/cursorless-in-neovim/) to get started.
|
21
cursorless.nvim/LICENSE
Normal file
21
cursorless.nvim/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 fidgetingbits, Cedric Halbronn, Brandon Virgil Rule, et al.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
118
cursorless.nvim/README.md
Normal file
118
cursorless.nvim/README.md
Normal file
@ -0,0 +1,118 @@
|
||||
<!-- vim-markdown-toc GFM -->
|
||||
|
||||
- [cursorless.nvim](#cursorlessnvim)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Installation](#installation)
|
||||
- [1. Install Cursorless neovim plugin](#1-install-cursorless-neovim-plugin)
|
||||
- [Option A: Lazy installation](#option-a-lazy-installation)
|
||||
- [Option B: Manual installation](#option-b-manual-installation)
|
||||
- [2. Tell neovim to run the plugin](#2-tell-neovim-to-run-the-plugin)
|
||||
- [3. Activate Cursorless commands in Talon](#3-activate-cursorless-commands-in-talon)
|
||||
- [Configuration](#configuration)
|
||||
- [Keyboard shortcut](#keyboard-shortcut)
|
||||
- [Absolute row numbers](#absolute-row-numbers)
|
||||
- [Frequently asked questions](#frequently-asked-questions)
|
||||
- [nvim does not support Lazy?](#nvim-does-not-support-lazy)
|
||||
- [nvim does not find the `neovim` globally installed package?](#nvim-does-not-find-the-neovim-globally-installed-package)
|
||||
- [Contributors](#contributors)
|
||||
|
||||
<!-- vim-markdown-toc -->
|
||||
|
||||
# cursorless.nvim
|
||||
|
||||
Very experimental Neovim plugin providing partial Cursorless support. We support much of the core functionality, but many features are not yet implemented, in particular hats ([#2567](https://github.com/cursorless-dev/cursorless/issues/2567)) and language-specific scopes ([#2568](https://github.com/cursorless-dev/cursorless/issues/2568)). Expect some rough edges, but please give it a try, and if you like it, consider [contributing](https://www.cursorless.org/docs/contributing/cursorless-in-neovim/)!
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [neovim](https://neovim.io/) (>= v0.10.0)
|
||||
- [Talon voice](https://talonvoice.com/)
|
||||
- [neovim-talon](https://github.com/hands-free-vim/neovim-talon)
|
||||
- [node/npm](https://nodejs.org/en)
|
||||
- [neovim node package](https://github.com/neovim/node-client) (>= 5.1.0 installed globally)
|
||||
- [talon.nvim](https://github.com/hands-free-vim/talon.nvim) (likely required, unless standalone neovim
|
||||
GUI (nvim-qt.exe, neovide, etc)
|
||||
|
||||
## Installation
|
||||
|
||||
### 1. Install Cursorless neovim plugin
|
||||
|
||||
Ideally, you want to use a neovim plugin manager like [lazy.nvim](https://github.com/folke/lazy.nvim).
|
||||
|
||||
#### Option A: Lazy installation
|
||||
|
||||
After the typical [lazy setup](https://github.com/folke/lazy.nvim?tab=readme-ov-file#-installation), you'll have to add the `cursorless.nvim` plugin to your `init.lua`.
|
||||
|
||||
```lua
|
||||
require('lazy').setup({
|
||||
'hands-free-vim/cursorless.nvim',
|
||||
})
|
||||
```
|
||||
|
||||
#### Option B: Manual installation
|
||||
|
||||
This method is not recommended but you can try directly cloning the plugin into your nvim data folder:
|
||||
|
||||
```
|
||||
git clone https://github.com/hands-free-vim/cursorless.nvim
|
||||
```
|
||||
|
||||
### 2. Tell neovim to run the plugin
|
||||
|
||||
If you aren't using a plugin manager that automatically calls setup for you (e.g. it is needed for lazy), you will need this somewhere in your neovim config, e.g. in [init.lua](https://neovim.io/doc/user/lua-guide.html#lua-guide-config):
|
||||
|
||||
```lua
|
||||
require("cursorless").setup()
|
||||
```
|
||||
|
||||
### 3. Activate Cursorless commands in Talon
|
||||
|
||||
Add a `.talon` file like the following anywhere in your Talon user directory (e.g. named `cursorless_neovim.talon`):
|
||||
|
||||
```talon
|
||||
app: neovim
|
||||
-
|
||||
tag(): user.cursorless
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Keyboard shortcut
|
||||
|
||||
By default the keyboard shortcut used to communicate with cursorless is `<C-S-f12>`, but this might not work for
|
||||
everybody and is configurable. You can change it by passing a different value in the configuration options passed to
|
||||
`setup()`:
|
||||
|
||||
```lua
|
||||
require("cursorless").setup({ shortcut = `<C-Q>`})
|
||||
```
|
||||
|
||||
_IMPORTANT_: If you change this shortcut, be sure to set the corresponding neovim-talon setting. This can be done by
|
||||
having a `.talon` file somewhere in your talon user directory that contains the following:
|
||||
|
||||
```talon
|
||||
settings():
|
||||
user.neovim_command_server_shortcut = "ctrl-q"
|
||||
```
|
||||
|
||||
### Absolute row numbers
|
||||
|
||||
You MUST currently use absolute row numbers in order to target rows using cursorless. The `talon.nvim` plugin will
|
||||
configure this automatically, but your own config may be overriding it. Be sure to disable relative numbers.
|
||||
|
||||
## Frequently asked questions
|
||||
|
||||
### nvim does not support Lazy?
|
||||
|
||||
Some Linux package managers ship with a version of `nvim` too old for Lazy. If this is the case, [install nvim](https://github.com/neovim/neovim/blob/master/INSTALL.md) via another method.
|
||||
|
||||
### nvim does not find the `neovim` globally installed package?
|
||||
|
||||
If you are on Linux, avoid using the snap package for `npm` as it may not be able to globally expose the neovim npm package due to sandboxing. If this is the case, install node via another method (nvm, brew, etc).
|
||||
|
||||
## Contributing
|
||||
|
||||
Welcome! So glad you've decided to help make Cursorless in Neovim better.
|
||||
|
||||
Note that Cursorless is maintained as a monorepo, hosted at [`cursorless`](https://github.com/cursorless-dev/cursorless), and the source of truth for all of the files here lives there, so that's where you'll want to file a PR. We automatically deploy from our monorepo to the [cursorless.nvim repo](https://github.com/hands-free-vim/cursorless.nvim) in CI.
|
||||
|
||||
See [the Cursorless neovim contributor docs](https://www.cursorless.org/docs/contributing/cursorless-in-neovim/) to get started.
|
27
cursorless.nvim/lua/cursorless/config.lua
Normal file
27
cursorless.nvim/lua/cursorless/config.lua
Normal file
@ -0,0 +1,27 @@
|
||||
local M = {}
|
||||
|
||||
local function default_shortcut()
|
||||
if require("cursorless.utils").is_platform_macos() then
|
||||
return "<C-M-\\>"
|
||||
end
|
||||
|
||||
if require("cursorless.utils").is_platform_windows() then
|
||||
return "<C-S-F12>"
|
||||
end
|
||||
|
||||
return "<C-`>"
|
||||
end
|
||||
|
||||
local config = {
|
||||
shortcut = default_shortcut(),
|
||||
}
|
||||
|
||||
function M.set_config(user_config)
|
||||
return vim.tbl_deep_extend("force", config, user_config or {})
|
||||
end
|
||||
|
||||
function M.get_config()
|
||||
return config
|
||||
end
|
||||
|
||||
return M
|
63
cursorless.nvim/lua/cursorless/cursorless.lua
Normal file
63
cursorless.nvim/lua/cursorless/cursorless.lua
Normal file
@ -0,0 +1,63 @@
|
||||
local M = {}
|
||||
|
||||
-- Get the first and last visible line of the current window/buffer
|
||||
-- @see https://vi.stackexchange.com/questions/28471/get-first-and-last-visible-line-from-other-buffer-than-current
|
||||
-- w0/w$ are indexed from 1, similarly to what is shown in neovim
|
||||
-- e.g. :lua print(vim.inspect(require('cursorless').window_get_visible_lines()))"
|
||||
-- window_get_visible_lines
|
||||
-- { [1] = 28, [2] = 74 }
|
||||
function M.window_get_visible_lines()
|
||||
-- print('window_get_visible_lines()')
|
||||
return { vim.fn.line("w0"), vim.fn.line("w$") }
|
||||
end
|
||||
|
||||
-- Get the coordinates of the current selection
|
||||
-- To manually test follow these steps:
|
||||
-- 1. In command mode :vmap <c-a> <Cmd>lua print(vim.inspect(require('cursorless').buffer_get_selection()))<Cr>
|
||||
-- 2. type "hello" on the first line and "world" on the second line
|
||||
-- 3. Enter visual mode and select "hello" on the first line and continue selection with "world"
|
||||
-- on the second line.
|
||||
-- 4. Hit ctrl+a to show the selection: {1, 1, 2, 5, false}
|
||||
-- 5. Hit 'o' to swap the cursor position and hit ctrl+a again: {1, 1, 2, 5, true}
|
||||
--
|
||||
-- If you want to directly see how it is parsed in the node extension:
|
||||
-- 1. run in command mode :vmap <c-a> <Cmd>:call CursorlessLoadExtension()<Cr>
|
||||
-- 2. Select some text and hit ctrl+a
|
||||
function M.buffer_get_selection()
|
||||
local start_pos = vim.fn.getpos("v") -- start of visual selection
|
||||
local start_line, start_col = start_pos[2], start_pos[3]
|
||||
local end_pos = vim.fn.getpos(".") -- end of visual selection (cursor position)
|
||||
local end_line, end_col = end_pos[2], end_pos[3]
|
||||
local reverse = false
|
||||
local mode = vim.api.nvim_get_mode().mode
|
||||
|
||||
-- Invert the values depending on if the cursor is before the start
|
||||
if end_line < start_line or end_col < start_col then
|
||||
start_line, start_col, end_line, end_col =
|
||||
end_line, end_col, start_line, start_col
|
||||
reverse = true
|
||||
end
|
||||
|
||||
-- See https://github.com/cursorless-dev/cursorless/issues/2537 if you want to add more modes
|
||||
if mode == "V" then
|
||||
-- Line and block-based visual modes are line-based, so we don't need to track the columns
|
||||
start_col = 1
|
||||
end_col = nil
|
||||
end
|
||||
|
||||
return { start_line, start_col, end_line, end_col, reverse }
|
||||
end
|
||||
|
||||
-- https://github.com/nvim-treesitter/nvim-treesitter/blob/master/lua/nvim-treesitter/ts_utils.lua#L278
|
||||
-- If you have a buffer with the line: "hello world"
|
||||
-- :lua require("cursorless.cursorless").select_range(1, 2, 1, 4)
|
||||
-- will highlight "llo"
|
||||
-- NOTE: works for any mode (n,i,v,nt) except in t mode
|
||||
function M.select_range(start_line, start_col, end_line, end_col)
|
||||
vim.cmd([[silent! normal! :noh]])
|
||||
vim.api.nvim_win_set_cursor(0, { start_line, start_col })
|
||||
vim.cmd([[silent! normal v]])
|
||||
vim.api.nvim_win_set_cursor(0, { end_line, end_col })
|
||||
end
|
||||
|
||||
return M
|
107
cursorless.nvim/lua/cursorless/init.lua
Normal file
107
cursorless.nvim/lua/cursorless/init.lua
Normal file
@ -0,0 +1,107 @@
|
||||
local M
|
||||
local function register_functions()
|
||||
local utils = require("cursorless.utils")
|
||||
local path = utils.cursorless_nvim_path()
|
||||
-- revert to using forward slashes as it works when passed to remote#host#RegisterPlugin()
|
||||
if utils.is_platform_windows() then
|
||||
path = path:gsub("\\", "/")
|
||||
end
|
||||
vim.fn["remote#host#RegisterPlugin"](
|
||||
"node",
|
||||
path .. "/node/command-server/",
|
||||
{
|
||||
{
|
||||
type = "function",
|
||||
name = "CommandServerLoadExtension",
|
||||
sync = false,
|
||||
opts = vim.empty_dict(),
|
||||
},
|
||||
{
|
||||
type = "function",
|
||||
name = "CommandServerRunCommand",
|
||||
sync = false,
|
||||
opts = vim.empty_dict(),
|
||||
},
|
||||
}
|
||||
)
|
||||
vim.fn["remote#host#RegisterPlugin"](
|
||||
"node",
|
||||
path .. "/node/cursorless-neovim/",
|
||||
{
|
||||
{
|
||||
type = "function",
|
||||
name = "CursorlessLoadExtension",
|
||||
sync = false,
|
||||
opts = vim.empty_dict(),
|
||||
},
|
||||
}
|
||||
)
|
||||
vim.fn["remote#host#RegisterPlugin"]("node", path .. "/node/test-harness/", {
|
||||
{
|
||||
type = "function",
|
||||
name = "TestHarnessRun",
|
||||
sync = false,
|
||||
opts = vim.empty_dict(),
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
-- this triggers loading the node process as well as calling one function
|
||||
-- in the cursorless-neovim, command-server and neovim-registry extensions
|
||||
-- in order to initialize them
|
||||
local function load_extensions()
|
||||
vim.fn.CursorlessLoadExtension()
|
||||
|
||||
if os.getenv("CURSORLESS_MODE") == "test" then
|
||||
-- make sure cursorless is loaded before starting the tests
|
||||
vim.uv.sleep(1000)
|
||||
vim.fn.TestHarnessRun()
|
||||
else
|
||||
vim.fn.CommandServerLoadExtension()
|
||||
end
|
||||
end
|
||||
|
||||
-- Cursorless command-server shortcut: CTRL+q
|
||||
-- https://stackoverflow.com/questions/40504408/can-i-map-a-key-binding-to-a-function-in-vimrc
|
||||
-- https://stackoverflow.com/questions/7642746/is-there-any-way-to-view-the-currently-mapped-keys-in-vim
|
||||
-- luacheck:ignore 631
|
||||
-- https://stackoverflow.com/questions/3776117/what-is-the-difference-between-the-remap-noremap-nnoremap-and-vnoremap-mapping
|
||||
local function configure_command_server_shortcut(shortcut)
|
||||
-- these mappings don't change the current mode
|
||||
-- https://neovim.io/doc/user/api.html#nvim_set_keymap()
|
||||
-- https://www.reddit.com/r/neovim/comments/pt92qn/mapping_cd_in_terminal_mode/
|
||||
local modes = { "i", "n", "c", "v", "t" }
|
||||
for _, mode in ipairs(modes) do
|
||||
vim.api.nvim_set_keymap(
|
||||
mode,
|
||||
shortcut,
|
||||
"<cmd>lua vim.fn.CommandServerRunCommand()<CR>",
|
||||
{ noremap = true }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
local function setup(user_config)
|
||||
if vim.fn.has("nvim-0.10.0") == 0 then
|
||||
vim.api.nvim_err_writeln(
|
||||
"ERROR: Cursorless requires Neovim 0.10.0 or later"
|
||||
)
|
||||
return
|
||||
end
|
||||
local config = require("cursorless.config").set_config(user_config)
|
||||
register_functions()
|
||||
load_extensions()
|
||||
configure_command_server_shortcut(config.shortcut)
|
||||
end
|
||||
|
||||
local cursorless = require("cursorless.cursorless")
|
||||
M = {
|
||||
setup = setup,
|
||||
config = require("cursorless.config").get_config,
|
||||
window_get_visible_lines = cursorless.window_get_visible_lines,
|
||||
buffer_get_selection = cursorless.buffer_get_selection,
|
||||
buffer_get_selection_text = cursorless.buffer_get_selection_text,
|
||||
select_range = cursorless.select_range,
|
||||
}
|
||||
|
||||
return M
|
69
cursorless.nvim/lua/cursorless/utils.lua
Normal file
69
cursorless.nvim/lua/cursorless/utils.lua
Normal file
@ -0,0 +1,69 @@
|
||||
local M = {}
|
||||
|
||||
-- :lua print(require('cursorless.utils').is_platform_windows())
|
||||
function M.is_platform_windows()
|
||||
return vim.uv.os_uname().version:find("Windows")
|
||||
end
|
||||
|
||||
-- :lua print(require('cursorless.utils').is_platform_macos())
|
||||
function M.is_platform_macos()
|
||||
return vim.uv.os_uname().version:find("Darwin")
|
||||
end
|
||||
|
||||
-- :lua print(require('cursorless.utils').get_path_separator())
|
||||
function M.get_path_separator()
|
||||
if M.is_platform_windows() then
|
||||
return "\\"
|
||||
end
|
||||
return "/"
|
||||
end
|
||||
|
||||
-- https://www.reddit.com/r/neovim/comments/tk1hby/get_the_path_to_the_current_lua_script_in_neovim/
|
||||
-- https://pgl.yoyo.org/luai/i/debug.getinfo
|
||||
-- https://www.gammon.com.au/scripts/doc.php?lua=debug.getinfo
|
||||
-- e.g. :lua print(require('cursorless.utils').cursorless_nvim_path())
|
||||
-- outputs: C:\Users\User\AppData\Local\nvim-data\lazy\talon.nvim
|
||||
-- NOTE: Development cursorless-neovim is installed in: C:\Users\User\AppData\Local\nvim\rplugin\node\cursorless-neovim
|
||||
function M.cursorless_nvim_path()
|
||||
--source_file=@C:/Users/User/AppData/Local/nvim-data/lazy/talon.nvim/lua/talon/utils.lua
|
||||
local str = debug.getinfo(1, "S").source
|
||||
-- print(('source_file=%s'):format(str))
|
||||
-- skip as the file name is prefixed by "@"
|
||||
str = str:sub(2)
|
||||
-- print(('source_file2=%s'):format(str))
|
||||
if M.is_platform_windows() then
|
||||
str = str:gsub("/", "\\")
|
||||
-- print('is_platform_windows')
|
||||
end
|
||||
-- print(('source_file3=%s'):format(str))
|
||||
-- remove where our current file is located to get talon.nvim base path
|
||||
str = str:sub(0, -1 - #"lua/cursorless/utils.lua")
|
||||
-- print(('talon.nvim=%s'):format(str))
|
||||
return str
|
||||
end
|
||||
|
||||
-- assumes we are in terminal mode and switch to normal terminal mode
|
||||
-- https://www.reddit.com/r/neovim/comments/uk3xmq/change_mode_in_lua/
|
||||
-- https://neovim.io/doc/user/api.html#nvim_feedkeys()
|
||||
-- https://neovim.io/doc/user/builtin.html#feedkeys()
|
||||
-- https://neovim.io/doc/user/api.html#nvim_replace_termcodes()
|
||||
-- e.g. run in command mode :tmap <c-a> <Cmd>lua mode_switch_nt()<Cr>
|
||||
function M.mode_switch_nt()
|
||||
local key = vim.api.nvim_replace_termcodes("<c-\\><c-n>", true, false, true)
|
||||
vim.api.nvim_feedkeys(key, "n", false)
|
||||
end
|
||||
|
||||
-- assumes we are in normal terminal mode and switch to terminal mode
|
||||
-- e.g. run in command mode :nmap <c-b> <Cmd>lua mode_switch_t()<Cr>
|
||||
function M.mode_switch_t()
|
||||
vim.api.nvim_feedkeys("i", "n", true)
|
||||
end
|
||||
|
||||
-- paste what is in the clipboard
|
||||
-- https://www.baeldung.com/linux/vim-paste-text
|
||||
-- e.g. run in command mode :imap <c-b> <Cmd>lua require('cursorless.utils').paste()<Cr>
|
||||
function M.paste()
|
||||
vim.cmd([[silent! normal! "+p]])
|
||||
end
|
||||
|
||||
return M
|
3
cursorless.nvim/node/command-server/README.md
Normal file
3
cursorless.nvim/node/command-server/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Command server
|
||||
|
||||
This directory contains a minified version of a `command-server`, which enables us to communicate with node from Talon. It is based on [command-server we use for VSCode](https://github.com/pokey/command-server/), but modified to run in a Neovim node subprocess. It can be built by following the instructions from https://github.com/hands-free-vim/command-server/tree/neovim#build
|
327
cursorless.nvim/node/command-server/index/index.cjs
Normal file
327
cursorless.nvim/node/command-server/index/index.cjs
Normal file
@ -0,0 +1,327 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if ((from && typeof from === "object") || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, {
|
||||
get: () => from[key],
|
||||
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable,
|
||||
});
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) =>
|
||||
__copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/index.ts
|
||||
var src_exports = {};
|
||||
__export(src_exports, {
|
||||
default: () => entry,
|
||||
});
|
||||
module.exports = __toCommonJS(src_exports);
|
||||
|
||||
// src/nativeIo.ts
|
||||
var import_fs = require("fs");
|
||||
var import_path2 = require("path");
|
||||
var import_constants = require("constants");
|
||||
|
||||
// src/paths.ts
|
||||
var import_os = require("os");
|
||||
var import_path = require("path");
|
||||
function getCommunicationDirPath() {
|
||||
const info = (0, import_os.userInfo)();
|
||||
const suffix = info.uid >= 0 ? `-${info.uid}` : "";
|
||||
return (0, import_path.join)(
|
||||
(0, import_os.tmpdir)(),
|
||||
`neovim-command-server${suffix}`,
|
||||
);
|
||||
}
|
||||
function getSignalDirPath() {
|
||||
return (0, import_path.join)(getCommunicationDirPath(), "signals");
|
||||
}
|
||||
function getRequestPath() {
|
||||
return (0, import_path.join)(getCommunicationDirPath(), "request.json");
|
||||
}
|
||||
function getResponsePath() {
|
||||
return (0, import_path.join)(getCommunicationDirPath(), "response.json");
|
||||
}
|
||||
|
||||
// src/nativeIo.ts
|
||||
var import_os2 = require("os");
|
||||
var import_promises = require("fs/promises");
|
||||
|
||||
// src/constants.ts
|
||||
var NEOVIM_COMMAND_TIMEOUT_MS = 3e3;
|
||||
|
||||
// src/nativeIo.ts
|
||||
var InboundSignal = class {
|
||||
constructor(path) {
|
||||
this.path = path;
|
||||
}
|
||||
/**
|
||||
* Gets the current version of the signal. This version string changes every
|
||||
* time the signal is emitted, and can be used to detect whether signal has
|
||||
* been emitted between two timepoints.
|
||||
* @returns The current signal version or null if the signal file could not be
|
||||
* found
|
||||
*/
|
||||
async getVersion() {
|
||||
try {
|
||||
return (await (0, import_promises.stat)(this.path)).mtimeMs.toString();
|
||||
} catch (err) {
|
||||
if (err.code !== "ENOENT") {
|
||||
throw err;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
var NativeIo = class {
|
||||
constructor() {
|
||||
this.responseFile = null;
|
||||
}
|
||||
async initialize() {
|
||||
const communicationDirPath = getCommunicationDirPath();
|
||||
console.log(`Creating communication dir ${communicationDirPath}`);
|
||||
(0, import_fs.mkdirSync)(communicationDirPath, {
|
||||
recursive: true,
|
||||
mode: 504,
|
||||
});
|
||||
const stats = (0, import_fs.lstatSync)(communicationDirPath);
|
||||
const info = (0, import_os2.userInfo)();
|
||||
if (
|
||||
!stats.isDirectory() ||
|
||||
stats.isSymbolicLink() ||
|
||||
stats.mode & import_constants.S_IWOTH || // On Windows, uid < 0, so we don't worry about it for simplicity
|
||||
(info.uid >= 0 && stats.uid !== info.uid)
|
||||
) {
|
||||
throw new Error(
|
||||
`Refusing to proceed because of invalid communication dir ${communicationDirPath}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
async prepareResponse() {
|
||||
if (this.responseFile) {
|
||||
throw new Error("response is already locked");
|
||||
}
|
||||
this.responseFile = await (0, import_promises.open)(
|
||||
getResponsePath(),
|
||||
"wx",
|
||||
);
|
||||
}
|
||||
async closeResponse() {
|
||||
if (!this.responseFile) {
|
||||
throw new Error("response is not locked");
|
||||
}
|
||||
await this.responseFile.close();
|
||||
this.responseFile = null;
|
||||
}
|
||||
/**
|
||||
* Reads the JSON-encoded request from the request file, unlinking the file
|
||||
* after reading.
|
||||
* @returns A promise that resolves to a Response object
|
||||
*/
|
||||
async readRequest() {
|
||||
const requestPath = getRequestPath();
|
||||
const stats = await (0, import_promises.stat)(requestPath);
|
||||
const request = JSON.parse(
|
||||
await (0, import_promises.readFile)(requestPath, "utf-8"),
|
||||
);
|
||||
if (
|
||||
Math.abs(stats.mtimeMs - /* @__PURE__ */ new Date().getTime()) >
|
||||
NEOVIM_COMMAND_TIMEOUT_MS
|
||||
) {
|
||||
throw new Error(
|
||||
"Request file is older than timeout; refusing to execute command",
|
||||
);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
/**
|
||||
* Writes the response to the response file as JSON.
|
||||
* @param file The file to write to
|
||||
* @param response The response object to JSON-encode and write to disk
|
||||
*/
|
||||
async writeResponse(response) {
|
||||
if (!this.responseFile) {
|
||||
throw new Error("response is not locked");
|
||||
}
|
||||
await this.responseFile.write(`${JSON.stringify(response)}
|
||||
`);
|
||||
}
|
||||
getInboundSignal(name) {
|
||||
const signalDir = getSignalDirPath();
|
||||
const path = (0, import_path2.join)(signalDir, name);
|
||||
return new InboundSignal(path);
|
||||
}
|
||||
};
|
||||
|
||||
// ../cursorless_fork/packages/neovim-registry/src/NeovimRegistry.ts
|
||||
var import_node_events = require("node:events");
|
||||
var NeovimRegistry = class {
|
||||
constructor() {
|
||||
this.apis = /* @__PURE__ */ new Map();
|
||||
this.commands = /* @__PURE__ */ new Map();
|
||||
this.eventEmitter = new import_node_events.EventEmitter();
|
||||
}
|
||||
registerExtensionApi(extensionId, api) {
|
||||
this.apis.set(extensionId, api);
|
||||
}
|
||||
getExtensionApi(extensionId) {
|
||||
return this.apis.get(extensionId);
|
||||
}
|
||||
registerCommand(commandId, callback) {
|
||||
this.commands.set(commandId, callback);
|
||||
}
|
||||
async executeCommand(commandId, ...rest) {
|
||||
return await this.commands.get(commandId)(...rest);
|
||||
}
|
||||
onEvent(eventName, listener) {
|
||||
return this.eventEmitter.on(eventName, listener);
|
||||
}
|
||||
emitEvent(eventName, ...args) {
|
||||
return this.eventEmitter.emit(eventName, ...args);
|
||||
}
|
||||
};
|
||||
|
||||
// ../cursorless_fork/packages/neovim-registry/src/index.ts
|
||||
function getNeovimRegistry() {
|
||||
if (global._neovimRegistry == null) {
|
||||
global._neovimRegistry = new NeovimRegistry();
|
||||
}
|
||||
return global._neovimRegistry;
|
||||
}
|
||||
|
||||
// src/commandRunner.ts
|
||||
var CommandRunner = class {
|
||||
constructor(io) {
|
||||
this.io = io;
|
||||
this.reloadConfiguration = this.reloadConfiguration.bind(this);
|
||||
this.runCommand = this.runCommand.bind(this);
|
||||
this.reloadConfiguration();
|
||||
}
|
||||
reloadConfiguration() {}
|
||||
/**
|
||||
* 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() {
|
||||
console.log(
|
||||
"------------------------------------------------------------------------------",
|
||||
);
|
||||
await this.io.prepareResponse();
|
||||
let request;
|
||||
try {
|
||||
request = await this.io.readRequest();
|
||||
} catch (err) {
|
||||
await this.io.closeResponse();
|
||||
throw err;
|
||||
}
|
||||
const { commandId, args, uuid, returnCommandOutput, waitForFinish } =
|
||||
request;
|
||||
const warnings = [];
|
||||
try {
|
||||
if (!commandId.match(this.allowRegex)) {
|
||||
throw new Error("Command not in allowList");
|
||||
}
|
||||
if (this.denyRegex != null && commandId.match(this.denyRegex)) {
|
||||
throw new Error("Command in denyList");
|
||||
}
|
||||
const commandPromise = getNeovimRegistry().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.message,
|
||||
uuid,
|
||||
warnings,
|
||||
});
|
||||
}
|
||||
await this.io.closeResponse();
|
||||
}
|
||||
};
|
||||
|
||||
// src/singletons/commandRunner.singleton.ts
|
||||
var cmdRunner_;
|
||||
function injectCommandRunner(cmdRunner) {
|
||||
cmdRunner_ = cmdRunner;
|
||||
}
|
||||
function commandRunner() {
|
||||
if (cmdRunner_ == null) {
|
||||
throw Error("Tried to access CommandRunner before it was injected");
|
||||
}
|
||||
return cmdRunner_;
|
||||
}
|
||||
|
||||
// src/extension.ts
|
||||
async function activate() {
|
||||
const io = new NativeIo();
|
||||
await io.initialize();
|
||||
const commandRunner2 = new CommandRunner(io);
|
||||
let focusedElementType;
|
||||
injectCommandRunner(commandRunner2);
|
||||
return {
|
||||
/**
|
||||
* The type of the focused element in vscode at the moment of the command being executed.
|
||||
*/
|
||||
getFocusedElementType: () => focusedElementType,
|
||||
/**
|
||||
* These signals can be used as a form of IPC to indicate that an event has
|
||||
* occurred.
|
||||
*/
|
||||
signals: {
|
||||
/**
|
||||
* This signal is emitted by the voice engine to indicate that a phrase has
|
||||
* just begun execution.
|
||||
*/
|
||||
prePhrase: io.getInboundSignal("prePhrase"),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// src/index.ts
|
||||
function entry(plugin) {
|
||||
plugin.setOptions({ dev: false });
|
||||
plugin.registerFunction(
|
||||
"CommandServerLoadExtension",
|
||||
async () => await loadExtension(plugin),
|
||||
{ sync: false },
|
||||
);
|
||||
plugin.registerFunction("CommandServerRunCommand", () => runCommand(), {
|
||||
sync: false,
|
||||
});
|
||||
}
|
||||
async function loadExtension(plugin) {
|
||||
console.log("loadExtension(command-server): start");
|
||||
await activate();
|
||||
console.log("loadExtension(command-server): done");
|
||||
}
|
||||
async function runCommand() {
|
||||
console.log("runCommand(command-server): start");
|
||||
commandRunner().runCommand();
|
||||
console.log("runCommand(command-server): done");
|
||||
}
|
33
cursorless.nvim/node/command-server/package.json
Normal file
33
cursorless.nvim/node/command-server/package.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "command-server",
|
||||
"description": "Exposes a file-based RPC API for running VSCode commands",
|
||||
"publisher": "saidelike",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/hands-free-vim/command-server"
|
||||
},
|
||||
"version": "0.9.1",
|
||||
"main": "./index/index.cjs",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@types/glob": "^7.1.3",
|
||||
"@types/mocha": "8.0.4",
|
||||
"@types/node": "^18.19.22",
|
||||
"@types/rimraf": "^3.0.0",
|
||||
"@types/vscode": "^1.53.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.9.0",
|
||||
"@typescript-eslint/parser": "^4.9.0",
|
||||
"esbuild": "^0.20.2",
|
||||
"eslint": "^7.15.0",
|
||||
"glob": "^7.1.6",
|
||||
"mocha": "8.1.3",
|
||||
"typescript": "^4.1.2",
|
||||
"vscode-test": "^1.4.1",
|
||||
"neovim": "^5.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimatch": "^3.0.4",
|
||||
"rimraf": "^3.0.2"
|
||||
}
|
||||
}
|
16
cursorless.nvim/test/helpers.lua
Normal file
16
cursorless.nvim/test/helpers.lua
Normal file
@ -0,0 +1,16 @@
|
||||
-- This file gets linked into plugin/helpers.lua of busted nvim config
|
||||
-- Functions that are exposed to all tests
|
||||
|
||||
function _G.get_selected_text()
|
||||
local _, ls, cs = unpack(vim.fn.getpos("v"))
|
||||
local _, le, ce = unpack(vim.fn.getpos("."))
|
||||
return vim.api.nvim_buf_get_text(0, ls - 1, cs - 1, le - 1, ce, {})
|
||||
end
|
||||
|
||||
function _G.convert_table_entries(tbl, func)
|
||||
local mapped = {}
|
||||
for k, v in pairs(tbl) do
|
||||
mapped[k] = func(v)
|
||||
end
|
||||
return mapped
|
||||
end
|
28
cursorless.nvim/test/nvim-shim.sh
Executable file
28
cursorless.nvim/test/nvim-shim.sh
Executable file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if ! [[ "${PWD}" == *"cursorless.nvim" ]]; then
|
||||
echo "ERROR: This script must be run from inside cursorless.nvim/ directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
test_folder=$(mktemp -d "${TMPDIR-/tmp}"/cursorless-busted-test-XXXXX)
|
||||
export XDG_CONFIG_HOME="${test_folder}/xdg/config/"
|
||||
export XDG_STATE_HOME="${test_folder}/xdg/local/state/"
|
||||
export XDG_DATA_HOME="${test_folder}/xdg/local/share/"
|
||||
dependency_folder="${XDG_DATA_HOME}/nvim/site/pack/testing/start/"
|
||||
plugin_folder="${XDG_CONFIG_HOME}/nvim/plugin/"
|
||||
|
||||
mkdir -p "${plugin_folder}" "${XDG_STATE_HOME}" "${dependency_folder}"
|
||||
ln -sf "${PWD}" "${dependency_folder}/cursorless.nvim"
|
||||
|
||||
# Link in standalone helper functions we want all tests to be able to call
|
||||
ln -sf "${PWD}/test/helpers.lua" "${plugin_folder}/helpers.lua"
|
||||
|
||||
# shellcheck disable=SC2068
|
||||
command nvim --cmd 'set loadplugins' -l $@
|
||||
exit_code=$?
|
||||
|
||||
rm -rf "${test_folder}"
|
||||
|
||||
exit $exit_code
|
79
cursorless.nvim/test/unit/cursorless_spec.lua
Normal file
79
cursorless.nvim/test/unit/cursorless_spec.lua
Normal file
@ -0,0 +1,79 @@
|
||||
describe("", function()
|
||||
local cursorless = require("cursorless.cursorless")
|
||||
|
||||
describe("window_get_visible_lines() ->", function()
|
||||
it("can read one visible line", function()
|
||||
local pos = vim.api.nvim_win_get_cursor(0)[2]
|
||||
local line = vim.api.nvim_get_current_line()
|
||||
local nline = line:sub(0, pos) .. "hello" .. line:sub(pos + 1)
|
||||
vim.api.nvim_set_current_line(nline)
|
||||
|
||||
local visible = cursorless.window_get_visible_lines()
|
||||
assert(table.concat(visible) == table.concat({ 1, 1 }))
|
||||
end)
|
||||
|
||||
it("can read all lines visible on the window", function()
|
||||
local maxlines = vim.api.nvim_win_get_height(0)
|
||||
local lines = {}
|
||||
for _ = 1, (maxlines + 1) do
|
||||
table.insert(lines, "hello ")
|
||||
end
|
||||
vim.api.nvim_buf_set_lines(0, 0, -1, false, lines)
|
||||
local visible = cursorless.window_get_visible_lines()
|
||||
assert(table.concat(visible) == table.concat({ 1, maxlines }))
|
||||
end)
|
||||
end)
|
||||
describe("select_range() ->", function()
|
||||
it("selects the specified range", function()
|
||||
local lines = "hello world"
|
||||
vim.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(lines, "\n"))
|
||||
cursorless.select_range(1, 2, 1, 4)
|
||||
|
||||
assert(table.concat(_G.get_selected_text()) == "llo")
|
||||
end)
|
||||
end)
|
||||
describe("buffer_get_selection() ->", function()
|
||||
it(
|
||||
"can get the forward selection in a format expected by cursorless",
|
||||
function()
|
||||
local lines = "hello world"
|
||||
vim.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(lines, "\n"))
|
||||
cursorless.select_range(1, 2, 1, 4)
|
||||
assert(
|
||||
table.concat(
|
||||
_G.convert_table_entries(
|
||||
cursorless.buffer_get_selection(),
|
||||
tostring
|
||||
),
|
||||
", "
|
||||
)
|
||||
== table.concat(
|
||||
_G.convert_table_entries({ 1, 3, 1, 5, false }, tostring),
|
||||
", "
|
||||
)
|
||||
)
|
||||
end
|
||||
)
|
||||
it(
|
||||
"can get the backward selection in a format expected by cursorless",
|
||||
function()
|
||||
local lines = "hello world"
|
||||
vim.api.nvim_buf_set_lines(0, 0, -1, false, vim.split(lines, "\n"))
|
||||
cursorless.select_range(1, 4, 1, 2)
|
||||
assert(
|
||||
table.concat(
|
||||
_G.convert_table_entries(
|
||||
cursorless.buffer_get_selection(),
|
||||
tostring
|
||||
),
|
||||
", "
|
||||
)
|
||||
== table.concat(
|
||||
_G.convert_table_entries({ 1, 3, 1, 5, true }, tostring),
|
||||
", "
|
||||
)
|
||||
)
|
||||
end
|
||||
)
|
||||
end)
|
||||
end)
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring line harp and whale
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: list
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: list
|
||||
elements:
|
||||
- type: primitive
|
||||
modifiers:
|
||||
@ -13,7 +14,7 @@ command:
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: h}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: w}
|
||||
- {type: implicit}
|
||||
destination: {type: implicit}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |+
|
||||
|
@ -1,13 +1,13 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: alternate highlight harp
|
||||
action:
|
||||
name: highlight
|
||||
args: [highlight1]
|
||||
targets:
|
||||
- type: primitive
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: h}
|
||||
highlightId: highlight1
|
||||
usePrePhraseSnapshot: true
|
||||
spokenFormError: highlight.highlightId
|
||||
initialState:
|
||||
|
@ -1,15 +1,18 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring air after air
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
modifiers:
|
||||
- {type: position, position: after}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: after
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
usePrePhraseSnapshot: true
|
||||
initialState:
|
||||
documentContents: a
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring air and bat and cap
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: list
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: list
|
||||
elements:
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
@ -12,7 +13,7 @@ command:
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: b}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: c}
|
||||
- {type: implicit}
|
||||
destination: {type: implicit}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |+
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring air and bat and cap after drum
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: list
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: list
|
||||
elements:
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
@ -12,10 +13,12 @@ command:
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: b}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: c}
|
||||
- type: primitive
|
||||
modifiers:
|
||||
- {type: position, position: after}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: d}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: after
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: d}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring air and bat and cap after item each
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: list
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: list
|
||||
elements:
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
@ -12,12 +13,15 @@ command:
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: b}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: c}
|
||||
- type: primitive
|
||||
modifiers:
|
||||
- {type: position, position: after}
|
||||
- type: containingScope
|
||||
scopeType: {type: collectionItem}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: e}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: after
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: collectionItem}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: e}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring air and bat and cap before drum
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: list
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: list
|
||||
elements:
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
@ -12,10 +13,12 @@ command:
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: b}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: c}
|
||||
- type: primitive
|
||||
modifiers:
|
||||
- {type: position, position: before}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: d}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: before
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: d}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring air and bat and cap before item each
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: list
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: list
|
||||
elements:
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
@ -12,12 +13,15 @@ command:
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: b}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: c}
|
||||
- type: primitive
|
||||
modifiers:
|
||||
- {type: position, position: before}
|
||||
- type: containingScope
|
||||
scopeType: {type: collectionItem}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: e}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: before
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: collectionItem}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: e}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |
|
||||
|
@ -1,15 +1,18 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring air before air
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
modifiers:
|
||||
- {type: position, position: before}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: before
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
usePrePhraseSnapshot: true
|
||||
initialState:
|
||||
documentContents: a
|
||||
|
@ -1,15 +1,20 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring air to end of air
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
- type: primitive
|
||||
modifiers:
|
||||
- {type: position, position: end}
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: to
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- {type: endOf}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
usePrePhraseSnapshot: true
|
||||
initialState:
|
||||
documentContents: a
|
||||
|
@ -1,15 +1,20 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring air to start of air
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
- type: primitive
|
||||
modifiers:
|
||||
- {type: position, position: start}
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: to
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- {type: startOf}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
usePrePhraseSnapshot: true
|
||||
initialState:
|
||||
documentContents: a
|
||||
|
@ -1,18 +1,21 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring arg made after look
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: m}
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: argumentOrParameter}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: l}
|
||||
modifiers:
|
||||
- {type: position, position: after}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: m}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: after
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: l}
|
||||
usePrePhraseSnapshot: true
|
||||
initialState:
|
||||
documentContents: |-
|
||||
|
@ -1,18 +1,21 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring arg made after vest
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: m}
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: argumentOrParameter}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
modifiers:
|
||||
- {type: position, position: after}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: m}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: after
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
usePrePhraseSnapshot: true
|
||||
initialState:
|
||||
documentContents: |-
|
||||
|
@ -1,18 +1,21 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring arg whale before look
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: w}
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: argumentOrParameter}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: l}
|
||||
modifiers:
|
||||
- {type: position, position: before}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: w}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: before
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: l}
|
||||
usePrePhraseSnapshot: true
|
||||
initialState:
|
||||
documentContents: |-
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring arg fine and zip
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: list
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: list
|
||||
elements:
|
||||
- type: primitive
|
||||
modifiers:
|
||||
@ -13,7 +14,7 @@ command:
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: f}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: z}
|
||||
- {type: implicit}
|
||||
destination: {type: implicit}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |-
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring arg odd and zip after just paren
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: list
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: list
|
||||
elements:
|
||||
- type: primitive
|
||||
modifiers:
|
||||
@ -13,11 +14,14 @@ command:
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: o}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: z}
|
||||
- type: primitive
|
||||
modifiers:
|
||||
- {type: position, position: after}
|
||||
- {type: toRawSelection}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: (}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: after
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- {type: toRawSelection}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: (}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |-
|
||||
|
@ -1,17 +1,21 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring fine after line vest
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: f}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
modifiers:
|
||||
- {type: position, position: after}
|
||||
- type: containingScope
|
||||
scopeType: {type: line}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: after
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: line}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
usePrePhraseSnapshot: true
|
||||
initialState:
|
||||
documentContents: |
|
||||
|
@ -1,17 +1,21 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring fine before line vest
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: f}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
modifiers:
|
||||
- {type: position, position: before}
|
||||
- type: containingScope
|
||||
scopeType: {type: line}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: before
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: line}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
usePrePhraseSnapshot: true
|
||||
initialState:
|
||||
documentContents: |2
|
||||
|
@ -1,18 +1,21 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring item air after cap
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: collectionItem}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: c}
|
||||
modifiers:
|
||||
- {type: position, position: after}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: a}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: after
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: c}
|
||||
usePrePhraseSnapshot: true
|
||||
initialState:
|
||||
documentContents: |-
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring line air and bat and cap after drum
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: list
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: list
|
||||
elements:
|
||||
- type: primitive
|
||||
modifiers:
|
||||
@ -15,10 +16,12 @@ command:
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: b}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: c}
|
||||
- type: primitive
|
||||
modifiers:
|
||||
- {type: position, position: after}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: d}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: after
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: d}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring line air and bat and cap before drum
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: list
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: list
|
||||
elements:
|
||||
- type: primitive
|
||||
modifiers:
|
||||
@ -15,10 +16,12 @@ command:
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: b}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: c}
|
||||
- type: primitive
|
||||
modifiers:
|
||||
- {type: position, position: before}
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: d}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: before
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: d}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |
|
||||
|
@ -1,12 +1,13 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring vest
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
- {type: implicit}
|
||||
destination: {type: implicit}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |
|
||||
|
@ -1,13 +1,18 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: bring vest to cap
|
||||
action: {name: replaceWithTarget}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: replaceWithTarget
|
||||
source:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
- type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: c}
|
||||
destination:
|
||||
type: primitive
|
||||
insertionMode: to
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: c}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |
|
||||
|
@ -1,12 +1,13 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: call fine
|
||||
action: {name: callAsFunction}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: callAsFunction
|
||||
callee:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: f}
|
||||
- {type: implicit}
|
||||
argument: {type: implicit}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |-
|
||||
|
@ -1,12 +1,13 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: call vest
|
||||
action: {name: callAsFunction}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: callAsFunction
|
||||
callee:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
- {type: implicit}
|
||||
argument: {type: implicit}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |
|
||||
|
@ -1,12 +1,14 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: call vest on cap
|
||||
action: {name: callAsFunction}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: callAsFunction
|
||||
callee:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
- type: primitive
|
||||
argument:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: c}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: carve vest
|
||||
action: {name: cutToClipboard}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: cutToClipboard
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: chuck arg made and air
|
||||
action: {name: remove}
|
||||
targets:
|
||||
- type: list
|
||||
action:
|
||||
name: remove
|
||||
target:
|
||||
type: list
|
||||
elements:
|
||||
- type: primitive
|
||||
modifiers:
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: chuck arg made and air and just sun
|
||||
action: {name: remove}
|
||||
targets:
|
||||
- type: list
|
||||
action:
|
||||
name: remove
|
||||
target:
|
||||
type: list
|
||||
elements:
|
||||
- type: primitive
|
||||
modifiers:
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: chuck every arg made
|
||||
action: {name: remove}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: remove
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: everyScope
|
||||
scopeType: {type: argumentOrParameter}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: chuck vest
|
||||
action: {name: remove}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: remove
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: change vest
|
||||
action: {name: clearAndSetSelection}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: clearAndSetSelection
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone arg
|
||||
action: {name: insertCopyAfter}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyAfter
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: argumentOrParameter}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone arg
|
||||
action: {name: insertCopyAfter}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyAfter
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: argumentOrParameter}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone every arg
|
||||
action: {name: insertCopyAfter}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyAfter
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: everyScope
|
||||
scopeType: {type: argumentOrParameter}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone harp
|
||||
action: {name: insertCopyAfter}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyAfter
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: h}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone harp
|
||||
action: {name: insertCopyAfter}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyAfter
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: h}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone token
|
||||
action: {name: insertCopyAfter}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyAfter
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: token}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone token
|
||||
action: {name: insertCopyAfter}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyAfter
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: token}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone token
|
||||
action: {name: insertCopyAfter}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyAfter
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: token}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone token
|
||||
action: {name: insertCopyAfter}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyAfter
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: token}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone token
|
||||
action: {name: insertCopyAfter}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyAfter
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: token}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone up arg
|
||||
action: {name: insertCopyBefore}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyBefore
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: argumentOrParameter}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone up arg
|
||||
action: {name: insertCopyBefore}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyBefore
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: argumentOrParameter}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone up every arg
|
||||
action: {name: insertCopyBefore}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyBefore
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: everyScope
|
||||
scopeType: {type: argumentOrParameter}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone up harp
|
||||
action: {name: insertCopyBefore}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyBefore
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: h}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone up harp
|
||||
action: {name: insertCopyBefore}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyBefore
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: h}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone up token
|
||||
action: {name: insertCopyBefore}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyBefore
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: token}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone up token
|
||||
action: {name: insertCopyBefore}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyBefore
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: token}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone up token
|
||||
action: {name: insertCopyBefore}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyBefore
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: token}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone up token
|
||||
action: {name: insertCopyBefore}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyBefore
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: token}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone up token
|
||||
action: {name: insertCopyBefore}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyBefore
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: token}
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone up vest
|
||||
action: {name: insertCopyBefore}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyBefore
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: clone vest
|
||||
action: {name: insertCopyAfter}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: insertCopyAfter
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: comment vest
|
||||
action: {name: toggleLineComment}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: toggleLineComment
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
|
37
data/fixtures/recorded/actions/copySecondToken.yml
Normal file
37
data/fixtures/recorded/actions/copySecondToken.yml
Normal file
@ -0,0 +1,37 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 6
|
||||
spokenForm: copy second token
|
||||
action:
|
||||
name: copyToClipboard
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: ordinalScope
|
||||
scopeType: {type: token}
|
||||
start: 1
|
||||
length: 1
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
documentContents: |
|
||||
|
||||
const value = "Hello world";
|
||||
selections:
|
||||
- anchor: {line: 1, character: 0}
|
||||
active: {line: 1, character: 0}
|
||||
marks: {}
|
||||
finalState:
|
||||
documentContents: |
|
||||
|
||||
const value = "Hello world";
|
||||
selections:
|
||||
- anchor: {line: 1, character: 0}
|
||||
active: {line: 1, character: 0}
|
||||
clipboard: value
|
||||
thatMark:
|
||||
- type: TokenTarget
|
||||
contentRange:
|
||||
start: {line: 1, character: 6}
|
||||
end: {line: 1, character: 11}
|
||||
isReversed: false
|
||||
hasExplicitRange: true
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: copy vest
|
||||
action: {name: copyToClipboard}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: copyToClipboard
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: v}
|
||||
usePrePhraseSnapshot: false
|
||||
initialState:
|
||||
|
@ -1,12 +1,13 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: curly repack round
|
||||
action:
|
||||
name: rewrapWithPairedDelimiter
|
||||
args: ['{', '}']
|
||||
targets:
|
||||
- type: primitive
|
||||
left: "{"
|
||||
right: "}"
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: surroundingPair, delimiter: parentheses}
|
||||
|
@ -1,14 +1,13 @@
|
||||
languageId: markdown
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: custom harp
|
||||
action:
|
||||
name: executeCommand
|
||||
args:
|
||||
- editor.action.addCommentLine
|
||||
- {}
|
||||
targets:
|
||||
- type: primitive
|
||||
commandId: editor.action.addCommentLine
|
||||
options: {}
|
||||
target:
|
||||
type: primitive
|
||||
mark: {type: decoratedSymbol, symbolColor: default, character: h}
|
||||
usePrePhraseSnapshot: false
|
||||
spokenFormError: Action 'executeCommand'
|
||||
|
@ -1,10 +1,11 @@
|
||||
languageId: typescript
|
||||
command:
|
||||
version: 5
|
||||
version: 6
|
||||
spokenForm: carve every arg made
|
||||
action: {name: cutToClipboard}
|
||||
targets:
|
||||
- type: primitive
|
||||
action:
|
||||
name: cutToClipboard
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: everyScope
|
||||
scopeType: {type: argumentOrParameter}
|
||||
|
30
data/fixtures/recorded/actions/dedentLine.yml
Normal file
30
data/fixtures/recorded/actions/dedentLine.yml
Normal file
@ -0,0 +1,30 @@
|
||||
languageId: plaintext
|
||||
command:
|
||||
version: 7
|
||||
spokenForm: dedent line
|
||||
action:
|
||||
name: outdentLine
|
||||
target:
|
||||
type: primitive
|
||||
modifiers:
|
||||
- type: containingScope
|
||||
scopeType: {type: line}
|
||||
usePrePhraseSnapshot: true
|
||||
initialState:
|
||||
documentContents: " foo"
|
||||
selections:
|
||||
- anchor: {line: 0, character: 0}
|
||||
active: {line: 0, character: 0}
|
||||
marks: {}
|
||||
finalState:
|
||||
documentContents: foo
|
||||
selections:
|
||||
- anchor: {line: 0, character: 0}
|
||||
active: {line: 0, character: 0}
|
||||
thatMark:
|
||||
- type: UntypedTarget
|
||||
contentRange:
|
||||
start: {line: 0, character: 0}
|
||||
end: {line: 0, character: 3}
|
||||
isReversed: false
|
||||
hasExplicitRange: true
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user