{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "code-highlight",
  "title": "Code Highlight",
  "description": "Helper used by the Get IT Done components.",
  "dependencies": [],
  "registryDependencies": [
    "https://zero-design.itdone.de/r/theme.json"
  ],
  "files": [
    {
      "path": "registry/ui/code-highlight.ts",
      "content": "export type CodeLanguage = 'ts' | 'js' | 'json' | 'css' | 'html' | 'bash' | 'python';\nexport type CodeTokenType =\n  | 'comment'\n  | 'string'\n  | 'number'\n  | 'keyword'\n  | 'function'\n  | 'property'\n  | 'tag'\n  | 'variable'\n  | 'punctuation'\n  | 'text';\n\nexport interface CodeToken {\n  type: CodeTokenType;\n  text: string;\n}\n\ntype Rule = [CodeTokenType, RegExp];\n\nconst jsKeywords =\n  'abstract|as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|private|protected|public|readonly|return|set|static|super|switch|this|throw|true|false|try|type|typeof|undefined|var|void|while|with|yield';\n\nconst bashKeywords =\n  'if|then|else|elif|fi|for|while|until|do|done|case|esac|in|function|export|local|return|exit|source|alias|unset|set';\n\nconst pythonKeywords =\n  'and|as|assert|async|await|break|class|continue|def|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|raise|return|try|while|with|yield|True|False|None';\n\nconst strings = String.raw`\"(?:[^\"\\\\\\n]|\\\\.)*\"|'(?:[^'\\\\\\n]|\\\\.)*'`;\n\n// Sticky rules tried in order at each position; the first match wins, anything else becomes plain text.\nconst rules: Record<CodeLanguage, Rule[]> = {\n  js: [\n    ['comment', /\\/\\/[^\\n]*|\\/\\*[\\s\\S]*?\\*\\//y],\n    ['string', new RegExp(`${strings}|\\`(?:[^\\`\\\\\\\\]|\\\\\\\\.)*\\``, 'y')],\n    ['number', /\\b\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?\\b/iy],\n    ['keyword', new RegExp(`\\\\b(?:${jsKeywords})\\\\b`, 'y')],\n    ['function', /[A-Za-z_$][\\w$]*(?=\\s*\\()/y],\n    ['punctuation', /[{}()[\\];,.<>:=+\\-*/!?&|%^~]/y],\n  ],\n  ts: [],\n  json: [\n    ['property', new RegExp(`(?:${strings})(?=\\\\s*:)`, 'y')],\n    ['string', new RegExp(strings, 'y')],\n    ['number', /-?\\b\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?\\b/iy],\n    ['keyword', /\\b(?:true|false|null)\\b/y],\n    ['punctuation', /[{}[\\],:]/y],\n  ],\n  css: [\n    ['comment', /\\/\\*[\\s\\S]*?\\*\\//y],\n    ['string', new RegExp(strings, 'y')],\n    ['keyword', /@[\\w-]+/y],\n    ['property', /-{0,2}[a-zA-Z][\\w-]*(?=\\s*:)/y],\n    ['number', /#[0-9a-fA-F]{3,8}\\b|-?\\b\\d+(?:\\.\\d+)?(?:px|rem|em|%|vh|vw|s|ms|deg)?/y],\n    ['function', /[a-zA-Z-]+(?=\\()/y],\n    ['punctuation', /[{}()[\\];,:>+~*]/y],\n  ],\n  html: [\n    ['comment', /<!--[\\s\\S]*?-->/y],\n    ['tag', /<\\/?[A-Za-z][\\w:-]*/y],\n    ['string', new RegExp(strings, 'y')],\n    ['property', /[A-Za-z_:@][\\w:.-]*(?=\\s*=)/y],\n    ['punctuation', /\\/?>|=/y],\n  ],\n  python: [\n    ['comment', /#[^\\n]*/y],\n    // Triple quoted strings (docstrings) first, then single line strings, both with an optional r, b, f or u prefix.\n    ['string', /[rRbBfFuU]{0,2}(?:\"\"\"[\\s\\S]*?(?:\"\"\"|$)|'''[\\s\\S]*?(?:'''|$))/y],\n    ['string', new RegExp(`[rRbBfFuU]{0,2}(?:${strings})`, 'y')],\n    ['function', /@[A-Za-z_][\\w.]*/y],\n    ['number', /\\b(?:0[xX][\\da-fA-F_]+|0[bB][01_]+|0[oO][0-7_]+|\\d[\\d_]*(?:\\.[\\d_]+)?(?:[eE][+-]?\\d+)?j?)\\b/y],\n    ['keyword', new RegExp(`\\\\b(?:${pythonKeywords})\\\\b`, 'y')],\n    ['function', /[A-Za-z_]\\w*(?=\\s*\\()/y],\n    ['punctuation', /[{}()[\\];,.:=+\\-*/<>!&|%^~@]/y],\n  ],\n  bash: [\n    ['comment', /#[^\\n]*/y],\n    ['string', new RegExp(strings, 'y')],\n    ['variable', /\\$\\{[^}]*\\}|\\$[A-Za-z_]\\w*|\\$[0-9?#@!*]/y],\n    ['keyword', new RegExp(`\\\\b(?:${bashKeywords})\\\\b`, 'y')],\n    ['property', /--?[A-Za-z][\\w-]*/y],\n    ['number', /\\b\\d+\\b/y],\n    ['punctuation', /[|&;<>()[\\]{}=]/y],\n  ],\n};\nrules.ts = rules.js;\n\nexport const tokenizeCode = (code: string, language: CodeLanguage): CodeToken[] => {\n  const list = rules[language] ?? [];\n  const tokens: CodeToken[] = [];\n  const push = (type: CodeTokenType, text: string) => {\n    const last = tokens[tokens.length - 1];\n    if (last && last.type === type) last.text += text;\n    else tokens.push({ type, text });\n  };\n  let index = 0;\n  while (index < code.length) {\n    let matched = false;\n    for (const [type, pattern] of list) {\n      pattern.lastIndex = index;\n      const result = pattern.exec(code);\n      if (result && result[0].length > 0) {\n        push(type, result[0]);\n        index += result[0].length;\n        matched = true;\n        break;\n      }\n    }\n    if (!matched) {\n      // Consume a whole identifier or whitespace run as plain text so keywords inside words do not match.\n      const word = /^(?:[\\w$-]+|\\s+|[\\s\\S])/.exec(code.slice(index));\n      const text = word ? word[0] : code[index];\n      push('text', text);\n      index += text.length;\n    }\n  }\n  return tokens;\n};\n\n// Colour roles by token. Default tone uses AA text roles; the inverse tone keeps one hue and varies emphasis.\nexport const codeTokenClasses = {\n  default: {\n    comment: 'italic text-text-subtle-on-muted',\n    string: 'text-text-success',\n    number: 'text-text-warning',\n    keyword: 'text-text-brand-on-subtle',\n    function: 'text-text-info-on-subtle',\n    property: 'text-text-info-on-subtle',\n    tag: 'text-text-brand-on-subtle',\n    variable: 'text-text-warning',\n    punctuation: 'text-text-subtle-on-muted',\n    text: '',\n  },\n  inverse: {\n    comment: 'italic text-text-inverse-subtle',\n    string: 'text-background',\n    number: 'text-text-inverse-subtle',\n    keyword: 'font-semibold text-background',\n    function: 'text-background',\n    property: 'text-text-inverse-subtle',\n    tag: 'font-semibold text-background',\n    variable: 'text-text-inverse-subtle',\n    punctuation: 'text-text-inverse-subtle',\n    text: '',\n  },\n} as const;\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}