Files
mixly3/common/modules/mixly-modules/common/monaco-tree-sitter.js

128 lines
3.6 KiB
JavaScript

goog.loadJs('common', () => {
goog.require('_');
goog.require('monaco');
goog.require('Mixly.Registry');
goog.require('Mixly.MonacoTheme');
goog.provide('Mixly.MonacoTreeSitter');
const { Registry, MonacoTheme } = Mixly;
class MonacoTreeSitter {
static {
this.workerPath = '../common/modules/mixly-modules/workers/common/tree-sitter/index.js';
this.supportTreeSitters_ = new Registry();
this.activeTreeSitters_ = new Registry();
/*this.supportTreeSitters_.register('python', {
workerName: 'pythonTreeSitterService',
wasm: 'tree-sitter-python.wasm'
});
this.supportTreeSitters_.register('cpp', {
workerName: 'cppTreeSitterService',
wasm: 'tree-sitter-cpp.wasm'
});*/
this.activateTreeSitter = async function (type) {
if (!this.supportTreeSitters_.hasKey(type)) return null;
const info = this.supportTreeSitters_.getItem(type);
if (this.activeTreeSitters_.hasKey(type)) {
const ts = this.activeTreeSitters_.getItem(type);
if (ts.loading) await ts.loading;
return ts;
}
const treeSitter = workerpool.pool(this.workerPath, {
workerOpts: { name: info.workerName },
workerType: 'web'
});
const grammar = await goog.readJson(
`../common/templates/json/tree-sitter/grammars/${type}.json`
);
treeSitter.loading = treeSitter.exec(
'init',
[info.wasm, grammar]
);
this.activeTreeSitters_.register(type, treeSitter);
await treeSitter.loading;
treeSitter.loading = null;
return treeSitter;
};
this.treeSitterPostion = function (pos) {
return {
row: pos.lineNumber - 1,
column: pos.column - 1
};
};
}
constructor(editor, opts) {
this.editor = editor;
this.seq = 0;
this.decorations = [];
this.refresh = _.debounce(
this.refresh.bind(this),
opts?.debounceUpdate ?? 15
);
}
dispose() {
this.pool.terminate(true);
this.decorations = [];
}
async updateWorker(type, theme, text) {
const treeSitter = await MonacoTreeSitter.activateTreeSitter(type);
if (!treeSitter) {
return;
}
const id = ++this.seq;
const dto = await treeSitter.exec('update', [text]);
if (id !== this.seq) return;
this.applyDecorations(type, theme, dto);
}
applyDecorations(type, theme, dto) {
const decos = [];
for (const [term, ranges] of Object.entries(dto)) {
const className = MonacoTheme.getClassNameOfTerm(type, theme, term);
for (const r of ranges) {
decos.push({
range: new monaco.Range(
r.startLineNumber,
r.startColumn,
r.endLineNumber,
r.endColumn
),
options: {
inlineClassName: className
}
});
}
}
this.decorations = this.editor.getEditor().deltaDecorations(this.decorations, decos);
}
refresh(type, theme, newText) {
this.updateWorker(type, theme, newText);
}
setValue(type, theme, newText) {
this.refresh(type, theme, newText);
}
}
Mixly.MonacoTreeSitter = MonacoTreeSitter;
});