diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index 0ac19d0e..00000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,32 +0,0 @@
-module.exports = {
- extends: [
- "eslint:recommended",
- "plugin:@typescript-eslint/recommended",
- "plugin:@typescript-eslint/recommended-requiring-type-checking",
- "plugin:@typescript-eslint/strict",
- ],
- parser: "@typescript-eslint/parser",
- parserOptions: {
- ecmaVersion: 6,
- sourceType: "module",
- project: "tsconfig.json",
- tsconfigRootDir: __dirname,
- },
- plugins: ["@typescript-eslint"],
- root: true,
- rules: {
- "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_.*" }],
- "@typescript-eslint/naming-convention": "warn",
- "@typescript-eslint/semi": "warn",
- "@typescript-eslint/consistent-type-definitions": ["error", "type"],
- "curly": "warn",
- "eqeqeq": "warn",
- "no-throw-literal": "warn",
- "semi": "off",
- "@typescript-eslint/explicit-function-return-type": "warn",
- "no-duplicate-imports": "warn",
- "sort-imports": "warn",
- "no-trailing-spaces": "warn",
- },
- ignorePatterns: ["webview-ui/**", ".eslintrc.js"],
-};
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 00000000..d921a30a
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,45 @@
+{
+ "extends": [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:@typescript-eslint/recommended-requiring-type-checking",
+ "plugin:@typescript-eslint/strict"
+ ],
+ "parser": "@typescript-eslint/parser",
+ "parserOptions": {
+ "ecmaVersion": 6,
+ "sourceType": "module",
+ "project": "tsconfig.json",
+ "tsconfigRootDir": "."
+ },
+ "plugins": [
+ "@typescript-eslint"
+ ],
+ "root": true,
+ "rules": {
+ "@typescript-eslint/no-unused-vars": [
+ "error",
+ {
+ "argsIgnorePattern": "^_.*"
+ }
+ ],
+ "@typescript-eslint/naming-convention": "warn",
+ "@typescript-eslint/semi": "warn",
+ "@typescript-eslint/consistent-type-definitions": [
+ "error",
+ "type"
+ ],
+ "curly": "warn",
+ "eqeqeq": "warn",
+ "no-throw-literal": "warn",
+ "semi": "off",
+ "@typescript-eslint/explicit-function-return-type": "warn",
+ "no-duplicate-imports": "warn",
+ "sort-imports": "warn",
+ "no-trailing-spaces": "warn"
+ },
+ "ignorePatterns": [
+ "webview-ui/**",
+ ".eslintrc.js"
+ ]
+}
\ No newline at end of file
diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml
index f562555b..effbe006 100644
--- a/.github/workflows/ci-cd.yml
+++ b/.github/workflows/ci-cd.yml
@@ -23,7 +23,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v4
with:
- node-version: 18
+ node-version: 20
- name: Install extension dependencies
run: yarn run install:all
- name: Build webview
@@ -54,13 +54,13 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v4
with:
- node-version: 18
+ node-version: 20
- name: Install extension dependencies
run: yarn run install:all
- name: Build webview
run: yarn run build:webview
- name: Package extension
- run: npx @vscode/vsce package --yarn --githubBranch ${{ github.ref_name }}
+ run: npx --yes @vscode/vsce package --yarn --githubBranch ${{ github.ref_name }}
- name: Upload extension
uses: actions/upload-artifact@v4
with:
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index c99d2b38..691748f5 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -22,7 +22,7 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v4
with:
- node-version: 18
+ node-version: 20
- name: Install extension dependencies
run: yarn run install:all
- name: Build webview
@@ -50,9 +50,17 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v4
with:
- node-version: 18
+ node-version: 20
- name: Install asset generation dependencies
- run: sudo apt install -y ffmpeg libnss3 xvfb
+ run: |
+ sudo mkdir -p /usr/local/bin
+ sudo ln -sf /bin/true /usr/local/bin/mandb # no-op to skip man-db triggers
+ sudo DEBIAN_FRONTEND=noninteractive apt update
+ sudo DEBIAN_FRONTEND=noninteractive \
+ apt install -y --no-install-recommends \
+ ffmpeg libnss3 xvfb \
+ -o Dpkg::Options::="--path-exclude=/usr/share/man/*" \
+ -o Dpkg::Options::="--path-exclude=/usr/share/doc/*"
- name: Install extension dependencies
run: yarn run install:all
- name: Build webview
@@ -75,7 +83,6 @@ jobs:
package:
name: Package extension
- needs: examples
runs-on: ubuntu-latest
steps:
- name: Checkout
@@ -83,13 +90,13 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v4
with:
- node-version: 18
+ node-version: 20
- name: Install extension dependencies
run: yarn run install:all
- name: Build webview
run: yarn run build:webview
- name: Package extension
- run: npx @vscode/vsce package --yarn --githubBranch ${{ env.BRANCH }}
+ run: npx --yes @vscode/vsce package --yarn --githubBranch ${{ env.BRANCH }}
- name: Upload extension
uses: actions/upload-artifact@v4
with:
diff --git a/.github/workflows/update-assets.yml b/.github/workflows/update-assets.yml
index 3de0f153..acc1fee6 100644
--- a/.github/workflows/update-assets.yml
+++ b/.github/workflows/update-assets.yml
@@ -20,9 +20,17 @@ jobs:
- name: Install Node.js
uses: actions/setup-node@v4
with:
- node-version: 18
+ node-version: 20
- name: Install asset generation dependencies
- run: sudo apt install -y ffmpeg libnss3 xvfb
+ run: |
+ sudo mkdir -p /usr/local/bin
+ sudo ln -sf /bin/true /usr/local/bin/mandb # no-op to skip man-db triggers
+ sudo DEBIAN_FRONTEND=noninteractive apt update
+ sudo DEBIAN_FRONTEND=noninteractive \
+ apt install -y --no-install-recommends \
+ ffmpeg libnss3 xvfb \
+ -o Dpkg::Options::="--path-exclude=/usr/share/man/*" \
+ -o Dpkg::Options::="--path-exclude=/usr/share/doc/*"
- name: Install extension dependencies
run: yarn run install:all
- name: Build webview
diff --git a/.vscodeignore b/.vscodeignore
index e132d362..68d19a62 100644
--- a/.vscodeignore
+++ b/.vscodeignore
@@ -7,8 +7,15 @@
!LICENSE
!README.md
!assets/extension-logo.png
-!node_modules/tree-sitter
+!out/extension.js
+!webview-ui/public
+
+# keep only non-compiled dependency files
!node_modules/node-gyp-build
!node_modules/node-addon-api
-!out/extension.js
-!webview-ui/public
\ No newline at end of file
+!node_modules/tree-sitter/src
+!node_modules/tree-sitter/vendor
+!node_modules/tree-sitter/binding.gyp
+!node_modules/tree-sitter/index.js
+!node_modules/tree-sitter/package.json
+!node_modules/tree-sitter/LICENSE
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3209b688..14e59e21 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,10 +1,34 @@
# Changelog
-# [Unreleased]
+# 0.8.0
+
+## Added
+
+- Multi-cursor support in Block Mode, thanks [@CB2Moon](https://github.com/selfint/code-blocks/pull/188)!
+
+ 
+
+- `toml` and `xml` support, thanks [@sanarise](https://github.com/selfint/code-blocks/pull/186)!
+
+- `sql` and `latex` support using [@derekstride/tree-sitter-sql](https://github.com/DerekStride/tree-sitter-sql) and [@derekstride/tree-sitter-sql](https://github.com/latex-lsp/tree-sitter-latex).
+
+- ESM-based parser loading for parsers like CSS ([#191](https://github.com/selfint/code-blocks/issues/191)).
+
+- 'Remove' option to notification when parser fails to load ([#180](https://github.com/selfint/code-blocks/issues/180)).
+
+- More languages are now tested in advance: TOML, XML, CSS, Zig, Swift, SQL, LaTeX.
## Fixed
-- Add 'Remove' option to notification if local parser installation fails to load.
+- Parser build method ([[#193](https://github.com/selfint/code-blocks/issues/193)]), now uses `node-gyp` instead of `tree-sitter-cli`.
+
+## Deprecated
+
+- Support for `node` v18, it might still work, but the extension now requires `node` v20+.
+
+## Removed
+
+- `codeBlocks.treeSitterCliPath` configuration: The Extension now only requires `npm`.
# 0.7.0
diff --git a/README.md b/README.md
index 7d513de9..b188b4fb 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-
+
@@ -24,14 +24,13 @@ Supercharge your editor with syntactically aware code navigation and manipulatio
### Block mode
-Syntactically aware code selection (e.g. select scope), navigation (e.g. goto next function)
-and manipulation (e.g. re-order function parameters), right inside your editor.
+Syntactically aware code selection (e.g. select scope), navigation (e.g. goto next function) and manipulation (e.g. re-order function parameters), right inside your editor.

### Code Blocks Editor
-Birds eye view over all your code blocks, with point and click refactoring.
+Bird's-eye view over all your code blocks, with point and click refactoring.

@@ -43,15 +42,7 @@ View your code's syntax tree directly
## Requirements
-- `node` / `npm`: Used to download tree-sitter language parsers. Can be installed from [here](https://nodejs.org/en/download).
-
-- **OPTIONAL:** `tree-sitter`: Used to for tree-sitter language parsers that need to be locally built.
-
- After installing `npm`, can be installed by running:
- `npm i -g tree-sitter-cli`.
-
- If you don't want to install `tree-sitter`, there's a good chance you don't
- need it. Try the extension without it, it will notify you if it's required.
+- `npm`: Used to download and build tree-sitter language parsers. Can be installed from [here](https://nodejs.org/en/download). Must be in `PATH`.
### Note
@@ -101,30 +92,24 @@ These are the default key bindings, they are only active when "block mode" is ac
### Global
-- `codeBlocks.treeSitterCliPath`: Path to the `tree-sitter` cli command. Defaults to `tree-sitter` (assumes command is in PATH).
-- `codeBlocks.colors.enabled`: Whether Block Mode should color selections or not. Defaults to `false`.
-- `codeBlocks.colors.sibling`: CSS string for sibling selection background color. Defaults to `var(--vscode-editor-selectionHighlightBackground)`.
-- `codeBlocks.colors.parent`: CSS string for parent selection background color. Defaults to `var(--vscode-editor-linkedEditingBackground)`.
-- `codeBlocks.ignoredLanguageIds`: Array of VScode [languageId](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers)s not to install/load parsers for.
+- `codeBlocks.colors.enabled`: Whether Block Mode should color selections or not. Defaults to `false`.
+- `codeBlocks.colors.sibling`: CSS string for sibling selection background color. Defaults to `var(--vscode-editor-selectionHighlightBackground)`.
+- `codeBlocks.colors.parent`: CSS string for parent selection background color. Defaults to `var(--vscode-editor-linkedEditingBackground)`.
+- `codeBlocks.ignoredLanguageIds`: Array of VScode [languageId](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers)s not to install/load parsers for.
### Language specific (advanced)
These configurations are set at the [languageId](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers) level.
-Most languages should just work™, if you find a language that requires manual configuration please [create an issue](https://github.com/selfint/code-blocks/issues).
-Or [create a pull request](https://github.com/selfint/code-blocks/pulls) with your configuration added to the `configurationDefaults` section of the `package.json` file.
+Most languages should just work™, if you find a language that requires manual configuration please [create an issue](https://github.com/selfint/code-blocks/issues). Or [create a pull request](https://github.com/selfint/code-blocks/pulls) with your configuration added to the `configurationDefaults` section of the `package.json` file.
-- `codeBlocks.npmPackageName`: [NPM](https://www.npmjs.com/) package name of the `tree-sitter` parser to use for the
- language. Defaults to `tree-sitter-`, change if the package name doesn't match the languageId.
+- `codeBlocks.npmPackageName`: [NPM](https://www.npmjs.com/) package name of the `tree-sitter` parser to use for the language. Defaults to `tree-sitter-`, change if the package name doesn't match the languageId.
-- `codeBlocks.parserName`: Filename of the WASM parser built by the `tree-sitter build --wasm` command, without the
- `.wasm` extension. Defaults to `tree-sitter-`, change if the parser filename doesn't match the languageId.
+- `codeBlocks.parserName`: Name to save parser as (defaults to `tree-sitter-`), change if the package name doesn't match the languageId (e.g., `tree-sitter-typescript` for `[typescriptreact]` languageId).
-- `codeBlocks.subdirectory`: Directory inside the NPM package containing the `tree-sitter` grammar. Defaults to the
- root directory of the package, change if the grammar isn't there.
+- `codeBlocks.subdirectory`: Directory inside the NPM package containing the `tree-sitter` grammar. Defaults to the root directory of the package, change if the grammar isn't there.
-- `codeBlocks.queries`: Tree-sitter [queries](https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax)
- to generate blocks, must contain at least one `@capture`. The name of the capture doesn't matter, the entire match will be a block.
+- `codeBlocks.queries`: Tree-sitter [queries](https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax) to generate blocks, must contain at least one `@capture`. The name of the capture doesn't matter, the entire match will be a block.
Required by [Code Blocks Editor](#code-blocks-editor).
@@ -136,8 +121,6 @@ Language ID: `typescriptreact`
NPM package name: [tree-sitter-typescript](https://www.npmjs.com/package/tree-sitter-typescript)
-WASM parser name: `tree-sitter-ts.wasm`
-
Desired blocks: JSX blocks, and documentation comments should be merged with documentees.
```jsonc
@@ -166,11 +149,11 @@ Desired blocks: JSX blocks, and documentation comments should be merged with doc
### Custom editors
-- Code Blocks Editor (viewType `codeBlocks.editor`): UI for moving code blocks inside a file. Useful when refactoring large blocks over long distances.
+- Code Blocks Editor (viewType `codeBlocks.editor`): UI for moving code blocks inside a file. Useful when refactoring large blocks over long distances.
## Known Issues
-- Out of bounds memory access ([#154](https://github.com/selfint/code-blocks/issues/154)): For now, reloading the editor fixes this.
+No known issues as of November 1, 2025.
## License
diff --git a/assets/examples/Block_Mode_-_Move_-_Rust_-_Functions.gif b/assets/examples/Block_Mode_-_Move_-_Rust_-_Functions.gif
index 9f38d957..bde92b31 100644
Binary files a/assets/examples/Block_Mode_-_Move_-_Rust_-_Functions.gif and b/assets/examples/Block_Mode_-_Move_-_Rust_-_Functions.gif differ
diff --git a/assets/examples/Block_Mode_-_Move_-_Rust_-_Match_arms.gif b/assets/examples/Block_Mode_-_Move_-_Rust_-_Match_arms.gif
index 12bf0eee..f6e538f6 100644
Binary files a/assets/examples/Block_Mode_-_Move_-_Rust_-_Match_arms.gif and b/assets/examples/Block_Mode_-_Move_-_Rust_-_Match_arms.gif differ
diff --git a/assets/examples/Block_Mode_-_Move_-_Rust_-_Parameters.gif b/assets/examples/Block_Mode_-_Move_-_Rust_-_Parameters.gif
index 459dcfc6..05fa2b81 100644
Binary files a/assets/examples/Block_Mode_-_Move_-_Rust_-_Parameters.gif and b/assets/examples/Block_Mode_-_Move_-_Rust_-_Parameters.gif differ
diff --git a/assets/examples/Block_Mode_-_Select_-_Rust.gif b/assets/examples/Block_Mode_-_Select_-_Rust.gif
index 57a35e6a..d03c5686 100644
Binary files a/assets/examples/Block_Mode_-_Select_-_Rust.gif and b/assets/examples/Block_Mode_-_Select_-_Rust.gif differ
diff --git a/assets/examples/Block_Mode_-_Select_-_TypeScript.gif b/assets/examples/Block_Mode_-_Select_-_TypeScript.gif
index cb07900a..a56490b0 100644
Binary files a/assets/examples/Block_Mode_-_Select_-_TypeScript.gif and b/assets/examples/Block_Mode_-_Select_-_TypeScript.gif differ
diff --git a/assets/examples/Block_Mode_-_Select_-_TypeScript_-_Selection_expands_to_block.gif b/assets/examples/Block_Mode_-_Select_-_TypeScript_-_Selection_expands_to_block.gif
index 1e7a0c1c..629f52ff 100644
Binary files a/assets/examples/Block_Mode_-_Select_-_TypeScript_-_Selection_expands_to_block.gif and b/assets/examples/Block_Mode_-_Select_-_TypeScript_-_Selection_expands_to_block.gif differ
diff --git a/assets/examples/Tree_Viewer.gif b/assets/examples/Tree_Viewer.gif
index b401f7b3..0cbed331 100644
Binary files a/assets/examples/Tree_Viewer.gif and b/assets/examples/Tree_Viewer.gif differ
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 00000000..1c147d90
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,63 @@
+import { defineConfig, globalIgnores } from "eslint/config";
+import typescriptEslint from "@typescript-eslint/eslint-plugin";
+import tsParser from "@typescript-eslint/parser";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+import js from "@eslint/js";
+import { FlatCompat } from "@eslint/eslintrc";
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+const compat = new FlatCompat({
+ baseDirectory: __dirname,
+ recommendedConfig: js.configs.recommended,
+ allConfig: js.configs.all,
+});
+
+export default defineConfig([
+ globalIgnores(["webview-ui/**/*", "**/.eslintrc.js"]),
+ {
+ extends: compat.extends(
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:@typescript-eslint/recommended-requiring-type-checking",
+ "plugin:@typescript-eslint/strict"
+ ),
+
+ plugins: {
+ "@typescript-eslint": typescriptEslint,
+ },
+
+ languageOptions: {
+ parser: tsParser,
+ ecmaVersion: 2022,
+ sourceType: "commonjs",
+
+ parserOptions: {
+ project: "tsconfig.json",
+ tsconfigRootDir: __dirname,
+ },
+ },
+
+ rules: {
+ "@typescript-eslint/no-unused-vars": [
+ "error",
+ {
+ argsIgnorePattern: "^_.*",
+ varsIgnorePattern: "^_",
+ caughtErrorsIgnorePattern: "^_",
+ },
+ ],
+
+ "@typescript-eslint/naming-convention": "warn",
+ "@typescript-eslint/consistent-type-definitions": ["error", "type"],
+ "curly": "warn",
+ "eqeqeq": "warn",
+ "no-throw-literal": "warn",
+ "@typescript-eslint/explicit-function-return-type": "warn",
+ "no-duplicate-imports": "warn",
+ "sort-imports": "warn",
+ "no-trailing-spaces": "warn",
+ },
+ },
+]);
diff --git a/package.json b/package.json
index 7874cf81..85288804 100644
--- a/package.json
+++ b/package.json
@@ -1,392 +1,394 @@
{
- "name": "code-blocks",
- "publisher": "selfint",
- "displayName": "Code Blocks",
- "description": "Move code blocks around",
- "repository": {
- "url": "https://github.com/selfint/code-blocks",
- "type": "git"
- },
- "bugs": {
- "url": "https://github.com/selfint/code-blocks/issues",
- "email": "selfint@gmail.com"
- },
- "homepage": "https://github.com/selfint/code-blocks#readme",
- "icon": "./assets/extension-logo.png",
- "galleryBanner": {
- "color": "#6295E3",
- "theme": "dark"
- },
- "version": "0.7.0",
- "private": true,
- "license": "MIT",
- "engines": {
- "vscode": "^1.79.0"
- },
- "categories": [
- "Visualization",
- "Other"
- ],
- "keywords": [
- "blocks",
- "code-blocks",
- "refactor",
- "tree-sitter",
- "treesitter",
- "visualization"
- ],
- "preview": true,
- "activationEvents": [
- "onLanguage"
- ],
- "main": "./out/extension.js",
- "contributes": {
- "customEditors": [
- {
- "viewType": "codeBlocks.editor",
- "displayName": "Code Blocks",
- "selector": [
- {
- "filenamePattern": "*"
- }
- ],
- "priority": "option"
- }
+ "name": "code-blocks",
+ "publisher": "selfint",
+ "displayName": "Code Blocks",
+ "description": "Move code blocks around",
+ "repository": {
+ "url": "https://github.com/selfint/code-blocks",
+ "type": "git"
+ },
+ "bugs": {
+ "url": "https://github.com/selfint/code-blocks/issues",
+ "email": "selfint@gmail.com"
+ },
+ "homepage": "https://github.com/selfint/code-blocks#readme",
+ "icon": "./assets/extension-logo.png",
+ "galleryBanner": {
+ "color": "#6295E3",
+ "theme": "dark"
+ },
+ "version": "0.8.0",
+ "private": true,
+ "license": "MIT",
+ "engines": {
+ "vscode": "^1.105.0"
+ },
+ "categories": [
+ "Visualization",
+ "Other"
],
- "commands": [
- {
- "command": "codeBlocks.open",
- "title": "Code Blocks: Open active file in Code Blocks editor"
- },
- {
- "command": "codeBlocks.openToTheSide",
- "title": "Code Blocks: Open active file in Code Blocks editor to the side"
- },
- {
- "command": "codeBlocks.toggleActive",
- "title": "Code Blocks: Toggle extension"
- },
- {
- "command": "codeBlocks.toggleBlockMode",
- "title": "Code Blocks: Toggle block mode"
- },
- {
- "command": "codeBlocks.moveUp",
- "title": "Code Blocks: Move selected block up"
- },
- {
- "command": "codeBlocks.moveDown",
- "title": "Code Blocks: Move selected block down"
- },
- {
- "command": "codeBlocks.navigateUp",
- "title": "Code Blocks: Navigate to previous block"
- },
- {
- "command": "codeBlocks.navigateDown",
- "title": "Code Blocks: Navigate to next block"
- },
- {
- "command": "codeBlocks.navigateUpForce",
- "title": "Code Blocks: Force navigate to previous block"
- },
- {
- "command": "codeBlocks.navigateDownForce",
- "title": "Code Blocks: Force navigate to next block"
- },
- {
- "command": "codeBlocks.selectBlock",
- "title": "Code Blocks: Select current block"
- },
- {
- "command": "codeBlocks.openTreeViewer",
- "title": "Code Blocks: Open tree viewer"
- },
- {
- "command": "codeBlocks.selectParent",
- "title": "Code Blocks: Scope selection - parent"
- },
- {
- "command": "codeBlocks.selectChild",
- "title": "Code Blocks: Scope selection - child"
- },
- {
- "command": "codeBlocks.selectNext",
- "title": "Code Blocks: Scope selection - next"
- },
- {
- "command": "codeBlocks.selectPrevious",
- "title": "Code Blocks: Scope selection - previous"
- },
- {
- "command": "codeBlocks.toggleBlockModeColors",
- "title": "Code Blocks: Toggle block mode colors"
- }
+ "keywords": [
+ "blocks",
+ "code-blocks",
+ "refactor",
+ "tree-sitter",
+ "treesitter",
+ "visualization"
],
- "keybindings": [
- {
- "command": "codeBlocks.moveUp",
- "key": "alt+left",
- "when": "editorTextFocus && codeBlocks.blockMode"
- },
- {
- "command": "codeBlocks.moveDown",
- "key": "alt+right",
- "when": "editorTextFocus && codeBlocks.blockMode"
- },
- {
- "command": "codeBlocks.navigateUp",
- "key": "ctrl+left",
- "mac": "cmd+left",
- "when": "editorTextFocus && codeBlocks.blockMode"
- },
- {
- "command": "codeBlocks.navigateDown",
- "key": "ctrl+right",
- "mac": "cmd+right",
- "when": "editorTextFocus && codeBlocks.blockMode"
- },
- {
- "command": "codeBlocks.navigateUpForce",
- "key": "ctrl+up",
- "mac": "cmd+up",
- "when": "editorTextFocus && codeBlocks.blockMode"
- },
- {
- "command": "codeBlocks.navigateDownForce",
- "key": "ctrl+down",
- "mac": "cmd+down",
- "when": "editorTextFocus && codeBlocks.blockMode"
- },
- {
- "command": "codeBlocks.selectNext",
- "key": "shift+right",
- "mac": "shift+right",
- "when": "editorTextFocus && codeBlocks.blockMode"
- },
- {
- "command": "codeBlocks.selectPrevious",
- "key": "shift+left",
- "mac": "shift+left",
- "when": "editorTextFocus && codeBlocks.blockMode"
- },
- {
- "command": "codeBlocks.selectParent",
- "key": "shift+up",
- "mac": "shift+up",
- "when": "editorTextFocus && codeBlocks.blockMode"
- },
- {
- "command": "codeBlocks.selectChild",
- "key": "shift+down",
- "mac": "shift+down",
- "when": "editorTextFocus && codeBlocks.blockMode"
- }
+ "preview": true,
+ "activationEvents": [
+ "onLanguage"
],
- "configuration": {
- "title": "CodeBlocks",
- "properties": {
- "codeBlocks.treeSitterCliPath": {
- "type": "string",
- "markdownDescription": "Path to the `tree-sitter` cli command, defaults to `tree-sitter`.",
- "default": "tree-sitter"
- },
- "codeBlocks.colors.enabled": {
- "type": "boolean",
- "description": "Whether block mode colors are enabled",
- "default": false
- },
- "codeBlocks.colors.sibling": {
- "type": "string",
- "description": "Background color of current block's siblings. Can be any valid css string.",
- "default": "var(--vscode-editor-selectionHighlightBackground)"
- },
- "codeBlocks.colors.parent": {
- "type": "string",
- "description": "Background color of current block's parent (only visible if there's no previous or next sibling). Can be any valid css string.",
- "default": "var(--vscode-editor-linkedEditingBackground)"
- },
- "codeBlocks.ignoredLanguageIds": {
- "type": "array",
- "markdownDescription": "Array of VScode [languageId](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers)s not to install/load parsers for.",
- "default": [
- "plaintext",
- "Log",
- "ignore"
- ]
- },
- "codeBlocks.queries": {
- "type": "array",
- "markdownDescription": "Tree-sitter [queries](https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax) to generate blocks, must contain a `@capture` (note that the entire match will be a block, not just the capture). Specified per [language ID](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers), example: `\"[python]\": {\"codeBlocks.queries\": [ \"(class_definition) @item\", \"(function_definition) @item\", \"(decorated_definition) @item\" ]}`",
- "editPresentation": "multilineText",
- "scope": "language-overridable"
- },
- "codeBlocks.npmPackageName": {
- "markdownDescription": "NPM package name of the tree-sitter grammar to use (defaults to `tree-sitter-`). Specified per [language ID](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers), example: `\"[yaml]\": {\"codeBlocks.npmPackageName\": \"@tree-sitter-grammars/tree-sitter-yaml\"}`.",
- "scope": "language-overridable",
- "type": [
- "string",
- "null"
- ]
- },
- "codeBlocks.parserName": {
- "type": [
- "string",
- "null"
- ],
- "markdownDescription": "Name to save parser as (defaults to `tree-sitter-`). Specified per [language ID](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers), example: `\"[typescriptreact]\": {\"codeBlocks.parserName\": \"tree-sitter-typescript\"}`.",
- "scope": "language-overridable"
+ "main": "./out/extension.js",
+ "contributes": {
+ "customEditors": [
+ {
+ "viewType": "codeBlocks.editor",
+ "displayName": "Code Blocks",
+ "selector": [
+ {
+ "filenamePattern": "*"
+ }
+ ],
+ "priority": "option"
+ }
+ ],
+ "commands": [
+ {
+ "command": "codeBlocks.open",
+ "title": "Code Blocks: Open active file in Code Blocks editor"
+ },
+ {
+ "command": "codeBlocks.openToTheSide",
+ "title": "Code Blocks: Open active file in Code Blocks editor to the side"
+ },
+ {
+ "command": "codeBlocks.toggleActive",
+ "title": "Code Blocks: Toggle extension"
+ },
+ {
+ "command": "codeBlocks.toggleBlockMode",
+ "title": "Code Blocks: Toggle block mode"
+ },
+ {
+ "command": "codeBlocks.moveUp",
+ "title": "Code Blocks: Move selected block up"
+ },
+ {
+ "command": "codeBlocks.moveDown",
+ "title": "Code Blocks: Move selected block down"
+ },
+ {
+ "command": "codeBlocks.navigateUp",
+ "title": "Code Blocks: Navigate to previous block"
+ },
+ {
+ "command": "codeBlocks.navigateDown",
+ "title": "Code Blocks: Navigate to next block"
+ },
+ {
+ "command": "codeBlocks.navigateUpForce",
+ "title": "Code Blocks: Force navigate to previous block"
+ },
+ {
+ "command": "codeBlocks.navigateDownForce",
+ "title": "Code Blocks: Force navigate to next block"
+ },
+ {
+ "command": "codeBlocks.selectBlock",
+ "title": "Code Blocks: Select current block"
+ },
+ {
+ "command": "codeBlocks.openTreeViewer",
+ "title": "Code Blocks: Open tree viewer"
+ },
+ {
+ "command": "codeBlocks.selectParent",
+ "title": "Code Blocks: Scope selection - parent"
+ },
+ {
+ "command": "codeBlocks.selectChild",
+ "title": "Code Blocks: Scope selection - child"
+ },
+ {
+ "command": "codeBlocks.selectNext",
+ "title": "Code Blocks: Scope selection - next"
+ },
+ {
+ "command": "codeBlocks.selectPrevious",
+ "title": "Code Blocks: Scope selection - previous"
+ },
+ {
+ "command": "codeBlocks.toggleBlockModeColors",
+ "title": "Code Blocks: Toggle block mode colors"
+ }
+ ],
+ "keybindings": [
+ {
+ "command": "codeBlocks.moveUp",
+ "key": "alt+left",
+ "when": "editorTextFocus && codeBlocks.blockMode"
+ },
+ {
+ "command": "codeBlocks.moveDown",
+ "key": "alt+right",
+ "when": "editorTextFocus && codeBlocks.blockMode"
+ },
+ {
+ "command": "codeBlocks.navigateUp",
+ "key": "ctrl+left",
+ "mac": "cmd+left",
+ "when": "editorTextFocus && codeBlocks.blockMode"
+ },
+ {
+ "command": "codeBlocks.navigateDown",
+ "key": "ctrl+right",
+ "mac": "cmd+right",
+ "when": "editorTextFocus && codeBlocks.blockMode"
+ },
+ {
+ "command": "codeBlocks.navigateUpForce",
+ "key": "ctrl+up",
+ "mac": "cmd+up",
+ "when": "editorTextFocus && codeBlocks.blockMode"
+ },
+ {
+ "command": "codeBlocks.navigateDownForce",
+ "key": "ctrl+down",
+ "mac": "cmd+down",
+ "when": "editorTextFocus && codeBlocks.blockMode"
+ },
+ {
+ "command": "codeBlocks.selectNext",
+ "key": "shift+right",
+ "mac": "shift+right",
+ "when": "editorTextFocus && codeBlocks.blockMode"
+ },
+ {
+ "command": "codeBlocks.selectPrevious",
+ "key": "shift+left",
+ "mac": "shift+left",
+ "when": "editorTextFocus && codeBlocks.blockMode"
+ },
+ {
+ "command": "codeBlocks.selectParent",
+ "key": "shift+up",
+ "mac": "shift+up",
+ "when": "editorTextFocus && codeBlocks.blockMode"
+ },
+ {
+ "command": "codeBlocks.selectChild",
+ "key": "shift+down",
+ "mac": "shift+down",
+ "when": "editorTextFocus && codeBlocks.blockMode"
+ }
+ ],
+ "configuration": {
+ "title": "CodeBlocks",
+ "properties": {
+ "codeBlocks.colors.enabled": {
+ "type": "boolean",
+ "description": "Whether block mode colors are enabled",
+ "default": false
+ },
+ "codeBlocks.colors.sibling": {
+ "type": "string",
+ "description": "Background color of current block's siblings. Can be any valid css string.",
+ "default": "var(--vscode-editor-selectionHighlightBackground)"
+ },
+ "codeBlocks.colors.parent": {
+ "type": "string",
+ "description": "Background color of current block's parent (only visible if there's no previous or next sibling). Can be any valid css string.",
+ "default": "var(--vscode-editor-linkedEditingBackground)"
+ },
+ "codeBlocks.ignoredLanguageIds": {
+ "type": "array",
+ "markdownDescription": "Array of VScode [languageId](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers)s not to install/load parsers for.",
+ "default": [
+ "plaintext",
+ "Log",
+ "ignore"
+ ]
+ },
+ "codeBlocks.queries": {
+ "type": "array",
+ "markdownDescription": "Tree-sitter [queries](https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax) to generate blocks, must contain a `@capture` (note that the entire match will be a block, not just the capture). Specified per [language ID](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers), example: `\"[python]\": {\"codeBlocks.queries\": [ \"(class_definition) @item\", \"(function_definition) @item\", \"(decorated_definition) @item\" ]}`",
+ "editPresentation": "multilineText",
+ "scope": "language-overridable"
+ },
+ "codeBlocks.npmPackageName": {
+ "markdownDescription": "NPM package name of the tree-sitter grammar to use (defaults to `tree-sitter-`). Specified per [language ID](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers), example: `\"[yaml]\": {\"codeBlocks.npmPackageName\": \"@tree-sitter-grammars/tree-sitter-yaml\"}`.",
+ "scope": "language-overridable",
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "codeBlocks.parserName": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "markdownDescription": "Name to save parser as (defaults to `tree-sitter-`). Specified per [language ID](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers), example: `\"[typescriptreact]\": {\"codeBlocks.parserName\": \"tree-sitter-typescript\"}`.",
+ "scope": "language-overridable"
+ },
+ "codeBlocks.subdirectory": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "markdownDescription": "Name of the subdirectory containing the tree-sitter grammar inside the npm package (leave empty to use the root directory). Use when an npm package contains multiple grammars. Specified per [language ID](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers), example: `\"[typescript]\": {\"codeBlocks.subdirectory\": \"typescript\"}`.",
+ "scope": "language-overridable"
+ }
+ }
},
- "codeBlocks.subdirectory": {
- "type": [
- "string",
- "null"
- ],
- "markdownDescription": "Name of the subdirectory containing the tree-sitter grammar inside the npm package (leave empty to use the root directory). Use when an npm package contains multiple grammars. Specified per [language ID](https://code.visualstudio.com/docs/languages/identifiers#_known-language-identifiers), example: `\"[typescript]\": {\"codeBlocks.subdirectory\": \"typescript\"}`.",
- "scope": "language-overridable"
+ "configurationDefaults": {
+ "[github-actions-workflow]": {
+ "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-yaml",
+ "codeBlocks.parserName": "tree-sitter-yaml"
+ },
+ "[jsonc]": {
+ "codeBlocks.npmPackageName": "tree-sitter-json"
+ },
+ "[zig]": {
+ "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-zig"
+ },
+ "[kotlin]": {
+ "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-kotlin"
+ },
+ "[yaml]": {
+ "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-yaml"
+ },
+ "[toml]": {
+ "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-toml"
+ },
+ "[xml]": {
+ "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-xml",
+ "codeBlocks.subdirectory": "xml"
+ },
+ "[markdown]": {
+ "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-markdown"
+ },
+ "[shellscript]": {
+ "codeBlocks.npmPackageName": "tree-sitter-bash",
+ "codeBlocks.parserName": "tree-sitter-bash"
+ },
+ "[rust]": {
+ "codeBlocks.queries": [
+ "(([ (attribute_item) (line_comment) ] @header . [ (attribute_item) (line_comment) ]* @header )? . (function_item) @item)",
+ "(([ (attribute_item) (line_comment) ] @header . [ (attribute_item) (line_comment) ]* @header )? . (mod_item) @item)",
+ "(([ (attribute_item) (line_comment) ] @header . [ (attribute_item) (line_comment) ]* @header )? . (struct_item) @item)",
+ "(([ (attribute_item) (line_comment) ] @header . [ (attribute_item) (line_comment) ]* @header )? . (impl_item) @item)",
+ "(([ (attribute_item) (line_comment) ] @header . [ (attribute_item) (line_comment) ]* @header )? . (enum_item) @item)",
+ "(([ (attribute_item) (line_comment) ] @header . [ (attribute_item) (line_comment) ]* @header )? . (field_declaration) @item)",
+ "(match_arm) @arm"
+ ]
+ },
+ "[typescript]": {
+ "codeBlocks.subdirectory": "typescript",
+ "codeBlocks.queries": [
+ "( (comment)* @header . (class_declaration) @item)",
+ "( (comment)* @header . (method_definition) @item)",
+ "( (comment)* @header . (function_declaration) @item)",
+ "( (comment)* @header . (export_statement) @item)"
+ ]
+ },
+ "[typescriptreact]": {
+ "codeBlocks.npmPackageName": "tree-sitter-typescript",
+ "codeBlocks.parserName": "tree-sitter-typescript",
+ "codeBlocks.subdirectory": "tsx",
+ "codeBlocks.queries": [
+ "( (comment)* @header . (class_declaration) @item)",
+ "( (comment)* @header . (method_definition) @item)",
+ "( (comment)* @header . (function_declaration) @item)",
+ "( (comment)* @header . (export_statement) @item)",
+ "(jsx_element) @item",
+ "(jsx_self_closing_element) @item"
+ ]
+ },
+ "[javascriptreact]": {
+ "codeBlocks.npmPackageName": "tree-sitter-javascript",
+ "codeBlocks.parserName": "tree-sitter-javascript",
+ "codeBlocks.queries": [
+ "( (comment)* @header . (class_declaration) @item)",
+ "( (comment)* @header . (method_definition) @item)",
+ "( (comment)* @header . (function_declaration) @item)",
+ "( (comment)* @header . (export_statement) @item)",
+ "(jsx_element) @item",
+ "(jsx_self_closing_element) @item"
+ ]
+ },
+ "[svelte]": {
+ "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-svelte",
+ "codeBlocks.queries": [
+ "( (comment)* @header . (element) @item)",
+ "( (comment)* @header . (each_statement) @item)",
+ "( (comment)* @header . (if_statement) @item)",
+ "( (comment)* @header . (style_element) @item)",
+ "( (comment)* @header . (script_element) @item)"
+ ]
+ },
+ "[python]": {
+ "codeBlocks.queries": [
+ "(class_definition) @item",
+ "(function_definition) @item",
+ "(decorated_definition) @item"
+ ]
+ },
+ "[java]": {
+ "codeBlocks.queries": [
+ "( (block_comment)* @header . (class_declaration) @item)",
+ "( (block_comment)* @header . (method_declaration) @item)"
+ ]
+ },
+ "[csharp]": {
+ "codeBlocks.npmPackageName": "tree-sitter-c-sharp",
+ "codeBlocks.parserName": "tree-sitter-c_sharp"
+ },
+ "[latex]": {
+ "codeBlocks.npmPackageName": "@pfoerster/tree-sitter-latex"
+ },
+ "[sql]": {
+ "codeBlocks.npmPackageName": "@derekstride/tree-sitter-sql"
+ }
}
- }
},
- "configurationDefaults": {
- "[github-actions-workflow]": {
- "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-yaml",
- "codeBlocks.parserName": "tree-sitter-yaml"
- },
- "[jsonc]": {
- "codeBlocks.npmPackageName": "tree-sitter-json"
- },
- "[zig]": {
- "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-zig"
- },
- "[kotlin]": {
- "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-kotlin"
- },
- "[yaml]": {
- "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-yaml"
- },
- "[toml]": {
- "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-toml"
- },
- "[xml]": {
- "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-xml",
- "codeBlocks.subdirectory": "xml"
- },
- "[markdown]": {
- "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-markdown"
- },
- "[shellscript]": {
- "codeBlocks.npmPackageName": "tree-sitter-bash",
- "codeBlocks.parserName": "tree-sitter-bash"
- },
- "[rust]": {
- "codeBlocks.queries": [
- "(([ (attribute_item) (line_comment) ] @header . [ (attribute_item) (line_comment) ]* @header )? . (function_item) @item)",
- "(([ (attribute_item) (line_comment) ] @header . [ (attribute_item) (line_comment) ]* @header )? . (mod_item) @item)",
- "(([ (attribute_item) (line_comment) ] @header . [ (attribute_item) (line_comment) ]* @header )? . (struct_item) @item)",
- "(([ (attribute_item) (line_comment) ] @header . [ (attribute_item) (line_comment) ]* @header )? . (impl_item) @item)",
- "(([ (attribute_item) (line_comment) ] @header . [ (attribute_item) (line_comment) ]* @header )? . (enum_item) @item)",
- "(([ (attribute_item) (line_comment) ] @header . [ (attribute_item) (line_comment) ]* @header )? . (field_declaration) @item)",
- "(match_arm) @arm"
- ]
- },
- "[typescript]": {
- "codeBlocks.subdirectory": "typescript",
- "codeBlocks.queries": [
- "( (comment)* @header . (class_declaration) @item)",
- "( (comment)* @header . (method_definition) @item)",
- "( (comment)* @header . (function_declaration) @item)",
- "( (comment)* @header . (export_statement) @item)"
- ]
- },
- "[typescriptreact]": {
- "codeBlocks.npmPackageName": "tree-sitter-typescript",
- "codeBlocks.parserName": "tree-sitter-typescript",
- "codeBlocks.subdirectory": "tsx",
- "codeBlocks.queries": [
- "( (comment)* @header . (class_declaration) @item)",
- "( (comment)* @header . (method_definition) @item)",
- "( (comment)* @header . (function_declaration) @item)",
- "( (comment)* @header . (export_statement) @item)",
- "(jsx_element) @item",
- "(jsx_self_closing_element) @item"
- ]
- },
- "[javascriptreact]": {
- "codeBlocks.npmPackageName": "tree-sitter-javascript",
- "codeBlocks.parserName": "tree-sitter-javascript",
- "codeBlocks.queries": [
- "( (comment)* @header . (class_declaration) @item)",
- "( (comment)* @header . (method_definition) @item)",
- "( (comment)* @header . (function_declaration) @item)",
- "( (comment)* @header . (export_statement) @item)",
- "(jsx_element) @item",
- "(jsx_self_closing_element) @item"
- ]
- },
- "[svelte]": {
- "codeBlocks.npmPackageName": "@tree-sitter-grammars/tree-sitter-svelte",
- "codeBlocks.queries": [
- "( (comment)* @header . (element) @item)",
- "( (comment)* @header . (each_statement) @item)",
- "( (comment)* @header . (if_statement) @item)",
- "( (comment)* @header . (style_element) @item)",
- "( (comment)* @header . (script_element) @item)"
- ]
- },
- "[python]": {
- "codeBlocks.queries": [
- "(class_definition) @item",
- "(function_definition) @item",
- "(decorated_definition) @item"
- ]
- },
- "[java]": {
- "codeBlocks.queries": [
- "( (block_comment)* @header . (class_declaration) @item)",
- "( (block_comment)* @header . (method_declaration) @item)"
- ]
- },
- "[csharp]": {
- "codeBlocks.npmPackageName": "tree-sitter-c-sharp",
- "codeBlocks.parserName": "tree-sitter-c_sharp"
- }
+ "scripts": {
+ "install:all": "yarn install --frozen-lockfile && cd webview-ui && yarn install --frozen-lockfile",
+ "start:webview": "cd webview-ui && yarn run dev",
+ "build:webview": "cd webview-ui && yarn run build && yarn run check",
+ "vscode:prepublish": "yarn run esbuild-base --minify",
+ "compile": "tsc -p ./",
+ "watch": "tsc -watch -p ./",
+ "pretest": "yarn run compile && yarn run lint",
+ "test": "node ./out/test/runTest.js",
+ "esbuild-base": "esbuild ./src/extension.ts --bundle --outfile=out/extension.js --external:vscode --external:tree-sitter --format=cjs --platform=node",
+ "esbuild": "yarn run esbuild-base --sourcemap",
+ "esbuild-watch": "yarn run esbuild-base --sourcemap --watch",
+ "lint": "tsc --noEmit && eslint src --ext ts"
+ },
+ "devDependencies": {
+ "@types/chai": "5.2.3",
+ "@types/glob": "8.1.0",
+ "@types/mocha": "10.0.10",
+ "@types/node": "24.9.2",
+ "@types/tar": "6.1.13",
+ "@types/vscode": "1.105.0",
+ "@types/which": "3.0.4",
+ "@typescript-eslint/eslint-plugin": "8.46.2",
+ "@typescript-eslint/parser": "8.46.2",
+ "@vscode/test-electron": "2.5.2",
+ "chai": "6.2.0",
+ "esbuild": "0.25.11",
+ "eslint": "9.38.0",
+ "glob": "11.0.3",
+ "mocha": "11.7.4",
+ "typescript": "5.9.3",
+ "typescript-eslint": "8.46.2"
+ },
+ "dependencies": {
+ "tar": "7.5.2",
+ "tree-sitter": "0.25.0",
+ "which": "5.0.0"
}
- },
- "scripts": {
- "install:all": "yarn install --frozen-lockfile && cd webview-ui && yarn install --frozen-lockfile",
- "start:webview": "cd webview-ui && yarn run dev",
- "build:webview": "cd webview-ui && yarn run build && yarn run check",
- "vscode:prepublish": "yarn run esbuild-base --minify",
- "compile": "tsc -p ./",
- "watch": "tsc -watch -p ./",
- "pretest": "yarn run compile && yarn run lint",
- "test": "node ./out/test/runTest.js",
- "esbuild-base": "esbuild ./src/extension.ts --bundle --outfile=out/extension.js --external:vscode --external:tree-sitter --format=cjs --platform=node",
- "esbuild": "yarn run esbuild-base --sourcemap",
- "esbuild-watch": "yarn run esbuild-base --sourcemap --watch",
- "lint": "tsc --noEmit && eslint src --ext ts"
- },
- "devDependencies": {
- "@types/chai": "5.2.3",
- "@types/glob": "8.0.1",
- "@types/mocha": "10.0.10",
- "@types/node": "24.9.2",
- "@types/tar": "6.1.13",
- "@types/vscode": "1.105.0",
- "@types/which": "3.0.4",
- "@typescript-eslint/eslint-plugin": "^5.49.0",
- "@typescript-eslint/parser": "^5.49.0",
- "@vscode/test-electron": "2.5.2",
- "chai": "6.2.0",
- "esbuild": "0.25.11",
- "eslint": "^8.44.0",
- "glob": "8.1.0",
- "mocha": "11.7.4",
- "typescript": "5.9.3"
- },
- "dependencies": {
- "tar": "7.5.2",
- "tree-sitter": "0.25.0",
- "which": "5.0.0"
- }
}
diff --git a/src/BlockMode.ts b/src/BlockMode.ts
index 7d7b545e..37521bf1 100644
--- a/src/BlockMode.ts
+++ b/src/BlockMode.ts
@@ -390,7 +390,12 @@ export function activate(): vscode.Disposable[] {
await vscode.commands.executeCommand("setContext", "codeBlocks.blockMode", active);
}),
blockModeActive.onDidChange((active) => {
- active ? statusBar.show() : statusBar.hide();
+ if (active) {
+ statusBar.show();
+ } else {
+ statusBar.hide();
+ }
+
resetDecorations();
if (vscode.window.activeTextEditor !== undefined) {
diff --git a/src/FileTree.ts b/src/FileTree.ts
index b65e0912..648bbb6c 100644
--- a/src/FileTree.ts
+++ b/src/FileTree.ts
@@ -1,10 +1,9 @@
import * as vscode from "vscode";
import { Block, getQueryBlocks } from "./BlockTree";
-import Parser, { Query, SyntaxNode, Tree } from "tree-sitter";
+import Parser, { type Language, Query, SyntaxNode, Tree } from "tree-sitter";
import { Result, err, ok } from "./result";
-import { Language } from "./Installer";
import { Selection } from "./Selection";
import { getLanguageConfig } from "./configuration";
import { getLogger } from "./outputChannel";
@@ -78,7 +77,6 @@ export class FileTree implements vscode.Disposable {
logger.log(
`Setting language for parser, language !== undefined = ${JSON.stringify(
// sanity check
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
language !== undefined
)}`
);
diff --git a/src/Installer.ts b/src/Installer.ts
index 13d14cb0..9f8bfd0b 100644
--- a/src/Installer.ts
+++ b/src/Installer.ts
@@ -5,47 +5,40 @@ import * as vscode from "vscode";
import { ExecException, ExecOptions, exec } from "child_process";
import { Result, err, ok } from "./result";
import { existsSync, rmSync } from "fs";
-import Parser from "tree-sitter";
+import type { Language } from "tree-sitter";
import { getLogger } from "./outputChannel";
import { mkdir } from "fs/promises";
+import { pathToFileURL } from "node:url";
import which from "which";
const NPM_INSTALL_URL = "https://nodejs.org/en/download";
-export type Language = Parser.Language;
-
export function getAbsoluteParserDir(parsersDir: string, parserName: string): string {
return path.resolve(path.join(parsersDir, parserName));
}
-export function getAbsoluteBindingsDir(parsersDir: string, parserName: string): string {
+export function getAbsoluteBindingsPath(parsersDir: string, parserName: string): string {
return path.resolve(path.join(parsersDir, parserName, "bindings", "node", "index.js"));
}
-export function loadParser(
+export async function loadParser(
parsersDir: string,
parserName: string,
subdirectory?: string
-): Result {
+): Promise> {
const logger = getLogger();
- const bindingsDir = getAbsoluteBindingsDir(parsersDir, parserName);
- if (!existsSync(bindingsDir)) {
- const msg = `Expected parser directory doesn't exist: ${bindingsDir}`;
+ const bindingsPath = getAbsoluteBindingsPath(parsersDir, parserName);
+ if (!existsSync(bindingsPath)) {
+ const msg = `Expected parser bindings don't exist: ${bindingsPath}`;
logger.log(msg);
return err(msg);
}
try {
- logger.log(`Loading parser from ${bindingsDir}`);
-
- // using dynamic import causes issues on windows
- // make sure to test well on windows before changing this
- // TODO(02/11/24): change to dynamic import
- // let { default: language } = (await import(bindingsDir)) as { default: Language };
+ logger.log(`Loading parser from ${bindingsPath}`);
- // eslint-disable-next-line @typescript-eslint/no-var-requires
- let language = require(bindingsDir) as Language;
+ let language = ((await import(pathToFileURL(bindingsPath).href)) as { default: Language }).default;
logger.log(`Got language: ${JSON.stringify(Object.keys(language))}`);
@@ -58,9 +51,11 @@ export function loadParser(
}
return ok(language);
- } catch (error) {
- logger.log(`Failed to load ${bindingsDir} > ${JSON.stringify(error)}`);
- return err(`Failed to load ${bindingsDir} > ${JSON.stringify(error)}`);
+ } catch (error: unknown) {
+ const msg = error instanceof Error ? `${error.name}: ${error.message}` : JSON.stringify(error);
+
+ logger.log(`Failed to load ${bindingsPath} > ${msg}`);
+ return err(`Failed to load ${bindingsPath} > ${msg}`);
}
}
@@ -69,7 +64,7 @@ export async function downloadAndBuildParser(
parserNpmPackage: string,
parserName: string,
npm: string,
- treeSitterCli: string,
+ rebuild: boolean = false,
onData?: (data: string) => void
): Promise> {
const logger = getLogger();
@@ -118,31 +113,24 @@ export async function downloadAndBuildParser(
}
// try to load parser optimistically
- const loadResult = loadParser(parsersDir, parserName);
- if (loadResult.status === "ok") {
- return ok(undefined);
- }
-
- logger.log(`Optimistic load failed, trying to build parser ${parserName}`);
- const treeSitterCliOk = await runCmd(`${treeSitterCli} --version`);
- if (treeSitterCliOk.status === "err") {
- const msg =
- `Parser ${parserName} requires local build, but
- tree-sitter cli command '${treeSitterCli}' failed:
- ${treeSitterCliOk.result[0].name} ${treeSitterCliOk.result[0].message.replace(/\n/g, " > ")}.` +
- (treeSitterCliOk.result[1].length > 1 ? ` Logs: ${treeSitterCliOk.result[1].join(">")}` : "");
-
- logger.log(msg);
- return err(msg);
+ if (!rebuild) {
+ const loadResult = await loadParser(parsersDir, parserName);
+ if (loadResult.status === "ok") {
+ return ok(undefined);
+ }
+ logger.log(`Optimistic load failed for parser ${parserName}`);
}
// if it fails, try to build it
- const buildResult = await runCmd(`${treeSitterCli} generate`, { cwd: parserDir }, (d) =>
- onData?.(d.toString())
+ logger.log(`Building parser ${parserName}`);
+ const buildResult = await runCmd(
+ `${npm} exec --yes --loglevel silly --prefix ${parsersDir} node-gyp rebuild --target=${process.versions.electron} --dist-url=https://electronjs.org/headers --runtime=electron`,
+ { cwd: parserDir },
+ (d) => onData?.(d.toString())
);
if (buildResult.status === "err") {
const msg =
- "Failed to build parser using tree-sitter cli > " +
+ "Failed to build parser > " +
buildResult.result[0].name +
": " +
buildResult.result[0].message.replace(/\n/g, " > ") +
@@ -192,7 +180,8 @@ export type GetLanguageError = {
export async function getLanguage(
parsersDir: string,
languageId: string,
- autoInstall = false
+ autoInstall = false,
+ rebuild = false
): Promise> {
const logger = getLogger();
@@ -206,7 +195,6 @@ export async function getLanguage(
const parserPackagePath = getAbsoluteParserDir(parsersDir, parserName);
const npm = "npm";
- const treeSitterCli = configuration.getTreeSitterCliPath();
if (!existsSync(parserPackagePath)) {
const doInstall = autoInstall
@@ -246,7 +234,6 @@ export async function getLanguage(
return ok(undefined);
}
- let number = 0;
const downloadResult = await vscode.window.withProgress(
{
location: vscode.ProgressLocation.Notification,
@@ -259,8 +246,8 @@ export async function getLanguage(
npmPackageName,
parserName,
npm,
- treeSitterCli,
- (data) => progress.report({ message: data, increment: number++ })
+ rebuild,
+ (data) => progress.report({ message: data })
);
}
);
@@ -273,7 +260,7 @@ export async function getLanguage(
}
}
- const loadResult = loadParser(parsersDir, parserName, subdirectory);
+ const loadResult = await loadParser(parsersDir, parserName, subdirectory);
if (loadResult.status === "err") {
const msg = `Failed to load parser for language ${languageId} > ${loadResult.result}`;
diff --git a/src/configuration.ts b/src/configuration.ts
index 291566d4..977d11ed 100644
--- a/src/configuration.ts
+++ b/src/configuration.ts
@@ -57,11 +57,3 @@ export function getColorConfig(): ColorConfig {
parentColor: colorConfig?.parentColor ?? defaultParentColor,
};
}
-
-export function getTreeSitterCliPath(): string {
- const treeSitterCliPath = vscode.workspace
- .getConfiguration("codeBlocks")
- .get("treeSitterCliPath");
-
- return treeSitterCliPath ?? "tree-sitter";
-}
diff --git a/src/examples/exampleUtils.ts b/src/examples/exampleUtils.ts
index 6de95fbd..b5c89552 100644
--- a/src/examples/exampleUtils.ts
+++ b/src/examples/exampleUtils.ts
@@ -2,25 +2,18 @@ import * as vscode from "vscode";
import { BlockMode, active, activeFileTree } from "../extension";
import { FileTree } from "../FileTree";
import { expect } from "chai";
-import { join } from "path";
-
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-import settings from "./examples-editor/.vscode/settings.json";
const TEST_START_SIGNAL = "@";
export async function initExample(): Promise {
- const exampleEditorPath = join(__dirname, "examples-editor");
await cmd("workbench.action.toggleLightDarkThemes");
- await cmd("vscode.openFolder", vscode.Uri.file(exampleEditorPath), {
- forceNewWindow: false,
- });
+ await cmd("workbench.action.toggleAuxiliaryBar");
await cmd("notifications.clearAll");
await sleep(100);
await cmd("notifications.clearAll");
}
export async function cmd(c: string, ...args: unknown[]): Promise {
- await vscode.commands.executeCommand(c, ...args);
+ return await vscode.commands.executeCommand(c, ...args);
}
export function zoomOut(): void {
@@ -42,14 +35,23 @@ export async function type(
): Promise {
const chars = text.split("");
const document = editor.document;
+
let target = position;
let offset = document.offsetAt(position);
for (const char of chars) {
const edit = new vscode.WorkspaceEdit();
edit.insert(document.uri, target, char);
+
editor.selection = new vscode.Selection(target, target);
await vscode.workspace.applyEdit(edit);
- const noise = Math.random() * (delay / 2) - delay / 4;
+
+ let noise = Math.random() * (delay / 2) - delay / 4;
+ if (char === " ") {
+ noise += delay;
+ } else if ("()[]{}:\"'".includes(char)) {
+ noise += delay * 1.5;
+ }
+
await sleep(delay + noise);
offset++;
target = document.positionAt(offset);
@@ -83,7 +85,11 @@ export async function openDocument({
content,
maximize = true,
cursor = undefined,
-}: OpenDocumentParams): Promise<{ activeEditor: vscode.TextEditor; fileTree: FileTree; realContent: string }> {
+}: OpenDocumentParams): Promise<{
+ activeEditor: vscode.TextEditor;
+ fileTree: FileTree;
+ realContent: string;
+}> {
if (!active.get()) {
active.set(true);
}
@@ -92,12 +98,14 @@ export async function openDocument({
BlockMode.toggleBlockMode();
}
- let cursorIndex = -1;
+ const selections = [];
if (cursor !== undefined) {
- cursorIndex = content.indexOf(cursor);
- expect(cursorIndex).not.to.equal(-1, `failed to find cursor '${cursor}' in content:\n${content}`);
-
- content = content.replace(cursor, "");
+ let cursorIndex = content.indexOf(cursor);
+ while (cursorIndex > -1) {
+ content = content.replace(cursor, "");
+ selections.push(cursorIndex);
+ cursorIndex = content.indexOf(cursor);
+ }
}
const activeEditor = await vscode.window.showTextDocument(
@@ -107,15 +115,19 @@ export async function openDocument({
})
);
- if (cursorIndex !== -1) {
- activeEditor.selection = new vscode.Selection(
- activeEditor.document.positionAt(cursorIndex),
- activeEditor.document.positionAt(cursorIndex)
+ if (selections.length > 0) {
+ activeEditor.selections = selections.map(
+ (cursorIndex) =>
+ new vscode.Selection(
+ activeEditor.document.positionAt(cursorIndex),
+ activeEditor.document.positionAt(cursorIndex)
+ )
);
}
if (maximize) {
- await vscode.commands.executeCommand("workbench.action.maximizeEditor");
+ await cmd("workbench.action.minimizeOtherEditors");
+ await cmd("workbench.action.closeSidebar");
}
let fileTree = activeFileTree.get();
@@ -144,7 +156,7 @@ export type TestSelectionCommandsParams = {
content: string;
cursor: string;
selectionCommands: SelectionCommand[];
- expectedSelectionContent: string;
+ expectedSelectionContent: string | string[];
pause: number;
};
@@ -156,6 +168,10 @@ export async function selectionExample({
language,
pause,
}: TestSelectionCommandsParams): Promise {
+ if (typeof expectedSelectionContent === "string") {
+ expectedSelectionContent = [expectedSelectionContent];
+ }
+
await initExample();
const { activeEditor } = await openDocument({
@@ -176,18 +192,19 @@ export async function selectionExample({
await sleep(pause);
}
- const selectionContent = activeEditor.document.getText(activeEditor.selection);
+ const selectionContent = activeEditor.selections
+ .map((s) => activeEditor.document.getText(s))
+ .join("\n--\n");
+
expect(selectionContent).to.equal(
- expectedSelectionContent,
+ expectedSelectionContent.join("\n--\n"),
"selection commands didn't produce desired selection"
);
return activeEditor;
}
-export type MoveCommand =
- | "codeBlocks.moveDown"
- | "codeBlocks.moveUp";
+export type MoveCommand = "codeBlocks.moveDown" | "codeBlocks.moveUp";
export type TestMoveCommandsParams = {
language: SupportedTestLanguages;
@@ -196,7 +213,7 @@ export type TestMoveCommandsParams = {
selectionCommands: SelectionCommand[];
selectionMessage: string;
moveCommands: MoveCommand[];
- expectedSelectionContent: string;
+ expectedSelectionContent: string | string[];
expectedContent: string;
pause: number;
};
@@ -211,6 +228,10 @@ export async function moveExample({
expectedContent,
pause,
}: TestMoveCommandsParams): Promise {
+ if (typeof expectedSelectionContent === "string") {
+ expectedSelectionContent = [expectedSelectionContent];
+ }
+
await initExample();
const { activeEditor } = await openDocument({
@@ -234,9 +255,12 @@ export async function moveExample({
await sleep(pause);
- const selectionContent = activeEditor.document.getText(activeEditor.selection);
+ const selectionContent = activeEditor.selections
+ .map((s) => activeEditor.document.getText(s))
+ .join("\n--\n");
+
expect(selectionContent).to.equal(
- expectedSelectionContent,
+ expectedSelectionContent.join("\n--\n"),
"selection commands didn't produce desired selection"
);
@@ -248,11 +272,13 @@ export async function moveExample({
}
const newContent = activeEditor.document.getText();
- const newSelectionContent = activeEditor.document.getText(activeEditor.selection);
+ const newSelectionContent = activeEditor.selections
+ .map((s) => activeEditor.document.getText(s))
+ .join("\n--\n");
expect(newContent).to.equal(expectedContent, "move command didn't produce desired content");
expect(newSelectionContent).to.equal(
- expectedSelectionContent,
+ expectedSelectionContent.join("\n--\n"),
"move command didn't preserve selection content"
);
}
@@ -293,13 +319,15 @@ export async function testNavigateCommands({
expect(newCursorIndex).to.equal(
expectedNavigationDestinationIndex,
"navigation commands didn't arrive to expected destination" +
- `\n\tactual: ${cleanContent.substring(0, newCursorIndex) +
- targetCursor +
- cleanContent.substring(newCursorIndex)
- }` +
- `\n\texpect: ${cleanContent.substring(0, expectedNavigationDestinationIndex) +
- targetCursor +
- cleanContent.substring(expectedNavigationDestinationIndex)
- }\n`
+ `\n\tactual: ${
+ cleanContent.substring(0, newCursorIndex) +
+ targetCursor +
+ cleanContent.substring(newCursorIndex)
+ }` +
+ `\n\texpect: ${
+ cleanContent.substring(0, expectedNavigationDestinationIndex) +
+ targetCursor +
+ cleanContent.substring(expectedNavigationDestinationIndex)
+ }\n`
);
}
diff --git a/src/examples/runExample.ts b/src/examples/runExample.ts
index 42172940..6ee7ed24 100644
--- a/src/examples/runExample.ts
+++ b/src/examples/runExample.ts
@@ -2,6 +2,10 @@ import * as path from "path";
import { runTests } from "@vscode/test-electron";
+// ensure settings.json gets copied to build directory
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+import settings from "./examples-editor/.vscode/settings.json";
+
async function main(): Promise {
try {
// The folder containing the Extension Manifest package.json
@@ -13,7 +17,11 @@ async function main(): Promise {
const extensionTestsPath = path.resolve(__dirname, `./suite/index`);
// Download VS Code, unzip it and run the integration test
- await runTests({ extensionDevelopmentPath, extensionTestsPath });
+ await runTests({
+ extensionDevelopmentPath,
+ extensionTestsPath,
+ launchArgs: [path.resolve(__dirname, "examples-editor")],
+ });
} catch (err) {
console.error("Failed to run tests", err);
process.exit(1);
diff --git a/src/examples/suite/Block_Mode_-_Move_-_Rust_-_Match_arms.example.ts b/src/examples/suite/Block_Mode_-_Move_-_Rust_-_Match_arms.example.ts
index 64e5bd02..832b9aa0 100644
--- a/src/examples/suite/Block_Mode_-_Move_-_Rust_-_Match_arms.example.ts
+++ b/src/examples/suite/Block_Mode_-_Move_-_Rust_-_Match_arms.example.ts
@@ -4,12 +4,17 @@ const TIMEOUT = process.env.EXAMPLE_TIMEOUT ?? "2m";
test("Block mode 2", async function () {
await moveExample({
language: "rust",
- content: `fn main() {
- match rand::thread_rng().gen_range(0..=3) {
+ content: `\
+fn main() {
+ match rand::thread_rng().gen_range(0..=7) {
0 => println!("hi"),
1 => println!("he@llo"),
2 => println!("howdy"),
- _ => println!("salutations"),
+ 3 => println!("hey"),
+ 4 => println!("hiya"),
+ 5 => println!("he@llo there"),
+ 6 => println!("salutations"),
+ _ => println!("general kenobi"),
}
}`,
cursor: "@",
@@ -17,18 +22,28 @@ test("Block mode 2", async function () {
"codeBlocks.selectParent",
"codeBlocks.selectParent",
"codeBlocks.selectParent",
+ "codeBlocks.selectParent",
"codeBlocks.selectPrevious",
],
selectionMessage: "Select match arms",
moveCommands: ["codeBlocks.moveDown", "codeBlocks.moveDown", "codeBlocks.moveUp"],
- expectedSelectionContent: `0 => println!("hi"),
+ expectedSelectionContent: [
+ `0 => println!("hi"),
1 => println!("hello"),`,
- expectedContent: `fn main() {
- match rand::thread_rng().gen_range(0..=3) {
+ `4 => println!("hiya"),
+ 5 => println!("hello there"),`,
+ ],
+ expectedContent: `\
+fn main() {
+ match rand::thread_rng().gen_range(0..=7) {
2 => println!("howdy"),
0 => println!("hi"),
1 => println!("hello"),
- _ => println!("salutations"),
+ 3 => println!("hey"),
+ 6 => println!("salutations"),
+ 4 => println!("hiya"),
+ 5 => println!("hello there"),
+ _ => println!("general kenobi"),
}
}`,
pause: 1000,
diff --git a/src/examples/suite/Tree_Viewer.example.ts b/src/examples/suite/Tree_Viewer.example.ts
index 5125a615..24a52ee2 100644
--- a/src/examples/suite/Tree_Viewer.example.ts
+++ b/src/examples/suite/Tree_Viewer.example.ts
@@ -44,7 +44,9 @@ source_file [1:0 - 10:0]
struct_item [2:0 - 5:1]
type_identifier [2:7 - 2:8]
field_declaration_list [2:9 - 5:1]
- line_comment [3:4 - 3:18]
+ line_comment [3:4 - 4:0]
+ outer_doc_comment_marker [3:6 - 3:7]
+ doc_comment [3:7 - 4:0]
field_declaration [4:4 - 4:10]
field_identifier [4:4 - 4:5]
primitive_type [4:7 - 4:10]
@@ -60,10 +62,12 @@ source_file [1:0 - 10:0]
await sleep(1500);
const didChange = new Promise((r) => {
- const disposable = vscode.workspace.onDidChangeTextDocument(event => {
+ const disposable = vscode.workspace.onDidChangeTextDocument((event) => {
if (event.document.uri.toString() === treeViewerDocument.uri.toString()) {
- if (event.document.getText() !== TreeViewer.placeholder &&
- !event.document.getText().startsWith("source_file")) {
+ if (
+ event.document.getText() !== TreeViewer.placeholder &&
+ !event.document.getText().startsWith("source_file")
+ ) {
r(disposable);
}
}
diff --git a/src/examples/suite/example.example.ts b/src/examples/suite/example.example.ts
index a8a042d3..96936f20 100644
--- a/src/examples/suite/example.example.ts
+++ b/src/examples/suite/example.example.ts
@@ -1,19 +1,20 @@
import * as vscode from "vscode";
-import { initExample, openDocument, sleep, startRecording } from "../exampleUtils";
+// import { initExample, openDocument, sleep, startRecording } from "../exampleUtils";
+import { initExample, sleep } from "../exampleUtils";
const TIMEOUT = process.env.EXAMPLE_TIMEOUT ?? "20s";
test("Example", async function () {
await initExample();
- startRecording();
+ // startRecording();
void vscode.window.showInformationMessage("Hello world");
await sleep(1500);
- await openDocument({
- language: "rust",
- content: `// hello world
-`,
- maximize: true,
- });
+ // await openDocument({
+ // language: "rust",
+ // content: `// hello world
+ // `,
+ // maximize: true,
+ // });
- await sleep(1500);
+ // await sleep(1500);
}).timeout(TIMEOUT);
diff --git a/src/examples/suite/index.ts b/src/examples/suite/index.ts
index 393c55f4..fcabcb41 100644
--- a/src/examples/suite/index.ts
+++ b/src/examples/suite/index.ts
@@ -1,48 +1,39 @@
import * as path from "path";
import Mocha from "mocha";
-import glob from "glob";
+import { glob } from "glob";
-export function run(): Promise {
- if (process.env.EXAMPLE === undefined) {
+export async function run(): Promise {
+ let example = process.env.EXAMPLE;
+ if (example === undefined) {
console.log("@".repeat(1000));
console.error("No example file specified, set EXAMPLE environ found");
process.exit(1);
}
// change extension to .js
- let example = process.env.EXAMPLE;
- example = example.substring(0, example.length - 2) + "js";
-
- // Create the mocha test
- const mocha = new Mocha({
- ui: "tdd",
- color: true,
- });
+ example = example.slice(0, -2) + "js";
+ const mocha = new Mocha({ ui: "tdd", color: true });
const testsRoot = path.resolve(__dirname, "..");
- return new Promise((c, e) => {
- glob(`suite/${example}`, { cwd: testsRoot }, (err, files) => {
- if (err) {
- return e(err);
- }
+ try {
+ const files = await glob(`suite/${example}`, { cwd: testsRoot });
- // Add files to the test suite
- files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f)));
+ // Add files to the test suite
+ files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f)));
- try {
- // Run the mocha test
- mocha.run((failures) => {
- if (failures > 0) {
- e(new Error(`${failures} tests failed.`));
- } else {
- c();
- }
- });
- } catch (err) {
- console.error(err);
- e(err);
- }
+ await new Promise((resolve, reject) => {
+ // Run the mocha test
+ mocha.run((failures) => {
+ if (failures > 0) {
+ reject(new Error(`${failures} tests failed.`));
+ } else {
+ resolve();
+ }
+ });
});
- });
+ } catch (err) {
+ console.error(err);
+ throw err;
+ }
}
diff --git a/src/test/suite/Installer.test.ts b/src/test/suite/Installer.test.ts
index 0b688c22..00c2ed94 100644
--- a/src/test/suite/Installer.test.ts
+++ b/src/test/suite/Installer.test.ts
@@ -4,10 +4,12 @@ import * as vscode from "vscode";
import Parser from "tree-sitter";
import { TreeViewer } from "../../TreeViewer";
import { openDocument } from "./testUtils";
+import path from "path";
export async function testParser(language: string, content?: string): Promise {
// fail the test if the parser could not be installed
- const result = await Installer.getLanguage("test-parsers", language, true);
+ const testParsersDir = path.resolve(__dirname, "..", "..", "..", "test-parsers");
+ const result = await Installer.getLanguage(testParsersDir, language, true, true);
if (result.status === "err") {
throw new Error(`Failed to install language: ${JSON.stringify(result.result)}`);
}
@@ -25,8 +27,8 @@ export async function testParser(language: string, content?: string): Promise