feat: highlight repl session

This commit is contained in:
Maciej Jur 2024-02-16 21:54:53 +01:00
parent d86b028a06
commit c671506a0b
Signed by: kamov
GPG key ID: 191CBFF5F72ECAFD
2 changed files with 62 additions and 23 deletions

View file

@ -180,7 +180,7 @@ export const { hl } = require('./treesitter.linux-x64-gnu.node');
Once we have this library we can load it inside Node (almost) like any other module.
```
```node
Welcome to Node.js v21.6.1.
Type ".help" for more information.
> const treesitter = await import('./dist/index.js')

View file

@ -9,18 +9,74 @@ function text(value: string) {
}
}
function span(name: string) {
function span(name: string, children: any[] = []) {
return {
type: 'element',
tagName: 'span',
properties: {
className: name.replace('.', '-'),
},
children: []
children,
}
}
function highlight(lang: string, code: string) {
const root: any[] = [];
const ptrs: any[] = [{ children: root }];
for (const event of treesitter.hl(lang, code)) {
switch (event.kind) {
case 'text': {
const node = text(event.text);
ptrs.at(-1).children.push(node);
} break;
case 'open': {
const node = span(event.name);
ptrs.at(-1).children.push(node);
ptrs.push(node);
} break;
case 'close': {
ptrs.pop();
} break;
}
}
return root;
}
function repl(prompt: string, lang: string, code: string) {
const chunks = [{ i: [] as any[], o: [] as any[] }];
for (const line of code.split('\n')) {
if (line.startsWith(prompt)) {
chunks.push({ i: [line], o: [] });
} else {
chunks.at(-1)!.o.push(line);
}
}
const out: any[] = [];
for (const { i, o } of chunks) {
if (i.length) {
out.push({
type: 'element',
tagName: 'div',
children: [
span('keyword-return', [text(prompt)]),
...highlight(lang, i[0].replace(prompt, '')),
]
});
}
if (o.length) {
out.push(text(o.join('\n')));
}
}
return out;
}
export default function rehypeTreesitter() {
return function (tree: any) {
visit(tree, null, (node, _, above) => {
@ -36,27 +92,10 @@ export default function rehypeTreesitter() {
...!!lang && { "data-lang": lang },
};
const root = { children: [] };
const ptrs: any[] = [root];
for (const event of treesitter.hl(lang, code)) {
switch (event.kind) {
case 'text': {
const inserted = text(event.text);
ptrs.at(-1).children.push(inserted);
} break;
case 'open': {
const inserted = span(event.name);
ptrs.at(-1).children.push(inserted);
ptrs.push(inserted);
} break;
case 'close': {
ptrs.pop();
} break;
}
switch (lang) {
case 'node': node.children = repl('>', 'js', code); break;
default: node.children = highlight(lang, code);
}
node.children = root.children;
});
};
}