Skip to content

Commit 1722660

Browse files
committed
feat: add general tree-sitter parser, and Rust, Python support
1 parent a39a549 commit 1722660

File tree

6 files changed

+117
-42
lines changed

6 files changed

+117
-42
lines changed

app/parser/TreeSitterGui.vue

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<script lang="ts">
2+
import type { TreeSitterOptions } from './tree-sitter'
3+
4+
const useOption = makeUseOption<TreeSitterOptions>()
5+
</script>
6+
7+
<script setup lang="ts">
8+
const wasmUrl = useOption('wasmUrl')
9+
</script>
10+
11+
<template>
12+
<div flex="~ col" gap2 text-sm font-mono>
13+
<label flex flex-col gap1>
14+
<span>WASM:</span>
15+
<textarea
16+
v-model="wasmUrl"
17+
text-md
18+
h-32
19+
border
20+
rounded-md
21+
px1
22+
py0.5
23+
accent-current
24+
/>
25+
</label>
26+
<div text-right>
27+
<a
28+
href="https://github.com/tree-sitter/tree-sitter/wiki/List-of-parsers"
29+
target="_blank"
30+
>
31+
Parser List
32+
</a>
33+
</div>
34+
</div>
35+
</template>
Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import json5 from 'json5'
22
import type { LanguageOption, Parser } from './index'
33

4-
// @unocss-include
5-
6-
const customParser: Parser = {
7-
id: 'custom-parser',
8-
label: 'custom',
9-
icon: 'i-ri:magic-fill',
4+
const jsonAst: Parser = {
5+
id: 'json-ast',
6+
label: 'JSON AST',
7+
// @unocss-include
8+
icon: 'i-ri:braces-line',
109
editorLanguage: 'json',
1110
options: {
1211
configurable: false,
@@ -20,15 +19,14 @@ const customParser: Parser = {
2019
},
2120
}
2221

23-
export const custom: LanguageOption = {
24-
label: 'JSON AST',
25-
icon: 'i-ri:magic-line',
26-
parsers: [customParser],
22+
export const general: LanguageOption = {
23+
label: 'General',
24+
icon: 'i-ri:code-line',
25+
parsers: [jsonAst, treeSitter],
2726
codeTemplate: JSON.stringify(
2827
{
2928
type: 'Program',
30-
body: [],
31-
sourceType: 'module',
29+
body: [{ type: 'ExpressionStatement' }],
3230
},
3331
undefined,
3432
2,

app/parser/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { angular } from './angular'
22
import { astro } from './astro'
33
import { csharp } from './csharp'
44
import { css } from './css'
5-
import { custom } from './custom'
5+
import { general } from './general'
66
import { graphql } from './graphql'
77
import { html } from './html'
88
import { java } from './java'
@@ -116,6 +116,6 @@ export const LANGUAGES = {
116116
wxml,
117117
graphql,
118118
protobuf,
119-
custom,
119+
general,
120120
}
121121
export type Language = keyof typeof LANGUAGES

app/parser/python.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,6 @@ def parse_code(code, options):
9999
export const python: LanguageOption = {
100100
label: 'Python',
101101
icon: 'i-vscode-icons:file-type-python',
102-
parsers: [pyodide],
102+
parsers: [pyodide, treeSitterPython],
103103
codeTemplate: pythonTemplate,
104104
}

app/parser/rust.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,6 @@ const jinxRust: Parser<typeof JinxRust, JinxRust.rs.ParserOptions> = {
8989
export const rust: LanguageOption = {
9090
label: 'Rust',
9191
icon: 'i-vscode-icons:file-type-rust',
92-
parsers: [syn, jinxRust],
92+
parsers: [syn, jinxRust, treeSitterRust],
9393
codeTemplate: rustTemplate,
9494
}

app/parser/tree-sitter.ts

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import type { Parser } from './index'
22
import type * as TreeSitter from 'web-tree-sitter'
33

4-
const common = {
4+
const shared = {
55
options: {
66
configurable: false,
77
defaultValue: {},
88
editorLanguage: 'json',
99
},
10+
icon: 'https://cdn.jsdelivr.net/gh/tree-sitter/tree-sitter/docs/src/assets/images/tree-sitter-small.png',
1011
init: (moduleUrl: string) => initTreeSitterParser(moduleUrl),
1112
parse(this: TreeSitter.Parser, code: string) {
1213
const parsed = this.parse(code)
@@ -15,24 +16,54 @@ const common = {
1516
getNodeLocation: genGetNodeLocation('treeSitter'),
1617
} as const
1718

19+
export interface TreeSitterOptions {
20+
wasmUrl: string
21+
}
22+
23+
export const treeSitter: Parser<void, TreeSitterOptions> = {
24+
id: 'tree-sitter',
25+
label: 'Tree Sitter',
26+
icon: shared.icon,
27+
editorLanguage: 'text',
28+
options: {
29+
configurable: true,
30+
defaultValue: {
31+
wasmUrl: getJsdelivrUrl(
32+
'tree-sitter-javascript',
33+
'/tree-sitter-javascript.wasm',
34+
),
35+
},
36+
editorLanguage: 'json',
37+
},
38+
pkgName: '',
39+
init: () => {},
40+
async parse(code, options) {
41+
if (!options.wasmUrl) {
42+
throw new Error('WASM URL is required in options')
43+
}
44+
45+
const parser = await initTreeSitterParser(options.wasmUrl)
46+
const parsed = parser.parse(code)
47+
return parsed && convertNode(parsed.rootNode)
48+
},
49+
getNodeLocation: shared.getNodeLocation,
50+
gui: () => import('./TreeSitterGui.vue'),
51+
}
52+
1853
export const treeSitterJavascript: Parser<TreeSitter.Parser> = {
19-
...common,
54+
...shared,
2055
id: 'tree-sitter-javascript',
2156
label: 'tree-sitter-javascript',
22-
// @unocss-include
23-
icon: 'i-vscode-icons:file-type-js',
2457
link: 'https://github.com/tree-sitter/tree-sitter-javascript',
2558
editorLanguage: 'javascript',
2659
pkgName: 'tree-sitter-javascript',
2760
getModuleUrl: (pkg) => getJsdelivrUrl(pkg, '/tree-sitter-javascript.wasm'),
2861
}
2962

3063
export const treeSitterTypescript: Parser<TreeSitter.Parser> = {
31-
...common,
64+
...shared,
3265
id: 'tree-sitter-typescript',
3366
label: 'tree-sitter-typescript',
34-
// @unocss-include
35-
icon: 'i-vscode-icons:file-type-typescript',
3667
link: 'https://github.com/tree-sitter/tree-sitter-typescript',
3768
editorLanguage: 'typescript',
3869
pkgName: 'tree-sitter-typescript',
@@ -48,30 +79,36 @@ export const treeSitterTsx: Parser<TreeSitter.Parser> = {
4879
}
4980

5081
export const treeSitterCSharp: Parser<TreeSitter.Parser> = {
82+
...shared,
5183
id: 'tree-sitter-c-sharp',
5284
label: 'tree-sitter',
53-
// @unocss-include
54-
icon: 'i-vscode-icons:file-type-csharp',
5585
link: 'https://github.com/tree-sitter/tree-sitter-c-sharp',
5686
editorLanguage: 'csharp',
57-
options: {
58-
configurable: false,
59-
defaultValue: {},
60-
editorLanguage: 'json',
61-
},
6287
pkgName: 'tree-sitter-c-sharp',
6388
getModuleUrl: (pkg) => getJsdelivrUrl(pkg, '/tree-sitter-c_sharp.wasm'),
64-
init(moduleUrl) {
65-
return initTreeSitterParser(moduleUrl)
66-
},
67-
parse(code) {
68-
const parsed = this.parse(code)
69-
return parsed && convertNode(parsed.rootNode)
70-
},
71-
getNodeLocation: genGetNodeLocation('treeSitter'),
7289
}
7390

74-
export function convertNode(node: TreeSitter.Node): any {
91+
export const treeSitterPython: Parser<TreeSitter.Parser> = {
92+
...shared,
93+
id: 'tree-sitter-python',
94+
label: 'tree-sitter-python',
95+
link: 'https://github.com/tree-sitter/tree-sitter-python',
96+
editorLanguage: 'python',
97+
pkgName: 'tree-sitter-python',
98+
getModuleUrl: (pkg) => getJsdelivrUrl(pkg, '/tree-sitter-python.wasm'),
99+
}
100+
101+
export const treeSitterRust: Parser<TreeSitter.Parser> = {
102+
...shared,
103+
id: 'tree-sitter-rust',
104+
label: 'tree-sitter-rust',
105+
link: 'https://github.com/tree-sitter/tree-sitter-rust',
106+
editorLanguage: 'rust',
107+
pkgName: 'tree-sitter-rust',
108+
getModuleUrl: (pkg) => getJsdelivrUrl(pkg, '/tree-sitter-rust.wasm'),
109+
}
110+
111+
function convertNode(node: TreeSitter.Node): any {
75112
const {
76113
startIndex,
77114
endIndex,
@@ -109,12 +146,17 @@ async function loadTreeSitter() {
109146
async function initTreeSitterParser(url: string) {
110147
const [{ Parser, Language }, response] = await Promise.all([
111148
loadTreeSitter(),
112-
fetch(url).then((res) => res.arrayBuffer()),
149+
fetch(url).then((res) => {
150+
if (!res.ok) {
151+
throw new Error(`Failed to load WASM: ${res.status} ${res.statusText}`)
152+
}
153+
return res.arrayBuffer()
154+
}),
113155
])
114-
const CSharpLanguage = await Language.load(new Uint8Array(response))
156+
const language = await Language.load(new Uint8Array(response))
115157

116158
const parser = new Parser()
117-
parser.setLanguage(CSharpLanguage)
159+
parser.setLanguage(language)
118160

119161
return parser
120162
}

0 commit comments

Comments
 (0)