node-tree-sitter icon indicating copy to clipboard operation
node-tree-sitter copied to clipboard

Can't use in VS Code extension

Open verhovsky opened this issue 1 year ago • 1 comments

node-tree-sitter is broken in a weird way when imported in VS Code. I tried creating a simple VS Code extension that just imports node-tree-sitter like this:

yo code # named it "hellotreesitter", otherwise all defaults
cd hellotreesitter
npm install tree-sitter --save
npm install --save-dev node-gyp electron-rebuild
./node_modules/.bin/electron-rebuild --version 27.2.3 -w tree-sitter

Then I added these lines to the top of src/extension.ts

console.log('import tree-sitter');
import * as Parser from 'tree-sitter';
console.log('tree-sitter imported');

Then I run the extension with F5, then in the new debug VS Code window run Cmd+Shift+P "Hello World". This works, but if I initialize a Parser object

console.log('import tree-sitter');
import * as Parser from 'tree-sitter';
console.log('tree-sitter imported');
const parser = new Parser();
console.log('Parser initialized');

it crashes right away when running "Hello World", and in the console I see "import tree-sitter" but I don't even see "tree-sitter imported".

verhovsky avatar Feb 10 '24 19:02 verhovsky

Hello, verhovsky:

I encountered node-gyp execution errors when installing tree-sitter-java (npm i tree-sitter-java), so I turned to the solution based on WebAssembly.

The steps are as follows:

  1. Install Web Tree-sitter. (npm i web-tree-sitter)
  2. Download the Grammar (mine is tree-sitter-java.wasm) and place it in the resources folder.
  3. The minimal executable extension.ts is as follows:
import { ExtensionContext, Uri } from "vscode";
import Parser from "web-tree-sitter";

export async function activate(context: ExtensionContext) {
  await Parser.init();
  const wasmUri = Uri.joinPath(
    context.extensionUri,
    "./resources/tree-sitter-java.wasm"
  ).fsPath;
  const Java = await Parser.Language.load(wasmUri);
  const javaParser = new Parser();
  javaParser.setLanguage(Java);
  const tree = javaParser.parse(
    "your code..."
  );
}

export function deactivate() {}

tzengshinfu avatar Feb 16 '24 09:02 tzengshinfu

This is fixed with tree-sitter 0.21.0 (and tree-sitter-bash 0.21.0)

verhovsky avatar Mar 21 '24 22:03 verhovsky

I would get a NODE_MODULE_VERSIONS error mismatch, I'm assuming vscode is an electron build and perhaps issues like these would arise.

For example:

Extension compiles

import Parser from 'tree-sitter';
// const Parser = require('tree-sitter');
// const TypeScript = require('tree-sitter-typescript').typescript;

Extension compiles

// import Parser from 'tree-sitter';
const Parser = require('tree-sitter');
// const TypeScript = require('tree-sitter-typescript').typescript;

Extension fails, can't find my activation command for some reason

// import Parser from 'tree-sitter';
const Parser = require('tree-sitter');
const TypeScript = require('tree-sitter-typescript').typescript;

I saw another extension use tree-sitter in vscode, but it's outdated

I explored their code and they also use that web-tree-sitter solution

Their code is 5 years old though. But it seems to imply we cannot use the original tree-sitter npm packages within vscode. I assume because of electron.

Here's that tree-sitter vscode extension I mentioned: https://github.com/georgewfraser/vscode-tree-sitter

jonathanpv avatar Apr 29 '24 20:04 jonathanpv

If basing off of the example above and get an error Argument must be a language it's due to being a promise from the load function so you must either wait or use a .then() statement

For the example above you would need to do

await Parser.Language.load()

or a .then()

since Parser.Language.load is a promise

jonathanpv avatar Apr 29 '24 20:04 jonathanpv