1
0
mirror of https://github.com/alecthomas/chroma.git synced 2025-11-25 22:32:32 +02:00

chore: add JS formatting with biome

This commit is contained in:
Alec Thomas
2025-07-01 10:16:32 +10:00
parent adeac8f5db
commit b69cd3d846
6 changed files with 152 additions and 115 deletions

View File

@@ -12,6 +12,10 @@ README.md: lexers/*/*.go
tokentype_string.go: types.go tokentype_string.go: types.go
go generate go generate
.PHONY: format-js
format-js:
biome format --write cmd/chromad/static/{index.js,chroma.js}
.PHONY: chromad .PHONY: chromad
chromad: build/chromad chromad: build/chromad

1
bin/.biome-1.9.4.pkg Symbolic link
View File

@@ -0,0 +1 @@
hermit

1
bin/biome Symbolic link
View File

@@ -0,0 +1 @@
.biome-1.9.4.pkg

6
biome.json Normal file
View File

@@ -0,0 +1,6 @@
{
"$schema": "https://biomejs.dev/schemas/2.0.5/schema.json",
"formatter": {
"indentStyle": "space"
}
}

View File

@@ -1,7 +1,7 @@
// chroma.js - TinyGo WASM runtime initialization for Chroma syntax highlighter // chroma.js - TinyGo WASM runtime initialization for Chroma syntax highlighter
// Import wasm_exec.js so that it initialises the Go WASM runtime. // Import wasm_exec.js so that it initialises the Go WASM runtime.
import './wasm_exec.js'; import "./wasm_exec.js";
class ChromaWASM { class ChromaWASM {
constructor() { constructor() {
@@ -17,13 +17,16 @@ class ChromaWASM {
this.go = new Go(); this.go = new Go();
// Load the WASM module // Load the WASM module
const wasmResponse = await fetch('./static/chroma.wasm'); const wasmResponse = await fetch("./static/chroma.wasm");
if (!wasmResponse.ok) { if (!wasmResponse.ok) {
throw new Error(`Failed to fetch chroma.wasm: ${wasmResponse.status}`); throw new Error(`Failed to fetch chroma.wasm: ${wasmResponse.status}`);
} }
const wasmBytes = await wasmResponse.arrayBuffer(); const wasmBytes = await wasmResponse.arrayBuffer();
const wasmModule = await WebAssembly.instantiate(wasmBytes, this.go.importObject); const wasmModule = await WebAssembly.instantiate(
wasmBytes,
this.go.importObject,
);
this.wasm = wasmModule.instance; this.wasm = wasmModule.instance;
@@ -31,9 +34,9 @@ class ChromaWASM {
this.go.run(this.wasm); this.go.run(this.wasm);
this.ready = true; this.ready = true;
console.log('Chroma WASM module initialized successfully'); console.log("Chroma WASM module initialized successfully");
} catch (error) { } catch (error) {
console.error('Failed to initialize Chroma WASM module:', error); console.error("Failed to initialize Chroma WASM module:", error);
throw error; throw error;
} }
} }
@@ -41,32 +44,36 @@ class ChromaWASM {
async waitForReady() { async waitForReady() {
await this.readyPromise; await this.readyPromise;
if (!this.ready) { if (!this.ready) {
throw new Error('Chroma WASM module failed to initialize'); throw new Error("Chroma WASM module failed to initialize");
} }
} }
async highlight(source, lexer, formatter, withClasses) { async highlight(source, lexer, formatter, withClasses) {
await this.waitForReady(); await this.waitForReady();
if (typeof window.highlight !== 'function') { if (typeof window.highlight !== "function") {
throw new Error('highlight function not available from WASM module'); throw new Error("highlight function not available from WASM module");
} }
try { try {
return window.highlight(source, lexer, formatter, withClasses); return window.highlight(source, lexer, formatter, withClasses);
} catch (error) { } catch (error) {
console.error('Error calling highlight function:', error); console.error("Error calling highlight function:", error);
throw error; throw error;
} }
} }
} }
export function isWasmSupported() { export function isWasmSupported() {
try { try {
if (typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function") { if (
typeof WebAssembly === "object" &&
typeof WebAssembly.instantiate === "function"
) {
// The smallest possible WebAssembly module (magic number + version) // The smallest possible WebAssembly module (magic number + version)
const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)); const module = new WebAssembly.Module(
Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00),
);
if (module instanceof WebAssembly.Module) { if (module instanceof WebAssembly.Module) {
// Try to instantiate the module to ensure it's truly runnable // Try to instantiate the module to ensure it's truly runnable
return new WebAssembly.Instance(module) instanceof WebAssembly.Instance; return new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
@@ -78,6 +85,5 @@ export function isWasmSupported() {
return false; return false;
} }
// Create global instance, null if WASM is not supported. // Create global instance, null if WASM is not supported.
export const chroma = isWasmSupported() ? new ChromaWASM() : null; export const chroma = isWasmSupported() ? new ChromaWASM() : null;

View File

@@ -2,12 +2,14 @@ import * as Base64 from "./base64.js";
import { chroma } from "./chroma.js"; import { chroma } from "./chroma.js";
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
var darkMode = (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches); var darkMode =
var style = document.createElement('style'); window.matchMedia &&
var ref = document.querySelector('script'); window.matchMedia("(prefers-color-scheme: dark)").matches;
var style = document.createElement("style");
var ref = document.querySelector("script");
ref.parentNode.insertBefore(style, ref); ref.parentNode.insertBefore(style, ref);
var form = document.getElementById('chroma'); var form = document.getElementById("chroma");
var textArea = form.elements["text"]; var textArea = form.elements["text"];
var styleSelect = form.elements["style"]; var styleSelect = form.elements["style"];
var languageSelect = form.elements["language"]; var languageSelect = form.elements["language"];
@@ -16,27 +18,29 @@ document.addEventListener("DOMContentLoaded", function () {
var output = document.getElementById("output"); var output = document.getElementById("output");
var htmlCheckbox = document.getElementById("html"); var htmlCheckbox = document.getElementById("html");
(document.querySelectorAll('.notification .delete') || []).forEach((el) => { (document.querySelectorAll(".notification .delete") || []).forEach((el) => {
const notification = el.parentNode; const notification = el.parentNode;
el.addEventListener('click', () => { el.addEventListener("click", () => {
notification.parentNode.removeChild(notification); notification.parentNode.removeChild(notification);
}); });
}); });
async function renderServer(formData) { async function renderServer(formData) {
return (await fetch("api/render", { return (
method: 'POST', await fetch("api/render", {
mode: 'cors', method: "POST",
cache: 'no-cache', mode: "cors",
credentials: 'same-origin', cache: "no-cache",
credentials: "same-origin",
headers: { headers: {
'X-CSRF-Token': csrfToken, "X-CSRF-Token": csrfToken,
'Content-Type': 'application/json', "Content-Type": "application/json",
}, },
redirect: 'follow', redirect: "follow",
referrer: 'no-referrer', referrer: "no-referrer",
body: JSON.stringify(formData), body: JSON.stringify(formData),
})).json(); })
).json();
} }
async function renderWasm(formData) { async function renderWasm(formData) {
@@ -49,16 +53,27 @@ document.addEventListener("DOMContentLoaded", function () {
} }
async function render(formData) { async function render(formData) {
return chroma !== null return chroma !== null ? renderWasm(formData) : renderServer(formData);
? renderWasm(formData)
: renderServer(formData);
} }
// https://stackoverflow.com/a/37697925/7980 // https://stackoverflow.com/a/37697925/7980
function handleTab(e) { function handleTab(e) {
var after, before, end, lastNewLine, changeLength, re, replace, selection, start, val; var after,
if ((e.charCode === 9 || e.keyCode === 9) && !e.altKey && !e.ctrlKey && !e.metaKey) { before,
end,
lastNewLine,
changeLength,
re,
replace,
selection,
start,
val;
if (
(e.charCode === 9 || e.keyCode === 9) &&
!e.altKey &&
!e.ctrlKey &&
!e.metaKey
) {
e.preventDefault(); e.preventDefault();
start = this.selectionStart; start = this.selectionStart;
end = this.selectionEnd; end = this.selectionEnd;
@@ -68,14 +83,14 @@ document.addEventListener("DOMContentLoaded", function () {
replace = true; replace = true;
if (start !== end) { if (start !== end) {
selection = val.substring(start, end); selection = val.substring(start, end);
if (~selection.indexOf('\n')) { if (~selection.indexOf("\n")) {
replace = false; replace = false;
changeLength = 0; changeLength = 0;
lastNewLine = before.lastIndexOf('\n'); lastNewLine = before.lastIndexOf("\n");
if (!~lastNewLine) { if (!~lastNewLine) {
selection = before + selection; selection = before + selection;
changeLength = before.length; changeLength = before.length;
before = ''; before = "";
} else { } else {
selection = before.substring(lastNewLine) + selection; selection = before.substring(lastNewLine) + selection;
changeLength = before.length - lastNewLine; changeLength = before.length - lastNewLine;
@@ -87,9 +102,9 @@ document.addEventListener("DOMContentLoaded", function () {
start--; start--;
changeLength--; changeLength--;
} }
selection = selection.replace(re, '$1'); selection = selection.replace(re, "$1");
} else { } else {
selection = selection.replace(/(\n|^)/g, '$1\t'); selection = selection.replace(/(\n|^)/g, "$1\t");
start++; start++;
changeLength++; changeLength++;
} }
@@ -99,7 +114,7 @@ document.addEventListener("DOMContentLoaded", function () {
} }
} }
if (replace && !e.shiftKey) { if (replace && !e.shiftKey) {
this.value = before + '\t' + after; this.value = before + "\t" + after;
this.selectionStart = this.selectionEnd = start + 1; this.selectionStart = this.selectionEnd = start + 1;
} }
} }
@@ -109,7 +124,8 @@ document.addEventListener("DOMContentLoaded", function () {
function debounce(func, wait, immediate) { function debounce(func, wait, immediate) {
var timeout; var timeout;
return function () { return function () {
var context = this, args = arguments; var context = this;
var args = arguments;
var later = function () { var later = function () {
timeout = null; timeout = null;
if (!immediate) func.apply(context, args); if (!immediate) func.apply(context, args);
@@ -123,11 +139,11 @@ document.addEventListener("DOMContentLoaded", function () {
function getFormJSON() { function getFormJSON() {
return { return {
"language": languageSelect.value, language: languageSelect.value,
"style": styleSelect.value, style: styleSelect.value,
"text": textArea.value, text: textArea.value,
"classes": htmlCheckbox.checked, classes: htmlCheckbox.checked,
} };
} }
async function update(event) { async function update(event) {
@@ -145,12 +161,12 @@ document.addEventListener("DOMContentLoaded", function () {
output.innerHTML = value.html; output.innerHTML = value.html;
} }
} catch (error) { } catch (error) {
console.error('Error highlighting code:', error); console.error("Error highlighting code:", error);
// Fallback: display plain text // Fallback: display plain text
if (htmlCheckbox.checked) { if (htmlCheckbox.checked) {
output.innerText = textArea.value; output.innerText = textArea.value;
} else { } else {
output.innerHTML = '<pre>' + textArea.value + '</pre>'; output.innerHTML = "<pre>" + textArea.value + "</pre>";
} }
} }
@@ -160,7 +176,7 @@ document.addEventListener("DOMContentLoaded", function () {
} }
function share(event) { function share(event) {
let data = JSON.stringify(getFormJSON()) let data = JSON.stringify(getFormJSON());
data = Base64.encodeURI(data); data = Base64.encodeURI(data);
location.hash = "#" + data; location.hash = "#" + data;
try { try {
@@ -172,26 +188,29 @@ document.addEventListener("DOMContentLoaded", function () {
} }
if (location.hash) { if (location.hash) {
let json = Base64.decode(location.hash.substring(1)) let json = Base64.decode(location.hash.substring(1));
json = JSON.parse(json); json = JSON.parse(json);
textArea.value = json.text; textArea.value = json.text;
languageSelect.value = json.language; languageSelect.value = json.language;
styleSelect.value = json.style; styleSelect.value = json.style;
htmlCheckbox.checked = json.classes; htmlCheckbox.checked = json.classes;
update(new Event('change')); update(new Event("change"));
} else if (darkMode) { } else if (darkMode) {
styleSelect.value = "monokai"; styleSelect.value = "monokai";
update(new Event("change")); update(new Event("change"));
} }
var eventHandler = (event) => update(event); var eventHandler = (event) => update(event);
var debouncedEventHandler = debounce(eventHandler, chroma === null ? 250 : 100); var debouncedEventHandler = debounce(
eventHandler,
chroma === null ? 250 : 100,
);
languageSelect.addEventListener('change', eventHandler); languageSelect.addEventListener("change", eventHandler);
styleSelect.addEventListener('change', eventHandler); styleSelect.addEventListener("change", eventHandler);
htmlCheckbox.addEventListener('change', eventHandler); htmlCheckbox.addEventListener("change", eventHandler);
copyButton.addEventListener('click', share); copyButton.addEventListener("click", share);
textArea.addEventListener('keydown', handleTab); textArea.addEventListener("keydown", handleTab);
textArea.addEventListener('change', debouncedEventHandler); textArea.addEventListener("change", debouncedEventHandler);
}); });