Add language tools package

This commit is contained in:
2026-07-09 18:34:41 +09:00
parent ac99c4cb4e
commit 0e2a7b35d2
20 changed files with 1434 additions and 16 deletions
+10 -2
View File
@@ -40,6 +40,14 @@ Production = Server & {
<span>JSR package</span>
<strong>jsr.io/@hare/decodal-wasm</strong>
</a>
<a href="https://www.npmjs.com/package/decodal-language-tools">
<span>Language tools package</span>
<strong>npmjs.com/package/decodal-language-tools</strong>
</a>
<a href="https://jsr.io/@hare/decodal-language-tools@0.1.2">
<span>Language tools on JSR</span>
<strong>jsr.io/@hare/decodal-language-tools</strong>
</a>
<a href="https://www.npmjs.com/package/decodal-codemirror">
<span>CodeMirror package</span>
<strong>npmjs.com/package/decodal-codemirror</strong>
@@ -62,8 +70,8 @@ Production = Server & {
<article class="home-card">
<h2>Where it runs</h2>
<p>
Use the Rust crate for runtime embedding, the WASM package in browsers, CodeMirror/Lezer for the Web editor,
and Tree-sitter for general editor integration.
Use the Rust crate for runtime embedding, the WASM package in browsers, language-tools for formatting,
CodeMirror/Lezer for the Web editor, and Tree-sitter for general editor integration.
</p>
</article>
<article class="home-card">
@@ -15,6 +15,7 @@ import ManualLayout from '../layouts/ManualLayout.astro';
</label>
<button id="load-example" type="button">Load</button>
<p id="status" class="status">Loading WASM...</p>
<button id="format" disabled>Format</button>
<button id="run" disabled>Run</button>
</div>
</div>
+20 -2
View File
@@ -1,4 +1,5 @@
import init, { evaluateProject } from 'decodal-wasm';
import initRuntime, { evaluateProject } from 'decodal-wasm';
import initTools, { formatSource } from 'decodal-language-tools';
import { EditorView, basicSetup } from 'codemirror';
import { keymap } from '@codemirror/view';
import { decodal } from 'decodal-codemirror';
@@ -10,6 +11,7 @@ const starterProject = playgroundExamples[0];
const editorHost = document.getElementById('editor');
const output = document.getElementById('output');
const run = document.getElementById('run');
const formatButton = document.getElementById('format');
const status = document.getElementById('status');
const fileTree = document.getElementById('file-tree');
const activeFile = document.getElementById('active-file');
@@ -176,6 +178,20 @@ function execute() {
output.classList.toggle('error', !result.ok);
}
function formatActiveFile() {
const result = JSON.parse(formatSource(getEditorText()));
if (!result.ok) {
output.textContent = result.error;
output.classList.add('error');
return;
}
setEditorText(result.source);
project.files[project.activePath] = result.source;
saveProject();
output.textContent = 'Formatted.';
output.classList.remove('error');
}
function renderFileTree() {
const tree = buildTree(Object.keys(project.files).sort());
fileTree.replaceChildren(renderTreeList(tree.children));
@@ -227,8 +243,9 @@ function compareNodes(a, b) {
}
try {
await init();
await Promise.all([initRuntime(), initTools()]);
run.disabled = false;
formatButton.disabled = false;
status.textContent = '';
execute();
} catch (error) {
@@ -236,6 +253,7 @@ try {
}
run.addEventListener('click', execute);
formatButton.addEventListener('click', formatActiveFile);
loadExample.addEventListener('click', () => {
const example = playgroundExamples.find((item) => item.id === exampleSelect.value);
if (!example) return;