mirror of
				https://github.com/alecthomas/chroma.git
				synced 2025-10-30 23:57:49 +02:00 
			
		
		
		
	chore: add JS formatting with biome
This commit is contained in:
		
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							| @@ -12,6 +12,10 @@ README.md: lexers/*/*.go | ||||
| tokentype_string.go: types.go | ||||
| 	go generate | ||||
|  | ||||
| .PHONY: format-js | ||||
| format-js: | ||||
| 	biome format --write cmd/chromad/static/{index.js,chroma.js} | ||||
|  | ||||
| .PHONY: chromad | ||||
| chromad: build/chromad | ||||
|  | ||||
|   | ||||
							
								
								
									
										1
									
								
								bin/.biome-1.9.4.pkg
									
									
									
									
									
										Symbolic link
									
								
							
							
						
						
									
										1
									
								
								bin/.biome-1.9.4.pkg
									
									
									
									
									
										Symbolic link
									
								
							| @@ -0,0 +1 @@ | ||||
| hermit | ||||
							
								
								
									
										6
									
								
								biome.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								biome.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| { | ||||
| 	"$schema": "https://biomejs.dev/schemas/2.0.5/schema.json", | ||||
| 	"formatter": { | ||||
| 		"indentStyle": "space" | ||||
| 	} | ||||
| } | ||||
| @@ -1,72 +1,79 @@ | ||||
| // 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'; | ||||
| import "./wasm_exec.js"; | ||||
|  | ||||
| class ChromaWASM { | ||||
|     constructor() { | ||||
|         this.go = null; | ||||
|         this.wasm = null; | ||||
|         this.ready = false; | ||||
|         this.readyPromise = this.init(); | ||||
|   constructor() { | ||||
|     this.go = null; | ||||
|     this.wasm = null; | ||||
|     this.ready = false; | ||||
|     this.readyPromise = this.init(); | ||||
|   } | ||||
|  | ||||
|   async init() { | ||||
|     try { | ||||
|       // Create a new Go instance | ||||
|       this.go = new Go(); | ||||
|  | ||||
|       // Load the WASM module | ||||
|       const wasmResponse = await fetch("./static/chroma.wasm"); | ||||
|       if (!wasmResponse.ok) { | ||||
|         throw new Error(`Failed to fetch chroma.wasm: ${wasmResponse.status}`); | ||||
|       } | ||||
|  | ||||
|       const wasmBytes = await wasmResponse.arrayBuffer(); | ||||
|       const wasmModule = await WebAssembly.instantiate( | ||||
|         wasmBytes, | ||||
|         this.go.importObject, | ||||
|       ); | ||||
|  | ||||
|       this.wasm = wasmModule.instance; | ||||
|  | ||||
|       // Run the Go program | ||||
|       this.go.run(this.wasm); | ||||
|  | ||||
|       this.ready = true; | ||||
|       console.log("Chroma WASM module initialized successfully"); | ||||
|     } catch (error) { | ||||
|       console.error("Failed to initialize Chroma WASM module:", error); | ||||
|       throw error; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async waitForReady() { | ||||
|     await this.readyPromise; | ||||
|     if (!this.ready) { | ||||
|       throw new Error("Chroma WASM module failed to initialize"); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async highlight(source, lexer, formatter, withClasses) { | ||||
|     await this.waitForReady(); | ||||
|  | ||||
|     if (typeof window.highlight !== "function") { | ||||
|       throw new Error("highlight function not available from WASM module"); | ||||
|     } | ||||
|  | ||||
|     async init() { | ||||
|         try { | ||||
|             // Create a new Go instance | ||||
|             this.go = new Go(); | ||||
|  | ||||
|             // Load the WASM module | ||||
|             const wasmResponse = await fetch('./static/chroma.wasm'); | ||||
|             if (!wasmResponse.ok) { | ||||
|                 throw new Error(`Failed to fetch chroma.wasm: ${wasmResponse.status}`); | ||||
|             } | ||||
|  | ||||
|             const wasmBytes = await wasmResponse.arrayBuffer(); | ||||
|             const wasmModule = await WebAssembly.instantiate(wasmBytes, this.go.importObject); | ||||
|  | ||||
|             this.wasm = wasmModule.instance; | ||||
|  | ||||
|             // Run the Go program | ||||
|             this.go.run(this.wasm); | ||||
|  | ||||
|             this.ready = true; | ||||
|             console.log('Chroma WASM module initialized successfully'); | ||||
|         } catch (error) { | ||||
|             console.error('Failed to initialize Chroma WASM module:', error); | ||||
|             throw error; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async waitForReady() { | ||||
|         await this.readyPromise; | ||||
|         if (!this.ready) { | ||||
|             throw new Error('Chroma WASM module failed to initialize'); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async highlight(source, lexer, formatter, withClasses) { | ||||
|         await this.waitForReady(); | ||||
|  | ||||
|         if (typeof window.highlight !== 'function') { | ||||
|             throw new Error('highlight function not available from WASM module'); | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|             return window.highlight(source, lexer, formatter, withClasses); | ||||
|         } catch (error) { | ||||
|             console.error('Error calling highlight function:', error); | ||||
|             throw error; | ||||
|         } | ||||
|     try { | ||||
|       return window.highlight(source, lexer, formatter, withClasses); | ||||
|     } catch (error) { | ||||
|       console.error("Error calling highlight function:", error); | ||||
|       throw error; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| export function isWasmSupported() { | ||||
|   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) | ||||
|       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) { | ||||
|         // Try to instantiate the module to ensure it's truly runnable | ||||
|         return new WebAssembly.Instance(module) instanceof WebAssembly.Instance; | ||||
| @@ -78,6 +85,5 @@ export function isWasmSupported() { | ||||
|   return false; | ||||
| } | ||||
|  | ||||
|  | ||||
| // Create global instance, null if WASM is not supported. | ||||
| export const chroma = isWasmSupported() ? new ChromaWASM() : null; | ||||
|   | ||||
| @@ -2,12 +2,14 @@ import * as Base64 from "./base64.js"; | ||||
| import { chroma } from "./chroma.js"; | ||||
|  | ||||
| document.addEventListener("DOMContentLoaded", function () { | ||||
| 	var darkMode = (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches); | ||||
|   var style = document.createElement('style'); | ||||
|   var ref = document.querySelector('script'); | ||||
|   var darkMode = | ||||
|     window.matchMedia && | ||||
|     window.matchMedia("(prefers-color-scheme: dark)").matches; | ||||
|   var style = document.createElement("style"); | ||||
|   var ref = document.querySelector("script"); | ||||
|   ref.parentNode.insertBefore(style, ref); | ||||
|  | ||||
|   var form = document.getElementById('chroma'); | ||||
|   var form = document.getElementById("chroma"); | ||||
|   var textArea = form.elements["text"]; | ||||
|   var styleSelect = form.elements["style"]; | ||||
|   var languageSelect = form.elements["language"]; | ||||
| @@ -16,49 +18,62 @@ document.addEventListener("DOMContentLoaded", function () { | ||||
|   var output = document.getElementById("output"); | ||||
|   var htmlCheckbox = document.getElementById("html"); | ||||
|  | ||||
|   (document.querySelectorAll('.notification .delete') || []).forEach((el) => { | ||||
|   (document.querySelectorAll(".notification .delete") || []).forEach((el) => { | ||||
|     const notification = el.parentNode; | ||||
|     el.addEventListener('click', () => { | ||||
|     el.addEventListener("click", () => { | ||||
|       notification.parentNode.removeChild(notification); | ||||
|     }); | ||||
|   }); | ||||
|  | ||||
|   async function renderServer(formData) { | ||||
| 		return (await fetch("api/render", { | ||||
| 				  method: 'POST', | ||||
| 					mode: 'cors', | ||||
| 					cache: 'no-cache', | ||||
| 					credentials: 'same-origin', | ||||
| 					headers: { | ||||
| 						'X-CSRF-Token': csrfToken, | ||||
| 						'Content-Type': 'application/json', | ||||
| 					}, | ||||
| 					redirect: 'follow', | ||||
| 					referrer: 'no-referrer', | ||||
| 					body: JSON.stringify(formData), | ||||
| 				})).json(); | ||||
|     return ( | ||||
|       await fetch("api/render", { | ||||
|         method: "POST", | ||||
|         mode: "cors", | ||||
|         cache: "no-cache", | ||||
|         credentials: "same-origin", | ||||
|         headers: { | ||||
|           "X-CSRF-Token": csrfToken, | ||||
|           "Content-Type": "application/json", | ||||
|         }, | ||||
|         redirect: "follow", | ||||
|         referrer: "no-referrer", | ||||
|         body: JSON.stringify(formData), | ||||
|       }) | ||||
|     ).json(); | ||||
|   } | ||||
|  | ||||
|   async function renderWasm(formData) { | ||||
| 		return await chroma.highlight( | ||||
| 			formData.text, | ||||
| 			formData.language, | ||||
| 			formData.style, | ||||
| 			formData.classes, | ||||
| 		); | ||||
|     return await chroma.highlight( | ||||
|       formData.text, | ||||
|       formData.language, | ||||
|       formData.style, | ||||
|       formData.classes, | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   async function render(formData) { | ||||
| 		return chroma !== null | ||||
| 			? renderWasm(formData) | ||||
| 			: renderServer(formData); | ||||
|     return chroma !== null ? renderWasm(formData) : renderServer(formData); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   // https://stackoverflow.com/a/37697925/7980 | ||||
|   function handleTab(e) { | ||||
|     var after, before, end, lastNewLine, changeLength, re, replace, selection, start, val; | ||||
|     if ((e.charCode === 9 || e.keyCode === 9) && !e.altKey && !e.ctrlKey && !e.metaKey) { | ||||
|     var after, | ||||
|       before, | ||||
|       end, | ||||
|       lastNewLine, | ||||
|       changeLength, | ||||
|       re, | ||||
|       replace, | ||||
|       selection, | ||||
|       start, | ||||
|       val; | ||||
|     if ( | ||||
|       (e.charCode === 9 || e.keyCode === 9) && | ||||
|       !e.altKey && | ||||
|       !e.ctrlKey && | ||||
|       !e.metaKey | ||||
|     ) { | ||||
|       e.preventDefault(); | ||||
|       start = this.selectionStart; | ||||
|       end = this.selectionEnd; | ||||
| @@ -68,14 +83,14 @@ document.addEventListener("DOMContentLoaded", function () { | ||||
|       replace = true; | ||||
|       if (start !== end) { | ||||
|         selection = val.substring(start, end); | ||||
|         if (~selection.indexOf('\n')) { | ||||
|         if (~selection.indexOf("\n")) { | ||||
|           replace = false; | ||||
|           changeLength = 0; | ||||
|           lastNewLine = before.lastIndexOf('\n'); | ||||
|           lastNewLine = before.lastIndexOf("\n"); | ||||
|           if (!~lastNewLine) { | ||||
|             selection = before + selection; | ||||
|             changeLength = before.length; | ||||
|             before = ''; | ||||
|             before = ""; | ||||
|           } else { | ||||
|             selection = before.substring(lastNewLine) + selection; | ||||
|             changeLength = before.length - lastNewLine; | ||||
| @@ -87,9 +102,9 @@ document.addEventListener("DOMContentLoaded", function () { | ||||
|               start--; | ||||
|               changeLength--; | ||||
|             } | ||||
|             selection = selection.replace(re, '$1'); | ||||
|             selection = selection.replace(re, "$1"); | ||||
|           } else { | ||||
|             selection = selection.replace(/(\n|^)/g, '$1\t'); | ||||
|             selection = selection.replace(/(\n|^)/g, "$1\t"); | ||||
|             start++; | ||||
|             changeLength++; | ||||
|           } | ||||
| @@ -99,7 +114,7 @@ document.addEventListener("DOMContentLoaded", function () { | ||||
|         } | ||||
|       } | ||||
|       if (replace && !e.shiftKey) { | ||||
|         this.value = before + '\t' + after; | ||||
|         this.value = before + "\t" + after; | ||||
|         this.selectionStart = this.selectionEnd = start + 1; | ||||
|       } | ||||
|     } | ||||
| @@ -109,7 +124,8 @@ document.addEventListener("DOMContentLoaded", function () { | ||||
|   function debounce(func, wait, immediate) { | ||||
|     var timeout; | ||||
|     return function () { | ||||
|       var context = this, args = arguments; | ||||
|       var context = this; | ||||
|       var args = arguments; | ||||
|       var later = function () { | ||||
|         timeout = null; | ||||
|         if (!immediate) func.apply(context, args); | ||||
| @@ -123,11 +139,11 @@ document.addEventListener("DOMContentLoaded", function () { | ||||
|  | ||||
|   function getFormJSON() { | ||||
|     return { | ||||
|       "language": languageSelect.value, | ||||
|       "style": styleSelect.value, | ||||
|       "text": textArea.value, | ||||
|       "classes": htmlCheckbox.checked, | ||||
|     } | ||||
|       language: languageSelect.value, | ||||
|       style: styleSelect.value, | ||||
|       text: textArea.value, | ||||
|       classes: htmlCheckbox.checked, | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   async function update(event) { | ||||
| @@ -145,12 +161,12 @@ document.addEventListener("DOMContentLoaded", function () { | ||||
|         output.innerHTML = value.html; | ||||
|       } | ||||
|     } catch (error) { | ||||
|       console.error('Error highlighting code:', error); | ||||
|       console.error("Error highlighting code:", error); | ||||
|       // Fallback: display plain text | ||||
|       if (htmlCheckbox.checked) { | ||||
|         output.innerText = textArea.value; | ||||
|       } else { | ||||
|         output.innerHTML = '<pre>' + textArea.value + '</pre>'; | ||||
|         output.innerHTML = "<pre>" + textArea.value + "</pre>"; | ||||
|       } | ||||
|     } | ||||
|  | ||||
| @@ -160,7 +176,7 @@ document.addEventListener("DOMContentLoaded", function () { | ||||
|   } | ||||
|  | ||||
|   function share(event) { | ||||
|     let data = JSON.stringify(getFormJSON()) | ||||
|     let data = JSON.stringify(getFormJSON()); | ||||
|     data = Base64.encodeURI(data); | ||||
|     location.hash = "#" + data; | ||||
|     try { | ||||
| @@ -172,26 +188,29 @@ document.addEventListener("DOMContentLoaded", function () { | ||||
|   } | ||||
|  | ||||
|   if (location.hash) { | ||||
|     let json = Base64.decode(location.hash.substring(1)) | ||||
|     let json = Base64.decode(location.hash.substring(1)); | ||||
|     json = JSON.parse(json); | ||||
|     textArea.value = json.text; | ||||
|     languageSelect.value = json.language; | ||||
|     styleSelect.value = json.style; | ||||
|     htmlCheckbox.checked = json.classes; | ||||
|     update(new Event('change')); | ||||
|   } else  if (darkMode) { | ||||
|   	styleSelect.value = "monokai"; | ||||
|    	update(new Event("change")); | ||||
|     update(new Event("change")); | ||||
|   } else if (darkMode) { | ||||
|     styleSelect.value = "monokai"; | ||||
|     update(new Event("change")); | ||||
|   } | ||||
|  | ||||
|   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); | ||||
|   styleSelect.addEventListener('change', eventHandler); | ||||
|   htmlCheckbox.addEventListener('change', eventHandler); | ||||
|   copyButton.addEventListener('click', share); | ||||
|   languageSelect.addEventListener("change", eventHandler); | ||||
|   styleSelect.addEventListener("change", eventHandler); | ||||
|   htmlCheckbox.addEventListener("change", eventHandler); | ||||
|   copyButton.addEventListener("click", share); | ||||
|  | ||||
|   textArea.addEventListener('keydown', handleTab); | ||||
|   textArea.addEventListener('change', debouncedEventHandler); | ||||
|   textArea.addEventListener("keydown", handleTab); | ||||
|   textArea.addEventListener("change", debouncedEventHandler); | ||||
| }); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user