tree-sitter / node-tree-sitter

Node.js bindings for tree-sitter
https://www.npmjs.com/package/tree-sitter
MIT License
649 stars 114 forks source link

Can't use in VS Code extension #189

Closed verhovsky closed 7 months ago

verhovsky commented 9 months ago

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 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 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".

tzengshinfu commented 8 months ago

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() {}

verhovsky commented 7 months ago

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

jonathanpv commented 6 months ago

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 commented 6 months ago

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