scripts/
static/
avatars/
fonts/
js/
hirad.js
2.9 KiB
hiril.js
3.0 KiB
radiant.svg
1.9 KiB
style.css
23.3 KiB
templates/
.gitignore
30 B
.gitsigners
112 B
AGENTS.md
7.5 KiB
LICENSE
89 B
README.md
1.9 KiB
deploy
723 B
discuss.go
16.7 KiB
git.go
3.5 KiB
git_cli.go
16.0 KiB
git_http.go
1.9 KiB
go.mod
572 B
go.sum
1.9 KiB
handler.go
11.3 KiB
handler_test.go
69.0 KiB
main.go
5.2 KiB
template.go
8.9 KiB
watch
272 B
static/js/hirad.js
raw
| 1 | (function (hirad) { |
| 2 | // |
| 3 | // hirad - Radiance Syntax Highlighter |
| 4 | // |
| 5 | // Copyright (c) 2020-2025 Alexis Sellier |
| 6 | // |
| 7 | const selector = hirad || '.language-radiance'; |
| 8 | const keywords = [ |
| 9 | 'fn', 'pub', 'if', 'else', 'for', 'while', 'break', 'switch', 'match', |
| 10 | 'record', 'union', 'const', 'align', 'let', 'use', 'mod', 'case', |
| 11 | 'continue', 'return', 'true', 'false', 'loop', 'extern', 'panic', |
| 12 | 'device', 'register', 'catch', 'throw', 'throws', |
| 13 | 'at', 'mut', 'nil', 'undefined', 'static', 'in', 'is', 'where', |
| 14 | 'as', 'and', 'or', 'xor', 'not', 'try', 'atomic', 'select', 'trait', |
| 15 | 'instance', 'assert' |
| 16 | ]; |
| 17 | const types = ['bool', 'u8', 'u16', 'u32', 'u64', 'i8', 'i16', 'i32', 'i64', 'f32', 'void', 'opaque']; |
| 18 | |
| 19 | // Syntax definition. |
| 20 | // |
| 21 | // The key becomes the class name of the span around the matched block of code. |
| 22 | const syntax = [ |
| 23 | ['comment', /(\/\/[^\n]*)/g], |
| 24 | ['string' , /("(?:(?!").|\\.)*"|'[^']{1,2}')/g], |
| 25 | ['number' , /\b(0x[0-9a-fA-F]+|0b[01]+|[0-9]+(?:\.[0-9]+)?)\b/g], |
| 26 | ['ref' , /(&|&'|\*)\b/g], |
| 27 | ['delim' , /(->|=>|\(|\)|\{|\}|\[|\])/g], |
| 28 | ['builtin', /(@[a-zA-Z]+)/g], |
| 29 | ['access' , /(\.|::)/g], |
| 30 | ['op' , /(=|!=|\.\.|\+|-|\*|\/|%|\?{1,2}|!{1,2}|>=?|<=?)/g], |
| 31 | ['keyword', new RegExp('\\b(' + keywords.join('|') + ')\\b', 'g')], |
| 32 | ['type' , new RegExp('\\b(' + types.join('|') + ')\\b', 'g')], |
| 33 | ]; |
| 34 | |
| 35 | const table = {}; |
| 36 | |
| 37 | // Encode ASCII characters to Braille to avoid conflicts between patterns. |
| 38 | const encode = (str) => { |
| 39 | const encoded = [...str].map(c => |
| 40 | c.charCodeAt(0) <= 127 ? String.fromCharCode(c.charCodeAt(0) + 0x2800) : c |
| 41 | ).join(''); |
| 42 | table[encoded] = str; |
| 43 | |
| 44 | return encoded; |
| 45 | }; |
| 46 | |
| 47 | // Decode Braille back to ASCII. |
| 48 | const decode = (str) => |
| 49 | table[str] || [...str].map(c => { |
| 50 | const code = c.charCodeAt(0) - 0x2800; |
| 51 | return code >= 0 && code <= 127 ? String.fromCharCode(code) : c; |
| 52 | }).join(''); |
| 53 | |
| 54 | // Escape HTML special characters. |
| 55 | const escape = (str) => |
| 56 | str.replace(/</g, '<').replace(/>/g, '>'); |
| 57 | |
| 58 | // Highlight all matching elements. |
| 59 | for (const node of document.querySelectorAll(selector)) { |
| 60 | for (const child of node.childNodes) { |
| 61 | if (child.nodeType !== Node.TEXT_NODE) continue; |
| 62 | if (/^\$\s/.test(child.nodeValue.trim())) continue; // Skip shell snippets. |
| 63 | |
| 64 | for (const [cls, re] of syntax) { |
| 65 | child.nodeValue = child.nodeValue.replace(re, (_, m) => |
| 66 | '\u00ab' + encode(cls) + '\u00b7' + |
| 67 | encode(m) + |
| 68 | '\u00b7' + encode(cls) + '\u00bb' |
| 69 | ); |
| 70 | } |
| 71 | } |
| 72 | node.innerHTML = node.innerHTML.replace( |
| 73 | /\u00ab(.+?)\u00b7(.+?)\u00b7\1\u00bb/g, |
| 74 | (_, name, value) => { |
| 75 | value = value.replace(/\u00ab[^\u00b7]+\u00b7|\u00b7[^\u00bb]+\u00bb/g, ''); |
| 76 | return '<span class="' + decode(name) + '">' + |
| 77 | escape(decode(value)) + |
| 78 | '</span>'; |
| 79 | } |
| 80 | ); |
| 81 | } |
| 82 | |
| 83 | })(window.hirad); |