From c22f4d58a288921e71739b58091c7952938a67a8 Mon Sep 17 00:00:00 2001 From: Cedric Halbronn Date: Thu, 13 Jun 2024 11:50:36 +0100 Subject: [PATCH] Cursorless neovim support --- .github/workflows/deploy.yaml | 35 + .github/workflows/pre-commit.yml | 2 + .github/workflows/test.yml | 27 +- .gitignore | 1 + .luacheckrc | 8 + .pre-commit-config.yaml | 10 + .vscode/extensions.json | 6 +- .vscode/launch.json | 16 + .vscode/settings.json | 9 +- .vscode/tasks.json | 80 ++ cursorless.nvim/README.md | 105 ++ cursorless.nvim/lua/cursorless/cursorless.lua | 141 ++ cursorless.nvim/lua/cursorless/init.lua | 114 ++ cursorless.nvim/lua/cursorless/utils.lua | 64 + .../node/command-server/out/index.cjs | 303 ++++ .../node/command-server/package.json | 44 + .../recorded/actions/copySecondToken.yml | 35 + .../recorded/actions/pasteBeforeToken.yml | 34 + docs/contributing/cursorless-in-neovim.md | 93 ++ .../src/types/RangeExpansionBehavior.ts | 2 +- .../cursorless-engine/src/CommandHistory.ts | 6 +- .../src/core/updateSelections/RangeUpdater.ts | 1 + .../cursorless-engine/src/cursorlessEngine.ts | 3 + .../src/languages/LanguageDefinitions.ts | 2 +- packages/cursorless-neovim-e2e/package.json | 35 + .../src/endToEndTestSetup.ts | 71 + .../src/shouldRunTest.ts | 114 ++ .../src/suite/recorded.neovim.test.ts | 99 ++ packages/cursorless-neovim-e2e/tsconfig.json | 19 + packages/cursorless-neovim/TERMINOLOGY.md | 7 + packages/cursorless-neovim/package.json | 43 + .../cursorless-neovim/scripts/debug-neovim.sh | 13 + .../scripts/populate-cursorless-nvim.sh | 47 + .../src/NeovimCommandServerApi.ts | 26 + .../src/constructTestHelpers.ts | 81 ++ packages/cursorless-neovim/src/extension.ts | 152 ++ packages/cursorless-neovim/src/index.ts | 36 + .../cursorless-neovim/src/registerCommands.ts | 122 ++ packages/cursorless-neovim/tsconfig.json | 22 + .../cursorless-org-docs/docusaurus.config.mts | 2 +- .../src/ide/vscode/VscodeIDE.ts | 4 +- .../src/ide/vscode/VscodeTextEditorImpl.ts | 2 +- .../meta-updater/src/updatePackageJson.ts | 28 +- packages/neovim-common/package.json | 36 + packages/neovim-common/src/TestHelpers.ts | 20 + packages/neovim-common/src/getExtensionApi.ts | 53 + .../src/ide/neovim/NeovimCapabilities.ts | 23 + .../src/ide/neovim/NeovimClipboard.ts | 15 + .../src/ide/neovim/NeovimConfiguration.ts | 73 + .../src/ide/neovim/NeovimEdit.ts | 226 +++ .../src/ide/neovim/NeovimEvents.ts | 63 + .../src/ide/neovim/NeovimFileSystem.ts | 67 + .../src/ide/neovim/NeovimGlobalState.ts | 15 + .../neovim-common/src/ide/neovim/NeovimIDE.ts | 348 +++++ .../src/ide/neovim/NeovimMessages.ts | 12 + .../src/ide/neovim/NeovimTextDocumentImpl.ts | 389 ++++++ .../src/ide/neovim/NeovimTextEditorImpl.ts | 195 +++ .../src/ide/neovim/NeovimTextLineImpl.ts | 67 + .../src/ide/neovim/hats/NeovimHats.ts | 42 + packages/neovim-common/src/index.ts | 18 + packages/neovim-common/src/neovimApi.ts | 171 +++ packages/neovim-common/src/neovimHelpers.ts | 28 + packages/neovim-common/src/runCommand.ts | 15 + .../src/testUtil/openNewEditor.ts | 36 + packages/neovim-common/tsconfig.json | 16 + packages/neovim-registry/package.json | 29 + .../neovim-registry/src/NeovimRegistry.ts | 39 + packages/neovim-registry/src/index.ts | 8 + packages/neovim-registry/tsconfig.json | 9 + packages/test-harness/package.json | 18 +- .../scripts/populate-cursorless-nvim.sh | 42 + packages/test-harness/src/config/init.lua | 10 + packages/test-harness/src/index.ts | 54 + .../src/launchNeovimAndRunTests.ts | 196 +++ .../src/launchVscodeAndRunTests.ts | 2 +- packages/test-harness/src/runAllTests.ts | 9 +- .../src/scripts/runNeovimTestsCI.ts | 11 + .../{runTestsCI.ts => runVscodeTestsCI.ts} | 2 +- packages/test-harness/tsconfig.json | 6 + patches/@types__nearley@2.11.5.patch | 2 +- patches/nearley@2.20.1.patch | 2 +- pnpm-lock.yaml | 1232 +++++++++-------- scripts/deploy-cursorless-nvim.sh | 36 + scripts/deploy-cursorless-talon.sh | 1 + scripts/install-neovim-dependencies.sh | 7 + tsconfig.json | 12 + 86 files changed, 5144 insertions(+), 575 deletions(-) create mode 100644 .luacheckrc create mode 100644 cursorless.nvim/README.md create mode 100644 cursorless.nvim/lua/cursorless/cursorless.lua create mode 100644 cursorless.nvim/lua/cursorless/init.lua create mode 100644 cursorless.nvim/lua/cursorless/utils.lua create mode 100644 cursorless.nvim/node/command-server/out/index.cjs create mode 100644 cursorless.nvim/node/command-server/package.json create mode 100644 data/fixtures/recorded/actions/copySecondToken.yml create mode 100644 data/fixtures/recorded/actions/pasteBeforeToken.yml create mode 100644 docs/contributing/cursorless-in-neovim.md create mode 100644 packages/cursorless-neovim-e2e/package.json create mode 100644 packages/cursorless-neovim-e2e/src/endToEndTestSetup.ts create mode 100644 packages/cursorless-neovim-e2e/src/shouldRunTest.ts create mode 100644 packages/cursorless-neovim-e2e/src/suite/recorded.neovim.test.ts create mode 100644 packages/cursorless-neovim-e2e/tsconfig.json create mode 100644 packages/cursorless-neovim/TERMINOLOGY.md create mode 100644 packages/cursorless-neovim/package.json create mode 100755 packages/cursorless-neovim/scripts/debug-neovim.sh create mode 100755 packages/cursorless-neovim/scripts/populate-cursorless-nvim.sh create mode 100644 packages/cursorless-neovim/src/NeovimCommandServerApi.ts create mode 100644 packages/cursorless-neovim/src/constructTestHelpers.ts create mode 100644 packages/cursorless-neovim/src/extension.ts create mode 100644 packages/cursorless-neovim/src/index.ts create mode 100644 packages/cursorless-neovim/src/registerCommands.ts create mode 100644 packages/cursorless-neovim/tsconfig.json create mode 100644 packages/neovim-common/package.json create mode 100644 packages/neovim-common/src/TestHelpers.ts create mode 100644 packages/neovim-common/src/getExtensionApi.ts create mode 100644 packages/neovim-common/src/ide/neovim/NeovimCapabilities.ts create mode 100644 packages/neovim-common/src/ide/neovim/NeovimClipboard.ts create mode 100644 packages/neovim-common/src/ide/neovim/NeovimConfiguration.ts create mode 100644 packages/neovim-common/src/ide/neovim/NeovimEdit.ts create mode 100644 packages/neovim-common/src/ide/neovim/NeovimEvents.ts create mode 100644 packages/neovim-common/src/ide/neovim/NeovimFileSystem.ts create mode 100644 packages/neovim-common/src/ide/neovim/NeovimGlobalState.ts create mode 100644 packages/neovim-common/src/ide/neovim/NeovimIDE.ts create mode 100644 packages/neovim-common/src/ide/neovim/NeovimMessages.ts create mode 100644 packages/neovim-common/src/ide/neovim/NeovimTextDocumentImpl.ts create mode 100644 packages/neovim-common/src/ide/neovim/NeovimTextEditorImpl.ts create mode 100644 packages/neovim-common/src/ide/neovim/NeovimTextLineImpl.ts create mode 100644 packages/neovim-common/src/ide/neovim/hats/NeovimHats.ts create mode 100644 packages/neovim-common/src/index.ts create mode 100644 packages/neovim-common/src/neovimApi.ts create mode 100644 packages/neovim-common/src/neovimHelpers.ts create mode 100644 packages/neovim-common/src/runCommand.ts create mode 100644 packages/neovim-common/src/testUtil/openNewEditor.ts create mode 100644 packages/neovim-common/tsconfig.json create mode 100644 packages/neovim-registry/package.json create mode 100644 packages/neovim-registry/src/NeovimRegistry.ts create mode 100644 packages/neovim-registry/src/index.ts create mode 100644 packages/neovim-registry/tsconfig.json create mode 100755 packages/test-harness/scripts/populate-cursorless-nvim.sh create mode 100644 packages/test-harness/src/config/init.lua create mode 100644 packages/test-harness/src/index.ts create mode 100644 packages/test-harness/src/launchNeovimAndRunTests.ts create mode 100644 packages/test-harness/src/scripts/runNeovimTestsCI.ts rename packages/test-harness/src/scripts/{runTestsCI.ts => runVscodeTestsCI.ts} (89%) create mode 100755 scripts/deploy-cursorless-nvim.sh mode change 100644 => 100755 scripts/deploy-cursorless-talon.sh create mode 100755 scripts/install-neovim-dependencies.sh diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index c9ac7ea536..4db5203bfe 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -40,6 +40,41 @@ 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 }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.CURSORLESS_BOT_TOKEN }} + - 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 + - name: Configure GPG Key + run: | + echo -n "$GPG_SIGNING_KEY" | base64 --decode | gpg --import + env: + GPG_SIGNING_KEY: ${{ secrets.CURSORLESS_BOT_GPG_SIGNING_KEY }} + - name: git config + 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 + push-cursorless-talon: name: Push cursorless-talon subrepo runs-on: ubuntu-latest diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 8ab2696c91..b319662d9e 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -24,6 +24,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.0 - uses: pre-commit-ci/lite-action@v1.0.1 if: always() diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c975db71b5..9291eaac3b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,16 +16,17 @@ 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 }} VSCODE_CRASH_DIR: ${{ github.workspace }}/artifacts/dumps VSCODE_LOGS_DIR: ${{ github.workspace }}/artifacts/logs CURSORLESS_REPO_ROOT: ${{ github.workspace }} + TEMP_DIR: ${{ github.workspace }}/temp steps: - uses: actions/checkout@v4 - run: corepack enable @@ -33,7 +34,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 @@ -42,9 +43,21 @@ jobs: if: runner.os == 'Linux' - run: pnpm --color test if: runner.os != 'Linux' + - run: bash -x scripts/install-neovim-dependencies.sh + - uses: rhysd/action-setup-vim@v1 + if: matrix.app_version != 'legacy' + id: vim + with: + version: ${{ matrix.app_version }} + neovim: true + - name: Run neovim unit tests using test-harness + run: xvfb-run -a pnpm -F @cursorless/test-harness testNeovim + if: runner.os == 'Linux' && matrix.app_version == 'stable' + env: + NEOVIM_PATH: ${{ steps.vim.outputs.executable }} - 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 @@ -53,10 +66,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 diff --git a/.gitignore b/.gitignore index 90e5d79bb0..88800c9dff 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ node_modules *.vsix /package-lock.json *.DS_Store +.luacheckcache # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. diff --git a/.luacheckrc b/.luacheckrc new file mode 100644 index 0000000000..f3fa0c0198 --- /dev/null +++ b/.luacheckrc @@ -0,0 +1,8 @@ +std = luajit +cache = true +codes = true +ignore = { "432" } + +globals = { + "vim", +} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 33c376f87b..429892ecdf 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -81,3 +81,13 @@ 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 + exclude: ^data/playground/lua/.*\.lua$ + - repo: https://github.com/JohnnyMorganz/StyLua + rev: v0.20.0 + hooks: + - id: stylua + exclude: ^data/playground/lua/.*\.lua$ diff --git a/.vscode/extensions.json b/.vscode/extensions.json index aa6154aa91..f304f9751d 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -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" ] } diff --git a/.vscode/launch.json b/.vscode/launch.json index 4ce3864f0d..3215041b91 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,6 +5,22 @@ { "version": "0.2.0", "configurations": [ + { + "name": "Run neovim extension", + "request": "attach", + "continueOnAttach": true, + "skipFiles": ["/**"], + "preLaunchTask": "Build neovim extension", + "type": "node" + }, + { + "name": "Neovim extension tests", + "request": "attach", + "continueOnAttach": true, + "skipFiles": ["/**"], + "preLaunchTask": "Build neovim extension tests", + "type": "node" + }, { "name": "Run extension", "type": "extensionHost", diff --git a/.vscode/settings.json b/.vscode/settings.json index 7380c4f033..04daeaa5d8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,7 +7,7 @@ "editor.defaultFormatter": "AndreasArvidsson.andreas-talon" }, "[talon]": { - "editor.defaultFormatter": "wenkokke.tree-sitter-talon" + "editor.defaultFormatter": "wenkokke.talonfmt-vscode" }, "editor.defaultFormatter": "esbenp.prettier-vscode", // Turn off tsc task auto detection since we have the necessary tasks as npm scripts @@ -25,5 +25,10 @@ "files.eol": "\n", "typescript.enablePromptUseWorkspaceTsdk": true, "typescript.tsdk": "node_modules/typescript/lib", - "eslint.workingDirectories": [{ "pattern": "packages/*/" }] + "eslint.workingDirectories": [{ "pattern": "packages/*/" }], + "Lua.runtime.version": "Lua 5.1", + "Lua.diagnostics.globals": ["vim", "talon"], + "[lua]": { + "editor.defaultFormatter": "JohnnyMorganz.stylua" + } } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 412dd4c42f..783933720b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -16,6 +16,86 @@ "isDefault": true } }, + { + "label": "Build neovim extension", + "dependsOn": ["neovim start", "ESBuild-cursorless-neovim"], + "group": "build" + }, + { + "label": "Build neovim extension tests", + "dependsOn": [ + "neovim test start", + "ESBuild-cursorless-neovim", + "TSBuild", + "Build test harness" + ], + "group": "build" + }, + { + "label": "ESBuild-cursorless-neovim", + "type": "npm", + "script": "compile", + "path": "packages/cursorless-neovim", + "dependsOn": [], + "presentation": { + "reveal": "silent" + }, + "group": "build" + }, + { + "label": "neovim start", + "type": "process", + "windows": { + "command": "powershell", + "args": [ + "(New-Object -ComObject WScript.Shell).Run(\"\"\"nvim\"\"\", 1, $false)" + ] + }, + "osx": { + "command": "osascript", + "args": [ + "-e", + "tell app \"Terminal\" to do script \"${workspaceFolder}/packages/cursorless-neovim/scripts/debug-neovim.sh ${workspaceFolder} development\"" + ] + }, + "group": "build", + "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 test start", + "type": "process", + "windows": { + "command": "powershell", + "args": [ + "(New-Object -ComObject WScript.Shell).Run(\"\"\"nvim\"\"\", 1, $false)" + ] + }, + "osx": { + "command": "osascript", + "args": [ + "-e", + "tell app \"Terminal\" to do script \"${workspaceFolder}/packages/cursorless-neovim/scripts/debug-neovim.sh ${workspaceFolder} test\"" + ] + }, + "group": "build", + "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": "Build extension only", "dependsOn": ["Populate dist", "ESBuild"], diff --git a/cursorless.nvim/README.md b/cursorless.nvim/README.md new file mode 100644 index 0000000000..1e7e9b303f --- /dev/null +++ b/cursorless.nvim/README.md @@ -0,0 +1,105 @@ + + +- [cursorless.nvim](#cursorlessnvim) + - [Prerequisites](#prerequisites) + - [Installation](#installation) + - [Configuration](#configuration) + - [Frequently asked questions](#frequently-asked-questions) + - [Contributors](#contributors) + + + +# cursorless.nvim + +Neovim plugin to support Cursorless + +## Prerequisites + +- [neovim](https://neovim.io/.) Tested with neovim version `v0.10.0` and above, but it may work with earlier versions. +- [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 ``, 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 = ``}) +``` + +_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). + +## Contributors + +Welcome! So glad you've decided to help make Cursorless in Neovim better. You'll want to start by getting [set up](https://github.com/saidelike/cursorless/blob/nvim-talon/docs/contributing/cursorless-in-neovim.md). You may also find the [Neovim API docs](https://neovim.io/doc/user/api.html) helpful to learn about Neovim extension development. diff --git a/cursorless.nvim/lua/cursorless/cursorless.lua b/cursorless.nvim/lua/cursorless/cursorless.lua new file mode 100644 index 0000000000..82c012c746 --- /dev/null +++ b/cursorless.nvim/lua/cursorless/cursorless.lua @@ -0,0 +1,141 @@ +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(dump_table(require('talon.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 + +-- https://www.reddit.com/r/neovim/comments/p4u4zy/how_to_pass_visual_selection_range_to_lua_function/ +-- https://neovim.io/doc/user/api.html#nvim_win_get_cursor() +-- +-- luacheck:ignore 631 +-- e.g. run in command mode :vmap lua print(vim.inspect(require('talon.cursorless').buffer_get_selection())) +-- then go in visual mode with "v" and select "hello" on the first line and continue selection with "air" +-- on the second line. +-- Then hit ctrl+b and it will show the selection +-- cline=2, ccol=2, vline=1, vcol=1 +-- sline=1, scol=1, eline=2, ecol=3, reverse=false +-- { 1, 1, 2, 3, false } +-- +-- if instead you select from the end of the "air" word on the second line +-- and select up to the beginning of "hello" on the first line +-- cline=1, ccol=0, vline=3, vcol=3 +-- sline=1, scol=1, eline=2, ecol=3, reverse=true +-- { 1, 1, 2, 3, true } +-- +-- if you want to directly see how it is parsed in the node extension, you can use the below: +-- e.g. run in command mode :vmap :call CursorlessLoadExtension() +-- and again use ctrl+a after selecting the text +function M.buffer_get_selection() + -- print('buffer_get_selection()') + local modeInfo = vim.api.nvim_get_mode() + local mode = modeInfo.mode + + local cursor = vim.api.nvim_win_get_cursor(0) + local cline, ccol = cursor[1], cursor[2] + local vline, vcol = vim.fn.line("v"), vim.fn.col("v") + -- print(('cline=%d, ccol=%d, vline=%d, vcol=%d'):format(cline, ccol, vcol, vcol)) + + local sline, scol + local eline, ecol + local reverse + if cline == vline then + -- if ccol <= vcol then + if ccol < vcol then + sline, scol = cline, ccol + eline, ecol = vline, vcol + scol = scol + 1 + reverse = true + else + sline, scol = vline, vcol + eline, ecol = cline, ccol + ecol = ecol + 1 + reverse = false + end + elseif cline < vline then + sline, scol = cline, ccol + eline, ecol = vline, vcol + scol = scol + 1 + reverse = true + else + sline, scol = vline, vcol + eline, ecol = cline, ccol + ecol = ecol + 1 + reverse = false + end + + if mode == "V" or mode == "CTRL-V" or mode == "\22" then + scol = 1 + ecol = nil + end + + -- print( + -- ('sline=%d, scol=%d, eline=%d, ecol=%d, reverse=%s'):format( + -- sline, + -- scol, + -- eline, + -- ecol, + -- tostring(reverse) + -- ) + -- ) + return { sline, scol, eline, ecol, reverse } +end + +-- https://www.reddit.com/r/neovim/comments/p4u4zy/how_to_pass_visual_selection_range_to_lua_function/ +-- luacheck:ignore 631 +-- e.g. run in command mode :vmap lua print(vim.inspect(require('talon.cursorless').buffer_get_selection_text())) +-- then go in visual mode with "v" and select "hello" on the first line and continue selection with "air" +-- on the second line. +-- Then hit ctrl+b and it will show the selection +-- { "hello", "air" } +function M.buffer_get_selection_text() + -- print('buffer_get_selection_text()') + local sline, scol, eline, ecol, _ = + unpack(require("talon.cursorless").buffer_get_selection()) + + local lines = vim.api.nvim_buf_get_lines(0, sline - 1, eline, 0) + if #lines == 0 then + return + end + + local startText, endText + if #lines == 1 then + startText = string.sub(lines[1], scol, ecol) + else + startText = string.sub(lines[1], scol) + endText = string.sub(lines[#lines], 1, ecol) + end + + local selection = { startText } + if #lines > 2 then + vim.list_extend(selection, vim.list_slice(lines, 2, #lines - 1)) + end + table.insert(selection, endText) + + return selection +end + +-- https://github.com/nvim-treesitter/nvim-treesitter/blob/master/lua/nvim-treesitter/ts_utils.lua#L278 +-- luacheck:ignore 631 +-- https://github.com/nvim-treesitter/nvim-treesitter-textobjects/blob/master/lua/nvim-treesitter/textobjects/select.lua#L114 +-- as an example if you put that in a vim buffer and do the following you can do a selection: +-- :w c:\work\tmp\test.lua +-- :so % +-- :lua select_range(5, 12, 5, 30) +-- for example it will highlight the last function name (nvim_win_set_cursor). +-- another example is :tmap lua require("talon.cursorless").select_range(4, 0, 4, 38) +-- NOTE: works for any mode (n,i,v,nt) except in t mode +function M.select_range(start_x, start_y, end_x, end_y) + vim.cmd([[normal! :noh]]) + vim.api.nvim_win_set_cursor(0, { start_x, start_y }) + vim.cmd([[normal v]]) + vim.api.nvim_win_set_cursor(0, { end_x, end_y }) +end + +return M diff --git a/cursorless.nvim/lua/cursorless/init.lua b/cursorless.nvim/lua/cursorless/init.lua new file mode 100644 index 0000000000..f966052e86 --- /dev/null +++ b/cursorless.nvim/lua/cursorless/init.lua @@ -0,0 +1,114 @@ +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() + -- 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/ + vim.api.nvim_set_keymap( + "i", + "", + "lua vim.fn.CommandServerRunCommand()", + { noremap = true } + ) + vim.api.nvim_set_keymap( + "n", + "", + "lua vim.fn.CommandServerRunCommand()", + { noremap = true } + ) + vim.api.nvim_set_keymap( + "c", + "", + "lua vim.fn.CommandServerRunCommand()", + { noremap = true } + ) + vim.api.nvim_set_keymap( + "v", + "", + "lua vim.fn.CommandServerRunCommand()", + { noremap = true } + ) + vim.api.nvim_set_keymap( + "t", + "", + "lua vim.fn.CommandServerRunCommand()", + { noremap = true } + ) +end + +local function setup() + register_functions() + load_extensions() + configure_command_server_shortcut() +end + +local M = { + setup = setup, +} + +return M diff --git a/cursorless.nvim/lua/cursorless/utils.lua b/cursorless.nvim/lua/cursorless/utils.lua new file mode 100644 index 0000000000..62105fb0a2 --- /dev/null +++ b/cursorless.nvim/lua/cursorless/utils.lua @@ -0,0 +1,64 @@ +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').get_path_separator()) +function M.get_path_separator() + if require("cursorless.utils").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 require("cursorless.utils").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 lua mode_switch_nt() +function M.mode_switch_nt() + local key = vim.api.nvim_replace_termcodes("", 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 lua mode_switch_t() +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 lua require('cursorless.utils').paste() +function M.paste() + vim.cmd([[normal! "+p]]) +end + +return M diff --git a/cursorless.nvim/node/command-server/out/index.cjs b/cursorless.nvim/node/command-server/out/index.cjs new file mode 100644 index 0000000000..d0d5461321 --- /dev/null +++ b/cursorless.nvim/node/command-server/out/index.cjs @@ -0,0 +1,303 @@ +"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"); +} +//# sourceMappingURL=index.cjs.map diff --git a/cursorless.nvim/node/command-server/package.json b/cursorless.nvim/node/command-server/package.json new file mode 100644 index 0000000000..3fb9eba465 --- /dev/null +++ b/cursorless.nvim/node/command-server/package.json @@ -0,0 +1,44 @@ +{ + "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": "./out/index.cjs", + "private": true, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "compile:tsc": "tsc --build", + "compile:esbuild": "esbuild ./src/index.ts --sourcemap --format=cjs --conditions=cursorless:bundler --bundle --outfile=./out/index.cjs --platform=node", + "compile": "pnpm compile:tsc && pnpm compile:esbuild", + "watch:tsc": "pnpm compile:tsc --watch", + "watch:esbuild": "pnpm compile:esbuild --watch", + "watch": "pnpm run --filter @cursorless/cursorless-neovim --parallel '/^watch:.*/'", + "clean": "rm -rf ./out tsconfig.tsbuildinfo ./dist ./build" + }, + "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": { + "@cursorless/neovim-registry": "link:../cursorless_fork/packages/neovim-registry", + "minimatch": "^3.0.4", + "rimraf": "^3.0.2" + } +} diff --git a/data/fixtures/recorded/actions/copySecondToken.yml b/data/fixtures/recorded/actions/copySecondToken.yml new file mode 100644 index 0000000000..1bc271a3fa --- /dev/null +++ b/data/fixtures/recorded/actions/copySecondToken.yml @@ -0,0 +1,35 @@ +languageId: plaintext +command: + version: 3 + spokenForm: copy second token + action: {name: copyToClipboard} + targets: + - type: primitive + modifiers: + - type: ordinalScope + scopeType: {type: token} + start: 1 + length: 1 +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 diff --git a/data/fixtures/recorded/actions/pasteBeforeToken.yml b/data/fixtures/recorded/actions/pasteBeforeToken.yml new file mode 100644 index 0000000000..0687b07a0d --- /dev/null +++ b/data/fixtures/recorded/actions/pasteBeforeToken.yml @@ -0,0 +1,34 @@ +languageId: plaintext +command: + version: 7 + spokenForm: paste before token + action: + name: pasteFromClipboard + destination: + type: primitive + insertionMode: before + target: + type: primitive + modifiers: + - type: containingScope + scopeType: {type: token} + usePrePhraseSnapshot: true +initialState: + documentContents: hello world + selections: + - anchor: {line: 0, character: 8} + active: {line: 0, character: 8} + marks: {} + clipboard: value +finalState: + documentContents: hello value world + selections: + - anchor: {line: 0, character: 14} + active: {line: 0, character: 14} + thatMark: + - type: UntypedTarget + contentRange: + start: {line: 0, character: 6} + end: {line: 0, character: 11} + isReversed: false + hasExplicitRange: true diff --git a/docs/contributing/cursorless-in-neovim.md b/docs/contributing/cursorless-in-neovim.md new file mode 100644 index 0000000000..5014aeb4ac --- /dev/null +++ b/docs/contributing/cursorless-in-neovim.md @@ -0,0 +1,93 @@ +# Cursorless in Neovim + +This document describes how to get set up to work on the Cursorless neovim plugin. + +## Initial setup + +### 1. Follow the initial contributor setup guide + +Follow the steps in [CONTRIBUTING.md](./CONTRIBUTING.md#initial-setup). + +### 2. Get production Cursorless neovim working + +Follow the installation steps in [cursorless.nvim](https://github.com/hands-free-vim/cursorless.nvim/tree/main#prerequisites). + +Confirm that production cursorless.nvim is working in neovim, eg say `"take first paint"` in a nonempty document. + +### 3. Switch to local debug version of cursorless.nvim + +You'll need to point your neovim configuration to use manually built plugin instead. You might have to locate where your neovim configuration is. + +Disable the production cursorless.nvim by commenting out the line containing `'hands-free-vim/cursorless.nvim'`. Enable the debug cursorless.nvim by adding it to the runtimepath. eg: + +```lua +require('lazy').setup({ + ... + 'hands-free-vim/talon.nvim', + -- production cursorless.nvim + -- 'hands-free-vim/cursorless.nvim', + ... +}) + +-- debug cursorless.nvim +vim.opt.runtimepath:append("C:\\path\\to\\cursorless\\dist\\cursorless.nvim") +``` + +Note that the above path should point to the `dist/cursorless.nvim` directory in your cloned cursorless repository. It may not already exist, but will be created automatically when you first launch the extension in debug mode. + +Note also that the above line must appear before the `require('cursorless').setup()` line in your neovim configuration. + +### 4. Add nvim executable path to your PATH + +On Mac and Linux, this should be done automatically. + +On Windows, open the Control Panel, navigate to `User Accounts > User Accounts`. Click on `Change my environment variables`. In the `User variables`, e.g. add the entry `C:\Program Files\Neovim\bin` to your `Path`. + +### 5. (Windows only) Create symlinks for the built plugins + +This step is only required on Windows if you don't run VSCode with Administrator privileges. + +Open a `cmd.exe` with Administrator privileges and create the symbolic links between the source folders and the built folder: + +```bat +mkdir C:\path\to\cursorless\dist\cursorless.nvim\node +mklink /D C:\path\to\cursorless\dist\cursorless.nvim\node\cursorless-neovim C:\path\to\cursorless\packages\cursorless-neovim +mklink /D C:\path\to\cursorless\dist\cursorless.nvim\node\test-harness C:\path\to\cursorless\packages\test-harness +``` + +Note that the `C:\path\to\cursorless` path above should match your cloned cursorless repository. + +## Running / testing extension locally + +You will need to add the [BufOnly.vim](https://github.com/vim-scripts/BufOnly.vim) neovim plugin if you want to be able to run the tests locally. For instance, with lazy: + +```lua +require('lazy').setup({ + 'vim-scripts/BufOnly.vim' +}) +``` + +In order to test out your local version of the extension or to run unit tests locally, you need to run the extension in debug mode. To do so you need to run the `workbench.action.debug.selectandstart` command in VSCode and then select either "Run neovim extension" or "Run neovim extension tests". + +The debug logs are written in `C:\path\to\cursorless\packages\cursorless-neovim\out\nvim_node.log`. + +NOTE: This will spawn a standalone nvim instance that is independent of VSCode. Consequently after you're done debugging, you need to close nvim. + +## Sending pull requests + +The [cursorless.nvim](https://github.com/hands-free-vim/cursorless.nvim) repo is part of the larger cursorless monorepo, and is currently part of a pending PR to that monorepo only. If you'd like to send a PR to `cursorless.nvim`, please send a PR against the `nvim-talon` branch of this [repo](https://github.com/saidelike/cursorless). + +## Frequently asked questions + +### init.lua: module 'cursorless' not found + +The first time you build Cursorless for neovim for debugging, you might encounter this error in `nvim` when it starts: + +``` +Error detected while processing C:\Users\User\AppData\Local\nvim\init.lua: +E5113: Error while calling lua chunk: C:\Users\User\AppData\Local\nvim\init.lua:50: module 'cursorless' not found: +``` + +This is expected because `nvim` is started before Cursorless is built and the `dist/cursorless.nvim` folder does not exist yet. Consequently, close `nvim` and restart your debugging session for it to work. + +If it still does not work, check that your `vim.opt.runtimepath` path point to the right folder as described in the installation instructions above. diff --git a/packages/common/src/types/RangeExpansionBehavior.ts b/packages/common/src/types/RangeExpansionBehavior.ts index 5a82df4fa0..2912ff9683 100644 --- a/packages/common/src/types/RangeExpansionBehavior.ts +++ b/packages/common/src/types/RangeExpansionBehavior.ts @@ -7,7 +7,7 @@ export enum RangeExpansionBehavior { */ openOpen = 0, /** - * The decoration's range will not widen when edits occur at the start of end. + * The decoration's range will not widen when edits occur at the start or end. */ closedClosed = 1, /** diff --git a/packages/cursorless-engine/src/CommandHistory.ts b/packages/cursorless-engine/src/CommandHistory.ts index 6b3b4e3239..fb637bb6ad 100644 --- a/packages/cursorless-engine/src/CommandHistory.ts +++ b/packages/cursorless-engine/src/CommandHistory.ts @@ -7,14 +7,12 @@ import { IDE, ReadOnlyHatMap, } from "@cursorless/common"; -import type { - CommandRunner, - CommandRunnerDecorator, -} from "@cursorless/cursorless-engine"; import { produce } from "immer"; import * as fs from "node:fs/promises"; import * as path from "node:path"; import { v4 as uuid } from "uuid"; +import { CommandRunner } from "./CommandRunner"; +import { CommandRunnerDecorator } from "./api/CursorlessEngineApi"; const filePrefix = "cursorlessCommandHistory"; diff --git a/packages/cursorless-engine/src/core/updateSelections/RangeUpdater.ts b/packages/cursorless-engine/src/core/updateSelections/RangeUpdater.ts index e261ff2fa9..b3a5297c2d 100644 --- a/packages/cursorless-engine/src/core/updateSelections/RangeUpdater.ts +++ b/packages/cursorless-engine/src/core/updateSelections/RangeUpdater.ts @@ -96,6 +96,7 @@ export class RangeUpdater { private listenForDocumentChanges() { this.disposable = ide().onDidChangeTextDocument( (event: TextDocumentChangeEvent) => { + const changes = event.contentChanges; const documentReplaceEditLists = this.getDocumentReplaceEditLists( event.document, ); diff --git a/packages/cursorless-engine/src/cursorlessEngine.ts b/packages/cursorless-engine/src/cursorlessEngine.ts index d869c8bc64..5baa773a13 100644 --- a/packages/cursorless-engine/src/cursorlessEngine.ts +++ b/packages/cursorless-engine/src/cursorlessEngine.ts @@ -44,6 +44,9 @@ export async function createCursorlessEngine( const rangeUpdater = new RangeUpdater(); + // NOTE: do not await on snippet loading and hats initialization because we don't want to + // block extension activation + const snippets = new Snippets(); snippets.init(); diff --git a/packages/cursorless-engine/src/languages/LanguageDefinitions.ts b/packages/cursorless-engine/src/languages/LanguageDefinitions.ts index 416e861ead..eb079fcbc7 100644 --- a/packages/cursorless-engine/src/languages/LanguageDefinitions.ts +++ b/packages/cursorless-engine/src/languages/LanguageDefinitions.ts @@ -56,7 +56,7 @@ export class LanguageDefinitions { editors.forEach(({ document }) => this.loadLanguage(document.languageId)); }); - // Use the repo root as the root for development mode, so that we can + // Use the repo root as the root for development mode, so that // we can make hot-reloading work for the queries this.queryDir = ide().runMode === "development" diff --git a/packages/cursorless-neovim-e2e/package.json b/packages/cursorless-neovim-e2e/package.json new file mode 100644 index 0000000000..fee3634842 --- /dev/null +++ b/packages/cursorless-neovim-e2e/package.json @@ -0,0 +1,35 @@ +{ + "name": "@cursorless/cursorless-neovim-e2e", + "version": "1.0.0", + "description": "Our neovim end-to-end tests", + "private": true, + "main": "./out/index.js", + "exports": { + ".": { + "cursorless:bundler": "./src/index.ts", + "default": "./out/index.js" + } + }, + "scripts": { + "compile": "tsc --build", + "watch": "tsc --build --watch", + "clean": "rm -rf ./out tsconfig.tsbuildinfo ./dist ./build" + }, + "keywords": [], + "author": "", + "license": "MIT", + "devDependencies": { + "@types/chai": "^4.3.14", + "@types/js-yaml": "^4.0.9", + "@types/lodash": "4.17.0", + "@types/sinon": "^17.0.3", + "neovim": "5.1.0" + }, + "dependencies": { + "@cursorless/common": "workspace:*", + "@cursorless/neovim-common": "workspace:*", + "@cursorless/neovim-registry": "workspace:*" + }, + "types": "./out/index.d.ts", + "type": "module" +} diff --git a/packages/cursorless-neovim-e2e/src/endToEndTestSetup.ts b/packages/cursorless-neovim-e2e/src/endToEndTestSetup.ts new file mode 100644 index 0000000000..5dbd3b8d8b --- /dev/null +++ b/packages/cursorless-neovim-e2e/src/endToEndTestSetup.ts @@ -0,0 +1,71 @@ +import { IDE, shouldUpdateFixtures, sleep, SpyIDE } from "@cursorless/common"; +import { getCursorlessApi, NeovimIDE } from "@cursorless/neovim-common"; +import { Context } from "mocha"; +import * as sinon from "sinon"; + +/** + * The number of times the current test has been retried. Will be 0 the first + * time the test runs and increase by 1 each time the test fails and needs to be + * rerun. + */ +let retryCount = -1; + +/** + * The title of the previously run test. Used to keep track of + * {@link retryCount}. + */ +let previousTestTitle = ""; + +export function endToEndTestSetup(suite: Mocha.Suite) { + // Disable multiple attempts for now to avoid it to hang for 10 minutes on CI + // suite.timeout("100s"); + // suite.retries(5); + suite.timeout("10s"); + suite.retries(0); + + let ide: IDE; + let injectIde: (ide: IDE) => void; + let spy: SpyIDE | undefined; + let neovimIDE: NeovimIDE; + + setup(async function (this: Context) { + const title = this.test!.fullTitle(); + retryCount = title === previousTestTitle ? retryCount + 1 : 0; + previousTestTitle = title; + ({ ide, injectIde, neovimIDE } = (await getCursorlessApi()).testHelpers!); + spy = new SpyIDE(ide); + injectIde(spy); + }); + + teardown(() => { + sinon.restore(); + injectIde(ide); + }); + + return { + getSpy() { + return spy; + }, + getNeovimIDE() { + return neovimIDE; + }, + }; +} + +/** + * Sleep function for use in tests that will be retried. Doubles the amount of + * time it sleeps each time a test is run, starting from {@link ms} / 4. + * + * If the developer used the update fixtures launch config, we sleep for {@link ms} * + * 2 every time so that they don't get spurious updates to fixtures due to not + * sleeping enough. + * @param ms The baseline number of milliseconds to sleep. + * @returns A promise that will resolve when the sleep is over + */ +export function sleepWithBackoff(ms: number) { + const timeToSleep = shouldUpdateFixtures() + ? ms * 2 + : ms * Math.pow(2, retryCount - 2); + + return sleep(timeToSleep); +} diff --git a/packages/cursorless-neovim-e2e/src/shouldRunTest.ts b/packages/cursorless-neovim-e2e/src/shouldRunTest.ts new file mode 100644 index 0000000000..00f22a988a --- /dev/null +++ b/packages/cursorless-neovim-e2e/src/shouldRunTest.ts @@ -0,0 +1,114 @@ +import { TestCaseFixtureLegacy } from "@cursorless/common"; + +const failingFixtures = [ + // actual finalState.selections.anchor is -1 compared to expected (other fixture.command.action.name == "insertCopyBefore" tests pass fine) + "recorded/actions/cloneToken4", + "recorded/actions/cloneUpToken4", + // -> Error: nvim_execute_lua: Cursor position outside buffer + "recorded/compoundTargets/chuckStartOfBlockPastStartOfFile", + // actual finalState.selections.anchor is -1 compared to expected + "recorded/implicitExpansion/chuckCoreThat", + "recorded/implicitExpansion/chuckLeadingThat", + "recorded/marks/chuckNothing", + // -> wrong fixture.finalState.selections + "recorded/implicitExpansion/cloneThat2", + "recorded/implicitExpansion/cloneThis", + "recorded/implicitExpansion/cloneThis2", +]; + +function isFailingFixture(name: string, fixture: TestCaseFixtureLegacy) { + const action = + typeof fixture.command.action === "object" + ? fixture.command.action.name + : fixture.command.action; + + switch (action) { + // "recorded/actions/insertEmptyLines/puffThis*" -> wrong fixture.finalState.selections and fixture.thatMark.contentRange + case "insertEmptyLinesAround": + return true; + // "recorded/actions/insertEmptyLines/floatThis*" -> Error: nvim_buf_get_lines: Index out of bounds + // -> or actual finalState.selections.anchor is -1 compared to expected + // actual finalState.thatMark.contentRange.start is -1 compared to expected + case "insertEmptyLineAfter": + return true; + // "recorded/actions/insertEmptyLines/dropThis*" -> wrong fixture.finalState.selections and fixture.thatMark.contentRange + case "insertEmptyLineBefore": + return true; + // "recorded/actions/cloneToken*" and "recorded/itemTextual/cloneTwoItems" -> wrong fixture.finalState.selections and fixture.thatMark.contentRange + case "insertCopyAfter": + return true; + // "recorded/implicitExpansion/pour*" -> not supported for now + case "editNewLineAfter": + return true; + // "recorded/actions/{decrement,increment}File" -> are not supported atm + case "decrement": + return true; + case "increment": + return true; + // "recorded/actions/snippets/*" -> not supported for now + case "insertSnippet": + return true; + case "wrapWithSnippet": + return true; + // "recorded/actions/insertEmptyLines/floatThis*" -> wrong fixture.finalState.selections and fixture.thatMark.contentRange + case "breakLine": + return true; + case "joinLines": + return true; + // "recorded/actions/shuffleThis" is not supported atm + case "randomizeTargets": + return true; + // "recorded/actions/pasteBeforeToken" -> wrong fixture.finalState.documentContents/selections/thatMark + case "pasteFromClipboard": + return true; + // "recorded/actions/copySecondToken" -> wrong fixture.finalState.clipboard + case "copyToClipboard": + return true; + } + + // "recorded/lineEndings/*" -> fixture.finalState.documentContents contains \n instead of \r\n + if (name.includes("/lineEndings/")) { + return true; + } + + // "recorded/fallback/take*" -> wrong fixture.finalState.selections + if (name.includes("/fallback/take")) { + return true; + } + + // We blacklist remaining unsorted failing tests + if (failingFixtures.includes(name)) { + return true; + } + + return false; +} + +export function shouldRunTest( + name: string, + fixture: TestCaseFixtureLegacy, +): boolean { + // We don't support decorated symbol marks (hats) yet + const hasMarks = + fixture.initialState.marks != null && + Object.keys(fixture.initialState.marks).length > 0; + + // we don't support multiple selections in neovim (we don't support multiple cursors atm) + const hasMultipleSelections = + fixture.initialState.selections.length > 1 || + (fixture.finalState && fixture.finalState.selections.length > 1); + + // We don't support Tree sitter yet (which requires a code languageId) + const needTreeSitter = fixture.languageId !== "plaintext"; + + if (hasMarks || hasMultipleSelections || needTreeSitter) { + return false; + } + + // Fixtures that will need to be fixed in the future + if (isFailingFixture(name, fixture)) { + return false; + } + + return true; +} diff --git a/packages/cursorless-neovim-e2e/src/suite/recorded.neovim.test.ts b/packages/cursorless-neovim-e2e/src/suite/recorded.neovim.test.ts new file mode 100644 index 0000000000..af5a8ead51 --- /dev/null +++ b/packages/cursorless-neovim-e2e/src/suite/recorded.neovim.test.ts @@ -0,0 +1,99 @@ +import { + TestCaseFixtureLegacy, + asyncSafety, + getRecordedTestPaths, + runRecordedTest, +} from "@cursorless/common"; +import { + NeovimIDE, + NeovimTextEditorImpl, + NewEditorOptions, + getCursorlessApi, + runCursorlessCommand, +} from "@cursorless/neovim-common"; +import * as yaml from "js-yaml"; +import type { NeovimClient } from "neovim"; +import { promises as fsp } from "node:fs"; +import { endToEndTestSetup, sleepWithBackoff } from "../endToEndTestSetup"; +import { shouldRunTest } from "../shouldRunTest"; + +suite("recorded test cases", async function () { + const { getSpy, getNeovimIDE } = endToEndTestSetup(this); + + suiteSetup(async () => {}); + + const tests = getRecordedTestPaths(); + + for (const { name, path } of tests) { + test( + name, + asyncSafety(async () => { + /** + * The neovim client is set by the test runner in test-harness/src/index.ts into the global object. + * This allows us to access it in the tests that are executed through mocha. + */ + const client = (global as any).additionalParameters.client; + + const buffer = await fsp.readFile(path); + const fixture = yaml.load(buffer.toString()) as TestCaseFixtureLegacy; + if (!shouldRunTest(name, fixture)) { + return this.ctx.skip(); + } + + await runRecordedTest({ + path, + spyIde: getSpy()!, + openNewTestEditor: async (content: string, languageId: string) => { + return await openNewTestEditor(client, getNeovimIDE()!, content, { + languageId, + }); + }, + sleepWithBackoff, + testHelpers: (await getCursorlessApi()).testHelpers!, + runCursorlessCommand, + }); + }), + ); + } +}); + +// NOTE: When the nvim-data/swap folder gets too big, neovim will start +// displaying a "press enter or type command to continue" message for every ":enew" command +// so the workaround is to delete that folder. +async function openNewTestEditor( + client: NeovimClient, + neovimIDE: NeovimIDE, + content: string, + { languageId = "plaintext", openBeside = false }: NewEditorOptions = {}, +): Promise { + // open a new buffer + // @see: https://vi.stackexchange.com/questions/8345/a-built-in-way-to-make-vim-open-a-new-buffer-with-file + await client.command(":enew"); + + if (!openBeside) { + // close all the other buffers + // @see: https://stackoverflow.com/questions/4545275/vim-close-all-buffers-but-this-one + await client.command(":BufOnly!"); + } + + // standardise newlines so we can easily split the lines + const newLines = content.replace(/(?:\r\n|\r|\n)/g, "\n").split("\n"); + + // set the buffer contents + const window = await client.window; + const buffer = await window.buffer; + await buffer.setLines(newLines, { start: 0, end: -1, strictIndexing: false }); + + // Not sure it matters but we try to set the right end of line type + const eol = content.includes("\r\n") ? "CRLF" : "LF"; + // https://stackoverflow.com/questions/82726/convert-dos-windows-line-endings-to-linux-line-endings-in-vim + if (eol === "CRLF") { + await client.command(":set ff=dos"); + } else { + await client.command(":set ff=unix"); + } + + const editor = await neovimIDE.updateTextEditor(); + + return editor; +} diff --git a/packages/cursorless-neovim-e2e/tsconfig.json b/packages/cursorless-neovim-e2e/tsconfig.json new file mode 100644 index 0000000000..5c6c95e260 --- /dev/null +++ b/packages/cursorless-neovim-e2e/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "out" + }, + "references": [ + { + "path": "../common" + }, + { + "path": "../neovim-common" + }, + { + "path": "../neovim-registry" + } + ], + "include": ["src/**/*.ts", "src/**/*.json", "../../typings/**/*.d.ts"] +} diff --git a/packages/cursorless-neovim/TERMINOLOGY.md b/packages/cursorless-neovim/TERMINOLOGY.md new file mode 100644 index 0000000000..a8fadf07cc --- /dev/null +++ b/packages/cursorless-neovim/TERMINOLOGY.md @@ -0,0 +1,7 @@ +# TextEditor/TextDocument vs Window/Buffer + +1. Each Cursorless "TextDocument" corresponds to a neovim "Buffer" +2. Each Cursorless "TextEditor" corresponds to a neovim "Window" +3. A "TextEditor" corresponds to a view of a "TextDocument". The same "TextDocument" can be opened in two different "TextEditor". +4. When a "Window" changes in neovim, we need to reflect its "TextEditor" +5. When a "Buffer" changes in neovim, we need to reflect its "TextDocument". diff --git a/packages/cursorless-neovim/package.json b/packages/cursorless-neovim/package.json new file mode 100644 index 0000000000..0fd1fceff3 --- /dev/null +++ b/packages/cursorless-neovim/package.json @@ -0,0 +1,43 @@ +{ + "name": "@cursorless/cursorless-neovim", + "version": "1.0.0", + "description": "cursorless in neovim", + "main": "./out/index.cjs", + "private": true, + "scripts": { + "compile:tsc": "tsc --build", + "compile:esbuild": "esbuild ./src/index.ts --sourcemap --format=cjs --conditions=cursorless:bundler --bundle --outfile=./out/index.cjs --platform=node", + "build": "pnpm populate-cursorless-nvim", + "compile": "pnpm compile:tsc && pnpm compile:esbuild && pnpm populate-cursorless-nvim", + "populate-cursorless-nvim": "bash ./scripts/populate-cursorless-nvim.sh", + "watch:tsc": "pnpm compile:tsc --watch", + "watch:esbuild": "pnpm compile:esbuild --watch", + "watch": "pnpm run --filter @cursorless/cursorless-neovim --parallel '/^watch:.*/'", + "clean": "rm -rf ./out tsconfig.tsbuildinfo ./dist ./build ../../dist" + }, + "keywords": [], + "author": "", + "license": "MIT", + "types": "./out/index.d.ts", + "exports": { + ".": { + "cursorless:bundler": "./src/index.ts", + "default": "./out/index.cjs" + } + }, + "dependencies": { + "@cursorless/common": "workspace:*", + "@cursorless/cursorless-engine": "workspace:*", + "@cursorless/neovim-common": "workspace:*", + "@cursorless/neovim-registry": "workspace:*" + }, + "devDependencies": { + "@types/chai": "^4.3.14", + "@types/js-yaml": "^4.0.9", + "@types/lodash": "4.17.0", + "@types/uuid": "^9.0.8", + "lodash": "^4.17.21", + "neovim": "5.1.0", + "vscode-uri": "^3.0.8" + } +} diff --git a/packages/cursorless-neovim/scripts/debug-neovim.sh b/packages/cursorless-neovim/scripts/debug-neovim.sh new file mode 100755 index 0000000000..514507afe2 --- /dev/null +++ b/packages/cursorless-neovim/scripts/debug-neovim.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail + +workspaceFolder="$1" +cursorless_mode="$2" + +export CURSORLESS_REPO_ROOT="${workspaceFolder}" +export NVIM_NODE_HOST_DEBUG="1" +export NVIM_NODE_LOG_FILE="${workspaceFolder}/packages/cursorless-neovim/out/nvim_node.log" +export NVIM_NODE_LOG_LEVEL="info" +export CURSORLESS_MODE="${cursorless_mode}" + +nvim diff --git a/packages/cursorless-neovim/scripts/populate-cursorless-nvim.sh b/packages/cursorless-neovim/scripts/populate-cursorless-nvim.sh new file mode 100755 index 0000000000..ac1613af27 --- /dev/null +++ b/packages/cursorless-neovim/scripts/populate-cursorless-nvim.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -euo pipefail + +in_dir=../../cursorless.nvim +out_dir=../../dist/cursorless.nvim + +# https://stackoverflow.com/questions/64182595/how-to-determine-if-ci-script-is-running-on-github-server +(env | grep CI 1>/dev/null) && is_ci=true || is_ci=false + +if [[ "$is_ci" == "true" ]]; then + # If running in CI, only copy the necessary files for deployment + + mkdir -p "$out_dir/node/cursorless-neovim/out" + + # copy static files such as .lua dependencies and command-server + cp -r "$in_dir" "$out_dir/../" + + # copy the built .js file + cp package.json "$out_dir/node/cursorless-neovim/" + cp out/index.cjs "$out_dir/node/cursorless-neovim/out/" +else + # If running locally, make the .map files available to allow debugging + + mkdir -p "$out_dir/node" + + # copy static files such as .lua dependencies and command-server + cp -r "$in_dir" "$out_dir/../" + + # For Windows, you need Administrator privileges to create a symlink, so we assume it was created manually by the user + # during initial setup to avoid having to run vscode as Administrator + # https://github.com/orgs/community/discussions/23591 + # https://stackoverflow.com/questions/18641864/git-bash-shell-fails-to-create-symbolic-links/40914277#40914277 + unameOut="$(uname -s)" + case "${unameOut}" in + Linux*) machine=Linux;; + Darwin*) machine=Mac;; + CYGWIN*) machine=Cygwin;; + MINGW*) machine=MinGw;; # Windows Git Bash + MSYS_NT*) machine=Git;; + *) machine="UNKNOWN:${unameOut}" + esac + + # Symlink so we inherit the .map files as well + if [[ "$machine" != "MinGw" ]]; then + ln -sf "$(pwd)" "$out_dir/node/cursorless-neovim" + fi +fi diff --git a/packages/cursorless-neovim/src/NeovimCommandServerApi.ts b/packages/cursorless-neovim/src/NeovimCommandServerApi.ts new file mode 100644 index 0000000000..dacccc01c1 --- /dev/null +++ b/packages/cursorless-neovim/src/NeovimCommandServerApi.ts @@ -0,0 +1,26 @@ +import { + CommandServerApi, + FocusedElementType, + InboundSignal, +} from "@cursorless/common"; +import type { NeovimClient } from "neovim/lib/api/client"; + +export class NeovimCommandServerApi implements CommandServerApi { + signals: { prePhrase: InboundSignal }; + + constructor(private client: NeovimClient) { + this.signals = { prePhrase: { getVersion: async () => null } }; + } + + // for vscode, it is actually stored into the command-server + // but for neovim, it is stored in cursorless + // https://github.com/pokey/command-server/blob/main/src/extension.ts#L32 + async getFocusedElementType(): Promise { + const currentMode = await this.client.mode; + if (currentMode.mode === "t" || currentMode.mode === "nt") { + return "terminal"; + } else { + return "textEditor"; + } + } +} diff --git a/packages/cursorless-neovim/src/constructTestHelpers.ts b/packages/cursorless-neovim/src/constructTestHelpers.ts new file mode 100644 index 0000000000..42a7570b3d --- /dev/null +++ b/packages/cursorless-neovim/src/constructTestHelpers.ts @@ -0,0 +1,81 @@ +import { + ExcludableSnapshotField, + ExtraSnapshotField, + FakeCommandServerApi, + HatTokenMap, + IDE, + NormalizedIDE, + ScopeProvider, + SerializedMarks, + StoredTargetKey, + TargetPlainObject, + TestCaseSnapshot, + TextEditor, +} from "@cursorless/common"; +import { + StoredTargetMap, + plainObjectToTarget, + takeSnapshot, +} from "@cursorless/cursorless-engine"; +import { + NeovimFileSystem, + NeovimIDE, + NeovimTestHelpers, +} from "@cursorless/neovim-common"; + +export function constructTestHelpers( + commandServerApi: FakeCommandServerApi, + storedTargets: StoredTargetMap, + hatTokenMap: HatTokenMap, + neovimIDE: NeovimIDE, + normalizedIde: NormalizedIDE, + fileSystem: NeovimFileSystem, + scopeProvider: ScopeProvider, + injectIde: (ide: IDE) => void, + runIntegrationTests: () => Promise, +): NeovimTestHelpers | undefined { + return { + commandServerApi: commandServerApi!, + ide: normalizedIde, + neovimIDE, + injectIde, + scopeProvider, + + // FIXME: Remove this once we have a better way to get this function + // accessible from our tests + takeSnapshot( + excludeFields: ExcludableSnapshotField[], + extraFields: ExtraSnapshotField[], + editor: TextEditor, + ide: IDE, + marks: SerializedMarks | undefined, + ): Promise { + return takeSnapshot( + storedTargets, + excludeFields, + extraFields, + editor, + ide, + marks, + undefined, + undefined, + ); + }, + + cursorlessTalonStateJsonPath: fileSystem.cursorlessTalonStateJsonPath, + cursorlessCommandHistoryDirPath: fileSystem.cursorlessCommandHistoryDirPath, + + setStoredTarget( + editor: TextEditor, + key: StoredTargetKey, + targets: TargetPlainObject[] | undefined, + ): void { + storedTargets.set( + key, + targets?.map((target) => plainObjectToTarget(editor, target)), + ); + }, + hatTokenMap, + runIntegrationTests, + }; +} diff --git a/packages/cursorless-neovim/src/extension.ts b/packages/cursorless-neovim/src/extension.ts new file mode 100644 index 0000000000..b84dcfc626 --- /dev/null +++ b/packages/cursorless-neovim/src/extension.ts @@ -0,0 +1,152 @@ +import { + FakeCommandServerApi, + FakeIDE, + NormalizedIDE, + Range, + TextDocument, +} from "@cursorless/common"; +import { + TreeSitter, + createCursorlessEngine, +} from "@cursorless/cursorless-engine"; +import { + EXTENSION_ID, + NeovimFileSystem, + NeovimHats, + NeovimIDE, +} from "@cursorless/neovim-common"; +import { getNeovimRegistry } from "@cursorless/neovim-registry"; +import * as crypto from "crypto"; +import type { NeovimClient } from "neovim/lib/api/client"; +import type { NvimPlugin } from "neovim/lib/host/NvimPlugin"; +import * as os from "os"; +import * as path from "path"; +import { Language, Tree } from "web-tree-sitter"; +import { NeovimCommandServerApi } from "./NeovimCommandServerApi"; +import { constructTestHelpers } from "./constructTestHelpers"; +import { registerCommands } from "./registerCommands"; + +/** + * This function is called from cursorless.nvim to initialize the Cursorless engine. + * NOTE: this is not the cursorless-neovim extension entrypoint (which is called at Neovim startup) + * We named it activate() in order to have the same structure as the extension entrypoint to match cursorless-vscode + */ +export async function activate(plugin: NvimPlugin) { + const client = plugin.nvim as NeovimClient; + + const { neovimIDE, hats, fileSystem } = await createNeovimIde(client); + + const normalizedIde = + neovimIDE.runMode === "production" + ? neovimIDE + : new NormalizedIDE( + neovimIDE, + new FakeIDE(), + neovimIDE.runMode === "test", + ); + + const fakeCommandServerApi = new FakeCommandServerApi(); + const neovimCommandServerApi = new NeovimCommandServerApi(client); + const commandServerApi = + neovimIDE.runMode === "test" + ? fakeCommandServerApi + : neovimCommandServerApi; + + const treeSitter: TreeSitter = createTreeSitter(); + + const { + commandApi, + storedTargets, + hatTokenMap, + scopeProvider, + snippets, + injectIde, + runIntegrationTests, + addCommandRunnerDecorator, + customSpokenFormGenerator, + } = await createCursorlessEngine( + treeSitter, + normalizedIde, + hats, + commandServerApi, + fileSystem, + ); + + await registerCommands(client, neovimIDE, commandApi, commandServerApi); + + const cursorlessApi = { + testHelpers: + neovimIDE.runMode === "test" + ? constructTestHelpers( + fakeCommandServerApi, + storedTargets, + hatTokenMap, + neovimIDE, + normalizedIde as NormalizedIDE, + fileSystem, + scopeProvider, + injectIde, + runIntegrationTests, + ) + : undefined, + + experimental: { + registerThirdPartySnippets: snippets.registerThirdPartySnippets, + }, + }; + getNeovimRegistry().registerExtensionApi(EXTENSION_ID, cursorlessApi); + + console.log("activate(): Cursorless extension loaded"); +} + +async function createNeovimIde(client: NeovimClient) { + const neovimIDE = new NeovimIDE(client); + await neovimIDE.init(); + + const hats = new NeovimHats(neovimIDE); + await hats.init(); + + // FIXME: Inject this from test harness. Would need to arrange to delay + // extension initialization, probably by returning a function from extension + // init that has parameters consisting of test configuration, and have that + // function do the actual initialization. + const cursorlessDir = + neovimIDE.runMode === "test" + ? path.join(os.tmpdir(), crypto.randomBytes(16).toString("hex")) + : path.join(os.homedir(), ".cursorless"); + + const fileSystem = new NeovimFileSystem(neovimIDE.runMode, cursorlessDir); + await fileSystem.initialize(); + + return { neovimIDE, hats, fileSystem }; +} + +// We don't need a parse tree for now, so just building a fake/empty one +function createTreeSitter(): TreeSitter { + return { + getNodeAtLocation(document: TextDocument, range: Range) { + throw new UnsupportedLanguageError(document.languageId); + }, + + getTree(document: TextDocument) { + return null as unknown as Tree; + }, + + loadLanguage(languageId: string) { + return Promise.resolve(false); + }, + getLanguage(languageId: string): Language | undefined { + return undefined; + }, + }; +} + +// https://github.com/cursorless-dev/vscode-parse-tree/blob/c0f1d024acca9ceace73bc0a0cd6106515303475/src/errors.ts#L1 +export class UnsupportedLanguageError extends Error { + constructor(language: string) { + super( + `Language '${language}' not supported by parse tree extension. See https://github.com/pokey/vscode-parse-tree#adding-a-new-language`, + ); + this.name = "UnsupportedLanguageError"; + } +} diff --git a/packages/cursorless-neovim/src/index.ts b/packages/cursorless-neovim/src/index.ts new file mode 100644 index 0000000000..354a4ba48e --- /dev/null +++ b/packages/cursorless-neovim/src/index.ts @@ -0,0 +1,36 @@ +import type { NvimPlugin } from "neovim"; +import { activate } from "./extension"; + +/** + * Extension entrypoint called by node-client on Neovim startup. + * - Register the functions that are exposed to Neovim. + * Note that these function need to start with a capital letter to be callable from Neovim. + */ +export default function entry(plugin: NvimPlugin) { + // We make sure the cursorless-neovim extension is only loaded once, + // as otherwise we will run our first copy when loading the extension + // and a different new copy for executing other functions + // At the moment, it doesn't matter that much because we don't call other functions + // That being said it doesn't hurt to set it to "false" anyway + // NOTE: this is the case because all the files are rolled up into a single index.cjs file + // and node-client would reload that index.cjs file if "dev" was set to "true" + plugin.setOptions({ dev: false }); + + plugin.registerFunction( + "CursorlessLoadExtension", + async () => await loadExtension(plugin), + { sync: false }, + ); +} + +/** + * Load the cursorless engine. + */ +async function loadExtension(plugin: NvimPlugin) { + console.log( + "===============================================================================================", + ); + console.log("loadExtension(cursorless-neovim): start"); + await activate(plugin); + console.log("loadExtension(cursorless-neovim): done"); +} diff --git a/packages/cursorless-neovim/src/registerCommands.ts b/packages/cursorless-neovim/src/registerCommands.ts new file mode 100644 index 0000000000..a9c827ce82 --- /dev/null +++ b/packages/cursorless-neovim/src/registerCommands.ts @@ -0,0 +1,122 @@ +import { + CURSORLESS_COMMAND_ID, + CommandResponse, + CommandServerApi, + CursorlessCommandId, + clientSupportsFallback, + ensureCommandShape, +} from "@cursorless/common"; + +import { CommandApi } from "@cursorless/cursorless-engine"; +import { + NeovimIDE, + modeSwitchNormalTerminal, + modeSwitchTerminal, +} from "@cursorless/neovim-common"; +import { getNeovimRegistry } from "@cursorless/neovim-registry"; +import type { NeovimClient } from "neovim"; + +export async function registerCommands( + client: NeovimClient, + neovimIDE: NeovimIDE, + commandApi: CommandApi, + commandServerApi: CommandServerApi, +): Promise { + const commands: Record any> = { + // The core Cursorless command + [CURSORLESS_COMMAND_ID]: async (...args: unknown[]) => { + const originalMode = await client.mode; + if (originalMode.mode === "t") { + // Switch to "nt" so we can easily call lua functions without any problems + modeSwitchNormalTerminal(client); + } + + try { + await neovimIDE.updateTextEditor(); + const result = await commandApi.runCommandSafe(...args); + + const command = ensureCommandShape(args); + const focusedElementType = + await commandServerApi.getFocusedElementType(); + if ( + focusedElementType === "terminal" && + clientSupportsFallback(command) + ) { + const commandResponse = result as CommandResponse; + if ( + "fallback" in commandResponse && + commandResponse.fallback.action === "insert" + ) { + // if user runs a terminal, and a "bring" command was requested, switch back to "t" mode + // so the fallback can do its magic + modeSwitchTerminal(client); + } + } + + return result; + } catch (e) { + if (neovimIDE.runMode !== "test") { + const err = e as Error; + console.error(err.stack); + neovimIDE.handleCommandError(err); + } + throw e; + } + }, + + // Cheatsheet commands + ["cursorless.showCheatsheet"]: dummyCommandHandler, + ["cursorless.internal.updateCheatsheetDefaults"]: dummyCommandHandler, + + // Testcase recorder commands + ["cursorless.recordTestCase"]: dummyCommandHandler, + ["cursorless.recordOneTestCaseThenPause"]: dummyCommandHandler, + ["cursorless.pauseRecording"]: dummyCommandHandler, + ["cursorless.resumeRecording"]: dummyCommandHandler, + ["cursorless.takeSnapshot"]: dummyCommandHandler, + + // Scope test recorder commands + ["cursorless.recordScopeTests.showUnimplementedFacets"]: + dummyCommandHandler, + ["cursorless.recordScopeTests.saveActiveDocument"]: dummyCommandHandler, + + // Other commands + ["cursorless.showQuickPick"]: dummyCommandHandler, + ["cursorless.showDocumentation"]: dummyCommandHandler, + ["cursorless.private.logQuickActions"]: dummyCommandHandler, + + // Hats + ["cursorless.toggleDecorations"]: dummyCommandHandler, + ["cursorless.recomputeDecorationStyles"]: dummyCommandHandler, + + // Scope visualizer + ["cursorless.showScopeVisualizer"]: dummyCommandHandler, + ["cursorless.hideScopeVisualizer"]: dummyCommandHandler, + + // Command history + ["cursorless.analyzeCommandHistory"]: dummyCommandHandler, + + // General keyboard commands + ["cursorless.keyboard.escape"]: dummyCommandHandler, + + // Targeted keyboard commands + ["cursorless.keyboard.targeted.targetHat"]: dummyCommandHandler, + ["cursorless.keyboard.targeted.targetScope"]: dummyCommandHandler, + ["cursorless.keyboard.targeted.targetSelection"]: dummyCommandHandler, + ["cursorless.keyboard.targeted.clearTarget"]: dummyCommandHandler, + ["cursorless.keyboard.targeted.runActionOnTarget"]: dummyCommandHandler, + + // Modal keyboard commands + ["cursorless.keyboard.modal.modeOn"]: dummyCommandHandler, + ["cursorless.keyboard.modal.modeOff"]: dummyCommandHandler, + ["cursorless.keyboard.modal.modeToggle"]: dummyCommandHandler, + }; + + Object.entries(commands).map(([commandId, callback]) => + getNeovimRegistry().registerCommand(commandId, callback), + ); +} + +export async function dummyCommandHandler(...args: any[]) { + console.debug(`dummyCommandHandler(): args=${args}`); +} diff --git a/packages/cursorless-neovim/tsconfig.json b/packages/cursorless-neovim/tsconfig.json new file mode 100644 index 0000000000..49d3285db5 --- /dev/null +++ b/packages/cursorless-neovim/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "out" + }, + "references": [ + { + "path": "../common" + }, + { + "path": "../cursorless-engine" + }, + { + "path": "../neovim-common" + }, + { + "path": "../neovim-registry" + } + ], + "include": ["src/**/*.ts", "src/**/*.json", "../../typings/**/*.d.ts"] +} diff --git a/packages/cursorless-org-docs/docusaurus.config.mts b/packages/cursorless-org-docs/docusaurus.config.mts index 694c7b1f0d..20ca4f7d55 100644 --- a/packages/cursorless-org-docs/docusaurus.config.mts +++ b/packages/cursorless-org-docs/docusaurus.config.mts @@ -159,7 +159,7 @@ const config: Config = { prism: { theme: themes.github, darkTheme: themes.dracula, - additionalLanguages: ["bash", "diff", "json", "python"], + additionalLanguages: ["bash", "diff", "json", "python", "lua"], }, colorMode: { respectPrefersColorScheme: true, diff --git a/packages/cursorless-vscode/src/ide/vscode/VscodeIDE.ts b/packages/cursorless-vscode/src/ide/vscode/VscodeIDE.ts index 9709cf4b57..418548b861 100644 --- a/packages/cursorless-vscode/src/ide/vscode/VscodeIDE.ts +++ b/packages/cursorless-vscode/src/ide/vscode/VscodeIDE.ts @@ -62,7 +62,7 @@ export class VscodeIDE implements IDE { return await vscodeShowQuickPick(items, options); } - setHighlightRanges( + async setHighlightRanges( highlightId: HighlightId | undefined, editor: TextEditor, ranges: GeneralizedRange[], @@ -78,7 +78,7 @@ export class VscodeIDE implements IDE { ); } - flashRanges(flashDescriptors: FlashDescriptor[]): Promise { + async flashRanges(flashDescriptors: FlashDescriptor[]): Promise { return this.flashHandler.flashRanges(flashDescriptors); } diff --git a/packages/cursorless-vscode/src/ide/vscode/VscodeTextEditorImpl.ts b/packages/cursorless-vscode/src/ide/vscode/VscodeTextEditorImpl.ts index 975116cc41..a2a3bd4d6e 100644 --- a/packages/cursorless-vscode/src/ide/vscode/VscodeTextEditorImpl.ts +++ b/packages/cursorless-vscode/src/ide/vscode/VscodeTextEditorImpl.ts @@ -84,7 +84,7 @@ export class VscodeTextEditorImpl implements EditableTextEditor { return vscodeRevealLine(this, lineNumber, at); } - public edit(edits: Edit[]): Promise { + public async edit(edits: Edit[]): Promise { return vscodeEdit(this.editor, edits); } diff --git a/packages/meta-updater/src/updatePackageJson.ts b/packages/meta-updater/src/updatePackageJson.ts index acfdd77f23..ce711f4ff8 100644 --- a/packages/meta-updater/src/updatePackageJson.ts +++ b/packages/meta-updater/src/updatePackageJson.ts @@ -44,7 +44,8 @@ export async function updatePackageJson( ? input.name : `@cursorless/${input.name}`; - const isLib = !isRoot && !input.private; + const isLib = + !isRoot && !input.private && input.name !== "@cursorless/neovim-registry"; const exportFields: Partial = !isLib ? {} @@ -68,6 +69,10 @@ export async function updatePackageJson( const isCursorlessVscode = input.name === "@cursorless/cursorless-vscode"; + const useGlobalDist = + input.name === "@cursorless/cursorless-neovim" || + input.name == "@cursorless/test-harness"; + const extraFields = isCursorlessVscode ? getCursorlessVscodeFields(input) : {}; @@ -76,8 +81,19 @@ export async function updatePackageJson( ...input, name, license: "MIT", - type: name === "@cursorless/cursorless-org-docs" ? undefined : "module", - scripts: await getScripts(input.scripts, name, packageDir, isRoot, isLib), + type: + name === "@cursorless/cursorless-org-docs" || + name === "@cursorless/cursorless-neovim" + ? undefined + : "module", + scripts: await getScripts( + input.scripts, + name, + packageDir, + isRoot, + isLib, + useGlobalDist, + ), ...exportFields, ...extraFields, }; @@ -101,6 +117,7 @@ async function getScripts( packageDir: string, isRoot: boolean, isLib: boolean, + useGlobalDist: boolean, ) { const scripts: PackageJson.Scripts = { ...(inputScripts ?? {}), @@ -125,7 +142,10 @@ async function getScripts( return scripts; } - const cleanDirs = ["./out", "tsconfig.tsbuildinfo", "./dist", "./build"]; + let cleanDirs = ["./out", "tsconfig.tsbuildinfo", "./dist", "./build"]; + if (useGlobalDist) { + cleanDirs = [...cleanDirs, "../../dist"]; + } const clean = `rm -rf ${cleanDirs.join(" ")}`; diff --git a/packages/neovim-common/package.json b/packages/neovim-common/package.json new file mode 100644 index 0000000000..9a58dd03f2 --- /dev/null +++ b/packages/neovim-common/package.json @@ -0,0 +1,36 @@ +{ + "name": "@cursorless/neovim-common", + "version": "1.0.0", + "description": "Common utility functions usable anywhere that neovim api is available", + "main": "./out/index.js", + "scripts": { + "compile:tsc": "tsc --build", + "compile:esbuild": "esbuild ./src/index.ts --sourcemap --format=esm --bundle --packages=external --outfile=./out/index.js", + "compile": "pnpm compile:tsc && pnpm compile:esbuild", + "watch:tsc": "pnpm compile:tsc --watch", + "watch:esbuild": "pnpm compile:esbuild --watch", + "watch": "pnpm run --filter @cursorless/neovim-common --parallel '/^watch:.*/'", + "clean": "rm -rf ./out tsconfig.tsbuildinfo ./dist ./build" + }, + "keywords": [], + "author": "", + "license": "MIT", + "types": "./out/index.d.ts", + "exports": { + ".": { + "cursorless:bundler": "./src/index.ts", + "default": "./out/index.js" + } + }, + "dependencies": { + "@cursorless/common": "workspace:*", + "@cursorless/neovim-registry": "workspace:*", + "@types/lodash": "4.17.0", + "@types/uuid": "^9.0.8", + "@types/vscode": "1.75.1", + "lodash": "^4.17.21", + "neovim": "5.1.0", + "vscode-uri": "^3.0.8" + }, + "type": "module" +} diff --git a/packages/neovim-common/src/TestHelpers.ts b/packages/neovim-common/src/TestHelpers.ts new file mode 100644 index 0000000000..c38d4a7b23 --- /dev/null +++ b/packages/neovim-common/src/TestHelpers.ts @@ -0,0 +1,20 @@ +import type { + IDE, + NormalizedIDE, + ScopeProvider, + TestHelpers, +} from "@cursorless/common"; +import { NeovimIDE } from "./ide/neovim/NeovimIDE"; + +export interface NeovimTestHelpers extends TestHelpers { + ide: NormalizedIDE; + neovimIDE: NeovimIDE; + injectIde: (ide: IDE) => void; + + scopeProvider: ScopeProvider; + + runIntegrationTests(): Promise; + + cursorlessTalonStateJsonPath: string; + cursorlessCommandHistoryDirPath: string; +} diff --git a/packages/neovim-common/src/getExtensionApi.ts b/packages/neovim-common/src/getExtensionApi.ts new file mode 100644 index 0000000000..12ca15a22a --- /dev/null +++ b/packages/neovim-common/src/getExtensionApi.ts @@ -0,0 +1,53 @@ +import type { SnippetMap } from "@cursorless/common"; +//import * as vscode from "vscode"; +import { getNeovimRegistry } from "@cursorless/neovim-registry"; +import { NeovimTestHelpers } from "./TestHelpers"; + +export interface CursorlessApi { + testHelpers: NeovimTestHelpers | undefined; + + experimental: { + registerThirdPartySnippets: ( + extensionId: string, + snippets: SnippetMap, + ) => void; + }; +} + +// See packages\cursorless-neovim\src\extension.ts:createTreeSitter() for neovim +// export interface ParseTreeApi { +// getNodeAtLocation(location: vscode.Location): SyntaxNode; +// getTreeForUri(uri: vscode.Uri): Tree; +// loadLanguage: (languageId: string) => Promise; +// getLanguage(languageId: string): Language | undefined; +// } + +export async function getExtensionApi(extensionId: string) { + const api = getNeovimRegistry().getExtensionApi(extensionId); + return api == null ? null : (api as T); +} + +export async function getExtensionApiStrict(extensionId: string) { + const api = getNeovimRegistry().getExtensionApi(extensionId); + + if (api == null) { + throw new Error(`Could not get ${extensionId} extension`); + } + + return api as T; +} + +export const EXTENSION_ID = "pokey.cursorless"; +export const getCursorlessApi = () => + getExtensionApiStrict(EXTENSION_ID); + +// export const getParseTreeApi = () => +// getExtensionApiStrict("pokey.parse-tree"); + +// See packages/cursorless-neovim/src/NeovimCommandServerApi.ts for neovim implementation +/** + * + * @returns Command server API or null if not installed + */ +// export const getCommandServerApi = () => +// getExtensionApi("pokey.command-server"); diff --git a/packages/neovim-common/src/ide/neovim/NeovimCapabilities.ts b/packages/neovim-common/src/ide/neovim/NeovimCapabilities.ts new file mode 100644 index 0000000000..fee028512f --- /dev/null +++ b/packages/neovim-common/src/ide/neovim/NeovimCapabilities.ts @@ -0,0 +1,23 @@ +import { Capabilities, CommandCapabilityMap } from "@cursorless/common"; + +const COMMAND_CAPABILITIES: CommandCapabilityMap = { + clipboardCopy: { acceptsLocation: false }, + toggleLineComment: undefined, + indentLine: undefined, + outdentLine: undefined, + rename: undefined, + quickFix: undefined, + revealDefinition: undefined, + revealTypeDefinition: undefined, + showHover: undefined, + showDebugHover: undefined, + extractVariable: undefined, + fold: undefined, + highlight: { acceptsLocation: true }, + unfold: undefined, + showReferences: undefined, +}; + +export class NeovimCapabilities implements Capabilities { + commands = COMMAND_CAPABILITIES; +} diff --git a/packages/neovim-common/src/ide/neovim/NeovimClipboard.ts b/packages/neovim-common/src/ide/neovim/NeovimClipboard.ts new file mode 100644 index 0000000000..fad736535d --- /dev/null +++ b/packages/neovim-common/src/ide/neovim/NeovimClipboard.ts @@ -0,0 +1,15 @@ +import type { Clipboard } from "@cursorless/common"; +import { getFromClipboard, putToClipboard } from "../../neovimApi"; +import type { NeovimClient } from "neovim"; + +export default class NeovimClipboard implements Clipboard { + constructor(private client: NeovimClient) {} + + async readText(): Promise { + return await getFromClipboard(this.client); + } + + async writeText(value: string): Promise { + return await putToClipboard(value, this.client); + } +} diff --git a/packages/neovim-common/src/ide/neovim/NeovimConfiguration.ts b/packages/neovim-common/src/ide/neovim/NeovimConfiguration.ts new file mode 100644 index 0000000000..bd8bf7e24f --- /dev/null +++ b/packages/neovim-common/src/ide/neovim/NeovimConfiguration.ts @@ -0,0 +1,73 @@ +import { get } from "lodash"; +import { Notifier } from "@cursorless/common"; +import { + Configuration, + ConfigurationScope, + CONFIGURATION_DEFAULTS, + CursorlessConfigKey, + CursorlessConfiguration, +} from "@cursorless/common"; +import { GetFieldType, Paths } from "@cursorless/common"; + +interface ConfigurationScopeValues { + scope: ConfigurationScope; + values: Partial; +} + +export default class NeovimConfiguration implements Configuration { + private notifier = new Notifier(); + private mocks: CursorlessConfiguration = { + ...CONFIGURATION_DEFAULTS, + }; + private scopes: ConfigurationScopeValues[] = []; + + constructor() { + this.onDidChangeConfiguration = this.onDidChangeConfiguration.bind(this); + } + + getOwnConfiguration>( + path: Path, + scope?: ConfigurationScope, + ): GetFieldType { + if (scope != null) { + for (const { scope: candidateScope, values } of this.scopes) { + if (scopeMatches(candidateScope, scope)) { + return (get(values, path) ?? get(this.mocks, path)) as GetFieldType< + CursorlessConfiguration, + Path + >; + } + } + } + + return get(this.mocks, path) as GetFieldType; + } + + onDidChangeConfiguration = this.notifier.registerListener; + + mockConfiguration( + key: T, + value: CursorlessConfiguration[T], + ): void { + this.mocks[key] = value; + this.notifier.notifyListeners(); + } + + mockConfigurationScope( + scope: ConfigurationScope, + values: Partial, + noNotification: boolean = false, + ): void { + this.scopes.push({ scope, values }); + if (!noNotification) { + this.notifier.notifyListeners(); + } + } +} + +function scopeMatches( + candidateScope: ConfigurationScope, + scope: ConfigurationScope, +): boolean { + return candidateScope.languageId === scope.languageId; +} diff --git a/packages/neovim-common/src/ide/neovim/NeovimEdit.ts b/packages/neovim-common/src/ide/neovim/NeovimEdit.ts new file mode 100644 index 0000000000..ebeb50cc3c --- /dev/null +++ b/packages/neovim-common/src/ide/neovim/NeovimEdit.ts @@ -0,0 +1,226 @@ +import { + Edit, + Position, + Range, + TextDocument, + TextDocumentContentChangeEvent, +} from "@cursorless/common"; +import type { NeovimClient, Window } from "neovim"; +import { NeovimIDE } from "./NeovimIDE"; +import { getNeovimRegistry } from "@cursorless/neovim-registry"; + +export default async function neovimEdit( + client: NeovimClient, + neovimIDE: NeovimIDE, + window: Window, + edits: Edit[], +): Promise { + console.debug("neovimEdit() [unsorted]:"); + for (const edit of edits) { + console.debug( + `\trange=${JSON.stringify(edit.range)}, text='${edit.text}', isReplace=${edit.isReplace}`, + ); + } + + edits.sort((a, b) => { + // console.debug( + // `a=${JSON.stringify(a.range)}, text='${a.text}', isReplace=${a.isReplace}`, + // ); + // console.debug( + // `b=${JSON.stringify(b.range)}, text='${b.text}', isReplace=${b.isReplace}`, + // ); + // We apply the insert/replace edits from the start of the document + // as a later one assume the previous ones have already been applied + if ((isInsert(a) || isReplace(a)) && (isInsert(b) || isReplace(b))) { + // console.debug("a is insert/replace and b is insert/replace"); + return 1; + } + // We apply the delete edits from the end of the document + // to make sure the edit ranges for the remaining ones are stable + if (a.range.start.line === b.range.start.line) { + // console.debug("a and b are on the same line"); + return b.range.start.character - a.range.start.character; + } + // console.debug("a and b are on different lines"); + return b.range.start.line - a.range.start.line; + }); + + console.debug("neovimEdit() [sorted]:"); + for (const edit of edits) { + console.debug( + `\trange=${JSON.stringify(edit.range)}, text='${edit.text}', isReplace=${edit.isReplace}`, + ); + } + const document = neovimIDE.getTextDocument( + await client.window.buffer, + ) as TextDocument; + const changes: TextDocumentContentChangeEvent[] = []; + for (const edit of edits) { + changes.push({ + range: edit.range, + rangeOffset: document.offsetAt(edit.range.start), + rangeLength: + document.offsetAt(edit.range.end) - document.offsetAt(edit.range.start), + text: edit.text, + }); + } + + getNeovimRegistry().emitEvent("onDidChangeTextDocument", { + document: document, + contentChanges: changes, + }); + + for (const edit of edits) { + const { range, text, isReplace } = edit; + + if (text === "") { + await neovimDelete(client, range); + } else if (range.isEmpty && !isReplace) { + await neovimInsert(client, range.start, text); + } else { + await neovimReplace(client, range, text); + } + } + + await neovimIDE.updateTextEditor(); + return true; +} + +async function neovimDelete(client: NeovimClient, range: Range): Promise { + console.debug(`neovimDelete(): range=${JSON.stringify(range)}`); + const buffer = await client.window.buffer; + + // only keep the end of the last line + const lastLine = ( + await buffer.getLines({ + start: range.end.line, + end: range.end.line + 1, + strictIndexing: true, + }) + )[0]; + const endOfLastLine = lastLine.slice(range.end.character); + + // are we only modifying one existing line? + if (range.start.line === range.end.line) { + // only keep the beginning and end of the line + const singleLine = lastLine.slice(0, range.start.character) + endOfLastLine; + // update that single line + await buffer.setLines(singleLine, { + start: range.start.line, + end: range.start.line + 1, + strictIndexing: true, + }); + return; + } + + // we are modifying multiple lines + + // are we not including the beginning of the first line? + if (range.start.character === 0) { + // if we are deleting from the start of the first line, we need to exclude the first line + await buffer.setLines(endOfLastLine, { + start: range.start.line, + end: range.end.line + 1, + strictIndexing: true, + }); + return; + } + + // only keep the beginning of the first line + const firstLine = ( + await buffer.getLines({ + start: range.start.line, + end: range.start.line + 1, + strictIndexing: true, + }) + )[0]; + const startOfFirstLine = firstLine.slice(0, range.start.character); + + // are we not including the newline at the end of the first line? + if (range.start.character <= firstLine.length) { + // if we are deleting from before the end of the first line, we need to append the last line to the first line + await buffer.setLines(startOfFirstLine + endOfLastLine, { + start: range.start.line, + end: range.end.line + 1, + strictIndexing: true, + }); + return; + } + + await buffer.setLines([startOfFirstLine, endOfLastLine], { + start: range.start.line, + end: range.end.line + 1, + strictIndexing: true, + }); +} + +async function neovimInsert( + client: NeovimClient, + position: Position, + text: string, +) { + console.debug( + `neovimInsert(): position=${JSON.stringify(position)}, text='${text}'`, + ); + // standardise newlines so we can easily split the lines + const newLines = text.replace(/(?:\r\n|\r|\n)/g, "\n").split("\n"); + + const buffer = await client.window.buffer; + + const lineWhereInsertion = ( + await buffer.getLines({ + start: position.line, + end: position.line + 1, + strictIndexing: true, + }) + )[0]; + const startOfFirstLine = lineWhereInsertion.slice(0, position.character); + const endOfLastLine = lineWhereInsertion.slice(position.character); + + // are we only inserting into one existing line? + if (newLines.length == 1) { + const singleLine = startOfFirstLine + newLines[0] + endOfLastLine; + // update that single line + await buffer.setLines(singleLine, { + start: position.line, + end: position.line + 1, + strictIndexing: true, + }); + return; + } + + // we are inserting multiple lines + + const firstLine = startOfFirstLine + newLines[0]; + const lastLine = newLines[newLines.length - 1] + endOfLastLine; + await buffer.setLines( + [firstLine, ...newLines.slice(1, newLines.length - 1), lastLine], + { + start: position.line, + end: position.line + 1, + strictIndexing: true, + }, + ); +} + +async function neovimReplace(client: NeovimClient, range: Range, text: string) { + console.debug( + `neovimReplace(): range=${JSON.stringify(range)}, text='${text}'`, + ); + await neovimDelete(client, range); + await neovimInsert(client, range.start, text); +} + +function isDelete(edit: Edit): boolean { + return edit.text === ""; +} + +function isInsert(edit: Edit): boolean { + return edit.range.isEmpty && !edit.isReplace; +} + +function isReplace(edit: Edit): boolean { + return ( + edit.text !== "" && (!edit.range.isEmpty || edit.isReplace ? true : false) + ); +} diff --git a/packages/neovim-common/src/ide/neovim/NeovimEvents.ts b/packages/neovim-common/src/ide/neovim/NeovimEvents.ts new file mode 100644 index 0000000000..7dde8cb4c0 --- /dev/null +++ b/packages/neovim-common/src/ide/neovim/NeovimEvents.ts @@ -0,0 +1,63 @@ +import { + Disposable, + Position, + Range, + TextDocument, + TextDocumentChangeEvent, + TextDocumentContentChangeEvent, +} from "@cursorless/common"; +import { getNeovimRegistry } from "@cursorless/neovim-registry"; + +import type { Buffer } from "neovim"; + +export function neovimOnDidChangeTextDocument( + listener: (event: TextDocumentChangeEvent) => void, +): Disposable { + getNeovimRegistry().onEvent("onDidChangeTextDocument", listener); + return dummyEvent(); +} + +export function neovimOnDidOpenTextDocument( + listener: (event: TextDocument) => any, + thisArgs?: any, + disposables?: Disposable[] | undefined, +): Disposable { + getNeovimRegistry().onEvent("onDidOpenTextDocument", listener); + return dummyEvent(); +} + +export function fromNeovimContentChange( + document: TextDocument, + buffer: Buffer, + firstLine: number, + lastLine: number, + linedata: string[], +): TextDocumentContentChangeEvent[] { + const result = []; + const text = linedata.join("\n"); + console.debug( + `fromNeovimContentChange(): document.getText(): '${document.getText()}'`, + ); + const range = new Range( + new Position(firstLine, 0), + new Position(lastLine - 1, document.lineAt(lastLine - 1).text.length), + ); + const rangeOffset = document.offsetAt(range.start); + const rangeLength = document.offsetAt(range.end) - rangeOffset; + result.push({ + range: range, + rangeOffset: rangeOffset, + rangeLength: rangeLength, + text: text, + }); + console.debug(`fromNeovimContentChange(): changes=${JSON.stringify(result)}`); + return result; +} + +function dummyEvent() { + return { + dispose() { + // empty + }, + }; +} diff --git a/packages/neovim-common/src/ide/neovim/NeovimFileSystem.ts b/packages/neovim-common/src/ide/neovim/NeovimFileSystem.ts new file mode 100644 index 0000000000..56ecb1ec8b --- /dev/null +++ b/packages/neovim-common/src/ide/neovim/NeovimFileSystem.ts @@ -0,0 +1,67 @@ +import { + Disposable, + FileSystem, + PathChangeListener, + RunMode, +} from "@cursorless/common"; +import { join } from "path"; +import * as fs from "fs"; + +export class NeovimFileSystem implements FileSystem { + public readonly cursorlessTalonStateJsonPath: string; + public readonly cursorlessCommandHistoryDirPath: string; + + constructor( + private readonly runMode: RunMode, + private readonly cursorlessDir: string, + ) { + this.cursorlessTalonStateJsonPath = join(this.cursorlessDir, "state.json"); + this.cursorlessCommandHistoryDirPath = join( + this.cursorlessDir, + "commandHistory", + ); + } + + public async initialize(): Promise { + if (!fs.existsSync(this.cursorlessDir)) { + try { + fs.mkdirSync(this.cursorlessDir); + } catch (err) { + console.debug("Cannot create cursorlessDir", this.cursorlessDir, err); + } + } + } + + /** + * Reads a file that comes bundled with Cursorless, with the utf-8 encoding. + * {@link path} is expected to be relative to the root of the extension + * bundle. If the file doesn't exist, returns `undefined`. + * + * Note that in development mode, it is possible to supply an absolute path to + * a file on the local filesystem, for things like hot-reloading. + * + * @param path The path of the file to read + * @returns The contents of path, decoded as UTF-8 + */ + public async readBundledFile(path: string): Promise { + // throw Error("readBundledFile() Not implemented"); + console.debug("readBundledFile() Not implemented"); + return undefined; + } + + private resolveBundledPath(path: string) { + throw Error("resolveBundledPath() Not implemented"); + } + + public watchDir(path: string, onDidChange: PathChangeListener): Disposable { + return dummyEvent(); + } +} + +function dummyEvent() { + return { + dispose() { + // empty + }, + }; +} diff --git a/packages/neovim-common/src/ide/neovim/NeovimGlobalState.ts b/packages/neovim-common/src/ide/neovim/NeovimGlobalState.ts new file mode 100644 index 0000000000..f852288141 --- /dev/null +++ b/packages/neovim-common/src/ide/neovim/NeovimGlobalState.ts @@ -0,0 +1,15 @@ +import type { State, StateData, StateKey } from "@cursorless/common"; +import { STATE_DEFAULTS } from "@cursorless/common"; + +export default class NeovimGlobalState implements State { + private readonly data: StateData = { ...STATE_DEFAULTS }; + + get(key: K): StateData[K] { + return this.data[key]; + } + + set(key: K, value: StateData[K]): Promise { + this.data[key] = value; + return Promise.resolve(); + } +} diff --git a/packages/neovim-common/src/ide/neovim/NeovimIDE.ts b/packages/neovim-common/src/ide/neovim/NeovimIDE.ts new file mode 100644 index 0000000000..430a075939 --- /dev/null +++ b/packages/neovim-common/src/ide/neovim/NeovimIDE.ts @@ -0,0 +1,348 @@ +import type { + Disposable, + EditableTextEditor, + IDE, + OpenUntitledTextDocumentOptions, + Range, + RunMode, + Selection, + TextDocumentChangeEvent, + TextEditor, + WorkspaceFolder, +} from "@cursorless/common"; +import { + Event, + FlashDescriptor, + GeneralizedRange, + QuickPickOptions, + TextDocument, + TextEditorSelectionChangeEvent, + TextEditorVisibleRangesChangeEvent, +} from "@cursorless/common"; +import { pull } from "lodash"; +import type { Buffer, NeovimClient, Window } from "neovim"; +import { v4 as uuid } from "uuid"; +import { NeovimCapabilities } from "./NeovimCapabilities"; +import NeovimClipboard from "./NeovimClipboard"; +import NeovimConfiguration from "./NeovimConfiguration"; +import NeovimGlobalState from "./NeovimGlobalState"; +import NeovimMessages from "./NeovimMessages"; +import { NeovimTextEditorImpl } from "./NeovimTextEditorImpl"; +import path from "path"; +import { URI } from "vscode-uri"; + +import { + bufferGetSelections, + getCursorlessNvimPath, + showErrorMessage, + windowGetVisibleRanges, +} from "../../neovimApi"; +import { + neovimOnDidChangeTextDocument, + neovimOnDidOpenTextDocument, +} from "./NeovimEvents"; +import { NeovimTextDocumentImpl } from "./NeovimTextDocumentImpl"; +import { getNeovimRegistry } from "@cursorless/neovim-registry"; + +export class NeovimIDE implements IDE { + readonly configuration: NeovimConfiguration; + readonly globalState: NeovimGlobalState; + readonly messages: NeovimMessages; + readonly clipboard: NeovimClipboard; + readonly capabilities: NeovimCapabilities; + private editorMap; + private documentMap; + private activeWindow: Window | undefined; + private activeBuffer: Buffer | undefined; + + cursorlessVersion: string = "0.0.0"; + workspaceFolders: readonly WorkspaceFolder[] | undefined = undefined; + private disposables: Disposable[] = []; + private assetsRoot_: string | undefined; + private cursorlessNeovimPath: string | undefined; + private quickPickReturnValue: string | undefined = undefined; + + constructor(private client: NeovimClient) { + this.configuration = new NeovimConfiguration(); + this.globalState = new NeovimGlobalState(); + this.messages = new NeovimMessages(); + this.clipboard = new NeovimClipboard(this.client); + this.capabilities = new NeovimCapabilities(); + this.editorMap = new Map(); + this.documentMap = new Map(); + this.activeWindow = undefined; + this.activeBuffer = undefined; + } + + async init() { + const rootPath = await getCursorlessNvimPath(this.client); + // we store the assets into a subfolder of cursorless.nvim + this.assetsRoot_ = path.join(rootPath, "assets"); + this.cursorlessNeovimPath = path.join( + rootPath, + "node", + "cursorless-neovim", + ); + } + + async showQuickPick( + _items: readonly string[], + _options?: QuickPickOptions, + ): Promise { + throw Error("showQuickPick Not implemented"); + } + + async setHighlightRanges( + _highlightId: string | undefined, + _editor: TextEditor, + _ranges: GeneralizedRange[], + ): Promise { + throw Error("setHighlightRanges Not implemented"); + } + + async flashRanges(_flashDescriptors: FlashDescriptor[]): Promise { + console.debug("flashRanges Not implemented"); + } + + get assetsRoot(): string { + if (this.assetsRoot_ == null) { + throw Error("Field `assetsRoot` has not yet been mocked"); + } + + return this.assetsRoot_; + } + + // See https://code.visualstudio.com/api/references/vscode-api#ExtensionMode + get runMode(): RunMode { + const runMode = process.env.CURSORLESS_MODE; + const ret = + runMode == null + ? "production" + : runMode === "test" + ? "test" + : runMode == "development" + ? "development" + : "unknown"; + if (ret === "unknown") { + throw Error("Invalid runMode"); + } + return ret; + } + + get activeTextEditor(): TextEditor | undefined { + // throw Error("activeTextEditor Not implemented"); + return this.getActiveTextEditor(); + } + + get activeEditableTextEditor(): EditableTextEditor | undefined { + // throw Error("activeEditableTextEditor Not implemented"); + return this.getActiveTextEditor(); + } + + private getActiveTextEditor() { + const editor = this.activeWindow + ? this.getTextEditor(this.activeWindow) + : undefined; + if (editor === undefined) { + console.debug("getActiveTextEditor: editor is undefined"); + } + return editor; + } + + private getTextEditor(w: Window) { + for (const [window, textEditor] of this.editorMap) { + if (window.id === w.id) { + return textEditor; + } + } + return undefined; + } + + public getTextDocument(b: Buffer) { + for (const [buffer, textDocument] of this.documentMap) { + if (buffer.id === b.id) { + return textDocument; + } + } + return undefined; + } + + get visibleTextEditors(): NeovimTextEditorImpl[] { + return Array.from(this.editorMap.values()); + // throw Error("visibleTextEditors Not implemented"); + } + + public getEditableTextEditor(editor: TextEditor): EditableTextEditor { + return editor as EditableTextEditor; + // throw Error("getEditableTextEditor Not implemented"); + } + + public async findInDocument( + _query: string, + _editor: TextEditor, + ): Promise { + throw Error("findInDocument Not implemented"); + } + + public async findInWorkspace(_query: string): Promise { + throw Error("findInWorkspace Not implemented"); + } + + public async openTextDocument(_path: string): Promise { + throw Error("openTextDocument Not implemented"); + } + + public async openUntitledTextDocument( + _options: OpenUntitledTextDocumentOptions, + ): Promise { + throw Error("openUntitledTextDocument Not implemented"); + } + + public async showInputBox(_options?: any): Promise { + throw Error("TextDocumentChangeEvent Not implemented"); + } + + public async executeCommand( + _command: string, + ..._args: any[] + ): Promise { + throw new Error("executeCommand Method not implemented."); + } + + public onDidChangeTextDocument( + listener: (event: TextDocumentChangeEvent) => void, + ): Disposable { + return neovimOnDidChangeTextDocument(listener); + } + + public onDidOpenTextDocument( + listener: (event: TextDocument) => any, + thisArgs?: any, + disposables?: Disposable[] | undefined, + ): Disposable { + return neovimOnDidOpenTextDocument(listener, thisArgs, disposables); + } + onDidCloseTextDocument: Event = dummyEvent; + onDidChangeActiveTextEditor: Event = dummyEvent; + onDidChangeVisibleTextEditors: Event = dummyEvent; + onDidChangeTextEditorSelection: Event = + dummyEvent; + onDidChangeTextEditorVisibleRanges: Event = + dummyEvent; + + /** + * Initialize the current editor (and current document). + * If the current editor already exists, it will only update the current document of that editor. + * + * when we receive our first cursorless command, we will initialize an editor an document for it. + * for the following commands, we will only update the document. + * + * Atm, we only initialize one editor(current window) with one document(current buffer) + */ + async updateTextEditor( + minimal: boolean = false, + ): Promise { + const window = await this.client.window; + const buffer = await window.buffer; + const lines = await buffer.lines; + let linesShown = lines; + if (lines.length >= 30) { + linesShown = lines.slice(0, 15).concat(["..."]).concat(lines.slice(-15)); + } + console.debug( + `updateTextEditor(): window:${window.id}, buffer:${buffer.id}, lines=${JSON.stringify(linesShown)}`, + ); + let selections: Selection[]; + let visibleRanges: Range[]; + if (!minimal) { + selections = await bufferGetSelections(window, this.client); + visibleRanges = await windowGetVisibleRanges(window, this.client, lines); + } else { + selections = []; + visibleRanges = []; + } + const editor = this.toNeovimEditor( + window, + buffer, + lines, + visibleRanges, + selections, + ); + + getNeovimRegistry().emitEvent("onDidOpenTextDocument", editor.document); + + return editor; + } + + toNeovimEditor( + window: Window, + buffer: Buffer, + lines: string[], + visibleRanges: Range[], + selections: Selection[], + ): NeovimTextEditorImpl { + let document = this.getTextDocument(buffer); + let editor = this.getTextEditor(window); + if (!document) { + console.debug( + `toNeovimEditor(): creating new document: buffer=${buffer.id}`, + ); + document = new NeovimTextDocumentImpl( + URI.parse(`neovim://${buffer.id}`), // URI.parse(`file://${buffer.id}`), + "plaintext", + 1, + "\n", + // "\r\n", + lines, + ); + this.documentMap.set(buffer, document); + } else { + console.debug(`toNeovimEditor(): updating document: buffer=${buffer.id}`); + document.update(lines); + } + if (!editor) { + console.debug( + `toNeovimEditor(): creating new editor: window=${window.id}`, + ); + editor = new NeovimTextEditorImpl( + uuid(), + this.client, + this, + window, + document, + visibleRanges, + selections, + ); + this.editorMap.set(window, editor); + } else { + console.debug(`toNeovimEditor(): updating editor: window=${window.id}`); + editor.updateDocument(visibleRanges, selections, document); + } + this.activeBuffer = buffer; + this.activeWindow = window; + + return this.activeTextEditor as NeovimTextEditorImpl; + } + + handleCommandError(err: Error) { + // if (err instanceof OutdatedExtensionError) { + // this.showUpdateExtensionErrorMessage(err); + // } else { + showErrorMessage(this.client, err.message); + // } + } + + disposeOnExit(...disposables: Disposable[]): () => void { + this.disposables.push(...disposables); + + return () => pull(this.disposables, ...disposables); + } +} + +function dummyEvent() { + return { + dispose() { + // empty + }, + }; +} diff --git a/packages/neovim-common/src/ide/neovim/NeovimMessages.ts b/packages/neovim-common/src/ide/neovim/NeovimMessages.ts new file mode 100644 index 0000000000..ee71484c44 --- /dev/null +++ b/packages/neovim-common/src/ide/neovim/NeovimMessages.ts @@ -0,0 +1,12 @@ +import type { MessageId, Messages, MessageType } from "@cursorless/common"; + +export default class NeovimMessages implements Messages { + async showMessage( + _type: MessageType, + _id: MessageId, + _message: string, + ..._options: string[] + ): Promise { + return undefined; + } +} diff --git a/packages/neovim-common/src/ide/neovim/NeovimTextDocumentImpl.ts b/packages/neovim-common/src/ide/neovim/NeovimTextDocumentImpl.ts new file mode 100644 index 0000000000..44c6ffd490 --- /dev/null +++ b/packages/neovim-common/src/ide/neovim/NeovimTextDocumentImpl.ts @@ -0,0 +1,389 @@ +import { + EndOfLine, + Position, + Range, + TextDocument, + TextLine, +} from "@cursorless/common"; +import { URI } from "vscode-uri"; +import NeovimTextLineImpl from "./NeovimTextLineImpl"; + +export class NeovimTextDocumentImpl implements TextDocument { + private _uri: URI; + private _languageId: string; + private _version: number; + private _lineCount: number; + private _eol: string; + + private _lines: string[]; + private _lineStarts: PrefixSumComputer | null; + private _cachedTextValue: string | null; + + get uri(): URI { + return this._uri; + } + + get languageId(): string { + return this._languageId; + } + + get version(): number { + return this._version; + } + + get lineCount(): number { + // console.debug(`lineCount(): ${this._lineCount}`); + return this._lineCount; + } + + get range(): Range { + const { end } = this.lineAt(this.lineCount - 1).range; + const range = new Range(0, 0, end.line, end.character); + // console.debug( + // `range(): (${range.start.line},${range.start.character}),(${range.end.line},${range.end.character})`, + // ); + return range; + } + + get eol(): EndOfLine { + return this._eol === "\n" ? "LF" : "CRLF"; + } + + constructor( + uri: URI, + languageId: string, + version: number, + eol: string, + lines: string[], + ) { + this._uri = uri; + this._languageId = languageId; + this._version = version; + this._eol = eol; + this._lines = lines; + + this._lineCount = lines.length; + this._lineStarts = null; + this._cachedTextValue = null; + } + + public update(lines: string[]) { + this._lines = lines; + + this._lineCount = lines.length; + this._lineStarts = null; + this._cachedTextValue = null; + } + + public lineAt(lineOrPosition: number | Position): TextLine { + let line: number | undefined; + if (lineOrPosition instanceof Position) { + line = lineOrPosition.line; + } else if (typeof lineOrPosition === "number") { + line = lineOrPosition; + } + // console.debug(`lineAt() line=${line}`); + + if ( + typeof line !== "number" || + line < 0 || + line >= this._lines.length || + Math.floor(line) !== line + ) { + throw new Error("Illegal value for `line`"); + } + + return new NeovimTextLineImpl( + line, + this._lines[line], + line === this._lines.length - 1, + ); + } + + public offsetAt(position: Position): number { + // console.debug( + // `offsetAt() position=(${position.line},${position.character})`, + // ); + position = this._validatePosition(position); + this._ensureLineStarts(); + // console.debug( + // `offsetAt() returning ${ + // this._lineStarts!.getPrefixSum(position.line - 1) + position.character + // }`, + // ); + return ( + this._lineStarts!.getPrefixSum(position.line - 1) + position.character + ); + } + + public positionAt(offset: number): Position { + // console.debug(`positionAt() offset=${offset}`); + offset = Math.floor(offset); + offset = Math.max(0, offset); + + this._ensureLineStarts(); + const out = this._lineStarts!.getIndexOf(offset); + + const lineLength = this._lines[out.index].length; + + // Ensure we return a valid position + return new Position(out.index, Math.min(out.remainder, lineLength)); + } + + public getText(range?: Range): string { + if (range === undefined) { + // console.debug(`getText(all)`); + if (this._cachedTextValue == null) { + this._cachedTextValue = this._lines.join(this._eol); + } + // if (this._lines.length > 10) { + // console.debug( + // `getText() returning multiple lines: '${this._lines.slice(0, 10).join(this._eol)}' \n[stripped...]}`, + // ); + // } else { + // console.debug( + // `getText() returning multiple lines: '${this._cachedTextValue}'`, + // ); + // } + return this._cachedTextValue; + } else { + // console.debug( + // `getText(range=(${range?.start.line},${range?.start.character}),(${range?.end.line},${range?.end.character}))`, + // ); + } + + range = this._validateRange(range); + + if (range.isEmpty) { + // console.debug(`getText() returning empty`); + return ""; + } + + if (range.isSingleLine) { + // console.debug( + // `getText() returning single line '${this._lines[ + // range.start.line + // ].substring(range.start.character, range.end.character)}'`, + // ); + return this._lines[range.start.line].substring( + range.start.character, + range.end.character, + ); + } + + const lineEnding = this._eol, + startLineIndex = range.start.line, + endLineIndex = range.end.line, + resultLines: string[] = []; + + resultLines.push( + this._lines[startLineIndex].substring(range.start.character), + ); + for (let i = startLineIndex + 1; i < endLineIndex; i++) { + resultLines.push(this._lines[i]); + } + resultLines.push( + this._lines[endLineIndex].substring(0, range.end.character), + ); + // if (resultLines.length > 10) { + // console.debug( + // `getText() returning multiple lines: '${resultLines.slice(0, 10).join(lineEnding)}' \n[stripped...]}`, + // ); + // } else { + // console.debug( + // `getText() returning multiple lines: '${resultLines.join(lineEnding)}'`, + // ); + // } + return resultLines.join(lineEnding); + } + + // ---- range math + + private _validateRange(range: Range): Range { + if (!(range instanceof Range)) { + throw new Error("Invalid argument"); + } + + const start = this._validatePosition(range.start); + const end = this._validatePosition(range.end); + + if (start === range.start && end === range.end) { + return range; + } + return new Range(start.line, start.character, end.line, end.character); + } + + private _validatePosition(position: Position): Position { + if (!(position instanceof Position)) { + throw new Error("Invalid argument"); + } + + if (this._lines.length === 0) { + return position.with(0, 0); + } + + let { line, character } = position; + let hasChanged = false; + + if (line < 0) { + line = 0; + character = 0; + hasChanged = true; + } else if (line >= this._lines.length) { + line = this._lines.length - 1; + character = this._lines[line].length; + hasChanged = true; + } else { + const maxCharacter = this._lines[line].length; + if (character < 0) { + character = 0; + hasChanged = true; + } else if (character > maxCharacter) { + character = maxCharacter; + hasChanged = true; + } + } + + if (!hasChanged) { + return position; + } + return new Position(line, character); + } + + private _ensureLineStarts(): void { + if (!this._lineStarts) { + const eolLength = this._eol.length; + const linesLength = this._lines.length; + const lineStartValues = new Uint32Array(linesLength); + for (let i = 0; i < linesLength; i++) { + lineStartValues[i] = this._lines[i].length + eolLength; + } + this._lineStarts = new PrefixSumComputer(lineStartValues); + } + } +} + +// ---- math helpers + +export function toUint32(v: number): number { + if (v < 0) { + return 0; + } + const maxUint32 = 4294967295; // 2^32 - 1 + if (v > maxUint32) { + return maxUint32; + } + return v | 0; +} + +export class PrefixSumComputer { + /** + * values[i] is the value at index i + */ + private values: Uint32Array; + + /** + * prefixSum[i] = SUM(heights[j]), 0 <= j <= i + */ + private prefixSum: Uint32Array; + + /** + * prefixSum[i], 0 <= i <= prefixSumValidIndex can be trusted + */ + private readonly prefixSumValidIndex: Int32Array; + + constructor(values: Uint32Array) { + this.values = values; + this.prefixSum = new Uint32Array(values.length); + this.prefixSumValidIndex = new Int32Array(1); + this.prefixSumValidIndex[0] = -1; + } + + public getCount(): number { + return this.values.length; + } + + public getTotalSum(): number { + if (this.values.length === 0) { + return 0; + } + return this._getPrefixSum(this.values.length - 1); + } + + /** + * Returns the sum of the first `index + 1` many items. + * @returns `SUM(0 <= j <= index, values[j])`. + */ + public getPrefixSum(index: number): number { + if (index < 0) { + return 0; + } + + index = toUint32(index); + return this._getPrefixSum(index); + } + + private _getPrefixSum(index: number): number { + if (index <= this.prefixSumValidIndex[0]) { + return this.prefixSum[index]; + } + + let startIndex = this.prefixSumValidIndex[0] + 1; + if (startIndex === 0) { + this.prefixSum[0] = this.values[0]; + startIndex++; + } + + if (index >= this.values.length) { + index = this.values.length - 1; + } + + for (let i = startIndex; i <= index; i++) { + this.prefixSum[i] = this.prefixSum[i - 1] + this.values[i]; + } + this.prefixSumValidIndex[0] = Math.max(this.prefixSumValidIndex[0], index); + return this.prefixSum[index]; + } + + public getIndexOf(sum: number): PrefixSumIndexOfResult { + sum = Math.floor(sum); + + // Compute all sums (to get a fully valid prefixSum) + this.getTotalSum(); + + let low = 0; + let high = this.values.length - 1; + let mid = 0; + let midStop = 0; + let midStart = 0; + + while (low <= high) { + mid = (low + (high - low) / 2) | 0; + + midStop = this.prefixSum[mid]; + midStart = midStop - this.values[mid]; + + if (sum < midStart) { + high = mid - 1; + } else if (sum >= midStop) { + low = mid + 1; + } else { + break; + } + } + + return new PrefixSumIndexOfResult(mid, sum - midStart); + } +} + +export class PrefixSumIndexOfResult { + _prefixSumIndexOfResultBrand: void = undefined; + + constructor( + public readonly index: number, + public readonly remainder: number, + ) { + this.index = index; + this.remainder = remainder; + } +} diff --git a/packages/neovim-common/src/ide/neovim/NeovimTextEditorImpl.ts b/packages/neovim-common/src/ide/neovim/NeovimTextEditorImpl.ts new file mode 100644 index 0000000000..e8f466c871 --- /dev/null +++ b/packages/neovim-common/src/ide/neovim/NeovimTextEditorImpl.ts @@ -0,0 +1,195 @@ +import { + BreakpointDescriptor, + Edit, + EditableTextEditor, + Position, + Range, + RevealLineAt, + Selection, + TextEditor, + TextEditorOptions, +} from "@cursorless/common"; +import type { NeovimClient, Window } from "neovim"; +import { bufferSetSelections } from "../../neovimApi"; +import { neovimClipboardCopy, neovimClipboardPaste } from "../../neovimHelpers"; +import neovimEdit from "./NeovimEdit"; +import { NeovimIDE } from "./NeovimIDE"; +import { NeovimTextDocumentImpl } from "./NeovimTextDocumentImpl"; + +export class NeovimTextEditorImpl implements EditableTextEditor { + private _document: NeovimTextDocumentImpl; + private _selections: Selection[]; + private _visibleRanges: Range[]; + + constructor( + public readonly id: string, + private client: NeovimClient, + private neovimIDE: NeovimIDE, + private window: Window, + doc: NeovimTextDocumentImpl, + visibleRanges: Range[], + selections: Selection[], + ) { + this._document = doc; + this._selections = selections; + this._visibleRanges = visibleRanges; + } + + get document(): NeovimTextDocumentImpl { + return this._document; + } + + public updateDocument( + visibleRanges: Range[], + selections: Selection[], + doc?: NeovimTextDocumentImpl, + lines?: string[], + ): NeovimTextDocumentImpl { + if (doc) { + this._document = doc; + } else if (lines) { + this._document.update(lines); + } else { + throw Error("updateDocument(): invalid arguments"); + } + this._selections = selections; + this._visibleRanges = visibleRanges; + return this._document; + } + + get selections(): Selection[] { + return this._selections as Selection[]; + // throw Error("get selections Not implemented"); + } + + async setSelections(selections: Selection[]): Promise { + // We assume setting it on the neovim buffer never fails + // as we cache the selections in the editor beforehand + this._selections = selections; + await bufferSetSelections(this.client, selections); + } + + get visibleRanges(): Range[] { + return this._visibleRanges; + } + + get options(): TextEditorOptions { + throw Error("get options Not implemented"); + } + + set options(options: TextEditorOptions) { + throw Error("set options Not implemented"); + } + + get isActive(): boolean { + return true; + } + + public isEqual(other: TextEditor): boolean { + return this.id === other.id; + } + + public async revealRange(range: Range): Promise { + // throw Error("revealRange Not implemented"); + } + + public revealLine(lineNumber: number, at: RevealLineAt): Promise { + throw Error("revealLine Not implemented"); + } + + public async edit(edits: Edit[]): Promise { + //throw Error("edit Not implemented"); + return await neovimEdit(this.client, this.neovimIDE, this.window, edits); + } + + public focus(): Promise { + return Promise.resolve(); + // throw Error("focus Not implemented"); + } + + public editNewNotebookCellAbove(): Promise< + (selection: Selection) => Selection + > { + throw Error("editNewNotebookCellAbove Not implemented"); + } + + public editNewNotebookCellBelow(): Promise { + throw Error("editNewNotebookCellBelow Not implemented"); + } + + public openLink(location?: Position | Range): Promise { + throw Error("openLink Not implemented"); + } + + public fold(ranges?: Range[]): Promise { + throw Error("fold Not implemented"); + } + + public unfold(ranges?: Range[]): Promise { + throw Error("unfold Not implemented"); + } + + public toggleBreakpoint(descriptors?: BreakpointDescriptor[]): Promise { + throw Error("toggleBreakpoint Not implemented"); + } + + public async toggleLineComment(_ranges?: Range[]): Promise { + throw Error("toggleLineComment Not implemented"); + } + + public async clipboardCopy(_ranges?: Range[]): Promise { + await neovimClipboardCopy(this.client, this.neovimIDE); + } + + public async clipboardPaste(_ranges?: Range[]): Promise { + await neovimClipboardPaste(this.client, this.neovimIDE); + } + + public async indentLine(_ranges?: Range[]): Promise { + throw Error("indentLine Not implemented"); + } + + public async outdentLine(_ranges?: Range[]): Promise { + throw Error("outdentLine Not implemented"); + } + + public async insertLineAfter(ranges?: Range[]): Promise { + throw Error("insertLineAfter Not implemented"); + } + + public insertSnippet(snippet: string, ranges?: Range[]): Promise { + throw Error("insertSnippet Not implemented"); + } + + public async rename(_range?: Range): Promise { + throw Error("rename Not implemented"); + } + + public async showReferences(_range?: Range): Promise { + throw Error("showReferences Not implemented"); + } + + public async quickFix(_range?: Range): Promise { + throw Error("quickFix Not implemented"); + } + + public async revealDefinition(_range?: Range): Promise { + throw Error("revealDefinition Not implemented"); + } + + public async revealTypeDefinition(_range?: Range): Promise { + throw Error("revealTypeDefinition Not implemented"); + } + + public async showHover(_range?: Range): Promise { + throw Error("showHover Not implemented"); + } + + public async showDebugHover(_range?: Range): Promise { + throw Error("showDebugHover Not implemented"); + } + + public async extractVariable(_range?: Range): Promise { + throw Error("extractVariable Not implemented"); + } +} diff --git a/packages/neovim-common/src/ide/neovim/NeovimTextLineImpl.ts b/packages/neovim-common/src/ide/neovim/NeovimTextLineImpl.ts new file mode 100644 index 0000000000..1ffea9121a --- /dev/null +++ b/packages/neovim-common/src/ide/neovim/NeovimTextLineImpl.ts @@ -0,0 +1,67 @@ +import { Range, TextLine } from "@cursorless/common"; + +export default class NeovimTextLineImpl implements TextLine { + private readonly _lineNumber: number; + private readonly _text: string; + private readonly _isLastLine: boolean; + + constructor(lineNumber: number, text: string, isLastLine: boolean) { + // console.debug( + // `NeovimTextLineImpl(): lineNumber=${lineNumber}, text='${text}', isLastLine=${isLastLine}`, + // ); + this._lineNumber = lineNumber; + this._text = text; + this._isLastLine = isLastLine; + } + + get lineNumber(): number { + return this._lineNumber; + } + + get text(): string { + // console.debug(`NeovimTextLineImpl.text()='${this._text}'`); + return this._text; + } + + get range(): Range { + // console.debug( + // `NeovimTextLineImpl.range(): range=(${this._lineNumber}, 0), (${this._lineNumber}, ${this._text.length})`, + // ); + return new Range(this._lineNumber, 0, this._lineNumber, this._text.length); + } + + get rangeIncludingLineBreak(): Range { + if (this._isLastLine) { + // console.debug( + // `NeovimTextLineImpl.rangeIncludingLineBreak(): last line=(${this.range.start.line}, ${this.range.start.character}), (${this.range.end.line}, ${this.range.end.character})`, + // ); + return this.range; + } + // console.debug( + // `NeovimTextLineImpl.rangeIncludingLineBreak(): range=(${ + // this._lineNumber + // }, 0), ${this._lineNumber + 1}, 0})`, + // ); + return new Range(this._lineNumber, 0, this._lineNumber + 1, 0); + } + + get firstNonWhitespaceCharacterIndex(): number { + const index = /^(\s*)/.exec(this._text)![1].length; + // console.debug( + // `NeovimTextLineImpl.firstNonWhitespaceCharacterIndex=${index}`, + // ); + return index; + } + + get lastNonWhitespaceCharacterIndex(): number { + const index = this.text.trimEnd().length; + // console.debug( + // `NeovimTextLineImpl.lastNonWhitespaceCharacterIndex index=${index}`, + // ); + return index; + } + + get isEmptyOrWhitespace(): boolean { + return this.firstNonWhitespaceCharacterIndex === this._text.length; + } +} diff --git a/packages/neovim-common/src/ide/neovim/hats/NeovimHats.ts b/packages/neovim-common/src/ide/neovim/hats/NeovimHats.ts new file mode 100644 index 0000000000..2f7db50d53 --- /dev/null +++ b/packages/neovim-common/src/ide/neovim/hats/NeovimHats.ts @@ -0,0 +1,42 @@ +import { + HatRange, + Hats, + HatStyleMap, + Listener, + Notifier, +} from "@cursorless/common"; +import { Disposable } from "vscode"; +import type { NeovimIDE } from "../NeovimIDE"; + +export class NeovimHats implements Hats { + enabledHatStyles: HatStyleMap; + isEnabled: boolean; + private enabledHatStyleNotifier: Notifier<[HatStyleMap]> = new Notifier(); + private isEnabledNotifier: Notifier<[boolean]> = new Notifier(); + + constructor(private ide: NeovimIDE) { + this.enabledHatStyles = {}; + // We don't support hats yet + this.isEnabled = false; + } + + async init() {} + + async setHatRanges(hatRanges: HatRange[]): Promise {} + + onDidChangeEnabledHatStyles(listener: Listener<[HatStyleMap]>): Disposable { + return this.enabledHatStyleNotifier.registerListener(listener); + } + + onDidChangeIsEnabled(listener: Listener<[boolean]>): Disposable { + return this.isEnabledNotifier.registerListener(listener); + } +} + +function dummyEvent() { + return { + [Symbol.dispose]() { + // empty + }, + }; +} diff --git a/packages/neovim-common/src/index.ts b/packages/neovim-common/src/index.ts new file mode 100644 index 0000000000..bf603dfc16 --- /dev/null +++ b/packages/neovim-common/src/index.ts @@ -0,0 +1,18 @@ +export * from "./getExtensionApi"; +export * from "./TestHelpers"; +export * from "./testUtil/openNewEditor"; +export * from "./runCommand"; +export * from "./neovimApi"; +export * from "./ide/neovim/NeovimCapabilities"; +export * from "./ide/neovim/NeovimClipboard"; +export * from "./ide/neovim/NeovimConfiguration"; +export * from "./ide/neovim/NeovimEdit"; +export * from "./ide/neovim/NeovimEvents"; +export * from "./ide/neovim/NeovimFileSystem"; +export * from "./ide/neovim/NeovimGlobalState"; +export * from "./ide/neovim/NeovimIDE"; +export * from "./ide/neovim/NeovimMessages"; +export * from "./ide/neovim/NeovimTextDocumentImpl"; +export * from "./ide/neovim/NeovimTextEditorImpl"; +export * from "./ide/neovim/NeovimTextLineImpl"; +export * from "./ide/neovim/hats/NeovimHats"; diff --git a/packages/neovim-common/src/neovimApi.ts b/packages/neovim-common/src/neovimApi.ts new file mode 100644 index 0000000000..08d3716999 --- /dev/null +++ b/packages/neovim-common/src/neovimApi.ts @@ -0,0 +1,171 @@ +// Helper directly calling into Neovim apis, generally lua, exported by cursorless.nvim +import { Position, Range, Selection } from "@cursorless/common"; +import type { NeovimClient } from "neovim/lib/api/client"; +import type { Window } from "neovim/lib/api/Window"; + +/** + * Get the current "selections" in the window(editor) + * + * At the moment we only support one selection because vim only supports one cursor + * At the moment, we only support the current window, hence why the argument is not used + */ +export async function bufferGetSelections( + window: Window, + client: NeovimClient, +): Promise { + const luaCode = `return require("cursorless.cursorless").buffer_get_selection()`; + // Note lines are indexed from 1, similarly to what is shown in neovim + // and columns are also indexed from 1 + const [startLine, startCol, endLine, endCol, reverse] = + (await client.executeLua(luaCode, [])) as [ + number, + number, + number, + number, + boolean, + ]; + // subtract 1 to the lines/columns to get the correct 0-based line/column numbers + let selections: Selection[]; + if (reverse === true) { + selections = [ + new Selection( + new Position(endLine - 1, endCol - 1), + new Position(startLine - 1, startCol - 1), + ), + ]; + } else { + selections = [ + new Selection( + new Position(startLine - 1, startCol - 1), + new Position(endLine - 1, endCol - 1), + ), + ]; + } + + console.debug( + `bufferGetSelections(): selections=(${selections[0].start.line}, ${selections[0].start.character}), (${selections[0].end.line}, ${selections[0].end.character}) neovim=(${startLine},${startCol}),(${endLine},${endCol}),reverse=${reverse}`, + ); + return selections; +} + +export async function bufferSetSelections( + // window: Window, + client: NeovimClient, + selections: Selection[], +) { + if (selections.length !== 1) { + throw new Error("bufferSetSelections() only supports one selection"); + } + + // cursorless has 0-based lines/columns, but neovim has 1-based lines and 0-based columns + // also, experience shows we need to subtract 1 from the end character to stop on it in visual mode (instead of after it) + // https://neovim.io/doc/user/api.html#nvim_win_set_cursor() + const luaCode = `return require("cursorless.cursorless").select_range(${ + selections[0].start.line + 1 + }, ${selections[0].start.character}, ${selections[0].end.line + 1}, ${ + selections[0].end.character + })`; + console.debug( + `bufferSetSelections() selections=(${selections[0].start.line},${selections[0].start.character}),(${selections[0].end.line},${selections[0].end.character}) luaCode="${luaCode}"`, + ); + await client.executeLua(luaCode, []); + // console.debug(`bufferSetSelections() done`); +} + +/** + * Get the current "visible" ranges in the window(editor) (vertically). + * This accounts only for vertical scrolling, and not for horizontal scrolling. + * + * At the moment, we only support the current window, hence why the argument is not used + */ +export async function windowGetVisibleRanges( + window: Window, + client: NeovimClient, + lines: string[], +): Promise { + // Get the first and last visible lines of the current window + // Note they are indexed from 1, similarly to what is shown in neovim* + const luaCode = `return require("cursorless.cursorless").window_get_visible_lines()`; + const [firstLine, lastLine] = (await client.executeLua(luaCode, [])) as [ + number, + number, + ]; + // subtract 1 to the lines to get the correct 0-based line numbers + const range = new Range( + new Position(firstLine - 1, 0), + // subtract -1 to the line.length to get the correct 0-based column number + new Position(lastLine - 1, lines[lastLine - 1].length - 1), + ); + console.debug( + `windowGetVisibleRanges(): range=(${range.start.line}, ${range.start.character}), (${range.end.line}, ${range.end.character})`, + ); + return [range]; +} + +export async function getCursorlessNvimPath( + client: NeovimClient, +): Promise { + const luaCode = `return require("cursorless.utils").cursorless_nvim_path()`; + const data = (await client.executeLua(luaCode, [])) as unknown as string; + return data as unknown as string; +} + +/** + * Save the data string into the operating system clipboard + * https://vimdoc.sourceforge.net/htmldoc/eval.html#setreg() + * https://stackoverflow.com/questions/11489428/how-can-i-make-vim-paste-from-and-copy-to-the-systems-clipboard?page=1&tab=scoredesc#tab-top + * https://stackoverflow.com/questions/30691466/what-is-difference-between-vims-clipboard-unnamed-and-unnamedplus-settings + */ +export async function putToClipboard(data: string, client: NeovimClient) { + await client.callFunction("setreg", ["*", data]); +} + +/** + * Return the string from the operating system clipboard + * https://vimdoc.sourceforge.net/htmldoc/eval.html#getreg() + */ +export async function getFromClipboard(client: NeovimClient): Promise { + return await client.callFunction("getreg", ["*"]); +} + +/** + * Paste at current position from the operating system clipboard + */ +export async function pasteFromClipboard(client: NeovimClient) { + const luaCode = `return require("cursorless.utils").paste()`; + await client.executeLua(luaCode, []); +} + +/** + * Switch from terminal (t) mode to normal terminal (nt) mode + * @param client + */ +export async function modeSwitchNormalTerminal( + client: NeovimClient, +): Promise { + const luaCode = `return require("cursorless.utils").mode_switch_nt()`; + await client.executeLua(luaCode, []); +} + +/** + * Switch from normal terminal (nt) mode to terminal (t) mode + * @param client + */ +export async function modeSwitchTerminal(client: NeovimClient): Promise { + const luaCode = `return require("cursorless.utils").mode_switch_t()`; + await client.executeLua(luaCode, []); +} + +/** + * Show an error message to the user + * @param client + * @param message + * @see https://neovim.io/doc/user/lua.html#vim.notify() + */ +export async function showErrorMessage( + client: NeovimClient, + message: string, +): Promise { + const luaCode = `vim.notify("${message}")`; + await client.executeLua(luaCode, []); +} diff --git a/packages/neovim-common/src/neovimHelpers.ts b/packages/neovim-common/src/neovimHelpers.ts new file mode 100644 index 0000000000..a9b34d393c --- /dev/null +++ b/packages/neovim-common/src/neovimHelpers.ts @@ -0,0 +1,28 @@ +// Helper wrappers, generally around neovimApi.ts + +import { + bufferGetSelections, + pasteFromClipboard, + putToClipboard, +} from "@cursorless/neovim-common"; +import { NeovimTextEditorImpl } from "./ide/neovim/NeovimTextEditorImpl"; +import type { NeovimClient } from "neovim"; +import { IDE } from "@cursorless/common"; + +export async function neovimClipboardCopy( + client: NeovimClient, + ide: IDE, +): Promise { + const editor = ide.activeTextEditor as NeovimTextEditorImpl; + const window = await client.window; + const selections = await bufferGetSelections(window, client); + const data = editor.document.getText(selections[0]); + await putToClipboard(data, client); +} + +export async function neovimClipboardPaste( + client: NeovimClient, + ide: IDE, +): Promise { + await pasteFromClipboard(client); +} diff --git a/packages/neovim-common/src/runCommand.ts b/packages/neovim-common/src/runCommand.ts new file mode 100644 index 0000000000..c25146c2e1 --- /dev/null +++ b/packages/neovim-common/src/runCommand.ts @@ -0,0 +1,15 @@ +import { + Command, + CommandResponse, + CURSORLESS_COMMAND_ID, +} from "@cursorless/common"; +import { getNeovimRegistry } from "@cursorless/neovim-registry"; + +export async function runCursorlessCommand( + command: Command, +): Promise { + return await getNeovimRegistry().executeCommand( + CURSORLESS_COMMAND_ID, + command, + ); +} diff --git a/packages/neovim-common/src/testUtil/openNewEditor.ts b/packages/neovim-common/src/testUtil/openNewEditor.ts new file mode 100644 index 0000000000..c063e99e53 --- /dev/null +++ b/packages/neovim-common/src/testUtil/openNewEditor.ts @@ -0,0 +1,36 @@ +import { NeovimTextEditorImpl } from ".."; +import { NeovimTextDocumentImpl } from "../ide/neovim/NeovimTextDocumentImpl"; + +export interface NewEditorOptions { + languageId?: string; + openBeside?: boolean; +} + +export async function openNewEditor( + content: string, + { languageId = "plaintext", openBeside = false }: NewEditorOptions = {}, +): Promise { + throw new Error("openNewEditor() Not implemented"); +} + +export async function reuseEditor( + editor: NeovimTextDocumentImpl, // vscode.TextEditor, + content: string, + language: string = "plaintext", +) { + throw new Error("reuseEditor() Not implemented"); +} + +/** + * Open a new notebook editor with the given cells + * @param cellContents A list of strings each of which will become the contents + * of a cell in the notebook + * @param language The language id to use for all the cells in the notebook + * @returns notebook + */ +export async function openNewNotebookEditor( + cellContents: string[], + language: string = "plaintext", +) { + throw new Error("openNewNotebookEditor() Not implemented"); +} diff --git a/packages/neovim-common/tsconfig.json b/packages/neovim-common/tsconfig.json new file mode 100644 index 0000000000..5b248ab992 --- /dev/null +++ b/packages/neovim-common/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "out" + }, + "references": [ + { + "path": "../common" + }, + { + "path": "../neovim-registry" + } + ], + "include": ["src/**/*.ts", "src/**/*.json", "../../typings/**/*.d.ts"] +} diff --git a/packages/neovim-registry/package.json b/packages/neovim-registry/package.json new file mode 100644 index 0000000000..3f4e36bd07 --- /dev/null +++ b/packages/neovim-registry/package.json @@ -0,0 +1,29 @@ +{ + "name": "@cursorless/neovim-registry", + "version": "1.0.0", + "description": "Registry to share apis and commands between packages for neovim", + "main": "./out/index.js", + "scripts": { + "clean": "rm -rf ./out tsconfig.tsbuildinfo ./dist ./build", + "compile:tsc": "tsc --build", + "compile:esbuild": "esbuild ./src/index.ts --sourcemap --format=cjs --bundle --outfile=./out/index.js --platform=node", + "compile": "pnpm compile:tsc && pnpm compile:esbuild", + "watch:tsc": "pnpm compile:tsc --watch", + "watch:esbuild": "pnpm compile:esbuild --watch", + "watch": "pnpm run --filter @cursorless/neovim-registry --parallel '/^watch:.*/'" + }, + "keywords": [], + "author": "", + "license": "MIT", + "types": "./out/index.d.ts", + "exports": { + ".": { + "cursorless:bundler": "./src/index.ts", + "default": "./out/index.js" + } + }, + "devDependencies": { + "neovim": "5.1.0" + }, + "type": "module" +} diff --git a/packages/neovim-registry/src/NeovimRegistry.ts b/packages/neovim-registry/src/NeovimRegistry.ts new file mode 100644 index 0000000000..bf5fc5f916 --- /dev/null +++ b/packages/neovim-registry/src/NeovimRegistry.ts @@ -0,0 +1,39 @@ +import { EventEmitter } from "node:events"; + +export class NeovimRegistry { + private apis: Map; + private commands: Map; + private eventEmitter: EventEmitter; + + constructor() { + this.apis = new Map(); + this.commands = new Map(); + this.eventEmitter = new EventEmitter(); + } + + public registerExtensionApi(extensionId: string, api: any) { + this.apis.set(extensionId, api); + } + + public getExtensionApi(extensionId: string): any { + return this.apis.get(extensionId); + } + + public registerCommand(commandId: string, callback: any) { + this.commands.set(commandId, callback); + } + + public async executeCommand(commandId: string, ...rest: any[]): Promise { + return await this.commands.get(commandId)(...rest); + } + + public onEvent( + eventName: string | symbol, + listener: (...args: any[]) => void, + ): EventEmitter { + return this.eventEmitter.on(eventName, listener); + } + public emitEvent(eventName: string | symbol, ...args: any[]): boolean { + return this.eventEmitter.emit(eventName, ...args); + } +} diff --git a/packages/neovim-registry/src/index.ts b/packages/neovim-registry/src/index.ts new file mode 100644 index 0000000000..88affc282d --- /dev/null +++ b/packages/neovim-registry/src/index.ts @@ -0,0 +1,8 @@ +import { NeovimRegistry } from "./NeovimRegistry"; + +export function getNeovimRegistry(): NeovimRegistry { + if ((global as any)._neovimRegistry == null) { + (global as any)._neovimRegistry = new NeovimRegistry(); + } + return (global as any)._neovimRegistry; +} diff --git a/packages/neovim-registry/tsconfig.json b/packages/neovim-registry/tsconfig.json new file mode 100644 index 0000000000..cea565539b --- /dev/null +++ b/packages/neovim-registry/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "out" + }, + "references": [], + "include": ["src/**/*.ts", "src/**/*.json", "../../typings/**/*.d.ts"] +} diff --git a/packages/test-harness/package.json b/packages/test-harness/package.json index 77f91dd7ec..06da85b5d9 100644 --- a/packages/test-harness/package.json +++ b/packages/test-harness/package.json @@ -3,18 +3,21 @@ "version": "0.1.0", "description": "Contains scripts and runners for testing Cursorless", "private": true, - "main": "./out/index.js", + "main": "./out/index.cjs", "scripts": { - "test": "env CURSORLESS_TEST=true my-ts-node src/scripts/runTestsCI.ts", + "test": "env CURSORLESS_TEST=true my-ts-node src/scripts/runVscodeTestsCI.ts", + "testNeovim": "env CURSORLESS_MODE=test my-ts-node src/scripts/runNeovimTestsCI.ts", "build:base": "esbuild --sourcemap --conditions=cursorless:bundler --bundle --external:vscode --format=cjs --platform=node", - "build": "pnpm run build:runner && pnpm run build:tests && pnpm run build:unit && pnpm run build:talon", + "build": "pnpm run build:runner && pnpm run build:main && pnpm run build:tests && pnpm run build:unit && pnpm run build:talon && pnpm run populate-cursorless-nvim", "build:runner": "pnpm run build:base ./src/runners/extensionTestsVscode.ts --outfile=dist/extensionTestsVscode.cjs", + "build:main": "pnpm run build:base ./src/index.ts --outfile=out/index.cjs", "build:unit": "pnpm run build:base ./src/scripts/runUnitTestsOnly.ts --outfile=dist/runUnitTestsOnly.cjs", "build:talon": "pnpm run build:base ./src/scripts/runTalonTests.ts --outfile=dist/runTalonTests.cjs", "build:tests": "bash ./scripts/build-tests.sh", "compile": "tsc --build", + "populate-cursorless-nvim": "bash ./scripts/populate-cursorless-nvim.sh", "watch": "tsc --build --watch", - "clean": "rm -rf ./out tsconfig.tsbuildinfo ./dist ./build", + "clean": "rm -rf ./out tsconfig.tsbuildinfo ./dist ./build ../../dist", "generate-test-subset-file": "my-ts-node ./src/scripts/generateTestSubsetFile.ts --always-open", "generate-test-subset-file-strict": "my-ts-node ./src/scripts/generateTestSubsetFile.ts --fail-if-not-exists" }, @@ -23,11 +26,16 @@ "license": "MIT", "dependencies": { "@cursorless/common": "workspace:*", - "glob": "^10.3.10" + "@cursorless/neovim-common": "workspace:*", + "@cursorless/neovim-registry": "workspace:*", + "glob": "^10.3.10", + "neovim": "5.1.0", + "tail": "2.2.6" }, "devDependencies": { "@types/glob": "^8.1.0", "@types/mocha": "^10.0.6", + "@types/tail": "2.2.3", "@vscode/test-electron": "^2.3.9", "mocha": "^10.3.0" }, diff --git a/packages/test-harness/scripts/populate-cursorless-nvim.sh b/packages/test-harness/scripts/populate-cursorless-nvim.sh new file mode 100755 index 0000000000..0a9a9ab6e8 --- /dev/null +++ b/packages/test-harness/scripts/populate-cursorless-nvim.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# We don't set -u so we can safely test for the presence of the "CI" environment variable or not +# Indeed, we can't just "env | grep CI" as it contains runNeovimTestsCI.ts, etc. which would give a false positive +# https://stackoverflow.com/questions/64182595/how-to-determine-if-ci-script-is-running-on-github-server +# https://gist.github.com/mohanpedala/1e2ff5661761d3abd0385e8223e16425#set--u +set -eo pipefail + +in_dir=../../cursorless.nvim +out_dir=../../dist/cursorless.nvim + +if [[ ! -z "$CI" ]]; then + # If running in CI, only copy the necessary files for testing + + mkdir -p "$out_dir/node/test-harness/out" + + # copy the built .js file + cp package.json "$out_dir/node/test-harness/" + cp out/index.cjs "$out_dir/node/test-harness/out/" +else + # If running locally, make the .map files available to allow debugging + + mkdir -p "$out_dir/node" + + # For Windows, you need Administrator privileges to create a symlink, so we assume it was created manually by the user + # during initial setup to avoid having to run vscode as Administrator + # https://github.com/orgs/community/discussions/23591 + # https://stackoverflow.com/questions/18641864/git-bash-shell-fails-to-create-symbolic-links/40914277#40914277 + unameOut="$(uname -s)" + case "${unameOut}" in + Linux*) machine=Linux;; + Darwin*) machine=Mac;; + CYGWIN*) machine=Cygwin;; + MINGW*) machine=MinGw;; # Windows Git Bash + MSYS_NT*) machine=Git;; + *) machine="UNKNOWN:${unameOut}" + esac + + # Symlink so we inherit the .map files as well + if [[ "$machine" != "MinGw" ]]; then + ln -sf "$(pwd)" "$out_dir/node/test-harness" + fi +fi diff --git a/packages/test-harness/src/config/init.lua b/packages/test-harness/src/config/init.lua new file mode 100644 index 0000000000..20b45e0223 --- /dev/null +++ b/packages/test-harness/src/config/init.lua @@ -0,0 +1,10 @@ +local temp_dir = os.getenv("TEMP_DIR") +local repo_root = os.getenv("CURSORLESS_REPO_ROOT") + +vim.cmd("source " .. temp_dir .. "/BufOnly.vim/plugin/BufOnly.vim") + +vim.opt.runtimepath:append(temp_dir .. "/talon.nvim") +vim.opt.runtimepath:append(repo_root .. "/dist/cursorless.nvim") + +require("talon").setup() +require("cursorless").setup() diff --git a/packages/test-harness/src/index.ts b/packages/test-harness/src/index.ts new file mode 100644 index 0000000000..818a7312e5 --- /dev/null +++ b/packages/test-harness/src/index.ts @@ -0,0 +1,54 @@ +import { TestType, runAllTests } from "./runAllTests"; + +import type { NeovimClient, NvimPlugin } from "neovim"; + +/** + * Runs all extension tests. This function should only be called after attaching to the + * "node" process, such as when testing cursorless in neovim. + * We use this runner for both the local test launch config + * and the CI test runner action. + * @returns A promise that resolves when tests have finished running + */ +// FIXME: this is neovim specific atm so in the future we can support other apps here +// with an environment variable +export async function run(plugin: NvimPlugin): Promise { + /** + * We need to pass the neovim client to the tests that are executed through mocha, + * so we add it to the global object. + * @see https://github.com/mochajs/mocha/issues/3780#issuecomment-583064196 + * @see https://stackoverflow.com/questions/69427050/how-to-extend-globalthis-global-type + */ + const client = plugin.nvim as NeovimClient; + (global as any).additionalParameters = { + client: client, + }; + let code = 0; + try { + await runAllTests(TestType.neovim, TestType.unit); + console.log(`==== TESTS FINISHED: code: ${code}`); + // console.log(`index.ts: killing neovim with q!`); + // await client.command(":q!"); + } catch (error) { + console.log(`==== TESTS ERROR:`); + console.error(error); + code = 1; + console.log(`==== TESTS FINISHED: code: ${code}`); + // https://stackoverflow.com/questions/11828270/how-do-i-exit-vim + // console.log(`index.ts: killing neovim with cq!`); + // await client.command(":cq!"); + } + // XXX: launchNeovimAndRunTests.ts will catch neovim exit code on CI + + // console.log(`index.ts: killing neovim with code ${code}`); +} + +/** + * Extension entrypoint called by node-client on Neovim startup. + * - Register the functions that are exposed to Neovim. + * Note that these function need to start with a capital letter to be callable from Neovim. + */ +export default function entry(plugin: NvimPlugin) { + plugin.registerFunction("TestHarnessRun", () => run(plugin), { + sync: false, + }); +} diff --git a/packages/test-harness/src/launchNeovimAndRunTests.ts b/packages/test-harness/src/launchNeovimAndRunTests.ts new file mode 100644 index 0000000000..4a8e9cd769 --- /dev/null +++ b/packages/test-harness/src/launchNeovimAndRunTests.ts @@ -0,0 +1,196 @@ +import { + getCursorlessRepoRoot, + getEnvironmentVariableStrict, +} from "@cursorless/common"; +import * as cp from "child_process"; +import { copyFile, mkdirSync, readdirSync } from "fs"; +import process from "node:process"; +import { Tail } from "tail"; + +/** + * Launches neovim, instructing it to run the test runner + * specified in {@link extensionTestsPath}. + * @param extensionTestsPath The path to test runner, passed to + * `--extensionTestsPath` + * + * Current working & workspace directory: + * - Windows: D:\a\cursorless\cursorless + * - Linux: /home/runner/work/cursorless/cursorless + * - OS X: /Users/runner/work/cursorless/cursorless + */ +export async function launchNeovimAndRunTests() { + let code = 1; // failure + try { + const cli = getEnvironmentVariableStrict("NEOVIM_PATH"); + + let nvimFolder = ""; + const initLuaFile = `${getCursorlessRepoRoot()}/packages/test-harness/src/config/init.lua`; + if (process.platform === "win32") { + nvimFolder = "C:/Users/runneradmin/AppData/Local/nvim/"; + } else if (process.platform === "linux") { + nvimFolder = "/home/runner/.config/nvim/"; + } else if (process.platform === "darwin") { + nvimFolder = "/Users/runner/.config/nvim/"; + } else { + console.error(`Unsupported platform: ${process.platform}`); + process.exit(1); + } + + console.log(`cli: ${cli}`); + + mkdirSync(nvimFolder, { recursive: true }); + + copyFile(initLuaFile, `${nvimFolder}/init.lua`, (err: any) => { + if (err) { + console.error(err); + } + }); + console.log("init.lua copying done"); + + console.log("listing nvim/:"); + readdirSync(nvimFolder).forEach((file) => { + console.log(`\t${file}`); + }); + + const logName = `${getCursorlessRepoRoot()}/packages/cursorless-neovim/out/nvim_node.log`; + + // testing normal nvim startup + //https://stackoverflow.com/questions/3025615/is-there-a-vim-runtime-log + // if (process.platform === "darwin" || process.platform === "win32") { + if (process.platform === "win32") { + // const { status, signal, error } = cp.spawnSync(cli, [`-V9`], { + const { status, signal, error } = cp.spawnSync(cli, [`-V25`], { + encoding: "utf-8", + stdio: "inherit", + env: { + ...process.env, + // "NVIM_NODE_HOST_DEBUG": "1", + NVIM_NODE_LOG_FILE: logName, + NVIM_NODE_LOG_LEVEL: "debug", + CURSORLESS_MODE: "test", + }, + }); + console.log(`status: ${status}`); + console.log(`signal: ${signal}`); + console.log(`error: ${error}`); + + console.log(`Exiting early`); + process.exit(0); + } + + const waitLuaFile = `${getCursorlessRepoRoot()}/packages/test-harness/src/config/wait.lua`; + // https://neovim.io/doc/user/starting.html#--headless + const subprocess = cp.spawn(cli, [`--headless`], { + env: { + ...process.env, + NVIM_NODE_LOG_FILE: logName, + NVIM_NODE_LOG_LEVEL: "info", // default for testing + CURSORLESS_MODE: "test", + }, + }); + console.log("nvim started done"); + + // do not wait for nvim to exit to avoid any blocking + subprocess.unref(); + + console.log(`pid: ${subprocess.pid}`); + + // Make sure the node log file exists + await delay(5000); + + console.log("listing cursorless-neovim/out/:"); + readdirSync( + `${getCursorlessRepoRoot()}/packages/cursorless-neovim/out/`, + ).forEach((file) => { + console.log(`\t${file}`); + }); + + await delay(10000); + + // read log file live and print to console + // https://stackoverflow.com/questions/26788504/using-node-js-to-read-a-live-file-line-by-line + let done = false; + let tailTest; + try { + tailTest = new Tail(logName, { + fromBeginning: true, + }); + } catch (error) { + console.log( + "Warning: A missing log file at nvim startup is typically the result of an invalid nvim config file", + ); + console.log(error); + code = 3; + process.exit(code); + } + tailTest.on("line", function (data: string) { + console.log(`neovim test: ${data}`); + if (data.includes("==== TESTS FINISHED:")) { + done = true; + console.log(`done: ${done}`); + const found = data.match(/.*==== TESTS FINISHED: code: (\d+).*/); + console.log(`found: ${found}`); + if (found !== null) { + code = parseInt(found[1]); + console.log(`code: ${code}`); + } + } + }); + tailTest.on("error", function (error) { + console.log("neovim test: ERROR: ", error); + if (error.includes("==== TESTS FINISHED:")) { + done = true; + console.log(`done: ${done}`); + } + }); + console.log("tail neovim test started"); + + console.log("waiting for tests to finish ..."); + + let count = 0; + const stepSeconds = 10; + while (true) { + count += stepSeconds; + await delay(stepSeconds * 1000); + if (done) { + console.log("done here, exiting loop"); + break; + } + // exit if tests take more than 5 minutes + if (count > 5 * 60) { + console.log("timeout, exiting loop"); + break; + } + } + subprocess.kill("SIGTERM"); + console.log(`killed: ${subprocess.killed}`); + + // XXX - code to replace above code, needs more testing + // code from packages\cursorless-vscode\src\scripts\initLaunchSandbox.ts + // await new Promise((resolve, reject) => { + // subprocess.on("error", reject); + // subprocess.on("exit", (code) => { + // console.log(`exit: Process returned code ${code}`); + // if (code === 0) { + // resolve(); + // } else { + // reject(new Error(`Process returned code ${code}`)); + // } + // }); + // }); + console.log("tests finished"); + + tailTest.unwatch(); + } catch (err) { + console.error("Test run threw exception:"); + console.error(err); + code = 2; + } + console.log(`Returned code: ${code}`); + process.exit(code); +} + +// https://stackoverflow.com/questions/37764665/how-to-implement-sleep-function-in-typescript +function delay(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} diff --git a/packages/test-harness/src/launchVscodeAndRunTests.ts b/packages/test-harness/src/launchVscodeAndRunTests.ts index c092469285..5ef5f48a7d 100644 --- a/packages/test-harness/src/launchVscodeAndRunTests.ts +++ b/packages/test-harness/src/launchVscodeAndRunTests.ts @@ -30,7 +30,7 @@ export async function launchVscodeAndRunTests(extensionTestsPath: string) { const crashDir = getEnvironmentVariableStrict("VSCODE_CRASH_DIR"); const logsDir = getEnvironmentVariableStrict("VSCODE_LOGS_DIR"); const useLegacyVscode = - getEnvironmentVariableStrict("VSCODE_VERSION") === "legacy"; + getEnvironmentVariableStrict("APP_VERSION") === "legacy"; // NB: We include the exact version here instead of in `test.yml` so that // we don't have to update the branch protection rules every time we bump diff --git a/packages/test-harness/src/runAllTests.ts b/packages/test-harness/src/runAllTests.ts index 999c61c61c..b41f320a75 100644 --- a/packages/test-harness/src/runAllTests.ts +++ b/packages/test-harness/src/runAllTests.ts @@ -8,7 +8,7 @@ import { glob } from "glob"; * Type of test to run, eg unit, vscode, talon */ export enum TestType { - /** Unit tests can be run without VSCode or Talon */ + /** Unit tests can be run without VSCode or Talon or Neovim */ unit, /** VSCode tests must be run from VSCode context */ @@ -16,6 +16,9 @@ export enum TestType { /** Talon tests require a running Talon instance */ talon, + + /** Neovim tests must be run from Neovim context */ + neovim, } export function runAllTests(...types: TestType[]) { @@ -23,6 +26,10 @@ export function runAllTests(...types: TestType[]) { path.join(getCursorlessRepoRoot(), "packages"), (files) => files.filter((f) => { + if (f.endsWith("neovim.test.cjs")) { + return types.includes(TestType.neovim); + } + if (f.endsWith("vscode.test.cjs")) { return types.includes(TestType.vscode); } diff --git a/packages/test-harness/src/scripts/runNeovimTestsCI.ts b/packages/test-harness/src/scripts/runNeovimTestsCI.ts new file mode 100644 index 0000000000..3d2bbb5359 --- /dev/null +++ b/packages/test-harness/src/scripts/runNeovimTestsCI.ts @@ -0,0 +1,11 @@ +/** + * This file can be run from node to run neovim tests in CI + */ + +import { launchNeovimAndRunTests } from "../launchNeovimAndRunTests"; + +(async () => { + // Note that we run all extension tests, including unit tests, in neovim, even though + // unit tests could be run separately. + await launchNeovimAndRunTests(); +})(); diff --git a/packages/test-harness/src/scripts/runTestsCI.ts b/packages/test-harness/src/scripts/runVscodeTestsCI.ts similarity index 89% rename from packages/test-harness/src/scripts/runTestsCI.ts rename to packages/test-harness/src/scripts/runVscodeTestsCI.ts index 9bcb65cb7a..6208df82ae 100644 --- a/packages/test-harness/src/scripts/runTestsCI.ts +++ b/packages/test-harness/src/scripts/runVscodeTestsCI.ts @@ -1,5 +1,5 @@ /** - * This file can be run from node to run tests in CI + * This file can be run from node to run vscode tests in CI */ import { getCursorlessRepoRoot } from "@cursorless/common"; diff --git a/packages/test-harness/tsconfig.json b/packages/test-harness/tsconfig.json index 96107efcd7..9a4285e6c8 100644 --- a/packages/test-harness/tsconfig.json +++ b/packages/test-harness/tsconfig.json @@ -8,6 +8,12 @@ "references": [ { "path": "../common" + }, + { + "path": "../neovim-common" + }, + { + "path": "../neovim-registry" } ] } diff --git a/patches/@types__nearley@2.11.5.patch b/patches/@types__nearley@2.11.5.patch index 776a237c0d..d19fef1d40 100644 --- a/patches/@types__nearley@2.11.5.patch +++ b/patches/@types__nearley@2.11.5.patch @@ -47,4 +47,4 @@ index 5cca1013513217cf5ec46c04e60cbb1dc2c7b2f1..289ca02c4bf917b0f6dacfe2d60d2e91 + reset(data: string | any[], state?: LexerState): void; /** * Returns e.g. {type, value, line, col, …}. Only the value attribute is required. - */ \ No newline at end of file + */ diff --git a/patches/nearley@2.20.1.patch b/patches/nearley@2.20.1.patch index 54ddf4962a..37461b844b 100644 --- a/patches/nearley@2.20.1.patch +++ b/patches/nearley@2.20.1.patch @@ -29,4 +29,4 @@ index b564e11e24d2bcc597d46bb01af84a1972cc6b9d..1d559ea3c96059f764bb5138a387039f + var value = lexer.constructor === StreamLexer ? token.value : lexer.transform?.(token) ?? token; var scannable = column.scannable; for (var w = scannable.length; w--; ) { - var state = scannable[w]; \ No newline at end of file + var state = scannable[w]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d7316a3fa3..78bc807119 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,10 +9,10 @@ patchedDependencies: hash: lazxwgumd4o5a3ibe55vftei5e path: patches/@docusaurus__theme-search-algolia@3.1.0.patch '@types/nearley@2.11.5': - hash: 5bomp3nnmdzdyzcgrxyr5kymae + hash: m6lvvh3c4y7yrjlmqdyj74zp2q path: patches/@types__nearley@2.11.5.patch nearley@2.20.1: - hash: mg2fc7wgvzub3myuz6m74hllma + hash: yc7aistj2i2qcwysldsvv2yuk4 path: patches/nearley@2.20.1.patch importers: @@ -27,7 +27,7 @@ importers: version: 18.18.2 '@typescript-eslint/eslint-plugin': specifier: ^7.4.0 - version: 7.4.0(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint@8.57.0)(typescript@5.4.3) + version: 7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.4.3) '@typescript-eslint/parser': specifier: ^7.4.0 version: 7.4.0(eslint@8.57.0)(typescript@5.4.3) @@ -42,10 +42,10 @@ importers: version: 9.1.0(eslint@8.57.0) eslint-import-resolver-typescript: specifier: 3.6.1 - version: 3.6.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-plugin-import@2.29.1)(eslint@8.57.0) + version: 3.6.1(@typescript-eslint/parser@7.4.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) eslint-plugin-import: specifier: 2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + version: 2.29.1(@typescript-eslint/parser@7.4.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-mocha: specifier: 10.4.1 version: 10.4.1(eslint@8.57.0) @@ -54,7 +54,7 @@ importers: version: 51.0.1(eslint@8.57.0) eslint-plugin-unused-imports: specifier: ^3.1.0 - version: 3.1.0(@typescript-eslint/eslint-plugin@7.4.0(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint@8.57.0)(typescript@5.4.3))(eslint@8.57.0) + version: 3.1.0(@typescript-eslint/eslint-plugin@7.4.0)(eslint@8.57.0) prettier: specifier: 3.2.5 version: 3.2.5 @@ -90,11 +90,11 @@ importers: version: 1.1.1 react-use: specifier: 17.5.0 - version: 17.5.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 17.5.0(react-dom@18.2.0)(react@18.2.0) devDependencies: '@testing-library/react': specifier: 14.2.2 - version: 14.2.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 14.2.2(react-dom@18.2.0)(react@18.2.0) '@types/jest': specifier: 29.5.12 version: 29.5.12 @@ -109,13 +109,13 @@ importers: version: 6.1.11 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)) + version: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2) jest-environment-jsdom: specifier: 29.7.0 version: 29.7.0 ts-jest: specifier: 29.1.2 - version: 29.1.2(@babel/core@7.24.3)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.3))(esbuild@0.20.2)(jest@29.7.0(@types/node@18.18.2)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)))(typescript@5.4.3) + version: 29.1.2(@babel/core@7.24.3)(esbuild@0.20.2)(jest@29.7.0)(typescript@5.4.3) typescript: specifier: ^5.4.3 version: 5.4.3 @@ -134,10 +134,10 @@ importers: devDependencies: '@effortlessmotion/html-webpack-inline-source-plugin': specifier: 1.0.3 - version: 1.0.3(html-webpack-plugin@5.6.0(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))))(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))) + version: 1.0.3(html-webpack-plugin@5.6.0)(webpack@5.91.0) '@testing-library/react': specifier: 14.2.2 - version: 14.2.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 14.2.2(react-dom@18.2.0)(react@18.2.0) '@types/jest': specifier: 29.5.12 version: 29.5.12 @@ -152,37 +152,37 @@ importers: version: 18.2.22 '@types/webpack': specifier: 5.28.5 - version: 5.28.5(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) + version: 5.28.5(esbuild@0.20.2)(webpack-cli@5.1.4) '@webpack-cli/generators': specifier: 3.0.7 - version: 3.0.7(encoding@0.1.13)(mem-fs@2.3.0)(prettier@3.2.5)(webpack-cli@5.1.4)(webpack@5.91.0) + version: 3.0.7(prettier@3.2.5)(webpack-cli@5.1.4)(webpack@5.91.0) autoprefixer: specifier: 10.4.19 version: 10.4.19(postcss@8.4.38) css-loader: specifier: 6.10.0 - version: 6.10.0(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))) + version: 6.10.0(webpack@5.91.0) html-webpack-plugin: specifier: 5.6.0 - version: 5.6.0(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))) + version: 5.6.0(webpack@5.91.0) jest: specifier: 29.7.0 - version: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)) + version: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2) postcss: specifier: 8.4.38 version: 8.4.38 postcss-loader: specifier: 8.1.1 - version: 8.1.1(postcss@8.4.38)(typescript@5.4.3)(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))) + version: 8.1.1(postcss@8.4.38)(typescript@5.4.3)(webpack@5.91.0) style-loader: specifier: 3.3.4 - version: 3.3.4(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))) + version: 3.3.4(webpack@5.91.0) tailwindcss: specifier: 3.4.1 - version: 3.4.1(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)) + version: 3.4.1(ts-node@10.9.2) ts-loader: specifier: 9.5.1 - version: 9.5.1(typescript@5.4.3)(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))) + version: 9.5.1(typescript@5.4.3)(webpack@5.91.0) ts-node: specifier: 10.9.2 version: 10.9.2(@types/node@18.18.2)(typescript@5.4.3) @@ -191,7 +191,7 @@ importers: version: 5.4.3 webpack: specifier: 5.91.0 - version: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) + version: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) webpack-cli: specifier: 5.1.4 version: 5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0) @@ -267,7 +267,7 @@ importers: version: 0.5.2 nearley: specifier: 2.20.1 - version: 2.20.1(patch_hash=mg2fc7wgvzub3myuz6m74hllma) + version: 2.20.1(patch_hash=yc7aistj2i2qcwysldsvv2yuk4) node-html-parser: specifier: ^6.1.12 version: 6.1.12 @@ -298,7 +298,7 @@ importers: version: 0.5.9 '@types/nearley': specifier: 2.11.5 - version: 2.11.5(patch_hash=5bomp3nnmdzdyzcgrxyr5kymae) + version: 2.11.5(patch_hash=m6lvvh3c4y7yrjlmqdyj74zp2q) '@types/sbd': specifier: ^1.0.5 version: 1.0.5 @@ -318,6 +318,71 @@ importers: specifier: ^17.0.1 version: 17.0.1 + packages/cursorless-neovim: + dependencies: + '@cursorless/common': + specifier: workspace:* + version: link:../common + '@cursorless/cursorless-engine': + specifier: workspace:* + version: link:../cursorless-engine + '@cursorless/neovim-common': + specifier: workspace:* + version: link:../neovim-common + '@cursorless/neovim-registry': + specifier: workspace:* + version: link:../neovim-registry + devDependencies: + '@types/chai': + specifier: ^4.3.14 + version: 4.3.14 + '@types/js-yaml': + specifier: ^4.0.9 + version: 4.0.9 + '@types/lodash': + specifier: 4.17.0 + version: 4.17.0 + '@types/uuid': + specifier: ^9.0.8 + version: 9.0.8 + lodash: + specifier: ^4.17.21 + version: 4.17.21 + neovim: + specifier: 5.1.0 + version: 5.1.0 + vscode-uri: + specifier: ^3.0.8 + version: 3.0.8 + + packages/cursorless-neovim-e2e: + dependencies: + '@cursorless/common': + specifier: workspace:* + version: link:../common + '@cursorless/neovim-common': + specifier: workspace:* + version: link:../neovim-common + '@cursorless/neovim-registry': + specifier: workspace:* + version: link:../neovim-registry + devDependencies: + '@types/chai': + specifier: ^4.3.14 + version: 4.3.14 + '@types/js-yaml': + specifier: ^4.0.9 + version: 4.0.9 + '@types/lodash': + specifier: 4.17.0 + version: 4.17.0 + '@types/sinon': + specifier: ^17.0.3 + version: 17.0.3 + neovim: + specifier: 5.1.0 + version: 5.1.0 + packages/cursorless-org: dependencies: '@cursorless/cheatsheet': @@ -325,16 +390,16 @@ importers: version: link:../cheatsheet '@mdx-js/loader': specifier: 3.0.1 - version: 3.0.1(webpack@5.91.0(esbuild@0.20.2)) + version: 3.0.1(webpack@5.91.0) '@mdx-js/react': specifier: 3.0.1 version: 3.0.1(@types/react@18.2.71)(react@18.2.0) '@next/mdx': specifier: 14.1.4 - version: 14.1.4(@mdx-js/loader@3.0.1(webpack@5.91.0(esbuild@0.20.2)))(@mdx-js/react@3.0.1(@types/react@18.2.71)(react@18.2.0)) + version: 14.1.4(@mdx-js/loader@3.0.1)(@mdx-js/react@3.0.1) next: specifier: 14.1.4 - version: 14.1.4(@babel/core@7.24.3)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 14.1.4(@babel/core@7.24.3)(react-dom@18.2.0)(react@18.2.0) react: specifier: ^18.2.0 version: 18.2.0 @@ -380,7 +445,7 @@ importers: version: 8.4.38 tailwindcss: specifier: 3.4.1 - version: 3.4.1(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)) + version: 3.4.1(ts-node@10.9.2) typescript: specifier: ^5.4.3 version: 5.4.3 @@ -392,25 +457,25 @@ importers: version: 4.22.1 '@docsearch/react': specifier: 3.6.0 - version: 3.6.0(@algolia/client-search@4.22.1)(@types/react@18.3.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(search-insights@2.13.0) + version: 3.6.0(@algolia/client-search@4.22.1)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)(search-insights@2.13.0) '@docusaurus/core': specifier: 3.1.1 - version: 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) + version: 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) '@docusaurus/preset-classic': specifier: 3.1.1 - version: 3.1.1(@algolia/client-search@4.22.1)(@types/react@18.3.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(search-insights@2.13.0)(typescript@5.4.3) + version: 3.1.1(@algolia/client-search@4.22.1)(@types/react@18.2.71)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(search-insights@2.13.0)(typescript@5.4.3) '@docusaurus/theme-classic': specifier: 3.1.1 - version: 3.1.1(@types/react@18.3.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) + version: 3.1.1(@types/react@18.2.71)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) '@docusaurus/theme-common': specifier: 3.1.1 - version: 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) + version: 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) '@docusaurus/theme-search-algolia': specifier: 3.1.1 - version: 3.1.1(patch_hash=lazxwgumd4o5a3ibe55vftei5e)(@algolia/client-search@4.22.1)(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@types/react@18.3.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(search-insights@2.13.0)(typescript@5.4.3) + version: 3.1.1(patch_hash=lazxwgumd4o5a3ibe55vftei5e)(@algolia/client-search@4.22.1)(@docusaurus/types@3.1.1)(@types/react@18.2.71)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(search-insights@2.13.0)(typescript@5.4.3) '@mdx-js/react': specifier: 3.0.1 - version: 3.0.1(@types/react@18.3.1)(react@18.2.0) + version: 3.0.1(@types/react@18.2.71)(react@18.2.0) clsx: specifier: ^2.1.0 version: 2.1.0 @@ -432,10 +497,10 @@ importers: devDependencies: '@docusaurus/module-type-aliases': specifier: 3.1.1 - version: 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) '@docusaurus/types': specifier: 3.1.1 - version: 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + version: 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) '@tsconfig/docusaurus': specifier: 2.0.2 version: 2.0.2 @@ -471,7 +536,7 @@ importers: version: 4.17.21 nearley: specifier: 2.20.1 - version: 2.20.1(patch_hash=mg2fc7wgvzub3myuz6m74hllma) + version: 2.20.1(patch_hash=yc7aistj2i2qcwysldsvv2yuk4) semver: specifier: ^7.6.0 version: 7.6.0 @@ -508,7 +573,7 @@ importers: version: 10.0.6 '@types/nearley': specifier: 2.11.5 - version: 2.11.5(patch_hash=5bomp3nnmdzdyzcgrxyr5kymae) + version: 2.11.5(patch_hash=m6lvvh3c4y7yrjlmqdyj74zp2q) '@types/node': specifier: 18.18.2 version: 18.18.2 @@ -638,14 +703,59 @@ importers: specifier: ^0.20.2 version: 0.20.2 + packages/neovim-common: + dependencies: + '@cursorless/common': + specifier: workspace:* + version: link:../common + '@cursorless/neovim-registry': + specifier: workspace:* + version: link:../neovim-registry + '@types/lodash': + specifier: 4.17.0 + version: 4.17.0 + '@types/uuid': + specifier: ^9.0.8 + version: 9.0.8 + '@types/vscode': + specifier: 1.75.1 + version: 1.75.1 + lodash: + specifier: ^4.17.21 + version: 4.17.21 + neovim: + specifier: 5.1.0 + version: 5.1.0 + vscode-uri: + specifier: ^3.0.8 + version: 3.0.8 + + packages/neovim-registry: + devDependencies: + neovim: + specifier: 5.1.0 + version: 5.1.0 + packages/test-harness: dependencies: '@cursorless/common': specifier: workspace:* version: link:../common + '@cursorless/neovim-common': + specifier: workspace:* + version: link:../neovim-common + '@cursorless/neovim-registry': + specifier: workspace:* + version: link:../neovim-registry glob: specifier: ^10.3.10 version: 10.3.10 + neovim: + specifier: 5.1.0 + version: 5.1.0 + tail: + specifier: 2.2.6 + version: 2.2.6 devDependencies: '@types/glob': specifier: ^8.1.0 @@ -653,6 +763,9 @@ importers: '@types/mocha': specifier: ^10.0.6 version: 10.0.6 + '@types/tail': + specifier: 2.2.3 + version: 2.2.3 '@vscode/test-electron': specifier: ^2.3.9 version: 2.3.9 @@ -672,6 +785,10 @@ importers: packages: + '@aashutoshrathi/word-wrap@1.2.6': + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + '@algolia/autocomplete-core@1.9.3': resolution: {integrity: sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==} @@ -1397,10 +1514,17 @@ packages: resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} + '@colors/colors@1.6.0': + resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} + engines: {node: '>=0.1.90'} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} + '@dabh/diagnostics@2.0.3': + resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==} + '@discoveryjs/json-ext@0.5.7': resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} engines: {node: '>=10.0.0'} @@ -1412,8 +1536,8 @@ packages: resolution: {integrity: sha512-HUFut4ztcVNmqy9gp/wxNbC7pTOHhgVVkHVGCACTuLhUKUhKAF9KYHJtMiLUJxEqiFLQiuri1fWF8zqwM/cu1w==} peerDependencies: '@types/react': '>= 16.8.0 < 19.0.0' - react: '>= 16.8.0 < 19.0.0' - react-dom: '>= 16.8.0 < 19.0.0' + react: '>= 16.8.0 < 19.0.0 || 18' + react-dom: '>= 16.8.0 < 19.0.0 || 18' search-insights: '>= 1 < 3' peerDependenciesMeta: '@types/react': @@ -1430,8 +1554,8 @@ packages: engines: {node: '>=18.0'} hasBin: true peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/cssnano-preset@3.1.1': resolution: {integrity: sha512-LnoIDjJWbirdbVZDMq+4hwmrTl2yHDnBf9MLG9qyExeAE3ac35s4yUhJI8yyTCdixzNfKit4cbXblzzqMu4+8g==} @@ -1445,8 +1569,8 @@ packages: resolution: {integrity: sha512-xN2IccH9+sv7TmxwsDJNS97BHdmlqWwho+kIVY4tcCXkp+k4QuzvWBeunIMzeayY4Fu13A6sAjHGv5qm72KyGA==} engines: {node: '>=18.0'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/module-type-aliases@3.1.1': resolution: {integrity: sha512-xBJyx0TMfAfVZ9ZeIOb1awdXgR4YJMocIEzTps91rq+hJDFJgJaylDtmoRhUxkwuYmNK1GJpW95b7DLztSBJ3A==} @@ -1458,64 +1582,64 @@ packages: resolution: {integrity: sha512-ew/3VtVoG3emoAKmoZl7oKe1zdFOsI0NbcHS26kIxt2Z8vcXKCUgK9jJJrz0TbOipyETPhqwq4nbitrY3baibg==} engines: {node: '>=18.0'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/plugin-content-docs@3.1.1': resolution: {integrity: sha512-lhFq4E874zw0UOH7ujzxnCayOyAt0f9YPVYSb9ohxrdCM8B4szxitUw9rIX4V9JLLHVoqIJb6k+lJJ1jrcGJ0A==} engines: {node: '>=18.0'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/plugin-content-pages@3.1.1': resolution: {integrity: sha512-NQHncNRAJbyLtgTim9GlEnNYsFhuCxaCNkMwikuxLTiGIPH7r/jpb7O3f3jUMYMebZZZrDq5S7om9a6rvB/YCA==} engines: {node: '>=18.0'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/plugin-debug@3.1.1': resolution: {integrity: sha512-xWeMkueM9wE/8LVvl4+Qf1WqwXmreMjI5Kgr7GYCDoJ8zu4kD+KaMhrh7py7MNM38IFvU1RfrGKacCEe2DRRfQ==} engines: {node: '>=18.0'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/plugin-google-analytics@3.1.1': resolution: {integrity: sha512-+q2UpWTqVi8GdlLoSlD5bS/YpxW+QMoBwrPrUH/NpvpuOi0Of7MTotsQf9JWd3hymZxl2uu1o3PIrbpxfeDFDQ==} engines: {node: '>=18.0'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/plugin-google-gtag@3.1.1': resolution: {integrity: sha512-0mMPiBBlQ5LFHTtjxuvt/6yzh8v7OxLi3CbeEsxXZpUzcKO/GC7UA1VOWUoBeQzQL508J12HTAlR3IBU9OofSw==} engines: {node: '>=18.0'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/plugin-google-tag-manager@3.1.1': resolution: {integrity: sha512-d07bsrMLdDIryDtY17DgqYUbjkswZQr8cLWl4tzXrt5OR/T/zxC1SYKajzB3fd87zTu5W5klV5GmUwcNSMXQXA==} engines: {node: '>=18.0'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/plugin-sitemap@3.1.1': resolution: {integrity: sha512-iJ4hCaMmDaUqRv131XJdt/C/jJQx8UreDWTRqZKtNydvZVh/o4yXGRRFOplea1D9b/zpwL1Y+ZDwX7xMhIOTmg==} engines: {node: '>=18.0'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/preset-classic@3.1.1': resolution: {integrity: sha512-jG4ys/hWYf69iaN/xOmF+3kjs4Nnz1Ay3CjFLDtYa8KdxbmUhArA9HmP26ru5N0wbVWhY+6kmpYhTJpez5wTyg==} engines: {node: '>=18.0'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/react-loadable@5.5.2': resolution: {integrity: sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==} @@ -1526,22 +1650,22 @@ packages: resolution: {integrity: sha512-GiPE/jbWM8Qv1A14lk6s9fhc0LhPEQ00eIczRO4QL2nAQJZXkjPG6zaVx+1cZxPFWbAsqSjKe2lqkwF3fGkQ7Q==} engines: {node: '>=18.0'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/theme-common@3.1.1': resolution: {integrity: sha512-38urZfeMhN70YaXkwIGXmcUcv2CEYK/2l4b05GkJPrbEbgpsIZM3Xc+Js2ehBGGZmfZq8GjjQ5RNQYG+MYzCYg==} engines: {node: '>=18.0'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/theme-search-algolia@3.1.1': resolution: {integrity: sha512-tBH9VY5EpRctVdaAhT+b1BY8y5dyHVZGFXyCHgTrvcXQy5CV4q7serEX7U3SveNT9zksmchPyct6i1sFDC4Z5g==} engines: {node: '>=18.0'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/theme-translations@3.1.1': resolution: {integrity: sha512-xvWQFwjxHphpJq5fgk37FXCDdAa2o+r7FX8IpMg+bGZBNXyWBu3MjZ+G4+eUVNpDhVinTc+j6ucL0Ain5KCGrg==} @@ -1550,8 +1674,8 @@ packages: '@docusaurus/types@3.1.1': resolution: {integrity: sha512-grBqOLnubUecgKFXN9q3uit2HFbCxTWX4Fam3ZFbMN0sWX9wOcDoA7lwdX/8AmeL20Oc4kQvWVgNrsT8bKRvzg==} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@docusaurus/utils-common@3.1.1': resolution: {integrity: sha512-eGne3olsIoNfPug5ixjepZAIxeYFzHHnor55Wb2P57jNbtVaFvij/T+MS8U0dtZRFi50QU+UPmRrXdVUM8uyMg==} @@ -1760,7 +1884,7 @@ packages: resolution: {integrity: sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==} peerDependencies: '@fortawesome/fontawesome-svg-core': ~1 || ~6 - react: '>=16.3' + react: '>=16.3 || 18' '@gar/promisify@1.1.3': resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} @@ -1783,8 +1907,8 @@ packages: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + '@humanwhocodes/object-schema@2.0.2': + resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -1906,7 +2030,11 @@ packages: resolution: {integrity: sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==} peerDependencies: '@types/react': '>=16' - react: '>=16' + react: '>=16 || 18' + + '@msgpack/msgpack@2.8.0': + resolution: {integrity: sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==} + engines: {node: '>= 10'} '@next/env@14.1.4': resolution: {integrity: sha512-e7X7bbn3Z6DWnDi75UWn+REgAbLEqxI8Tq2pkFOFAMpWAWApz/YCUhtWMWn410h8Q2fYiYL7Yg5OlxMOCfFjJQ==} @@ -2609,8 +2737,8 @@ packages: resolution: {integrity: sha512-SOUuM2ysCvjUWBXTNfQ/ztmnKDmqaiPV3SvoIuyxMUca45rbSWWAT/qB8CUs/JQ/ux/8JFs9DNdFQ3f6jH3crA==} engines: {node: '>=14'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.0.0 || 18 + react-dom: ^18.0.0 || 18 '@tootallnate/once@1.1.2': resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} @@ -2854,9 +2982,6 @@ packages: '@types/react@18.2.71': resolution: {integrity: sha512-PxEsB9OjmQeYGffoWnYAd/r5FiJuUw2niFQHPc2v2idwh8wGPkkYzOHuinNJJY6NZqfoTCiOIizDOz38gYNsyw==} - '@types/react@18.3.1': - resolution: {integrity: sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==} - '@types/retry@0.12.0': resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} @@ -2899,12 +3024,18 @@ packages: '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/tail@2.2.3': + resolution: {integrity: sha512-Hnf352egOlDR4nVTaGX0t/kmTNXHMdovF2C7PVDFtHTHJPFmIspOI1b86vEOxU7SfCq/dADS7ptbqgG/WGGxnA==} + '@types/tinycolor2@1.4.6': resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==} '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/triple-beam@1.3.5': + resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} + '@types/unist@2.0.10': resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} @@ -3515,8 +3646,8 @@ packages: resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - bole@5.0.12: - resolution: {integrity: sha512-G5H5siOlUrcyvYr7kVlQyYMWip0dZ8qa+Uiy+d9QxOvBY2eaP/g8YsJVwvf3VIMbXmYxZIAOmmsuN3rL5r6gwQ==} + bole@5.0.11: + resolution: {integrity: sha512-KB0Ye0iMAW5BnNbnLfMSQcnI186hKUzE2fpkZWqcxsoTR7eqzlTidSOMYPHJOn/yR7VGH7uSZp37qH9q2Et0zQ==} bonjour-service@1.2.1: resolution: {integrity: sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==} @@ -3844,10 +3975,16 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + color-support@1.1.3: resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} hasBin: true + color@3.2.1: + resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} + colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} @@ -3858,6 +3995,9 @@ packages: resolution: {integrity: sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==} engines: {node: '>=0.1.90'} + colorspace@1.1.4: + resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==} + combine-promises@1.2.0: resolution: {integrity: sha512-VcQB1ziGD0NXrhKxiwyNbCDmRzs/OShMs2GqW2DlU2A/Sd0nQxE1oWDAE5O0ygSx5mgQOn9eIFh7yKPgFRVkPQ==} engines: {node: '>=10'} @@ -4491,6 +4631,9 @@ packages: emoticon@4.0.1: resolution: {integrity: sha512-dqx7eA9YaqyvYtUhJwT4rC1HIp82j5ybS1/vQ42ur+jBe17dJMwZE4+gvL1XadSFfxaPFFGt3Xsw+Y8akThDlw==} + enabled@2.0.0: + resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} + encodeurl@1.0.2: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} @@ -4896,6 +5039,9 @@ packages: fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fecha@4.2.3: + resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} + feed@4.2.2: resolution: {integrity: sha512-u5/sxGfiMfZNtJ3OvQpXcvotFpYkL0n9u9mM2vkui2nGo8b4wvDkJ8gAkYqbA8QpGyFCv3RK0Z+Iv+9veCS9bQ==} engines: {node: '>=0.4.0'} @@ -4976,6 +5122,9 @@ packages: flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + fn.name@1.1.0: + resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} + follow-redirects@1.15.6: resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} engines: {node: '>=4.0'} @@ -5576,6 +5725,9 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + is-async-function@2.0.0: resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} engines: {node: '>= 0.4'} @@ -6148,6 +6300,9 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} + kuler@2.0.0: + resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} + language-subtag-registry@0.3.22: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} @@ -6249,6 +6404,10 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + logform@2.6.0: + resolution: {integrity: sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==} + engines: {node: '>= 12.0.0'} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -6771,6 +6930,11 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + neovim@5.1.0: + resolution: {integrity: sha512-9eTxqknziWkN8CBOx1SKdK+0Dfp1NHKHKyJaeOYu+x6qjaV9z3hB211wKhLaFGtyYmGZxVaIe1aLtvuTHmuZTA==} + engines: {node: '>=10'} + hasBin: true + nerf-dart@1.0.0: resolution: {integrity: sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==} @@ -6780,8 +6944,8 @@ packages: hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - react: ^18.2.0 - react-dom: ^18.2.0 + react: ^18.2.0 || 18 + react-dom: ^18.2.0 || 18 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': @@ -7012,6 +7176,9 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + one-time@1.0.0: + resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} + onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} @@ -7028,8 +7195,8 @@ packages: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} ora@5.4.1: @@ -7659,7 +7826,7 @@ packages: prism-react-renderer@2.3.1: resolution: {integrity: sha512-Rdf+HzBLR7KYjzpJ1rSoxT9ioO85nZngQEoFIhL07XhtJHlCU3SOz0GJ6+qvMyQe0Se+BV3qpe6Yd/NmQF5Juw==} peerDependencies: - react: '>=16.0.0' + react: '>=16.0.0 || 18' prismjs@1.29.0: resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} @@ -7801,7 +7968,7 @@ packages: react-dom@18.2.0: resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: - react: ^18.2.0 + react: ^18.2.0 || 18 react-error-overlay@6.0.11: resolution: {integrity: sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==} @@ -7812,14 +7979,14 @@ packages: react-helmet-async@1.3.0: resolution: {integrity: sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==} peerDependencies: - react: ^16.6.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 + react: ^16.6.0 || ^17.0.0 || ^18.0.0 || 18 + react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 || 18 react-helmet-async@2.0.4: resolution: {integrity: sha512-yxjQMWposw+akRfvpl5+8xejl4JtUlHnEBcji6u8/e6oc7ozT+P9PNTWMhCbz2y9tc5zPegw2BvKjQA+NwdEjQ==} peerDependencies: - react: ^16.6.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 + react: ^16.6.0 || ^17.0.0 || ^18.0.0 || 18 + react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 || 18 react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -7834,7 +8001,7 @@ packages: resolution: {integrity: sha512-aN1biKC5v4DQkmQBlZjuMFR09MKZGMPtIg+cut8zEeg2HXd6gl2gRy0n4HMacHf0dznQgo0SVXN7eT8zV3hEuQ==} engines: {node: '>=14'} peerDependencies: - react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 || 18 react-loadable-ssr-addon-v5-slorber@1.0.1: resolution: {integrity: sha512-lq3Lyw1lGku8zUEJPDxsNm1AfYHBrO9Y1+olAYwpUJ2IGFBskM0DMKok97A6LWUpHm+o7IvQBOWu9MLenp9Z+A==} @@ -7846,23 +8013,23 @@ packages: react-player@2.15.1: resolution: {integrity: sha512-ni1XFuYZuhIKKdeFII+KRLmIPcvCYlyXvtSMhNOgssdfnSovmakBtBTW2bxowPvmpKy5BTR4jC4CF79ucgHT+g==} peerDependencies: - react: '>=16.6.0' + react: '>=16.6.0 || 18' react-router-config@5.1.1: resolution: {integrity: sha512-DuanZjaD8mQp1ppHjgnnUnyOlqYXZVjnov/JzFhjLEwd3Z4dYjMSnqrEzzGThH47vpCOqPPwJM2FtthLeJ8Pbg==} peerDependencies: - react: '>=15' + react: '>=15 || 18' react-router: '>=5' react-router-dom@5.3.4: resolution: {integrity: sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==} peerDependencies: - react: '>=15' + react: '>=15 || 18' react-router@5.3.4: resolution: {integrity: sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==} peerDependencies: - react: '>=15' + react: '>=15 || 18' react-string-replace@1.1.1: resolution: {integrity: sha512-26TUbLzLfHQ5jO5N7y3Mx88eeKo0Ml0UjCQuX4BMfOd/JX+enQqlKpL1CZnmjeBRvQE8TR+ds9j1rqx9CxhKHQ==} @@ -8137,7 +8304,6 @@ packages: right-pad@1.0.1: resolution: {integrity: sha512-bYBjgxmkvTAfgIYy328fmkwhp39v8lwVgWhhrzxPV3yHtcSqyYKe9/XOhvW48UFjATg3VuJbpsp5822ACNvkmw==} engines: {node: '>= 0.10'} - deprecated: Please use String.prototype.padEnd() over this package. rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} @@ -8188,14 +8354,14 @@ packages: resolution: {integrity: sha512-vdTshSQ2JsRCgT8eKZWNJIL26C6bVqy1SOmuCMlKHegVeo8KYRobRrefOdUq9OozSPUUiSxrylteeRmLOMFfWg==} engines: {node: '>=12'} - safe-execa@0.1.4: - resolution: {integrity: sha512-GI3k4zl4aLC3lxZNEEXAxxcXE6E3TfOsJ5xxJPhcAv9MWwnH2O9I0HrDmZFsVnu/C8wzRYSsTHdoVRmL0VicDw==} - engines: {node: '>=12'} - safe-regex-test@1.0.3: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} + safe-stable-stringify@2.4.3: + resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} + engines: {node: '>=10'} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -8358,6 +8524,9 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} hasBin: true + simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + sinon@17.0.1: resolution: {integrity: sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==} @@ -8407,8 +8576,8 @@ packages: resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} engines: {node: '>= 10'} - socks@2.8.3: - resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} + socks@2.8.1: + resolution: {integrity: sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} sort-css-media-queries@2.1.0: @@ -8503,6 +8672,9 @@ packages: stack-generator@2.0.10: resolution: {integrity: sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==} + stack-trace@0.0.10: + resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -8654,7 +8826,7 @@ packages: peerDependencies: '@babel/core': '*' babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || 18' peerDependenciesMeta: '@babel/core': optional: true @@ -8712,6 +8884,10 @@ packages: engines: {node: '>=16'} hasBin: true + tail@2.2.6: + resolution: {integrity: sha512-IQ6G4wK/t8VBauYiGPLx+d3fA5XjSVagjWV5SIYzvEvglbQjwEcukeYI68JOPpdydjxhZ9sIgzRlSmwSpphHyw==} + engines: {node: '>= 6.0.0'} + tailwindcss@3.4.1: resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==} engines: {node: '>=14.0.0'} @@ -8754,6 +8930,9 @@ packages: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} + text-hex@1.0.0: + resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} + text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -8844,6 +9023,10 @@ packages: resolution: {integrity: sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ==} engines: {node: '>=12'} + triple-beam@1.4.1: + resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} + engines: {node: '>= 14.0.0'} + trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} @@ -9360,9 +9543,13 @@ packages: wildcard@2.0.1: resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} + winston-transport@4.7.0: + resolution: {integrity: sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==} + engines: {node: '>= 12.0.0'} + + winston@3.11.0: + resolution: {integrity: sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==} + engines: {node: '>= 12.0.0'} workerpool@6.2.1: resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} @@ -9517,6 +9704,8 @@ packages: snapshots: + '@aashutoshrathi/word-wrap@1.2.6': {} + '@algolia/autocomplete-core@1.9.3(@algolia/client-search@4.22.1)(algoliasearch@4.22.1)(search-insights@2.13.0)': dependencies: '@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@4.22.1)(algoliasearch@4.22.1)(search-insights@2.13.0) @@ -10412,29 +10601,36 @@ snapshots: '@colors/colors@1.5.0': optional: true + '@colors/colors@1.6.0': {} + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 + '@dabh/diagnostics@2.0.3': + dependencies: + colorspace: 1.1.4 + enabled: 2.0.0 + kuler: 2.0.0 + '@discoveryjs/json-ext@0.5.7': {} '@docsearch/css@3.6.0': {} - '@docsearch/react@3.6.0(@algolia/client-search@4.22.1)(@types/react@18.3.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(search-insights@2.13.0)': + '@docsearch/react@3.6.0(@algolia/client-search@4.22.1)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)(search-insights@2.13.0)': dependencies: '@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.22.1)(algoliasearch@4.22.1)(search-insights@2.13.0) '@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.22.1)(algoliasearch@4.22.1) '@docsearch/css': 3.6.0 + '@types/react': 18.2.71 algoliasearch: 4.22.1 - optionalDependencies: - '@types/react': 18.3.1 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) search-insights: 2.13.0 transitivePeerDependencies: - '@algolia/client-search' - '@docusaurus/core@3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3)': + '@docusaurus/core@3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3)': dependencies: '@babel/core': 7.24.3 '@babel/generator': 7.24.1 @@ -10448,15 +10644,15 @@ snapshots: '@babel/traverse': 7.24.1 '@docusaurus/cssnano-preset': 3.1.1 '@docusaurus/logger': 3.1.1 - '@docusaurus/mdx-loader': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@docusaurus/mdx-loader': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) '@docusaurus/react-loadable': 5.5.2(react@18.2.0) - '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) - '@docusaurus/utils-common': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)) - '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) + '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) + '@docusaurus/utils-common': 3.1.1(@docusaurus/types@3.1.1) + '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) '@slorber/static-site-generator-webpack-plugin': 4.0.7 '@svgr/webpack': 6.5.1 autoprefixer: 10.4.19(postcss@8.4.38) - babel-loader: 9.1.3(@babel/core@7.24.3)(webpack@5.91.0(esbuild@0.20.2)) + babel-loader: 9.1.3(@babel/core@7.24.3)(webpack@5.91.0) babel-plugin-dynamic-import-node: 2.3.3 boxen: 6.2.1 chalk: 4.1.2 @@ -10465,48 +10661,48 @@ snapshots: cli-table3: 0.6.4 combine-promises: 1.2.0 commander: 5.1.0 - copy-webpack-plugin: 11.0.0(webpack@5.91.0(esbuild@0.20.2)) + copy-webpack-plugin: 11.0.0(webpack@5.91.0) core-js: 3.36.1 - css-loader: 6.10.0(webpack@5.91.0(esbuild@0.20.2)) - css-minimizer-webpack-plugin: 4.2.2(clean-css@5.3.3)(esbuild@0.20.2)(webpack@5.91.0(esbuild@0.20.2)) + css-loader: 6.10.0(webpack@5.91.0) + css-minimizer-webpack-plugin: 4.2.2(clean-css@5.3.3)(esbuild@0.20.2)(webpack@5.91.0) cssnano: 5.1.15(postcss@8.4.38) del: 6.1.1 detect-port: 1.5.1 escape-html: 1.0.3 eta: 2.2.0 - file-loader: 6.2.0(webpack@5.91.0(esbuild@0.20.2)) + file-loader: 6.2.0(webpack@5.91.0) fs-extra: 11.2.0 html-minifier-terser: 7.2.0 html-tags: 3.3.1 - html-webpack-plugin: 5.6.0(webpack@5.91.0(esbuild@0.20.2)) + html-webpack-plugin: 5.6.0(webpack@5.91.0) leven: 3.1.0 lodash: 4.17.21 - mini-css-extract-plugin: 2.8.1(webpack@5.91.0(esbuild@0.20.2)) + mini-css-extract-plugin: 2.8.1(webpack@5.91.0) postcss: 8.4.38 - postcss-loader: 7.3.4(postcss@8.4.38)(typescript@5.4.3)(webpack@5.91.0(esbuild@0.20.2)) + postcss-loader: 7.3.4(postcss@8.4.38)(typescript@5.4.3)(webpack@5.91.0) prompts: 2.4.2 react: 18.2.0 - react-dev-utils: 12.0.1(eslint@8.57.0)(typescript@5.4.3)(webpack@5.91.0(esbuild@0.20.2)) + react-dev-utils: 12.0.1(eslint@8.57.0)(typescript@5.4.3)(webpack@5.91.0) react-dom: 18.2.0(react@18.2.0) - react-helmet-async: 1.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + react-helmet-async: 1.3.0(react-dom@18.2.0)(react@18.2.0) react-loadable: '@docusaurus/react-loadable@5.5.2(react@18.2.0)' - react-loadable-ssr-addon-v5-slorber: 1.0.1(@docusaurus/react-loadable@5.5.2(react@18.2.0))(webpack@5.91.0(esbuild@0.20.2)) + react-loadable-ssr-addon-v5-slorber: 1.0.1(@docusaurus/react-loadable@5.5.2)(webpack@5.91.0) react-router: 5.3.4(react@18.2.0) - react-router-config: 5.1.1(react-router@5.3.4(react@18.2.0))(react@18.2.0) + react-router-config: 5.1.1(react-router@5.3.4)(react@18.2.0) react-router-dom: 5.3.4(react@18.2.0) rtl-detect: 1.1.2 semver: 7.6.0 serve-handler: 6.1.5 shelljs: 0.8.5 - terser-webpack-plugin: 5.3.10(esbuild@0.20.2)(webpack@5.91.0(esbuild@0.20.2)) + terser-webpack-plugin: 5.3.10(esbuild@0.20.2)(webpack@5.91.0) tslib: 2.6.2 update-notifier: 6.0.2 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.91.0(esbuild@0.20.2)))(webpack@5.91.0(esbuild@0.20.2)) - webpack: 5.91.0(esbuild@0.20.2) + url-loader: 4.1.1(file-loader@6.2.0)(webpack@5.91.0) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) webpack-bundle-analyzer: 4.10.1 - webpack-dev-server: 4.15.2(webpack@5.91.0(esbuild@0.20.2)) + webpack-dev-server: 4.15.2(webpack@5.91.0) webpack-merge: 5.10.0 - webpackbar: 5.0.2(webpack@5.91.0(esbuild@0.20.2)) + webpackbar: 5.0.2(webpack@5.91.0) transitivePeerDependencies: - '@docusaurus/types' - '@parcel/css' @@ -10538,18 +10734,18 @@ snapshots: chalk: 4.1.2 tslib: 2.6.2 - '@docusaurus/mdx-loader@3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@docusaurus/mdx-loader@3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/parser': 7.24.1 '@babel/traverse': 7.24.1 '@docusaurus/logger': 3.1.1 - '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) - '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) + '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) + '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) '@mdx-js/mdx': 3.0.1 '@slorber/remark-comment': 1.0.0 escape-html: 1.0.3 estree-util-value-to-estree: 3.0.1 - file-loader: 6.2.0(webpack@5.91.0(esbuild@0.20.2)) + file-loader: 6.2.0(webpack@5.91.0) fs-extra: 11.2.0 image-size: 1.1.1 mdast-util-mdx: 3.0.0 @@ -10565,9 +10761,9 @@ snapshots: tslib: 2.6.2 unified: 11.0.4 unist-util-visit: 5.0.0 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.91.0(esbuild@0.20.2)))(webpack@5.91.0(esbuild@0.20.2)) + url-loader: 4.1.1(file-loader@6.2.0)(webpack@5.91.0) vfile: 6.0.1 - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) transitivePeerDependencies: - '@docusaurus/types' - '@swc/core' @@ -10576,17 +10772,17 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/module-type-aliases@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@docusaurus/module-type-aliases@3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0)': dependencies: '@docusaurus/react-loadable': 5.5.2(react@18.2.0) - '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) '@types/history': 4.7.11 '@types/react': 18.2.71 '@types/react-router-config': 5.0.11 '@types/react-router-dom': 5.3.3 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-helmet-async: 2.0.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + react-helmet-async: 2.0.4(react-dom@18.2.0)(react@18.2.0) react-loadable: '@docusaurus/react-loadable@5.5.2(react@18.2.0)' transitivePeerDependencies: - '@swc/core' @@ -10595,15 +10791,15 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/plugin-content-blog@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3)': + '@docusaurus/plugin-content-blog@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3)': dependencies: - '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) + '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) '@docusaurus/logger': 3.1.1 - '@docusaurus/mdx-loader': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) - '@docusaurus/utils-common': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)) - '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) + '@docusaurus/mdx-loader': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) + '@docusaurus/utils-common': 3.1.1(@docusaurus/types@3.1.1) + '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) cheerio: 1.0.0-rc.12 feed: 4.2.2 fs-extra: 11.2.0 @@ -10615,7 +10811,7 @@ snapshots: tslib: 2.6.2 unist-util-visit: 5.0.0 utility-types: 3.11.0 - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) transitivePeerDependencies: - '@parcel/css' - '@rspack/core' @@ -10634,15 +10830,15 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-content-docs@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3)': + '@docusaurus/plugin-content-docs@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3)': dependencies: - '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) + '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) '@docusaurus/logger': 3.1.1 - '@docusaurus/mdx-loader': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/module-type-aliases': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) - '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) + '@docusaurus/mdx-loader': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/module-type-aliases': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) + '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) '@types/react-router-config': 5.0.11 combine-promises: 1.2.0 fs-extra: 11.2.0 @@ -10652,7 +10848,7 @@ snapshots: react-dom: 18.2.0(react@18.2.0) tslib: 2.6.2 utility-types: 3.11.0 - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) transitivePeerDependencies: - '@parcel/css' - '@rspack/core' @@ -10671,18 +10867,18 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-content-pages@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3)': + '@docusaurus/plugin-content-pages@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3)': dependencies: - '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/mdx-loader': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) - '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) + '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/mdx-loader': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) + '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) fs-extra: 11.2.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) tslib: 2.6.2 - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) transitivePeerDependencies: - '@parcel/css' - '@rspack/core' @@ -10701,11 +10897,11 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-debug@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3)': + '@docusaurus/plugin-debug@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3)': dependencies: - '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) + '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) fs-extra: 11.2.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -10729,11 +10925,11 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-analytics@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3)': + '@docusaurus/plugin-google-analytics@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3)': dependencies: - '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) + '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) tslib: 2.6.2 @@ -10755,11 +10951,11 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-gtag@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3)': + '@docusaurus/plugin-google-gtag@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3)': dependencies: - '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) + '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) '@types/gtag.js': 0.0.12 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -10782,11 +10978,11 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-google-tag-manager@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3)': + '@docusaurus/plugin-google-tag-manager@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3)': dependencies: - '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) + '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) tslib: 2.6.2 @@ -10808,14 +11004,14 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/plugin-sitemap@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3)': + '@docusaurus/plugin-sitemap@3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3)': dependencies: - '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) + '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) '@docusaurus/logger': 3.1.1 - '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) - '@docusaurus/utils-common': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)) - '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) + '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) + '@docusaurus/utils-common': 3.1.1(@docusaurus/types@3.1.1) + '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) fs-extra: 11.2.0 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -10839,21 +11035,21 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/preset-classic@3.1.1(@algolia/client-search@4.22.1)(@types/react@18.3.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(search-insights@2.13.0)(typescript@5.4.3)': - dependencies: - '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/plugin-content-blog': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/plugin-content-docs': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/plugin-content-pages': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/plugin-debug': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/plugin-google-analytics': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/plugin-google-gtag': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/plugin-google-tag-manager': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/plugin-sitemap': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/theme-classic': 3.1.1(@types/react@18.3.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/theme-common': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/theme-search-algolia': 3.1.1(patch_hash=lazxwgumd4o5a3ibe55vftei5e)(@algolia/client-search@4.22.1)(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@types/react@18.3.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(search-insights@2.13.0)(typescript@5.4.3) - '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@docusaurus/preset-classic@3.1.1(@algolia/client-search@4.22.1)(@types/react@18.2.71)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(search-insights@2.13.0)(typescript@5.4.3)': + dependencies: + '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/plugin-content-blog': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/plugin-content-docs': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/plugin-content-pages': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/plugin-debug': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/plugin-google-analytics': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/plugin-google-gtag': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/plugin-google-tag-manager': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/plugin-sitemap': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/theme-classic': 3.1.1(@types/react@18.2.71)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/theme-common': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/theme-search-algolia': 3.1.1(patch_hash=lazxwgumd4o5a3ibe55vftei5e)(@algolia/client-search@4.22.1)(@docusaurus/types@3.1.1)(@types/react@18.2.71)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(search-insights@2.13.0)(typescript@5.4.3) + '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) transitivePeerDependencies: @@ -10883,21 +11079,21 @@ snapshots: prop-types: 15.8.1 react: 18.2.0 - '@docusaurus/theme-classic@3.1.1(@types/react@18.3.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3)': + '@docusaurus/theme-classic@3.1.1(@types/react@18.2.71)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3)': dependencies: - '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/mdx-loader': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/module-type-aliases': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/plugin-content-blog': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/plugin-content-docs': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/plugin-content-pages': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/theme-common': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) + '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/mdx-loader': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/module-type-aliases': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/plugin-content-blog': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/plugin-content-docs': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/plugin-content-pages': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/theme-common': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) '@docusaurus/theme-translations': 3.1.1 - '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) - '@docusaurus/utils-common': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)) - '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) - '@mdx-js/react': 3.0.1(@types/react@18.3.1)(react@18.2.0) + '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) + '@docusaurus/utils-common': 3.1.1(@docusaurus/types@3.1.1) + '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) + '@mdx-js/react': 3.0.1(@types/react@18.2.71)(react@18.2.0) clsx: 2.1.0 copy-text-to-clipboard: 3.2.0 infima: 0.2.0-alpha.43 @@ -10931,15 +11127,15 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/theme-common@3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3)': + '@docusaurus/theme-common@3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3)': dependencies: - '@docusaurus/mdx-loader': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/module-type-aliases': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/plugin-content-blog': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/plugin-content-docs': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/plugin-content-pages': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) - '@docusaurus/utils-common': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)) + '@docusaurus/mdx-loader': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/module-type-aliases': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) + '@docusaurus/plugin-content-blog': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/plugin-content-docs': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/plugin-content-pages': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) + '@docusaurus/utils-common': 3.1.1(@docusaurus/types@3.1.1) '@types/history': 4.7.11 '@types/react': 18.2.71 '@types/react-router-config': 5.0.11 @@ -10969,16 +11165,16 @@ snapshots: - vue-template-compiler - webpack-cli - '@docusaurus/theme-search-algolia@3.1.1(patch_hash=lazxwgumd4o5a3ibe55vftei5e)(@algolia/client-search@4.22.1)(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@types/react@18.3.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(search-insights@2.13.0)(typescript@5.4.3)': + '@docusaurus/theme-search-algolia@3.1.1(patch_hash=lazxwgumd4o5a3ibe55vftei5e)(@algolia/client-search@4.22.1)(@docusaurus/types@3.1.1)(@types/react@18.2.71)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(search-insights@2.13.0)(typescript@5.4.3)': dependencies: - '@docsearch/react': 3.6.0(@algolia/client-search@4.22.1)(@types/react@18.3.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(search-insights@2.13.0) - '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) + '@docsearch/react': 3.6.0(@algolia/client-search@4.22.1)(@types/react@18.2.71)(react-dom@18.2.0)(react@18.2.0)(search-insights@2.13.0) + '@docusaurus/core': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) '@docusaurus/logger': 3.1.1 - '@docusaurus/plugin-content-docs': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) - '@docusaurus/theme-common': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(typescript@5.4.3) + '@docusaurus/plugin-content-docs': 3.1.1(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) + '@docusaurus/theme-common': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)(eslint@8.57.0)(react-dom@18.2.0)(react@18.2.0)(typescript@5.4.3) '@docusaurus/theme-translations': 3.1.1 - '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) - '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) + '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) + '@docusaurus/utils-validation': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) algoliasearch: 4.22.1 algoliasearch-helper: 3.16.3(algoliasearch@4.22.1) clsx: 2.1.0 @@ -11016,7 +11212,7 @@ snapshots: fs-extra: 11.2.0 tslib: 2.6.2 - '@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0)': dependencies: '@mdx-js/mdx': 3.0.1 '@types/history': 4.7.11 @@ -11025,9 +11221,9 @@ snapshots: joi: 17.12.2 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - react-helmet-async: 1.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + react-helmet-async: 1.3.0(react-dom@18.2.0)(react@18.2.0) utility-types: 3.11.0 - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) webpack-merge: 5.10.0 transitivePeerDependencies: - '@swc/core' @@ -11036,16 +11232,15 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils-common@3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))': + '@docusaurus/utils-common@3.1.1(@docusaurus/types@3.1.1)': dependencies: + '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) tslib: 2.6.2 - optionalDependencies: - '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) - '@docusaurus/utils-validation@3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)': + '@docusaurus/utils-validation@3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)': dependencies: '@docusaurus/logger': 3.1.1 - '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2) + '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2) joi: 17.12.2 js-yaml: 4.1.0 tslib: 2.6.2 @@ -11057,12 +11252,13 @@ snapshots: - uglify-js - webpack-cli - '@docusaurus/utils@3.1.1(@docusaurus/types@3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(esbuild@0.20.2)': + '@docusaurus/utils@3.1.1(@docusaurus/types@3.1.1)(esbuild@0.20.2)': dependencies: '@docusaurus/logger': 3.1.1 + '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0)(react@18.2.0) '@svgr/webpack': 6.5.1 escape-string-regexp: 4.0.0 - file-loader: 6.2.0(webpack@5.91.0(esbuild@0.20.2)) + file-loader: 6.2.0(webpack@5.91.0) fs-extra: 11.2.0 github-slugger: 1.5.0 globby: 11.1.0 @@ -11074,10 +11270,8 @@ snapshots: resolve-pathname: 3.0.0 shelljs: 0.8.5 tslib: 2.6.2 - url-loader: 4.1.1(file-loader@6.2.0(webpack@5.91.0(esbuild@0.20.2)))(webpack@5.91.0(esbuild@0.20.2)) - webpack: 5.91.0(esbuild@0.20.2) - optionalDependencies: - '@docusaurus/types': 3.1.1(esbuild@0.20.2)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + url-loader: 4.1.1(file-loader@6.2.0)(webpack@5.91.0) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) transitivePeerDependencies: - '@swc/core' - esbuild @@ -11090,13 +11284,13 @@ snapshots: effect: 2.0.0-next.62 fast-check: 3.15.0 - '@effortlessmotion/html-webpack-inline-source-plugin@1.0.3(html-webpack-plugin@5.6.0(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))))(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)))': + '@effortlessmotion/html-webpack-inline-source-plugin@1.0.3(html-webpack-plugin@5.6.0)(webpack@5.91.0)': dependencies: escape-string-regexp: 4.0.0 - html-webpack-plugin: 5.6.0(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))) + html-webpack-plugin: 5.6.0(webpack@5.91.0) slash: 3.0.0 source-map-url: 0.4.1 - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) '@esbuild/aix-ppc64@0.20.2': optional: true @@ -11218,7 +11412,7 @@ snapshots: '@humanwhocodes/config-array@0.11.14': dependencies: - '@humanwhocodes/object-schema': 2.0.3 + '@humanwhocodes/object-schema': 2.0.2 debug: 4.3.4(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: @@ -11226,7 +11420,7 @@ snapshots: '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/object-schema@2.0.3': {} + '@humanwhocodes/object-schema@2.0.2': {} '@isaacs/cliui@8.0.2': dependencies: @@ -11258,7 +11452,7 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 - '@jest/core@29.7.0(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3))': + '@jest/core@29.7.0(ts-node@10.9.2)': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -11272,7 +11466,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)) + jest-config: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -11440,11 +11634,11 @@ snapshots: '@leichtgewicht/ip-codec@2.0.4': {} - '@mdx-js/loader@3.0.1(webpack@5.91.0(esbuild@0.20.2))': + '@mdx-js/loader@3.0.1(webpack@5.91.0)': dependencies: '@mdx-js/mdx': 3.0.1 source-map: 0.7.4 - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) transitivePeerDependencies: - supports-color @@ -11482,11 +11676,7 @@ snapshots: '@types/react': 18.2.71 react: 18.2.0 - '@mdx-js/react@3.0.1(@types/react@18.3.1)(react@18.2.0)': - dependencies: - '@types/mdx': 2.0.12 - '@types/react': 18.3.1 - react: 18.2.0 + '@msgpack/msgpack@2.8.0': {} '@next/env@14.1.4': {} @@ -11494,12 +11684,11 @@ snapshots: dependencies: glob: 10.3.10 - '@next/mdx@14.1.4(@mdx-js/loader@3.0.1(webpack@5.91.0(esbuild@0.20.2)))(@mdx-js/react@3.0.1(@types/react@18.2.71)(react@18.2.0))': + '@next/mdx@14.1.4(@mdx-js/loader@3.0.1)(@mdx-js/react@3.0.1)': dependencies: - source-map: 0.7.4 - optionalDependencies: - '@mdx-js/loader': 3.0.1(webpack@5.91.0(esbuild@0.20.2)) + '@mdx-js/loader': 3.0.1(webpack@5.91.0) '@mdx-js/react': 3.0.1(@types/react@18.2.71)(react@18.2.0) + source-map: 0.7.4 '@next/swc-darwin-arm64@14.1.4': optional: true @@ -11698,11 +11887,11 @@ snapshots: dependencies: '@octokit/types': 6.41.0 - '@octokit/core@3.6.0(encoding@0.1.13)': + '@octokit/core@3.6.0': dependencies: '@octokit/auth-token': 2.5.0 - '@octokit/graphql': 4.8.0(encoding@0.1.13) - '@octokit/request': 5.6.3(encoding@0.1.13) + '@octokit/graphql': 4.8.0 + '@octokit/request': 5.6.3 '@octokit/request-error': 2.1.0 '@octokit/types': 6.41.0 before-after-hook: 2.2.3 @@ -11716,9 +11905,9 @@ snapshots: is-plain-object: 5.0.0 universal-user-agent: 6.0.1 - '@octokit/graphql@4.8.0(encoding@0.1.13)': + '@octokit/graphql@4.8.0': dependencies: - '@octokit/request': 5.6.3(encoding@0.1.13) + '@octokit/request': 5.6.3 '@octokit/types': 6.41.0 universal-user-agent: 6.0.1 transitivePeerDependencies: @@ -11726,18 +11915,18 @@ snapshots: '@octokit/openapi-types@12.11.0': {} - '@octokit/plugin-paginate-rest@2.21.3(@octokit/core@3.6.0(encoding@0.1.13))': + '@octokit/plugin-paginate-rest@2.21.3(@octokit/core@3.6.0)': dependencies: - '@octokit/core': 3.6.0(encoding@0.1.13) + '@octokit/core': 3.6.0 '@octokit/types': 6.41.0 - '@octokit/plugin-request-log@1.0.4(@octokit/core@3.6.0(encoding@0.1.13))': + '@octokit/plugin-request-log@1.0.4(@octokit/core@3.6.0)': dependencies: - '@octokit/core': 3.6.0(encoding@0.1.13) + '@octokit/core': 3.6.0 - '@octokit/plugin-rest-endpoint-methods@5.16.2(@octokit/core@3.6.0(encoding@0.1.13))': + '@octokit/plugin-rest-endpoint-methods@5.16.2(@octokit/core@3.6.0)': dependencies: - '@octokit/core': 3.6.0(encoding@0.1.13) + '@octokit/core': 3.6.0 '@octokit/types': 6.41.0 deprecation: 2.3.1 @@ -11747,23 +11936,23 @@ snapshots: deprecation: 2.3.1 once: 1.4.0 - '@octokit/request@5.6.3(encoding@0.1.13)': + '@octokit/request@5.6.3': dependencies: '@octokit/endpoint': 6.0.12 '@octokit/request-error': 2.1.0 '@octokit/types': 6.41.0 is-plain-object: 5.0.0 - node-fetch: 2.7.0(encoding@0.1.13) + node-fetch: 2.7.0 universal-user-agent: 6.0.1 transitivePeerDependencies: - encoding - '@octokit/rest@18.12.0(encoding@0.1.13)': + '@octokit/rest@18.12.0': dependencies: - '@octokit/core': 3.6.0(encoding@0.1.13) - '@octokit/plugin-paginate-rest': 2.21.3(@octokit/core@3.6.0(encoding@0.1.13)) - '@octokit/plugin-request-log': 1.0.4(@octokit/core@3.6.0(encoding@0.1.13)) - '@octokit/plugin-rest-endpoint-methods': 5.16.2(@octokit/core@3.6.0(encoding@0.1.13)) + '@octokit/core': 3.6.0 + '@octokit/plugin-paginate-rest': 2.21.3(@octokit/core@3.6.0) + '@octokit/plugin-request-log': 1.0.4(@octokit/core@3.6.0) + '@octokit/plugin-rest-endpoint-methods': 5.16.2(@octokit/core@3.6.0) transitivePeerDependencies: - encoding @@ -12027,7 +12216,7 @@ snapshots: '@pnpm/logger@5.0.0': dependencies: - bole: 5.0.12 + bole: 5.0.11 ndjson: 2.0.0 '@pnpm/manifest-utils@5.0.1(@pnpm/logger@5.0.0)': @@ -12389,7 +12578,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.4.3))': + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0)': dependencies: '@babel/core': 7.24.3 '@svgr/babel-preset': 8.1.0(@babel/core@7.24.3) @@ -12406,7 +12595,7 @@ snapshots: deepmerge: 4.3.1 svgo: 2.8.0 - '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.4.3))(typescript@5.4.3)': + '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0)(typescript@5.4.3)': dependencies: '@svgr/core': 8.1.0(typescript@5.4.3) cosmiconfig: 8.3.6(typescript@5.4.3) @@ -12436,8 +12625,8 @@ snapshots: '@babel/preset-react': 7.24.1(@babel/core@7.24.3) '@babel/preset-typescript': 7.24.1(@babel/core@7.24.3) '@svgr/core': 8.1.0(typescript@5.4.3) - '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.4.3)) - '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.4.3))(typescript@5.4.3) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0) + '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0)(typescript@5.4.3) transitivePeerDependencies: - supports-color - typescript @@ -12461,7 +12650,7 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 - '@testing-library/react@14.2.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)': + '@testing-library/react@14.2.2(react-dom@18.2.0)(react@18.2.0)': dependencies: '@babel/runtime': 7.24.1 '@testing-library/dom': 9.3.4 @@ -12668,7 +12857,7 @@ snapshots: '@types/ms@0.7.34': {} - '@types/nearley@2.11.5(patch_hash=5bomp3nnmdzdyzcgrxyr5kymae)': {} + '@types/nearley@2.11.5(patch_hash=m6lvvh3c4y7yrjlmqdyj74zp2q)': {} '@types/node-forge@1.3.11': dependencies: @@ -12725,11 +12914,6 @@ snapshots: '@types/scheduler': 0.23.0 csstype: 3.1.3 - '@types/react@18.3.1': - dependencies: - '@types/prop-types': 15.7.12 - csstype: 3.1.3 - '@types/retry@0.12.0': {} '@types/retry@0.12.2': {} @@ -12775,10 +12959,14 @@ snapshots: '@types/stack-utils@2.0.3': {} + '@types/tail@2.2.3': {} + '@types/tinycolor2@1.4.6': {} '@types/tough-cookie@4.0.5': {} + '@types/triple-beam@1.3.5': {} + '@types/unist@2.0.10': {} '@types/unist@3.0.2': {} @@ -12792,11 +12980,11 @@ snapshots: '@types/vscode@1.75.1': {} - '@types/webpack@5.28.5(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))': + '@types/webpack@5.28.5(esbuild@0.20.2)(webpack-cli@5.1.4)': dependencies: '@types/node': 18.18.2 tapable: 2.2.1 - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) transitivePeerDependencies: - '@swc/core' - esbuild @@ -12813,7 +13001,7 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@7.4.0(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint@8.57.0)(typescript@5.4.3)': + '@typescript-eslint/eslint-plugin@7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.4.3)': dependencies: '@eslint-community/regexpp': 4.10.0 '@typescript-eslint/parser': 7.4.0(eslint@8.57.0)(typescript@5.4.3) @@ -12828,7 +13016,6 @@ snapshots: natural-compare: 1.4.0 semver: 7.6.0 ts-api-utils: 1.3.0(typescript@5.4.3) - optionalDependencies: typescript: 5.4.3 transitivePeerDependencies: - supports-color @@ -12841,7 +13028,6 @@ snapshots: '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 - optionalDependencies: typescript: 5.4.3 transitivePeerDependencies: - supports-color @@ -12854,7 +13040,6 @@ snapshots: '@typescript-eslint/visitor-keys': 7.4.0 debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 - optionalDependencies: typescript: 5.4.3 transitivePeerDependencies: - supports-color @@ -12876,7 +13061,6 @@ snapshots: debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 ts-api-utils: 1.3.0(typescript@5.4.3) - optionalDependencies: typescript: 5.4.3 transitivePeerDependencies: - supports-color @@ -12895,7 +13079,6 @@ snapshots: minimatch: 9.0.3 semver: 7.6.0 ts-api-utils: 1.3.0(typescript@5.4.3) - optionalDependencies: typescript: 5.4.3 transitivePeerDependencies: - supports-color @@ -12910,7 +13093,6 @@ snapshots: minimatch: 9.0.3 semver: 7.6.0 ts-api-utils: 1.3.0(typescript@5.4.3) - optionalDependencies: typescript: 5.4.3 transitivePeerDependencies: - supports-color @@ -13026,35 +13208,33 @@ snapshots: '@webassemblyjs/ast': 1.12.1 '@xtuc/long': 4.2.2 - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)))': + '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.91.0)': dependencies: - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) webpack-cli: 5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0) - '@webpack-cli/generators@3.0.7(encoding@0.1.13)(mem-fs@2.3.0)(prettier@3.2.5)(webpack-cli@5.1.4)(webpack@5.91.0)': + '@webpack-cli/generators@3.0.7(prettier@3.2.5)(webpack-cli@5.1.4)(webpack@5.91.0)': dependencies: - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) + prettier: 3.2.5 + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) webpack-cli: 5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0) yeoman-environment: 3.19.3 - yeoman-generator: 5.10.0(encoding@0.1.13)(mem-fs@2.3.0)(yeoman-environment@3.19.3) - optionalDependencies: - prettier: 3.2.5 + yeoman-generator: 5.10.0(yeoman-environment@3.19.3) transitivePeerDependencies: - bluebird - encoding - mem-fs - supports-color - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)))': + '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.91.0)': dependencies: - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) webpack-cli: 5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0) - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))(webpack-dev-server@5.0.4(webpack-cli@5.1.4)(webpack@5.91.0))(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)))': + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack-dev-server@5.0.4)(webpack@5.91.0)': dependencies: - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) webpack-cli: 5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0) - optionalDependencies: webpack-dev-server: 5.0.4(webpack-cli@5.1.4)(webpack@5.91.0) '@xobotyi/scrollbar-width@1.9.5': {} @@ -13133,7 +13313,7 @@ snapshots: indent-string: 4.0.0 ajv-formats@2.1.1(ajv@8.12.0): - optionalDependencies: + dependencies: ajv: 8.12.0 ajv-keywords@3.5.2(ajv@6.12.6): @@ -13397,12 +13577,12 @@ snapshots: transitivePeerDependencies: - supports-color - babel-loader@9.1.3(@babel/core@7.24.3)(webpack@5.91.0(esbuild@0.20.2)): + babel-loader@9.1.3(@babel/core@7.24.3)(webpack@5.91.0): dependencies: '@babel/core': 7.24.3 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) babel-plugin-dynamic-import-node@2.3.3: dependencies: @@ -13527,7 +13707,7 @@ snapshots: transitivePeerDependencies: - supports-color - bole@5.0.12: + bole@5.0.11: dependencies: fast-safe-stringify: 2.1.1 individual: 3.0.0 @@ -13941,14 +14121,29 @@ snapshots: color-name@1.1.4: {} + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + color-support@1.1.3: {} + color@3.2.1: + dependencies: + color-convert: 1.9.3 + color-string: 1.9.1 + colord@2.9.3: {} colorette@2.0.20: {} colors@1.0.3: {} + colorspace@1.1.4: + dependencies: + color: 3.2.1 + text-hex: 1.0.0 + combine-promises@1.2.0: {} combined-stream@1.0.8: @@ -14038,7 +14233,7 @@ snapshots: dependencies: toggle-selection: 1.0.6 - copy-webpack-plugin@11.0.0(webpack@5.91.0(esbuild@0.20.2)): + copy-webpack-plugin@11.0.0(webpack@5.91.0): dependencies: fast-glob: 3.3.2 glob-parent: 6.0.2 @@ -14046,7 +14241,7 @@ snapshots: normalize-path: 3.0.0 schema-utils: 4.2.0 serialize-javascript: 6.0.2 - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) core-js-compat@3.36.1: dependencies: @@ -14082,7 +14277,6 @@ snapshots: js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 - optionalDependencies: typescript: 5.4.3 cosmiconfig@9.0.0(typescript@5.4.3): @@ -14091,16 +14285,15 @@ snapshots: import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 - optionalDependencies: typescript: 5.4.3 - create-jest@29.7.0(@types/node@18.18.2)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)): + create-jest@29.7.0(@types/node@18.18.2)(ts-node@10.9.2): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)) + jest-config: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -14131,20 +14324,7 @@ snapshots: dependencies: hyphenate-style-name: 1.0.4 - css-loader@6.10.0(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))): - dependencies: - icss-utils: 5.1.0(postcss@8.4.38) - postcss: 8.4.38 - postcss-modules-extract-imports: 3.0.0(postcss@8.4.38) - postcss-modules-local-by-default: 4.0.4(postcss@8.4.38) - postcss-modules-scope: 3.1.1(postcss@8.4.38) - postcss-modules-values: 4.0.0(postcss@8.4.38) - postcss-value-parser: 4.2.0 - semver: 7.6.0 - optionalDependencies: - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) - - css-loader@6.10.0(webpack@5.91.0(esbuild@0.20.2)): + css-loader@6.10.0(webpack@5.91.0): dependencies: icss-utils: 5.1.0(postcss@8.4.38) postcss: 8.4.38 @@ -14154,21 +14334,19 @@ snapshots: postcss-modules-values: 4.0.0(postcss@8.4.38) postcss-value-parser: 4.2.0 semver: 7.6.0 - optionalDependencies: - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) - css-minimizer-webpack-plugin@4.2.2(clean-css@5.3.3)(esbuild@0.20.2)(webpack@5.91.0(esbuild@0.20.2)): + css-minimizer-webpack-plugin@4.2.2(clean-css@5.3.3)(esbuild@0.20.2)(webpack@5.91.0): dependencies: + clean-css: 5.3.3 cssnano: 5.1.15(postcss@8.4.38) + esbuild: 0.20.2 jest-worker: 29.7.0 postcss: 8.4.38 schema-utils: 4.2.0 serialize-javascript: 6.0.2 source-map: 0.6.1 - webpack: 5.91.0(esbuild@0.20.2) - optionalDependencies: - clean-css: 5.3.3 - esbuild: 0.20.2 + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) css-select@4.3.0: dependencies: @@ -14324,7 +14502,6 @@ snapshots: debug@4.3.4(supports-color@8.1.1): dependencies: ms: 2.1.2 - optionalDependencies: supports-color: 8.1.1 debuglog@1.0.1: {} @@ -14579,6 +14756,8 @@ snapshots: emoticon@4.0.1: {} + enabled@2.0.0: {} + encodeurl@1.0.2: {} encoding@0.1.13: @@ -14777,12 +14956,11 @@ snapshots: '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.3) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.4.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) eslint-plugin-react: 7.34.1(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.57.0) - optionalDependencies: typescript: 5.4.3 transitivePeerDependencies: - eslint-import-resolver-webpack @@ -14800,13 +14978,13 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0): dependencies: debug: 4.3.4(supports-color@8.1.1) enhanced-resolve: 5.16.0 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.4.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.3 is-core-module: 2.13.1 @@ -14817,13 +14995,13 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-plugin-import@2.29.1)(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.4.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0): dependencies: debug: 4.3.4(supports-color@8.1.1) enhanced-resolve: 5.16.0 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.4.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.4.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.3 is-core-module: 2.13.1 @@ -14834,30 +15012,29 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: - debug: 3.2.7 - optionalDependencies: '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.4.3) + debug: 3.2.7 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.4.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: - debug: 3.2.7 - optionalDependencies: '@typescript-eslint/parser': 7.4.0(eslint@8.57.0)(typescript@5.4.3) + debug: 3.2.7 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.4.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.4.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: + '@typescript-eslint/parser': 7.4.0(eslint@8.57.0)(typescript@5.4.3) array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 @@ -14866,7 +15043,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.4.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -14876,8 +15053,6 @@ snapshots: object.values: 1.2.0 semver: 6.3.1 tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 7.4.0(eslint@8.57.0)(typescript@5.4.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -14958,12 +15133,11 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-unused-imports@3.1.0(@typescript-eslint/eslint-plugin@7.4.0(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint@8.57.0)(typescript@5.4.3))(eslint@8.57.0): + eslint-plugin-unused-imports@3.1.0(@typescript-eslint/eslint-plugin@7.4.0)(eslint@8.57.0): dependencies: + '@typescript-eslint/eslint-plugin': 7.4.0(@typescript-eslint/parser@7.4.0)(eslint@8.57.0)(typescript@5.4.3) eslint: 8.57.0 eslint-rule-composer: 0.3.0 - optionalDependencies: - '@typescript-eslint/eslint-plugin': 7.4.0(@typescript-eslint/parser@7.4.0(eslint@8.57.0)(typescript@5.4.3))(eslint@8.57.0)(typescript@5.4.3) eslint-rule-composer@0.3.0: {} @@ -15023,7 +15197,7 @@ snapshots: lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.4 + optionator: 0.9.3 strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: @@ -15227,6 +15401,8 @@ snapshots: dependencies: bser: 2.1.1 + fecha@4.2.3: {} + feed@4.2.2: dependencies: xml-js: 1.6.11 @@ -15241,11 +15417,11 @@ snapshots: dependencies: flat-cache: 3.2.0 - file-loader@6.2.0(webpack@5.91.0(esbuild@0.20.2)): + file-loader@6.2.0(webpack@5.91.0): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) filelist@1.0.4: dependencies: @@ -15312,6 +15488,8 @@ snapshots: flatted@3.3.1: {} + fn.name@1.1.0: {} + follow-redirects@1.15.6: {} for-each@0.3.3: @@ -15323,7 +15501,7 @@ snapshots: cross-spawn: 7.0.3 signal-exit: 4.1.0 - fork-ts-checker-webpack-plugin@6.5.3(eslint@8.57.0)(typescript@5.4.3)(webpack@5.91.0(esbuild@0.20.2)): + fork-ts-checker-webpack-plugin@6.5.3(eslint@8.57.0)(typescript@5.4.3)(webpack@5.91.0): dependencies: '@babel/code-frame': 7.24.2 '@types/json-schema': 7.0.15 @@ -15331,6 +15509,7 @@ snapshots: chokidar: 3.6.0 cosmiconfig: 6.0.0 deepmerge: 4.3.1 + eslint: 8.57.0 fs-extra: 9.1.0 glob: 7.2.3 memfs: 3.5.3 @@ -15339,9 +15518,7 @@ snapshots: semver: 7.6.0 tapable: 1.1.3 typescript: 5.4.3 - webpack: 5.91.0(esbuild@0.20.2) - optionalDependencies: - eslint: 8.57.0 + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) form-data-encoder@2.1.4: {} @@ -15460,9 +15637,9 @@ snapshots: github-slugger@1.5.0: {} - github-username@6.0.0(encoding@0.1.13): + github-username@6.0.0: dependencies: - '@octokit/rest': 18.12.0(encoding@0.1.13) + '@octokit/rest': 18.12.0 transitivePeerDependencies: - encoding @@ -15567,7 +15744,7 @@ snapshots: graceful-git@3.1.2: dependencies: retry: 0.12.0 - safe-execa: 0.1.4 + safe-execa: 0.1.2 graphemer@1.4.0: {} @@ -15780,25 +15957,14 @@ snapshots: html-void-elements@3.0.0: {} - html-webpack-plugin@5.6.0(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))): - dependencies: - '@types/html-minifier-terser': 6.1.0 - html-minifier-terser: 6.1.0 - lodash: 4.17.21 - pretty-error: 4.0.0 - tapable: 2.2.1 - optionalDependencies: - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) - - html-webpack-plugin@5.6.0(webpack@5.91.0(esbuild@0.20.2)): + html-webpack-plugin@5.6.0(webpack@5.91.0): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 lodash: 4.17.21 pretty-error: 4.0.0 tapable: 2.2.1 - optionalDependencies: - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) htmlparser2@6.1.0: dependencies: @@ -15853,13 +16019,12 @@ snapshots: http-proxy-middleware@2.0.6(@types/express@4.17.21): dependencies: + '@types/express': 4.17.21 '@types/http-proxy': 1.17.14 http-proxy: 1.18.1 is-glob: 4.0.3 is-plain-obj: 3.0.0 micromatch: 4.0.5 - optionalDependencies: - '@types/express': 4.17.21 transitivePeerDependencies: - debug @@ -16054,6 +16219,8 @@ snapshots: is-arrayish@0.2.1: {} + is-arrayish@0.3.2: {} + is-async-function@2.0.0: dependencies: has-tostringtag: 1.0.2 @@ -16354,16 +16521,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@18.18.2)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)): + jest-cli@29.7.0(@types/node@18.18.2)(ts-node@10.9.2): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)) + '@jest/core': 29.7.0(ts-node@10.9.2) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)) + create-jest: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)) + jest-config: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -16373,11 +16540,12 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@18.18.2)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)): + jest-config@29.7.0(@types/node@18.18.2)(ts-node@10.9.2): dependencies: '@babel/core': 7.24.3 '@jest/test-sequencer': 29.7.0 '@jest/types': 29.6.3 + '@types/node': 18.18.2 babel-jest: 29.7.0(@babel/core@7.24.3) chalk: 4.1.2 ci-info: 3.9.0 @@ -16397,8 +16565,6 @@ snapshots: pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 - optionalDependencies: - '@types/node': 18.18.2 ts-node: 10.9.2(@types/node@18.18.2)(typescript@5.4.3) transitivePeerDependencies: - babel-plugin-macros @@ -16496,7 +16662,7 @@ snapshots: jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): - optionalDependencies: + dependencies: jest-resolve: 29.7.0 jest-regex-util@29.6.3: {} @@ -16640,12 +16806,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@18.18.2)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)): + jest@29.7.0(@types/node@18.18.2)(ts-node@10.9.2): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)) + '@jest/core': 29.7.0(ts-node@10.9.2) '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)) + jest-cli: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -16774,6 +16940,8 @@ snapshots: kleur@3.0.3: {} + kuler@2.0.0: {} + language-subtag-registry@0.3.22: {} language-tags@1.0.9: @@ -16868,6 +17036,15 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 + logform@2.6.0: + dependencies: + '@colors/colors': 1.6.0 + '@types/triple-beam': 1.3.5 + fecha: 4.2.3 + ms: 2.1.3 + safe-stable-stringify: 2.4.3 + triple-beam: 1.4.1 + longest-streak@3.1.0: {} loose-envify@1.4.0: @@ -17189,12 +17366,11 @@ snapshots: ejs: 3.1.9 globby: 11.1.0 isbinaryfile: 5.0.2 + mem-fs: 2.3.0 minimatch: 7.4.6 multimatch: 5.0.0 normalize-path: 3.0.0 textextensions: 5.16.0 - optionalDependencies: - mem-fs: 2.3.0 mem-fs@2.3.0: dependencies: @@ -17565,11 +17741,11 @@ snapshots: min-indent@1.0.1: {} - mini-css-extract-plugin@2.8.1(webpack@5.91.0(esbuild@0.20.2)): + mini-css-extract-plugin@2.8.1(webpack@5.91.0): dependencies: schema-utils: 4.2.0 tapable: 2.2.1 - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) minimalistic-assert@1.0.1: {} @@ -17725,7 +17901,7 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - nano-css@5.6.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + nano-css@5.6.1(react-dom@18.2.0)(react@18.2.0): dependencies: '@jridgewell/sourcemap-codec': 1.4.15 css-tree: 1.1.3 @@ -17750,7 +17926,7 @@ snapshots: split2: 3.2.2 through2: 4.0.2 - nearley@2.20.1(patch_hash=mg2fc7wgvzub3myuz6m74hllma): + nearley@2.20.1(patch_hash=yc7aistj2i2qcwysldsvv2yuk4): dependencies: commander: 2.20.3 moo: 0.5.2 @@ -17761,9 +17937,14 @@ snapshots: neo-async@2.6.2: {} + neovim@5.1.0: + dependencies: + '@msgpack/msgpack': 2.8.0 + winston: 3.11.0 + nerf-dart@1.0.0: {} - next@14.1.4(@babel/core@7.24.3)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + next@14.1.4(@babel/core@7.24.3)(react-dom@18.2.0)(react@18.2.0): dependencies: '@next/env': 14.1.4 '@swc/helpers': 0.5.2 @@ -17808,11 +17989,9 @@ snapshots: emojilib: 2.4.0 skin-tone: 2.0.0 - node-fetch@2.7.0(encoding@0.1.13): + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 - optionalDependencies: - encoding: 0.1.13 node-forge@1.3.1: {} @@ -18077,6 +18256,10 @@ snapshots: dependencies: wrappy: 1.0.2 + one-time@1.0.0: + dependencies: + fn.name: 1.1.0 + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 @@ -18096,14 +18279,14 @@ snapshots: opener@1.5.2: {} - optionator@0.9.4: + optionator@0.9.3: dependencies: + '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 - word-wrap: 1.2.5 ora@5.4.1: dependencies: @@ -18439,32 +18622,30 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.4.38 - postcss-load-config@4.0.2(postcss@8.4.38)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)): + postcss-load-config@4.0.2(postcss@8.4.38)(ts-node@10.9.2): dependencies: lilconfig: 3.1.1 - yaml: 2.4.1 - optionalDependencies: postcss: 8.4.38 ts-node: 10.9.2(@types/node@18.18.2)(typescript@5.4.3) + yaml: 2.4.1 - postcss-loader@7.3.4(postcss@8.4.38)(typescript@5.4.3)(webpack@5.91.0(esbuild@0.20.2)): + postcss-loader@7.3.4(postcss@8.4.38)(typescript@5.4.3)(webpack@5.91.0): dependencies: cosmiconfig: 8.3.6(typescript@5.4.3) jiti: 1.21.0 postcss: 8.4.38 semver: 7.6.0 - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) transitivePeerDependencies: - typescript - postcss-loader@8.1.1(postcss@8.4.38)(typescript@5.4.3)(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))): + postcss-loader@8.1.1(postcss@8.4.38)(typescript@5.4.3)(webpack@5.91.0): dependencies: cosmiconfig: 9.0.0(typescript@5.4.3) jiti: 1.21.0 postcss: 8.4.38 semver: 7.6.0 - optionalDependencies: - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) transitivePeerDependencies: - typescript @@ -18803,7 +18984,7 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-dev-utils@12.0.1(eslint@8.57.0)(typescript@5.4.3)(webpack@5.91.0(esbuild@0.20.2)): + react-dev-utils@12.0.1(eslint@8.57.0)(typescript@5.4.3)(webpack@5.91.0): dependencies: '@babel/code-frame': 7.24.2 address: 1.2.2 @@ -18814,7 +18995,7 @@ snapshots: escape-string-regexp: 4.0.0 filesize: 8.0.7 find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.5.3(eslint@8.57.0)(typescript@5.4.3)(webpack@5.91.0(esbuild@0.20.2)) + fork-ts-checker-webpack-plugin: 6.5.3(eslint@8.57.0)(typescript@5.4.3)(webpack@5.91.0) global-modules: 2.0.0 globby: 11.1.0 gzip-size: 6.0.0 @@ -18829,9 +19010,8 @@ snapshots: shell-quote: 1.8.1 strip-ansi: 6.0.1 text-table: 0.2.0 - webpack: 5.91.0(esbuild@0.20.2) - optionalDependencies: typescript: 5.4.3 + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) transitivePeerDependencies: - eslint - supports-color @@ -18847,7 +19027,7 @@ snapshots: react-fast-compare@3.2.2: {} - react-helmet-async@1.3.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + react-helmet-async@1.3.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@babel/runtime': 7.24.1 invariant: 2.2.4 @@ -18857,7 +19037,7 @@ snapshots: react-fast-compare: 3.2.2 shallowequal: 1.1.0 - react-helmet-async@2.0.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + react-helmet-async@2.0.4(react-dom@18.2.0)(react@18.2.0): dependencies: invariant: 2.2.4 react: 18.2.0 @@ -18875,11 +19055,11 @@ snapshots: dependencies: react: 18.2.0 - react-loadable-ssr-addon-v5-slorber@1.0.1(@docusaurus/react-loadable@5.5.2(react@18.2.0))(webpack@5.91.0(esbuild@0.20.2)): + react-loadable-ssr-addon-v5-slorber@1.0.1(@docusaurus/react-loadable@5.5.2)(webpack@5.91.0): dependencies: '@babel/runtime': 7.24.1 react-loadable: '@docusaurus/react-loadable@5.5.2(react@18.2.0)' - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) react-player@2.15.1(react@18.2.0): dependencies: @@ -18890,7 +19070,7 @@ snapshots: react: 18.2.0 react-fast-compare: 3.2.2 - react-router-config@5.1.1(react-router@5.3.4(react@18.2.0))(react@18.2.0): + react-router-config@5.1.1(react-router@5.3.4)(react@18.2.0): dependencies: '@babel/runtime': 7.24.1 react: 18.2.0 @@ -18927,7 +19107,7 @@ snapshots: react: 18.2.0 tslib: 2.6.2 - react-use@17.5.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + react-use@17.5.0(react-dom@18.2.0)(react@18.2.0): dependencies: '@types/js-cookie': 2.2.7 '@xobotyi/scrollbar-width': 1.9.5 @@ -18935,7 +19115,7 @@ snapshots: fast-deep-equal: 3.1.3 fast-shallow-equal: 1.0.0 js-cookie: 2.2.1 - nano-css: 5.6.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + nano-css: 5.6.1(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-universal-interface: 0.6.2(react@18.2.0)(tslib@2.6.2) @@ -19317,18 +19497,14 @@ snapshots: execa: 5.1.1 path-name: 1.0.0 - safe-execa@0.1.4: - dependencies: - '@zkochan/which': 2.0.3 - execa: 5.1.1 - path-name: 1.0.0 - safe-regex-test@1.0.3: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-regex: 1.1.4 + safe-stable-stringify@2.4.3: {} + safer-buffer@2.1.2: {} sanitize-html@2.13.0: @@ -19534,6 +19710,10 @@ snapshots: transitivePeerDependencies: - supports-color + simple-swizzle@0.2.2: + dependencies: + is-arrayish: 0.3.2 + sinon@17.0.1: dependencies: '@sinonjs/commons': 3.0.1 @@ -19583,7 +19763,7 @@ snapshots: dependencies: agent-base: 6.0.2 debug: 4.3.4(supports-color@8.1.1) - socks: 2.8.3 + socks: 2.8.1 transitivePeerDependencies: - supports-color @@ -19591,7 +19771,7 @@ snapshots: dependencies: agent-base: 6.0.2 debug: 4.3.4(supports-color@8.1.1) - socks: 2.8.3 + socks: 2.8.1 transitivePeerDependencies: - supports-color @@ -19599,11 +19779,11 @@ snapshots: dependencies: agent-base: 6.0.2 debug: 4.3.4(supports-color@8.1.1) - socks: 2.8.3 + socks: 2.8.1 transitivePeerDependencies: - supports-color - socks@2.8.3: + socks@2.8.1: dependencies: ip-address: 9.0.5 smart-buffer: 4.2.0 @@ -19703,6 +19883,8 @@ snapshots: dependencies: stackframe: 1.3.4 + stack-trace@0.0.10: {} + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 @@ -19852,9 +20034,9 @@ snapshots: strnum@1.0.5: {} - style-loader@3.3.4(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))): + style-loader@3.3.4(webpack@5.91.0): dependencies: - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) style-to-object@0.4.4: dependencies: @@ -19866,10 +20048,9 @@ snapshots: styled-jsx@5.1.1(@babel/core@7.24.3)(react@18.2.0): dependencies: + '@babel/core': 7.24.3 client-only: 0.0.1 react: 18.2.0 - optionalDependencies: - '@babel/core': 7.24.3 stylehacks@5.1.1(postcss@8.4.38): dependencies: @@ -19948,7 +20129,9 @@ snapshots: transitivePeerDependencies: - typescript - tailwindcss@3.4.1(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)): + tail@2.2.6: {} + + tailwindcss@3.4.1(ts-node@10.9.2): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -19967,7 +20150,7 @@ snapshots: postcss: 8.4.38 postcss-import: 15.1.0(postcss@8.4.38) postcss-js: 4.0.1(postcss@8.4.38) - postcss-load-config: 4.0.2(postcss@8.4.38)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)) + postcss-load-config: 4.0.2(postcss@8.4.38)(ts-node@10.9.2) postcss-nested: 6.0.1(postcss@8.4.38) postcss-selector-parser: 6.0.16 resolve: 1.22.8 @@ -19988,27 +20171,15 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 - terser-webpack-plugin@5.3.10(esbuild@0.20.2)(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))): + terser-webpack-plugin@5.3.10(esbuild@0.20.2)(webpack@5.91.0): dependencies: '@jridgewell/trace-mapping': 0.3.25 - jest-worker: 27.5.1 - schema-utils: 3.3.0 - serialize-javascript: 6.0.2 - terser: 5.29.2 - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) - optionalDependencies: esbuild: 0.20.2 - - terser-webpack-plugin@5.3.10(esbuild@0.20.2)(webpack@5.91.0(esbuild@0.20.2)): - dependencies: - '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.29.2 - webpack: 5.91.0(esbuild@0.20.2) - optionalDependencies: - esbuild: 0.20.2 + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) terser@5.29.2: dependencies: @@ -20023,6 +20194,8 @@ snapshots: glob: 7.2.3 minimatch: 3.1.2 + text-hex@1.0.0: {} + text-table@0.2.0: {} textextensions@5.16.0: {} @@ -20094,6 +20267,8 @@ snapshots: trim-newlines@4.1.1: {} + triple-beam@1.4.1: {} + trough@2.2.0: {} ts-api-utils@1.3.0(typescript@5.4.3): @@ -20104,11 +20279,13 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@29.1.2(@babel/core@7.24.3)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.3))(esbuild@0.20.2)(jest@29.7.0(@types/node@18.18.2)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)))(typescript@5.4.3): + ts-jest@29.1.2(@babel/core@7.24.3)(esbuild@0.20.2)(jest@29.7.0)(typescript@5.4.3): dependencies: + '@babel/core': 7.24.3 bs-logger: 0.2.6 + esbuild: 0.20.2 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3)) + jest: 29.7.0(@types/node@18.18.2)(ts-node@10.9.2) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -20116,13 +20293,8 @@ snapshots: semver: 7.6.0 typescript: 5.4.3 yargs-parser: 21.1.1 - optionalDependencies: - '@babel/core': 7.24.3 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.24.3) - esbuild: 0.20.2 - ts-loader@9.5.1(typescript@5.4.3)(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))): + ts-loader@9.5.1(typescript@5.4.3)(webpack@5.91.0): dependencies: chalk: 4.1.2 enhanced-resolve: 5.16.0 @@ -20130,7 +20302,7 @@ snapshots: semver: 7.6.0 source-map: 0.7.4 typescript: 5.4.3 - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) ts-node@10.9.2(@types/node@18.18.2)(typescript@5.4.3): dependencies: @@ -20369,14 +20541,13 @@ snapshots: url-join@4.0.1: {} - url-loader@4.1.1(file-loader@6.2.0(webpack@5.91.0(esbuild@0.20.2)))(webpack@5.91.0(esbuild@0.20.2)): + url-loader@4.1.1(file-loader@6.2.0)(webpack@5.91.0): dependencies: + file-loader: 6.2.0(webpack@5.91.0) loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.3.0 - webpack: 5.91.0(esbuild@0.20.2) - optionalDependencies: - file-loader: 6.2.0(webpack@5.91.0(esbuild@0.20.2)) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) url-parse@1.5.10: dependencies: @@ -20506,9 +20677,10 @@ snapshots: webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))(webpack-dev-server@5.0.4(webpack-cli@5.1.4)(webpack@5.91.0))(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))) + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.91.0) + '@webpack-cli/generators': 3.0.7(prettier@3.2.5)(webpack-cli@5.1.4)(webpack@5.91.0) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.91.0) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack-dev-server@5.0.4)(webpack@5.91.0) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.3 @@ -20517,22 +20689,20 @@ snapshots: import-local: 3.1.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) - webpack-merge: 5.10.0 - optionalDependencies: - '@webpack-cli/generators': 3.0.7(encoding@0.1.13)(mem-fs@2.3.0)(prettier@3.2.5)(webpack-cli@5.1.4)(webpack@5.91.0) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) webpack-dev-server: 5.0.4(webpack-cli@5.1.4)(webpack@5.91.0) + webpack-merge: 5.10.0 - webpack-dev-middleware@5.3.4(webpack@5.91.0(esbuild@0.20.2)): + webpack-dev-middleware@5.3.4(webpack@5.91.0): dependencies: colorette: 2.0.20 memfs: 3.5.3 mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.2.0 - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) - webpack-dev-middleware@7.1.1(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))): + webpack-dev-middleware@7.1.1(webpack@5.91.0): dependencies: colorette: 2.0.20 memfs: 4.8.0 @@ -20540,10 +20710,9 @@ snapshots: on-finished: 2.4.1 range-parser: 1.2.1 schema-utils: 4.2.0 - optionalDependencies: - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) - webpack-dev-server@4.15.2(webpack@5.91.0(esbuild@0.20.2)): + webpack-dev-server@4.15.2(webpack@5.91.0): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -20573,10 +20742,9 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 5.3.4(webpack@5.91.0(esbuild@0.20.2)) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) + webpack-dev-middleware: 5.3.4(webpack@5.91.0) ws: 8.16.0 - optionalDependencies: - webpack: 5.91.0(esbuild@0.20.2) transitivePeerDependencies: - bufferutil - debug @@ -20613,11 +20781,10 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.1.1(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))) - ws: 8.16.0 - optionalDependencies: - webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) webpack-cli: 5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0) + webpack-dev-middleware: 7.1.1(webpack@5.91.0) + ws: 8.16.0 transitivePeerDependencies: - bufferutil - debug @@ -20632,7 +20799,7 @@ snapshots: webpack-sources@3.2.3: {} - webpack@5.91.0(esbuild@0.20.2): + webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.5 @@ -20655,54 +20822,22 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(esbuild@0.20.2)(webpack@5.91.0(esbuild@0.20.2)) + terser-webpack-plugin: 5.3.10(esbuild@0.20.2)(webpack@5.91.0) watchpack: 2.4.1 - webpack-sources: 3.2.3 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0)): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.5 - '@webassemblyjs/ast': 1.12.1 - '@webassemblyjs/wasm-edit': 1.12.1 - '@webassemblyjs/wasm-parser': 1.12.1 - acorn: 8.11.3 - acorn-import-assertions: 1.9.0(acorn@8.11.3) - browserslist: 4.23.0 - chrome-trace-event: 1.0.3 - enhanced-resolve: 5.16.0 - es-module-lexer: 1.5.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 3.3.0 - tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(esbuild@0.20.2)(webpack@5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0))) - watchpack: 2.4.1 - webpack-sources: 3.2.3 - optionalDependencies: webpack-cli: 5.1.4(@webpack-cli/generators@3.0.7)(webpack-dev-server@5.0.4)(webpack@5.91.0) + webpack-sources: 3.2.3 transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js - webpackbar@5.0.2(webpack@5.91.0(esbuild@0.20.2)): + webpackbar@5.0.2(webpack@5.91.0): dependencies: chalk: 4.1.2 consola: 2.15.3 pretty-time: 1.1.0 std-env: 3.7.0 - webpack: 5.91.0(esbuild@0.20.2) + webpack: 5.91.0(esbuild@0.20.2)(webpack-cli@5.1.4) websocket-driver@0.7.4: dependencies: @@ -20797,7 +20932,25 @@ snapshots: wildcard@2.0.1: {} - word-wrap@1.2.5: {} + winston-transport@4.7.0: + dependencies: + logform: 2.6.0 + readable-stream: 3.6.2 + triple-beam: 1.4.1 + + winston@3.11.0: + dependencies: + '@colors/colors': 1.6.0 + '@dabh/diagnostics': 2.0.3 + async: 3.2.5 + is-stream: 2.0.1 + logform: 2.6.0 + one-time: 1.0.0 + readable-stream: 3.6.2 + safe-stable-stringify: 2.4.3 + stack-trace: 0.0.10 + triple-beam: 1.4.1 + winston-transport: 4.7.0 workerpool@6.2.1: {} @@ -20950,13 +21103,13 @@ snapshots: - bluebird - supports-color - yeoman-generator@5.10.0(encoding@0.1.13)(mem-fs@2.3.0)(yeoman-environment@3.19.3): + yeoman-generator@5.10.0(yeoman-environment@3.19.3): dependencies: chalk: 4.1.2 dargs: 7.0.0 debug: 4.3.4(supports-color@8.1.1) execa: 5.1.1 - github-username: 6.0.0(encoding@0.1.13) + github-username: 6.0.0 lodash: 4.17.21 mem-fs-editor: 9.7.0(mem-fs@2.3.0) minimist: 1.2.8 @@ -20967,7 +21120,6 @@ snapshots: shelljs: 0.8.5 sort-keys: 4.2.0 text-table: 0.2.0 - optionalDependencies: yeoman-environment: 3.19.3 transitivePeerDependencies: - bluebird diff --git a/scripts/deploy-cursorless-nvim.sh b/scripts/deploy-cursorless-nvim.sh new file mode 100755 index 0000000000..c322973d30 --- /dev/null +++ b/scripts/deploy-cursorless-nvim.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# This script is used to push to the cursorless.nvim github production repo +set -euo pipefail + +# Clone current cursorless.nvim main +mkdir -p dist && cd dist +git clone 'https://github.com/hands-free-vim/cursorless.nvim.git' cursorless.nvim-remote +cd - + +out_dir=dist/cursorless.nvim-remote + +# Delete the old files +cd "$out_dir" +git rm -r README.md lua/ vim/ node/ +cd - + +# +# Merge the build .js and the static files +# + +# copy .lua, .vim dependencies, command-server and other static files +cp -r cursorless.nvim/README.md "$out_dir/" +cp -r cursorless.nvim/lua "$out_dir/" +cp -r cursorless.nvim/vim "$out_dir/" +cp -r cursorless.nvim/node "$out_dir/" + +# copy the built .js file +mkdir -p "$out_dir/node/cursorless-neovim/out" +cp packages/cursorless-neovim/package.json "$out_dir/node/cursorless-neovim/" +cp packages/cursorless-neovim/out/index.cjs "$out_dir/node/cursorless-neovim/out/" + +# Push to cursorless.nvim +cd "$out_dir" +git add * +git commit -m "Deploy cursorless.nvim" +git push diff --git a/scripts/deploy-cursorless-talon.sh b/scripts/deploy-cursorless-talon.sh old mode 100644 new mode 100755 index 26b2ff97b9..b9429910b4 --- a/scripts/deploy-cursorless-talon.sh +++ b/scripts/deploy-cursorless-talon.sh @@ -1,3 +1,4 @@ +#!/usr/bin/env bash # This script is used to push the cursorless-talon subtree to the cursorless # talon repo. We proceed by first performing a git subtree split and then # cherrypicking any new commits onto the cursorless-talon main branch diff --git a/scripts/install-neovim-dependencies.sh b/scripts/install-neovim-dependencies.sh new file mode 100755 index 0000000000..32fc3ab471 --- /dev/null +++ b/scripts/install-neovim-dependencies.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail + +npm install -g neovim@5.1.0 + +git clone https://github.com/vim-scripts/BufOnly.vim ${TEMP_DIR}/BufOnly.vim +git clone https://github.com/hands-free-vim/talon.nvim ${TEMP_DIR}/talon.nvim diff --git a/tsconfig.json b/tsconfig.json index e05ff589f5..6a6d00bfc4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,6 +14,12 @@ { "path": "./packages/cursorless-engine" }, + { + "path": "./packages/cursorless-neovim" + }, + { + "path": "./packages/cursorless-neovim-e2e" + }, { "path": "./packages/cursorless-org" }, @@ -29,6 +35,12 @@ { "path": "./packages/meta-updater" }, + { + "path": "./packages/neovim-common" + }, + { + "path": "./packages/neovim-registry" + }, { "path": "./packages/test-harness" },