SLOPSHOPPER

Claude Code Themes

Draws Claude's replies in color: headings, bold, italics, inline code, links, list markers and highlighted code blocks, in a Monokai Pro theme. Display only…

newrows
v?MITupdated 2026-10-05danishmughal/claude-code-themes
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · themes
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Bash(bun test) ⎿ 3 pass, 1 fail Done. I made refresh reject expired claims and added an audit call. ✻ Worked for 42s · done 4:20 PM ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts

Draws

Claude's reply
Done. I made refresh reject expired claims and added an audit call.
README

Claude Code Themes

Monokai Pro colors for Claude Code's replies.

Out of the box, Claude Code draws bold text, italics and headings in the same color as everything else, and colors code blocks from a fixed set of 16 terminal colors. Its /theme setting can't change either. This plugin can. It's a mod that redraws each reply with a full palette: colored headings and emphasis, highlighted inline code and links, and Monokai syntax highlighting in code blocks.

It only changes how replies look. Your saved conversations and what Claude reads stay exactly the same, and it adds nothing to your token usage.

Quickstart

Paste either prompt into Claude Code.

Install Only

Set up Claude Code Themes for me (github.com/danishmughal/claude-code-themes):

1. Check that `claude --version` is 2.1.287 or newer; run `claude update` if not.
2. Run `claude plugin marketplace add danishmughal/claude-code-themes`.
3. Read the repo's README and ask me which theme I want.
4. Run `claude plugin install themes@claude-code-themes --config theme=<my pick>`.
5. Tell me to run /reload-plugins.

Install and Show Support with a Star ⭐ ❤️

Set up Claude Code Themes for me (github.com/danishmughal/claude-code-themes):

1. Check that `claude --version` is 2.1.287 or newer; run `claude update` if not.
2. Run `claude plugin marketplace add danishmughal/claude-code-themes`.
3. Read the repo's README and ask me which theme I want.
4. Run `claude plugin install themes@claude-code-themes --config theme=<my pick>`.
5. Star the repo: `gh api -X PUT user/starred/danishmughal/claude-code-themes`
   (skip this if gh isn't signed in).
6. Tell me to run /reload-plugins.

Claude asks which theme you want and installs it. After /reload-plugins, the next reply comes back in color.

Contents

Install

You need Claude Code 2.1.287 or later, and a terminal that shows full 24-bit color.

claude plugin marketplace add danishmughal/claude-code-themes
claude plugin install themes@claude-code-themes

This repository is private, so the machine needs GitHub access to it: either an SSH key loaded in ssh-agent, or gh auth login followed by gh auth setup-git.

Then start a new session. To confirm the plugin loaded, run /plugin; it shows 1 mod active · themes.

If the install prints 1 userConfig option not yet set, that's only the theme choice. Until you pick one, you get the default, monokai-pro-classic.

Choose a theme

There's one theme for each of the six Monokai Pro palettes. Pick the one that matches your terminal's theme; Warp includes all six.

Switch anytime with /plugin configure themes@claude-code-themes inside Claude Code, or choose one when you install:

claude plugin install themes@claude-code-themes --config theme=monokai-pro

Every theme colors the same parts of a reply:

| Part of a reply | Color | | :- | :- | | Headings and list markers | green | | Bold and italic text | blue | | Inline code, and code blocks with no language | orange | | Link text | purple | | Code blocks | keywords red, declarations blue, strings yellow, numbers purple, functions and types green, comments gray |

Themes

Each screenshot is a real Claude Code session showing the same reply, on the theme's matching terminal background.

Claude Code default

For comparison, this is a reply without the plugin. Bold is only heavier, headings are plain, and code uses the terminal's 16 basic colors.

A Claude Code reply with Claude Code's own dark theme

monokai-pro

The Monokai Pro default, on a warm charcoal background, #2d2a2e.

#ff6188 red · #fc9867 orange · #ffd866 yellow · #a9dc76 green · #78dce8 blue · #ab9df2 purple

A Claude Code reply in the monokai-pro theme

monokai-pro-classic

The original Monokai colors, on #272822. This is the plugin's default.

#f92672 red · #fd971f orange · #e6db74 yellow · #a6e22e green · #66d9ef blue · #ae81ff purple

A Claude Code reply in the monokai-pro-classic theme

monokai-pro-machine

Cooler, brighter colors on a blue-gray background, #273136.

#ff6d7e red · #ffb270 orange · #ffed72 yellow · #a2e57b green · #7cd5f1 blue · #baa0f8 purple

A Claude Code reply in the monokai-pro-machine theme

monokai-pro-octagon

Softer, muted colors on a navy background, #282a3a.

#ff657a red · #ff9b5e orange · #ffd76d yellow · #bad761 green · #9cd1bb blue · #c39ac9 purple

A Claude Code reply in the monokai-pro-octagon theme

monokai-pro-ristretto

Warm colors on a dark brown background, #2c2525.

#fd6883 red · #f38d70 orange · #f9cc6c yellow · #adda78 green · #85dacc blue · #a8a9eb purple

A Claude Code reply in the monokai-pro-ristretto theme

monokai-pro-spectrum

Saturated colors on a neutral gray background, #222222.

#fc618d red · #fd9353 orange · #fce566 yellow · #7bd88f green · #5ad4e6 blue · #948ae3 purple

A Claude Code reply in the monokai-pro-spectrum theme

Update

claude plugin update themes@claude-code-themes

Or turn on auto-update for this marketplace under Marketplaces in /plugin.

Troubleshooting

  • /plugin doesn't list the mod. Claude Code sessions older than 2.1.287 save a setting that switches mods off, and newer sessions read it when they start. Restart any old sessions, or run claude -p /cost once to refresh the setting, then open a new session.
  • Another mod also redraws replies. Only one mod can draw a reply, so turn the other one off in /plugin.
  • Some parts still look like stock Claude Code. Tables, quotes, code in a language this plugin doesn't include, and the Claude desktop app keep Claude Code's own look.

How it works

The plugin handles one event: Claude Code asking how to draw a reply (ui.render for AssistantMessage).

  • hooks/draw.ts reads the reply with the same markdown parser Claude Code uses (marked, with Claude Code's settings), so line breaks, lists, numbering and spacing match what Claude Code would draw. It then draws paragraphs, lists, headings and code blocks in color.
  • hooks/highlight.ts highlights code with highlight.js, using the token rules of Claude Code's built-in Monokai Extended colors.
  • hooks/palettes.ts holds the themes. To add one, add an entry there and its name to the options list in .claude-plugin/plugin.json.

To work on the plugin:

claude --plugin-dir .      # load this checkout; edits reload as you save
claude plugin validate .
claude plugin test

Third-party code

  • hooks/vendor/marked.js is marked 18.0.14, the lib/marked.esm.js file from its npm package (MIT, see hooks/vendor/marked.LICENSE).
  • hooks/vendor/hljs/ is highlight.js 11.12.0: es/core.js and es/languages/<name>.min.js from @highlightjs/cdn-assets, each language saved as <name>.js (BSD-3-Clause, see hooks/vendor/hljs/LICENSE). To add a language, copy its file in and register it in hooks/highlight.ts.

License

MIT

Source 35 files
hooks/register.ts 17 lines
1import type { Register } from 'claude-code'
2
3import { draw } from './draw'
4import { themeNamed } from './palettes'
5
6export const register: Register = (on, options) => {
7  // The theme picked with /plugin configure, read each time the mod loads
8  const theme = themeNamed((options as { theme?: unknown } | undefined)?.theme)
9
10  // Redraws each reply block in the theme's colors. Only the drawing changes:
11  // the stored message, and what Claude reads next turn, stay as written.
12  on('ui.render', { component: 'AssistantMessage' }, ($, e, next) => {
13    if (e.surface !== 'terminal') return next(e)
14    return draw($.ui.resolve(e), e.props.text, e.props.isFirstOfReply, theme) ?? next(e)
15  })
16}
17
hooks/draw.ts 259 lines
1// Draws one assistant reply block the way Claude Code's own renderer does,
2// in the chosen theme's colors. Paragraphs, lists, headings and code blocks
3// are drawn here from marked's tokens; every other block (tables, quotes,
4// rules) goes to Claude Code's own Markdown element unchanged.
5import type { Elements, RenderElement, RenderNode } from 'claude-code'
6
7import { highlight, languageOf } from './highlight'
8import { lex } from './lexer'
9import type { Token } from './lexer'
10import type { Theme } from './palettes'
11
12type Table = Elements['terminal']
13
14// The theme of the draw in progress; draw() runs start to finish without
15// awaiting, so no other draw can change it midway
16let theme: Theme
17
18// Element string and Markdown text limits
19const MAX_CHARS = 10000
20// The reply bullet: BLACK CIRCLE FOR RECORD, U+23FA, which Claude Code draws on
21// macOS. Elsewhere it draws U+25CF; a mod has no way to read the platform.
22const BULLET = String.fromCodePoint(0x23fa)
23// Claude Code caps a nested list's indent at this many columns
24const MAX_INDENT = 32
25
26class Unsupported extends Error {}
27
28// Returns null when Claude Code should draw the block itself
29export function draw(t: Table, text: string, isFirstOfReply: boolean, active: Theme): RenderElement | null {
30  theme = active
31  let body: RenderElement[]
32  try {
33    body = blocks(t, lex(text))
34  } catch (err) {
35    if (err instanceof Unsupported) return null
36    throw err
37  }
38  if (body.length === 0) return null
39  const dot = isFirstOfReply
40    ? [t.Box({ minWidth: 2, flexShrink: 0, children: [t.Text({ color: 'text', children: [BULLET] })] })]
41    : []
42  return t.Box({
43    flexDirection: 'row',
44    alignItems: 'flex-start',
45    width: '100%',
46    marginTop: isFirstOfReply ? 1 : 0,
47    children: [...dot, t.Box({ flexDirection: 'column', flexGrow: 1, flexShrink: 1, children: body })],
48  })
49}
50
51// Top-level blocks, spaced as the engine's string output spaces them: a blank
52// line wherever the source had one, and always after a heading
53function blocks(t: Table, tokens: Token[]): RenderElement[] {
54  const out: RenderElement[] = []
55  let gap = false
56  for (const tok of tokens) {
57    if (tok.type === 'space') {
58      gap = true
59      continue
60    }
61    const el = block(t, tok)
62    out.push(out.length > 0 && gap ? t.Box({ marginTop: 1, children: [el] }) : el)
63    gap = tok.type === 'heading'
64  }
65  return out
66}
67
68function block(t: Table, tok: Token): RenderElement {
69  if (tok.type === 'paragraph') return prose(t, tok.tokens ?? [])
70  if (tok.type === 'list') return list(t, tok, 0)
71  if (tok.type === 'heading') return heading(t, tok)
72  if (tok.type === 'code') return code(t, tok) ?? engine(t, tok.raw)
73  return engine(t, tok.raw)
74}
75
76// A code block: the theme's code colors for a language this mod bundles, the
77// inline code color for a fence with no language, plain for indented code, as
78// the engine draws that. Null for a language only the engine knows.
79function code(t: Table, tok: Token): RenderElement | null {
80  const text = tok.text ?? ''
81  if (tok.codeBlockStyle === 'indented') return t.Text({ children: pieces(text) })
82  const info = (tok.lang ?? '').trim()
83  if (!info) return t.Text({ color: theme.markdown.code, children: pieces(text) })
84  const language = languageOf(info)
85  const spans = language ? highlight(text, language, theme) : null
86  if (!spans) return null
87  return t.Text({
88    children: spans.flatMap((s) =>
89      s.color === theme.foreground ? pieces(s.text) : [t.Text({ color: s.color, children: pieces(s.text) })],
90    ),
91  })
92}
93
94// A string as Text children within the per-string limit
95function pieces(s: string): string[] {
96  const out: string[] = []
97  for (let i = 0; i < s.length; i += MAX_CHARS) out.push(s.slice(i, i + MAX_CHARS))
98  return out
99}
100
101// The engine's heading weights (# bold, italic and underlined; the rest
102// bold), in the heading color
103function heading(t: Table, tok: Token): RenderElement {
104  const top = tok.depth === 1
105  return t.Text({
106    bold: true,
107    color: theme.markdown.heading,
108    ...(top ? { italic: true, underline: true } : {}),
109    children: inline(t, tok.tokens ?? []),
110  })
111}
112
113function engine(t: Table, raw: string): RenderElement {
114  const text = raw.replace(/\n+$/, '')
115  if (text.length > MAX_CHARS) throw new Unsupported()
116  return t.Markdown({ text })
117}
118
119function prose(t: Table, tokens: Token[]): RenderElement {
120  return t.Text({ children: inline(t, tokens) })
121}
122
123// A list, with the engine's markers: "-" for bullets, and for numbers 1. at
124// the top level, a. one level down, i. two levels down
125function list(t: Table, tok: Token, depth: number): RenderElement {
126  const items = tok.items ?? []
127  const first = tok.start === '' || tok.start === undefined ? 1 : tok.start
128  const last = first + items.length - 1
129  const rows = items.map((item, i) => {
130    const marker = tok.ordered ? `${number(first + i, depth, first, last)}.` : '-'
131    const content = itemBody(t, item, depth)
132    const row = t.Box({
133      flexDirection: 'row',
134      children: [
135        t.Box({
136          minWidth: Math.min(marker.length + 1, MAX_INDENT),
137          flexShrink: 0,
138          children: [t.Text({ color: theme.markdown.marker, children: [marker] })],
139        }),
140        t.Box({ flexDirection: 'column', flexGrow: 1, flexShrink: 1, children: content }),
141      ],
142    })
143    return i > 0 && tok.loose ? t.Box({ marginTop: 1, children: [row] }) : row
144  })
145  return t.Box({ flexDirection: 'column', children: rows })
146}
147
148function number(n: number, depth: number, first: number, last: number): string {
149  if (depth === 1 && first >= 1) return letters(n)
150  if (depth === 2 && first >= 1 && last <= 3999) return roman(n)
151  return String(n)
152}
153
154function letters(n: number): string {
155  let s = ''
156  while (n > 0) {
157    n--
158    s = String.fromCharCode(97 + (n % 26)) + s
159    n = Math.floor(n / 26)
160  }
161  return s
162}
163
164const ROMAN: [number, string][] = [
165  [1000, 'm'], [900, 'cm'], [500, 'd'], [400, 'cd'], [100, 'c'], [90, 'xc'],
166  [50, 'l'], [40, 'xl'], [10, 'x'], [9, 'ix'], [5, 'v'], [4, 'iv'], [1, 'i'],
167]
168
169function roman(n: number): string {
170  let s = ''
171  for (const [v, r] of ROMAN) while (n >= v) (s += r), (n -= v)
172  return s
173}
174
175// An item holds text (tight lists), paragraphs (loose lists), nested lists
176// and code, which sits under the item's text. Tables and quotes inside an
177// item get layout this mod doesn't reproduce, so such a reply is left to the
178// engine.
179function itemBody(t: Table, item: Token, depth: number): RenderElement[] {
180  const out: RenderElement[] = []
181  for (const tok of item.tokens ?? []) {
182    if (tok.type === 'space') continue
183    if (tok.type === 'text' || tok.type === 'paragraph') out.push(prose(t, tok.tokens ?? [{ type: 'text', raw: tok.raw, text: tok.text }]))
184    else if (tok.type === 'list') out.push(list(t, tok, depth + 1))
185    else if (tok.type === 'code') out.push(code(t, tok) ?? t.Text({ children: pieces(tok.text ?? '') }))
186    else if (tok.type === 'checkbox') continue
187    else throw new Unsupported()
188  }
189  if (item.task) {
190    const box = t.Text({ children: [item.checked ? '[x] ' : '[ ] '] })
191    if (out.length > 0) out[0] = t.Box({ flexDirection: 'row', children: [box, out[0]] })
192  }
193  return out
194}
195
196// Inline tokens as Text children, styled as the engine styles them, in the
197// theme's colors
198function inline(t: Table, tokens: Token[]): RenderNode[] {
199  const out: RenderNode[] = []
200  for (const tok of tokens) {
201    switch (tok.type) {
202      case 'text':
203        if (tok.tokens) out.push(...inline(t, tok.tokens))
204        else out.push(chars(tok.text ?? tok.raw))
205        break
206      case 'strong':
207        out.push(t.Text({ bold: true, color: theme.markdown.strong, children: inline(t, tok.tokens ?? []) }))
208        break
209      case 'em':
210        out.push(t.Text({ italic: true, color: theme.markdown.em, children: inline(t, tok.tokens ?? []) }))
211        break
212      case 'del':
213        out.push(t.Text({ strikethrough: true, children: inline(t, tok.tokens ?? []) }))
214        break
215      case 'codespan':
216        out.push(t.Text({ color: theme.markdown.code, children: [chars(tok.text ?? '')] }))
217        break
218      case 'link':
219        out.push(link(t, tok))
220        break
221      case 'br':
222        out.push('\n')
223        break
224      case 'checkbox':
225        break
226      case 'image':
227        out.push(chars(tok.text ? `${tok.text} (${tok.href})` : tok.href ?? tok.raw))
228        break
229      default:
230        out.push(chars(tok.text ?? tok.raw))
231    }
232  }
233  return out
234}
235
236function chars(s: string): string {
237  if (s.length > MAX_CHARS) throw new Unsupported()
238  return s
239}
240
241// The Link element refuses the whole tree over a bad href, so anything but a
242// plain https link is drawn as text
243function link(t: Table, tok: Token): RenderNode {
244  const label = t.Text({ color: theme.markdown.link, children: inline(t, tok.tokens ?? []) })
245  const href = safeHref(tok.href ?? '')
246  return href ? t.Link({ href, children: [label] }) : label
247}
248
249function safeHref(href: string): string | null {
250  try {
251    const u = new URL(href)
252    if (u.protocol !== 'https:' || u.username || u.password) return null
253    if (u.href.length > 2048 || !/^[\x21-\x7e]+$/.test(u.href)) return null
254    return u.href
255  } catch {
256    return null
257  }
258}
259
hooks/palettes.ts 92 lines
1// The themes replies can be drawn in. Each Monokai Pro filter is its
2// published palette; Warp and most editors ship a matching terminal theme of
3// the same name, so pick the one your terminal uses.
4type Palette = {
5  red: string
6  orange: string
7  yellow: string
8  green: string
9  blue: string
10  purple: string
11  comment: string
12  foreground: string
13}
14
15const PALETTES: Record<string, Palette> = {
16  'monokai-pro': {
17    red: '#ff6188', orange: '#fc9867', yellow: '#ffd866', green: '#a9dc76',
18    blue: '#78dce8', purple: '#ab9df2', comment: '#727072', foreground: '#fcfcfa',
19  },
20  'monokai-pro-classic': {
21    red: '#f92672', orange: '#fd971f', yellow: '#e6db74', green: '#a6e22e',
22    blue: '#66d9ef', purple: '#ae81ff', comment: '#6e7066', foreground: '#fdfff1',
23  },
24  'monokai-pro-machine': {
25    red: '#ff6d7e', orange: '#ffb270', yellow: '#ffed72', green: '#a2e57b',
26    blue: '#7cd5f1', purple: '#baa0f8', comment: '#6b7678', foreground: '#f2fffc',
27  },
28  'monokai-pro-octagon': {
29    red: '#ff657a', orange: '#ff9b5e', yellow: '#ffd76d', green: '#bad761',
30    blue: '#9cd1bb', purple: '#c39ac9', comment: '#696d77', foreground: '#eaf2f1',
31  },
32  'monokai-pro-ristretto': {
33    red: '#fd6883', orange: '#f38d70', yellow: '#f9cc6c', green: '#adda78',
34    blue: '#85dacc', purple: '#a8a9eb', comment: '#72696a', foreground: '#fff1f3',
35  },
36  'monokai-pro-spectrum': {
37    red: '#fc618d', orange: '#fd9353', yellow: '#fce566', green: '#7bd88f',
38    blue: '#5ad4e6', purple: '#948ae3', comment: '#69676c', foreground: '#f7f1ff',
39  },
40}
41
42export const DEFAULT_THEME = 'monokai-pro-classic'
43
44export type Theme = {
45  name: string
46  foreground: string
47  // Markdown roles, as Monokai's standard editor theme assigns them
48  markdown: { heading: string; strong: string; em: string; code: string; link: string; marker: string }
49  // highlight.js scopes, as Claude Code's Monokai Extended table assigns them
50  scopes: Map<string, string>
51}
52
53// The named theme, or the default for a name this version doesn't know
54export function themeNamed(name: unknown): Theme {
55  const key = typeof name === 'string' && name in PALETTES ? name : DEFAULT_THEME
56  const p = PALETTES[key]!
57  return {
58    name: key,
59    foreground: p.foreground,
60    markdown: { heading: p.green, strong: p.blue, em: p.blue, code: p.orange, link: p.purple, marker: p.green },
61    scopes: new Map([
62      ['keyword', p.red],
63      // keywords that declare something, as Monokai draws storage
64      ['_storage', p.blue],
65      ['built_in', p.green],
66      ['type', p.green],
67      ['literal', p.purple],
68      ['number', p.purple],
69      ['string', p.yellow],
70      ['title', p.green],
71      ['title.function', p.green],
72      ['title.class', p.green],
73      ['title.class.inherited', p.green],
74      ['params', p.orange],
75      ['comment', p.comment],
76      ['meta', p.comment],
77      ['attr', p.green],
78      ['attribute', p.green],
79      ['variable', p.foreground],
80      ['variable.language', p.foreground],
81      ['property', p.foreground],
82      ['operator', p.red],
83      ['punctuation', p.foreground],
84      ['symbol', p.purple],
85      ['regexp', p.yellow],
86      ['subst', p.foreground],
87    ]),
88  }
89}
90
91export const THEMES = Object.keys(PALETTES)
92
hooks/highlight.ts 111 lines
1// Syntax highlighting for code blocks. Claude Code highlights reply code with
2// a fixed 16-color table and keeps Monokai Extended for its diff view; this
3// uses that diff view's scope rules, in the theme's colors, over the same
4// highlighter (highlight.js).
5import hljs from './vendor/hljs/core.js'
6import bash from './vendor/hljs/languages/bash.js'
7import c from './vendor/hljs/languages/c.js'
8import cpp from './vendor/hljs/languages/cpp.js'
9import csharp from './vendor/hljs/languages/csharp.js'
10import css from './vendor/hljs/languages/css.js'
11import diff from './vendor/hljs/languages/diff.js'
12import dockerfile from './vendor/hljs/languages/dockerfile.js'
13import go from './vendor/hljs/languages/go.js'
14import graphql from './vendor/hljs/languages/graphql.js'
15import ini from './vendor/hljs/languages/ini.js'
16import java from './vendor/hljs/languages/java.js'
17import javascript from './vendor/hljs/languages/javascript.js'
18import json from './vendor/hljs/languages/json.js'
19import kotlin from './vendor/hljs/languages/kotlin.js'
20import makefile from './vendor/hljs/languages/makefile.js'
21import markdown from './vendor/hljs/languages/markdown.js'
22import php from './vendor/hljs/languages/php.js'
23import plaintext from './vendor/hljs/languages/plaintext.js'
24import python from './vendor/hljs/languages/python.js'
25import ruby from './vendor/hljs/languages/ruby.js'
26import rust from './vendor/hljs/languages/rust.js'
27import scss from './vendor/hljs/languages/scss.js'
28import shell from './vendor/hljs/languages/shell.js'
29import sql from './vendor/hljs/languages/sql.js'
30import swift from './vendor/hljs/languages/swift.js'
31import typescript from './vendor/hljs/languages/typescript.js'
32import xml from './vendor/hljs/languages/xml.js'
33import yaml from './vendor/hljs/languages/yaml.js'
34
35import type { Theme } from './palettes'
36
37const GRAMMARS = {
38  bash, c, cpp, csharp, css, diff, dockerfile, go, graphql, ini, java, javascript, json, kotlin,
39  makefile, markdown, php, plaintext, python, ruby, rust, scss, shell, sql, swift, typescript, xml, yaml,
40}
41for (const [name, grammar] of Object.entries(GRAMMARS)) hljs.registerLanguage(name, grammar)
42
43// Keywords that declare something take the storage color, as in Monokai
44const STORAGE = new Set([
45  'const', 'let', 'var', 'function', 'class', 'type', 'interface', 'enum', 'namespace', 'module',
46  'def', 'fn', 'func', 'struct', 'trait', 'impl',
47])
48
49export type Span = { text: string; color: string }
50
51type Node = { scope?: string; children: (string | Node)[] }
52
53// A code block's language as Claude Code reads it: the whole info string,
54// else its first word
55export function languageOf(info: string): string | null {
56  const word = info.match(/^[\w.+#-]+/)?.[0] ?? ''
57  if (info && hljs.getLanguage(info)) return info
58  if (word && hljs.getLanguage(word)) return word
59  return null
60}
61
62const cache = new Map<string, Span[]>()
63const CACHE_SIZE = 64
64
65// Colored runs for the code, or null when highlight.js can't read it
66export function highlight(code: string, language: string, theme: Theme): Span[] | null {
67  const key = theme.name + '\0' + language + '\0' + code
68  const hit = cache.get(key)
69  if (hit) return hit
70  let root: Node | undefined
71  try {
72    const result = hljs.highlight(code, { language, ignoreIllegals: true })
73    root = result._emitter?.rootNode
74  } catch {
75    return null
76  }
77  if (!root || !Array.isArray(root.children)) return null
78  const spans: Span[] = []
79  walk(root, undefined, theme, spans)
80  if (cache.size >= CACHE_SIZE) cache.delete(cache.keys().next().value!)
81  cache.set(key, spans)
82  return spans
83}
84
85function walk(node: Node, inherited: string | undefined, theme: Theme, out: Span[]) {
86  const scope = node.scope ?? inherited
87  for (const child of node.children) {
88    if (typeof child !== 'string') {
89      walk(child, scope, theme, out)
90      continue
91    }
92    const color = colorOf(scope, child, theme)
93    const last = out[out.length - 1]
94    if (last && last.color === color) last.text += child
95    else out.push({ text: child, color })
96  }
97}
98
99function colorOf(scope: string | undefined, text: string, theme: Theme): string {
100  if (!scope) return theme.foreground
101  if (scope === 'keyword' && STORAGE.has(text.trim())) return theme.scopes.get('_storage')!
102  let s = scope
103  for (;;) {
104    const color = theme.scopes.get(s)
105    if (color) return color
106    const dot = s.lastIndexOf('.')
107    if (dot < 0) return theme.foreground
108    s = s.slice(0, dot)
109  }
110}
111
hooks/lexer.ts 42 lines
1import { Marked } from './vendor/marked.js'
2
3// Claude Code lexes replies with marked plus two tokenizer overrides. Using
4// the same ones here keeps this mod's blocks identical to the engine's:
5// strikethrough needs a double tilde, and reference definitions stay text.
6const DOUBLE_TILDE = /^~~(?=[^\s~])((?:\\.|[^\\])*?(?:\\.|[^\s~\\]))~~(?=[^~]|$)/
7
8const md = new Marked({ gfm: true })
9md.use({
10  tokenizer: {
11    del(src: string) {
12      const m = DOUBLE_TILDE.exec(src)
13      if (!m || m[1] === undefined) return undefined
14      return { type: 'del', raw: m[0], text: m[1], tokens: this.lexer.inlineTokens(m[1]) }
15    },
16    def() {
17      return undefined
18    },
19  },
20})
21
22export type Token = {
23  type: string
24  raw: string
25  text?: string
26  tokens?: Token[]
27  items?: Token[]
28  ordered?: boolean
29  start?: number | ''
30  loose?: boolean
31  task?: boolean
32  checked?: boolean
33  href?: string
34  depth?: number
35  lang?: string
36  codeBlockStyle?: string
37}
38
39export function lex(text: string): Token[] {
40  return md.lexer(text) as Token[]
41}
42
hooks/vendor/hljs/core.js 2607 lines
1/*!
2  Highlight.js v11.12.0 (git: f7f7d3803b)
3  (c) 2006-2026 Josh Goebel <hello@joshgoebel.com> and other contributors
4  License: BSD-3-Clause
5 */
6/* eslint-disable no-multi-assign */
7
8function deepFreeze(obj) {
9  if (obj instanceof Map) {
10    obj.clear =
11      obj.delete =
12      obj.set =
13        function () {
14          throw new Error('map is read-only');
15        };
16  } else if (obj instanceof Set) {
17    obj.add =
18      obj.clear =
19      obj.delete =
20        function () {
21          throw new Error('set is read-only');
22        };
23  }
24
25  // Freeze self
26  Object.freeze(obj);
27
28  Object.getOwnPropertyNames(obj).forEach((name) => {
29    const prop = obj[name];
30    const type = typeof prop;
31
32    // Freeze prop if it is an object or function and also not already frozen
33    if ((type === 'object' || type === 'function') && !Object.isFrozen(prop)) {
34      deepFreeze(prop);
35    }
36  });
37
38  return obj;
39}
40
41/** @typedef {import('highlight.js').CallbackResponse} CallbackResponse */
42/** @typedef {import('highlight.js').CompiledMode} CompiledMode */
43/** @implements CallbackResponse */
44
45class Response {
46  /**
47   * @param {CompiledMode} mode
48   */
49  constructor(mode) {
50    // eslint-disable-next-line no-undefined
51    if (mode.data === undefined) mode.data = {};
52
53    this.data = mode.data;
54    this.isMatchIgnored = false;
55  }
56
57  ignoreMatch() {
58    this.isMatchIgnored = true;
59  }
60}
61
62/**
63 * @param {string} value
64 * @returns {string}
65 */
66function escapeHTML(value) {
67  return value
68    .replace(/&/g, '&amp;')
69    .replace(/</g, '&lt;')
70    .replace(/>/g, '&gt;')
71    .replace(/"/g, '&quot;')
72    .replace(/'/g, '&#x27;');
73}
74
75/**
76 * performs a shallow merge of multiple objects into one
77 *
78 * @template T
79 * @param {T} original
80 * @param {Record<string,any>[]} objects
81 * @returns {T} a single new object
82 */
83function inherit$1(original, ...objects) {
84  /** @type Record<string,any> */
85  const result = Object.create(null);
86
87  for (const key in original) {
88    result[key] = original[key];
89  }
90  objects.forEach(function(obj) {
91    for (const key in obj) {
92      result[key] = obj[key];
93    }
94  });
95  return /** @type {T} */ (result);
96}
97
98/**
99 * @typedef {object} Renderer
100 * @property {(text: string) => void} addText
101 * @property {(node: Node) => void} openNode
102 * @property {(node: Node) => void} closeNode
103 * @property {() => string} value
104 */
105
106/** @typedef {{scope?: string, language?: string, sublanguage?: boolean}} Node */
107/** @typedef {{walk: (r: Renderer) => void}} Tree */
108/** */
109
110const SPAN_CLOSE = '</span>';
111
112/**
113 * Determines if a node needs to be wrapped in <span>
114 *
115 * @param {Node} node */
116const emitsWrappingTags = (node) => {
117  // rarely we can have a sublanguage where language is undefined
118  // TODO: track down why
119  return !!node.scope;
120};
121
122/**
123 *
124 * @param {string} name
125 * @param {{prefix:string}} options
126 */
127const scopeToCSSClass = (name, { prefix }) => {
128  // sub-language
129  if (name.startsWith("language:")) {
130    return name.replace("language:", "language-");
131  }
132  // tiered scope: comment.line
133  if (name.includes(".")) {
134    const pieces = name.split(".");
135    return [
136      `${prefix}${pieces.shift()}`,
137      ...(pieces.map((x, i) => `${x}${"_".repeat(i + 1)}`))
138    ].join(" ");
139  }
140  // simple scope
141  return `${prefix}${name}`;
142};
143
144/** @type {Renderer} */
145class HTMLRenderer {
146  /**
147   * Creates a new HTMLRenderer
148   *
149   * @param {Tree} parseTree - the parse tree (must support `walk` API)
150   * @param {{classPrefix: string}} options
151   */
152  constructor(parseTree, options) {
153    this.buffer = "";
154    this.classPrefix = options.classPrefix;
155    parseTree.walk(this);
156  }
157
158  /**
159   * Adds texts to the output stream
160   *
161   * @param {string} text */
162  addText(text) {
163    this.buffer += escapeHTML(text);
164  }
165
166  /**
167   * Adds a node open to the output stream (if needed)
168   *
169   * @param {Node} node */
170  openNode(node) {
171    if (!emitsWrappingTags(node)) return;
172
173    const className = scopeToCSSClass(node.scope,
174      { prefix: this.classPrefix });
175    this.span(className);
176  }
177
178  /**
179   * Adds a node close to the output stream (if needed)
180   *
181   * @param {Node} node */
182  closeNode(node) {
183    if (!emitsWrappingTags(node)) return;
184
185    this.buffer += SPAN_CLOSE;
186  }
187
188  /**
189   * returns the accumulated buffer
190  */
191  value() {
192    return this.buffer;
193  }
194
195  // helpers
196
197  /**
198   * Builds a span element
199   *
200   * @param {string} className */
201  span(className) {
202    this.buffer += `<span class="${className}">`;
203  }
204}
205
206/** @typedef {{scope?: string, language?: string, children: Node[]} | string} Node */
207/** @typedef {{scope?: string, language?: string, children: Node[]} } DataNode */
208/** @typedef {import('highlight.js').Emitter} Emitter */
209/**  */
210
211/** @returns {DataNode} */
212const newNode = (opts = {}) => {
213  /** @type DataNode */
214  const result = { children: [] };
215  Object.assign(result, opts);
216  return result;
217};
218
219class TokenTree {
220  constructor() {
221    /** @type DataNode */
222    this.rootNode = newNode();
223    this.stack = [this.rootNode];
224  }
225
226  get top() {
227    return this.stack[this.stack.length - 1];
228  }
229
230  get root() { return this.rootNode; }
231
232  /** @param {Node} node */
233  add(node) {
234    this.top.children.push(node);
235  }
236
237  /** @param {string} scope */
238  openNode(scope) {
239    /** @type Node */
240    const node = newNode({ scope });
241    this.add(node);
242    this.stack.push(node);
243  }
244
245  closeNode() {
246    if (this.stack.length > 1) {
247      return this.stack.pop();
248    }
249    // eslint-disable-next-line no-undefined
250    return undefined;
251  }
252
253  closeAllNodes() {
254    while (this.closeNode());
255  }
256
257  toJSON() {
258    return JSON.stringify(this.rootNode, null, 4);
259  }
260
261  /**
262   * @typedef { import("./html_renderer").Renderer } Renderer
263   * @param {Renderer} builder
264   */
265  walk(builder) {
266    // this does not
267    return this.constructor._walk(builder, this.rootNode);
268    // this works
269    // return TokenTree._walk(builder, this.rootNode);
270  }
271
272  /**
273   * @param {Renderer} builder
274   * @param {Node} node
275   */
276  static _walk(builder, node) {
277    if (typeof node === "string") {
278      builder.addText(node);
279    } else if (node.children) {
280      builder.openNode(node);
281      node.children.forEach((child) => this._walk(builder, child));
282      builder.closeNode(node);
283    }
284    return builder;
285  }
286
287  /**
288   * @param {Node} node
289   */
290  static _collapse(node) {
291    if (typeof node === "string") return;
292    if (!node.children) return;
293
294    if (node.children.every(el => typeof el === "string")) {
295      // node.text = node.children.join("");
296      // delete node.children;
297      node.children = [node.children.join("")];
298    } else {
299      node.children.forEach((child) => {
300        TokenTree._collapse(child);
301      });
302    }
303  }
304}
305
306/**
307  Currently this is all private API, but this is the minimal API necessary
308  that an Emitter must implement to fully support the parser.
309
310  Minimal interface:
311
312  - addText(text)
313  - __addSublanguage(emitter, subLanguageName)
314  - startScope(scope)
315  - endScope()
316  - finalize()
317  - toHTML()
318
319*/
320
321/**
322 * @implements {Emitter}
323 */
324class TokenTreeEmitter extends TokenTree {
325  /**
326   * @param {*} options
327   */
328  constructor(options) {
329    super();
330    this.options = options;
331  }
332
333  /**
334   * @param {string} text
335   */
336  addText(text) {
337    if (text === "") { return; }
338
339    this.add(text);
340  }
341
342  /** @param {string} scope */
343  startScope(scope) {
344    this.openNode(scope);
345  }
346
347  endScope() {
348    this.closeNode();
349  }
350
351  /**
352   * @param {Emitter & {root: DataNode}} emitter
353   * @param {string} name
354   */
355  __addSublanguage(emitter, name) {
356    /** @type DataNode */
357    const node = emitter.root;
358    if (name) node.scope = `language:${name}`;
359
360    this.add(node);
361  }
362
363  toHTML() {
364    const renderer = new HTMLRenderer(this, this.options);
365    return renderer.value();
366  }
367
368  finalize() {
369    this.closeAllNodes();
370    return true;
371  }
372}
373
374/**
375 * @param {string} value
376 * @returns {RegExp}
377 * */
378
379/**
380 * @param {RegExp | string } re
381 * @returns {string}
382 */
383function source(re) {
384  if (!re) return null;
385  if (typeof re === "string") return re;
386
387  return re.source;
388}
389
390/**
391 * @param {RegExp | string } re
392 * @returns {string}
393 */
394function lookahead(re) {
395  return concat('(?=', re, ')');
396}
397
398/**
399 * @param {RegExp | string } re
400 * @returns {string}
401 */
402function anyNumberOfTimes(re) {
403  return concat('(?:', re, ')*');
404}
405
406/**
407 * @param {RegExp | string } re
408 * @returns {string}
409 */
410function optional(re) {
411  return concat('(?:', re, ')?');
412}
413
414/**
415 * @param {...(RegExp | string) } args
416 * @returns {string}
417 */
418function concat(...args) {
419  const joined = args.map((x) => source(x)).join("");
420  return joined;
421}
422
423/**
424 * @param { Array<string | RegExp | Object> } args
425 * @returns {object}
426 */
427function stripOptionsFromArgs(args) {
428  const opts = args[args.length - 1];
429
430  if (typeof opts === 'object' && opts.constructor === Object) {
431    args.splice(args.length - 1, 1);
432    return opts;
433  } else {
434    return {};
435  }
436}
437
438/** @typedef { {capture?: boolean} } RegexEitherOptions */
439
440/**
441 * Any of the passed expresssions may match
442 *
443 * Creates a huge this | this | that | that match
444 * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args
445 * @returns {string}
446 */
447function either(...args) {
448  /** @type { object & {capture?: boolean} }  */
449  const opts = stripOptionsFromArgs(args);
450  const joined = '('
451    + (opts.capture ? "" : "?:")
452    + args.map((x) => source(x)).join("|") + ")";
453  return joined;
454}
455
456/**
457 * @param {RegExp | string} re
458 * @returns {number}
459 */
460function countMatchGroups(re) {
461  return (new RegExp(re.toString() + '|')).exec('').length - 1;
462}
463
464/**
465 * Does lexeme start with a regular expression match at the beginning
466 * @param {RegExp} re
467 * @param {string} lexeme
468 */
469function startsWith(re, lexeme) {
470  const match = re && re.exec(lexeme);
471  return match && match.index === 0;
472}
473
474// BACKREF_RE matches an open parenthesis or backreference. To avoid an
475// incorrect parse, it also matches the constructs where the meaning of
476// parentheses, escapes, or capture counting changes.
477const BACKREF_RE = new RegExp(either(
478  /\[(?:[^\\\]]|\\.)*\]/, // a character class, inside which ( and \ lose their meaning
479  /\(\?<(?![=!])[^>]+>/, // a named capture group `(?<name>` (not a lookbehind `(?<=` / `(?<!`)
480  /\(\?'[^']+'/, // a named capture group `(?'name'`
481  /\(\??/, // an opening parenthesis, capturing or non-capturing / lookahead
482  /\\([1-9][0-9]*)/, // a backreference like `\1`
483  /\\./ // any other escape sequence
484));
485
486// **INTERNAL** Not intended for outside usage
487// join logically computes regexps.join(separator), but fixes the
488// backreferences so they continue to match.
489// it also places each individual regular expression into it's own
490// match group, keeping track of the sequencing of those match groups
491// is currently an exercise for the caller. :-)
492/**
493 * @param {(string | RegExp)[]} regexps
494 * @param {{joinWith: string}} opts
495 * @returns {string}
496 */
497function _rewriteBackreferences(regexps, { joinWith }) {
498  let numCaptures = 0;
499
500  return regexps.map((regex) => {
501    numCaptures += 1;
502    const offset = numCaptures;
503    let re = source(regex);
504    let out = '';
505
506    while (re.length > 0) {
507      const match = BACKREF_RE.exec(re);
508      if (!match) {
509        out += re;
510        break;
511      }
512      out += re.substring(0, match.index);
513      re = re.substring(match.index + match[0].length);
514      if (match[0][0] === '\\' && match[1]) {
515        // Adjust the backreference.
516        out += '\\' + String(Number(match[1]) + offset);
517      } else {
518        out += match[0];
519        if (match[0] === '(' || /^\(\?[<']/.test(match[0])) {
520          numCaptures++;
521        }
522      }
523    }
524    return out;
525  }).map(re => `(${re})`).join(joinWith);
526}
527
528/** @typedef {import('highlight.js').Mode} Mode */
529/** @typedef {import('highlight.js').ModeCallback} ModeCallback */
530
531// Common regexps
532const MATCH_NOTHING_RE = /\b\B/;
533const IDENT_RE = '[a-zA-Z]\\w*';
534const UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*';
535const NUMBER_RE = '\\b\\d+(\\.\\d+)?';
536const C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float
537const BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b...
538const RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~';
539
540/**
541* @param { Partial<Mode> & {binary?: string | RegExp} } opts
542*/
543const SHEBANG = (opts = {}) => {
544  const beginShebang = /^#![ ]*\//;
545  if (opts.binary) {
546    opts.begin = concat(
547      beginShebang,
548      /.*\b/,
549      opts.binary,
550      /\b.*/);
551  }
552  return inherit$1({
553    scope: 'meta',
554    begin: beginShebang,
555    end: /$/,
556    relevance: 0,
557    /** @type {ModeCallback} */
558    "on:begin": (m, resp) => {
559      if (m.index !== 0) resp.ignoreMatch();
560    }
561  }, opts);
562};
563
564// Common modes
565const BACKSLASH_ESCAPE = {
566  begin: '\\\\[\\s\\S]', relevance: 0
567};
568const APOS_STRING_MODE = {
569  scope: 'string',
570  begin: '\'',
571  end: '\'',
572  illegal: '\\n',
573  contains: [BACKSLASH_ESCAPE]
574};
575const QUOTE_STRING_MODE = {
576  scope: 'string',
577  begin: '"',
578  end: '"',
579  illegal: '\\n',
580  contains: [BACKSLASH_ESCAPE]
581};
582const PHRASAL_WORDS_MODE = {
583  begin: /\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
584};
585/**
586 * Creates a comment mode
587 *
588 * @param {string | RegExp} begin
589 * @param {string | RegExp} end
590 * @param {Mode | {}} [modeOptions]
591 * @returns {Partial<Mode>}
592 */
593const COMMENT = function(begin, end, modeOptions = {}) {
594  const mode = inherit$1(
595    {
596      scope: 'comment',
597      begin,
598      end,
599      contains: []
600    },
601    modeOptions
602  );
603  mode.contains.push({
604    scope: 'doctag',
605    // hack to avoid the space from being included. the space is necessary to
606    // match here to prevent the plain text rule below from gobbling up doctags
607    begin: '[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)',
608    end: /(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,
609    excludeBegin: true,
610    relevance: 0
611  });
612  const ENGLISH_WORD = either(
613    // list of common 1 and 2 letter words in English
614    "I",
615    "a",
616    "is",
617    "so",
618    "us",
619    "to",
620    "at",
621    "if",
622    "in",
623    "it",
624    "on",
625    // note: this is not an exhaustive list of contractions, just popular ones
626    /[A-Za-z]+['](d|ve|re|ll|t|s|n)/, // contractions - can't we'd they're let's, etc
627    /[A-Za-z]+[-][a-z]+/, // `no-way`, etc.
628    /[A-Za-z][a-z]{2,}/ // allow capitalized words at beginning of sentences
629  );
630  // looking like plain text, more likely to be a comment
631  mode.contains.push(
632    {
633      // TODO: how to include ", (, ) without breaking grammars that use these for
634      // comment delimiters?
635      // begin: /[ ]+([()"]?([A-Za-z'-]{3,}|is|a|I|so|us|[tT][oO]|at|if|in|it|on)[.]?[()":]?([.][ ]|[ ]|\))){3}/
636      // ---
637
638      // this tries to find sequences of 3 english words in a row (without any
639      // "programming" type syntax) this gives us a strong signal that we've
640      // TRULY found a comment - vs perhaps scanning with the wrong language.
641      // It's possible to find something that LOOKS like the start of the
642      // comment - but then if there is no readable text - good chance it is a
643      // false match and not a comment.
644      //
645      // for a visual example please see:
646      // https://github.com/highlightjs/highlight.js/issues/2827
647
648      begin: concat(
649        /[ ]+/, // necessary to prevent us gobbling up doctags like /* @author Bob Mcgill */
650        '(',
651        ENGLISH_WORD,
652        /[.]?[:]?([.][ ]|[ ])/,
653        '){3}') // look for 3 words in a row
654    }
655  );
656  return mode;
657};
658const C_LINE_COMMENT_MODE = COMMENT('//', '$');
659const C_BLOCK_COMMENT_MODE = COMMENT('/\\*', '\\*/');
660const HASH_COMMENT_MODE = COMMENT('#', '$');
661const NUMBER_MODE = {
662  scope: 'number',
663  begin: NUMBER_RE,
664  relevance: 0
665};
666const C_NUMBER_MODE = {
667  scope: 'number',
668  begin: C_NUMBER_RE,
669  relevance: 0
670};
671const BINARY_NUMBER_MODE = {
672  scope: 'number',
673  begin: BINARY_NUMBER_RE,
674  relevance: 0
675};
676const REGEXP_MODE = {
677  scope: "regexp",
678  begin: /\/(?=[^/\n]*\/)/,
679  end: /\/[gimuy]*/,
680  contains: [
681    BACKSLASH_ESCAPE,
682    {
683      begin: /\[/,
684      end: /\]/,
685      relevance: 0,
686      contains: [BACKSLASH_ESCAPE]
687    }
688  ]
689};
690const TITLE_MODE = {
691  scope: 'title',
692  begin: IDENT_RE,
693  relevance: 0
694};
695const UNDERSCORE_TITLE_MODE = {
696  scope: 'title',
697  begin: UNDERSCORE_IDENT_RE,
698  relevance: 0
699};
700const METHOD_GUARD = {
701  // excludes method names from keyword processing
702  begin: '\\.\\s*' + UNDERSCORE_IDENT_RE,
703  relevance: 0
704};
705
706/**
707 * Adds end same as begin mechanics to a mode
708 *
709 * Your mode must include at least a single () match group as that first match
710 * group is what is used for comparison
711 * @param {Partial<Mode>} mode
712 */
713const END_SAME_AS_BEGIN = function(mode) {
714  return Object.assign(mode,
715    {
716      /** @type {ModeCallback} */
717      'on:begin': (m, resp) => { resp.data._beginMatch = m[1]; },
718      /** @type {ModeCallback} */
719      'on:end': (m, resp) => { if (resp.data._beginMatch !== m[1]) resp.ignoreMatch(); }
720    });
721};
722
723var MODES = /*#__PURE__*/Object.freeze({
724  __proto__: null,
725  APOS_STRING_MODE: APOS_STRING_MODE,
726  BACKSLASH_ESCAPE: BACKSLASH_ESCAPE,
727  BINARY_NUMBER_MODE: BINARY_NUMBER_MODE,
728  BINARY_NUMBER_RE: BINARY_NUMBER_RE,
729  COMMENT: COMMENT,
730  C_BLOCK_COMMENT_MODE: C_BLOCK_COMMENT_MODE,
731  C_LINE_COMMENT_MODE: C_LINE_COMMENT_MODE,
732  C_NUMBER_MODE: C_NUMBER_MODE,
733  C_NUMBER_RE: C_NUMBER_RE,
734  END_SAME_AS_BEGIN: END_SAME_AS_BEGIN,
735  HASH_COMMENT_MODE: HASH_COMMENT_MODE,
736  IDENT_RE: IDENT_RE,
737  MATCH_NOTHING_RE: MATCH_NOTHING_RE,
738  METHOD_GUARD: METHOD_GUARD,
739  NUMBER_MODE: NUMBER_MODE,
740  NUMBER_RE: NUMBER_RE,
741  PHRASAL_WORDS_MODE: PHRASAL_WORDS_MODE,
742  QUOTE_STRING_MODE: QUOTE_STRING_MODE,
743  REGEXP_MODE: REGEXP_MODE,
744  RE_STARTERS_RE: RE_STARTERS_RE,
745  SHEBANG: SHEBANG,
746  TITLE_MODE: TITLE_MODE,
747  UNDERSCORE_IDENT_RE: UNDERSCORE_IDENT_RE,
748  UNDERSCORE_TITLE_MODE: UNDERSCORE_TITLE_MODE
749});
750
751/**
752@typedef {import('highlight.js').CallbackResponse} CallbackResponse
753@typedef {import('highlight.js').CompilerExt} CompilerExt
754*/
755
756// Grammar extensions / plugins
757// See: https://github.com/highlightjs/highlight.js/issues/2833
758
759// Grammar extensions allow "syntactic sugar" to be added to the grammar modes
760// without requiring any underlying changes to the compiler internals.
761
762// `compileMatch` being the perfect small example of now allowing a grammar
763// author to write `match` when they desire to match a single expression rather
764// than being forced to use `begin`.  The extension then just moves `match` into
765// `begin` when it runs.  Ie, no features have been added, but we've just made
766// the experience of writing (and reading grammars) a little bit nicer.
767
768// ------
769
770// TODO: We need negative look-behind support to do this properly
771/**
772 * Skip a match if it has a preceding dot
773 *
774 * This is used for `beginKeywords` to prevent matching expressions such as
775 * `bob.keyword.do()`. The mode compiler automatically wires this up as a
776 * special _internal_ 'on:begin' callback for modes with `beginKeywords`
777 * @param {RegExpMatchArray} match
778 * @param {CallbackResponse} response
779 */
780function skipIfHasPrecedingDot(match, response) {
781  const before = match.input[match.index - 1];
782  if (before === ".") {
783    response.ignoreMatch();
784  }
785}
786
787/**
788 *
789 * @type {CompilerExt}
790 */
791function scopeClassName(mode, _parent) {
792  // eslint-disable-next-line no-undefined
793  if (mode.className !== undefined) {
794    mode.scope = mode.className;
795    delete mode.className;
796  }
797}
798
799/**
800 * `beginKeywords` syntactic sugar
801 * @type {CompilerExt}
802 */
803function beginKeywords(mode, parent) {
804  if (!parent) return;
805  if (!mode.beginKeywords) return;
806
807  // for languages with keywords that include non-word characters checking for
808  // a word boundary is not sufficient, so instead we check for a word boundary
809  // or whitespace - this does no harm in any case since our keyword engine
810  // doesn't allow spaces in keywords anyways and we still check for the boundary
811  // first
812  mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')(?!\\.)(?=\\b|\\s)';
813  mode.__beforeBegin = skipIfHasPrecedingDot;
814  mode.keywords = mode.keywords || mode.beginKeywords;
815  delete mode.beginKeywords;
816
817  // prevents double relevance, the keywords themselves provide
818  // relevance, the mode doesn't need to double it
819  // eslint-disable-next-line no-undefined
820  if (mode.relevance === undefined) mode.relevance = 0;
821}
822
823/**
824 * Allow `illegal` to contain an array of illegal values
825 * @type {CompilerExt}
826 */
827function compileIllegal(mode, _parent) {
828  if (!Array.isArray(mode.illegal)) return;
829
830  mode.illegal = either(...mode.illegal);
831}
832
833/**
834 * `match` to match a single expression for readability
835 * @type {CompilerExt}
836 */
837function compileMatch(mode, _parent) {
838  if (!mode.match) return;
839  if (mode.begin || mode.end) throw new Error("begin & end are not supported with match");
840
841  mode.begin = mode.match;
842  delete mode.match;
843}
844
845/**
846 * provides the default 1 relevance to all modes
847 * @type {CompilerExt}
848 */
849function compileRelevance(mode, _parent) {
850  // eslint-disable-next-line no-undefined
851  if (mode.relevance === undefined) mode.relevance = 1;
852}
853
854// allow beforeMatch to act as a "qualifier" for the match
855// the full match begin must be [beforeMatch][begin]
856const beforeMatchExt = (mode, parent) => {
857  if (!mode.beforeMatch) return;
858  // starts conflicts with endsParent which we need to make sure the child
859  // rule is not matched multiple times
860  if (mode.starts) throw new Error("beforeMatch cannot be used with starts");
861
862  const originalMode = Object.assign({}, mode);
863  Object.keys(mode).forEach((key) => { delete mode[key]; });
864
865  mode.keywords = originalMode.keywords;
866  mode.begin = concat(originalMode.beforeMatch, lookahead(originalMode.begin));
867  mode.starts = {
868    relevance: 0,
869    contains: [
870      Object.assign(originalMode, { endsParent: true })
871    ]
872  };
873  mode.relevance = 0;
874
875  delete originalMode.beforeMatch;
876};
877
878// keywords that should have no default relevance value
879const COMMON_KEYWORDS = [
880  'of',
881  'and',
882  'for',
883  'in',
884  'not',
885  'or',
886  'if',
887  'then',
888  'parent', // common variable name
889  'list', // common variable name
890  'value' // common variable name
891];
892
893const DEFAULT_KEYWORD_SCOPE = "keyword";
894
895/**
896 * Given raw keywords from a language definition, compile them.
897 *
898 * @param {string | Record<string,string|string[]> | Array<string>} rawKeywords
899 * @param {boolean} caseInsensitive
900 */
901function compileKeywords(rawKeywords, caseInsensitive, scopeName = DEFAULT_KEYWORD_SCOPE) {
902  /** @type {import("highlight.js/private").KeywordDict} */
903  const compiledKeywords = Object.create(null);
904
905  // input can be a string of keywords, an array of keywords, or a object with
906  // named keys representing scopeName (which can then point to a string or array)
907  if (typeof rawKeywords === 'string') {
908    compileList(scopeName, rawKeywords.split(" "));
909  } else if (Array.isArray(rawKeywords)) {
910    compileList(scopeName, rawKeywords);
911  } else {
912    Object.keys(rawKeywords).forEach(function(scopeName) {
913      // collapse all our objects back into the parent object
914      Object.assign(
915        compiledKeywords,
916        compileKeywords(rawKeywords[scopeName], caseInsensitive, scopeName)
917      );
918    });
919  }
920  return compiledKeywords;
921
922  // ---
923
924  /**
925   * Compiles an individual list of keywords
926   *
927   * Ex: "for if when while|5"
928   *
929   * @param {string} scopeName
930   * @param {Array<string>} keywordList
931   */
932  function compileList(scopeName, keywordList) {
933    if (caseInsensitive) {
934      keywordList = keywordList.map(x => x.toLowerCase());
935    }
936    keywordList.forEach(function(keyword) {
937      const pair = keyword.split('|');
938      compiledKeywords[pair[0]] = [scopeName, scoreForKeyword(pair[0], pair[1])];
939    });
940  }
941}
942
943/**
944 * Returns the proper score for a given keyword
945 *
946 * Also takes into account comment keywords, which will be scored 0 UNLESS
947 * another score has been manually assigned.
948 * @param {string} keyword
949 * @param {string} [providedScore]
950 */
951function scoreForKeyword(keyword, providedScore) {
952  // manual scores always win over common keywords
953  // so you can force a score of 1 if you really insist
954  if (providedScore) {
955    return Number(providedScore);
956  }
957
958  return commonKeyword(keyword) ? 0 : 1;
959}
960
961/**
962 * Determines if a given keyword is common or not
963 *
964 * @param {string} keyword */
965function commonKeyword(keyword) {
966  return COMMON_KEYWORDS.includes(keyword.toLowerCase());
967}
968
969/*
970
971For the reasoning behind this please see:
972https://github.com/highlightjs/highlight.js/issues/2880#issuecomment-747275419
973
974*/
975
976/**
977 * @type {Record<string, boolean>}
978 */
979const seenDeprecations = {};
980
981/**
982 * @param {string} message
983 */
984const error = (message) => {
985  console.error(message);
986};
987
988/**
989 * @param {string} message
990 * @param {any} args
991 */
992const warn = (message, ...args) => {
993  console.log(`WARN: ${message}`, ...args);
994};
995
996/**
997 * @param {string} version
998 * @param {string} message
999 */
1000const deprecated = (version, message) => {
1001  if (seenDeprecations[`${version}/${message}`]) return;
1002
1003  console.log(`Deprecated as of ${version}. ${message}`);
1004  seenDeprecations[`${version}/${message}`] = true;
1005};
1006
1007/* eslint-disable no-throw-literal */
1008
1009/**
1010@typedef {import('highlight.js').CompiledMode} CompiledMode
1011*/
1012
1013const MultiClassError = new Error();
1014
1015/**
1016 * Renumbers labeled scope names to account for additional inner match
1017 * groups that otherwise would break everything.
1018 *
1019 * Lets say we 3 match scopes:
1020 *
1021 *   { 1 => ..., 2 => ..., 3 => ... }
1022 *
1023 * So what we need is a clean match like this:
1024 *
1025 *   (a)(b)(c) => [ "a", "b", "c" ]
1026 *
1027 * But this falls apart with inner match groups:
1028 *
1029 * (a)(((b)))(c) => ["a", "b", "b", "b", "c" ]
1030 *
1031 * Our scopes are now "out of alignment" and we're repeating `b` 3 times.
1032 * What needs to happen is the numbers are remapped:
1033 *
1034 *   { 1 => ..., 2 => ..., 5 => ... }
1035 *
1036 * We also need to know that the ONLY groups that should be output
1037 * are 1, 2, and 5.  This function handles this behavior.
1038 *
1039 * @param {CompiledMode} mode
1040 * @param {Array<RegExp | string>} regexes
1041 * @param {{key: "beginScope"|"endScope"}} opts
1042 */
1043function remapScopeNames(mode, regexes, { key }) {
1044  let offset = 0;
1045  const scopeNames = mode[key];
1046  /** @type Record<number,boolean> */
1047  const emit = {};
1048  /** @type Record<number,string> */
1049  const positions = {};
1050
1051  for (let i = 1; i <= regexes.length; i++) {
1052    positions[i + offset] = scopeNames[i];
1053    emit[i + offset] = true;
1054    offset += countMatchGroups(regexes[i - 1]);
1055  }
1056  // we use _emit to keep track of which match groups are "top-level" to avoid double
1057  // output from inside match groups
1058  mode[key] = positions;
1059  mode[key]._emit = emit;
1060  mode[key]._multi = true;
1061}
1062
1063/**
1064 * @param {CompiledMode} mode
1065 */
1066function beginMultiClass(mode) {
1067  if (!Array.isArray(mode.begin)) return;
1068
1069  if (mode.skip || mode.excludeBegin || mode.returnBegin) {
1070    error("skip, excludeBegin, returnBegin not compatible with beginScope: {}");
1071    throw MultiClassError;
1072  }
1073
1074  if (typeof mode.beginScope !== "object" || mode.beginScope === null) {
1075    error("beginScope must be object");
1076    throw MultiClassError;
1077  }
1078
1079  remapScopeNames(mode, mode.begin, { key: "beginScope" });
1080  mode.begin = _rewriteBackreferences(mode.begin, { joinWith: "" });
1081}
1082
1083/**
1084 * @param {CompiledMode} mode
1085 */
1086function endMultiClass(mode) {
1087  if (!Array.isArray(mode.end)) return;
1088
1089  if (mode.skip || mode.excludeEnd || mode.returnEnd) {
1090    error("skip, excludeEnd, returnEnd not compatible with endScope: {}");
1091    throw MultiClassError;
1092  }
1093
1094  if (typeof mode.endScope !== "object" || mode.endScope === null) {
1095    error("endScope must be object");
1096    throw MultiClassError;
1097  }
1098
1099  remapScopeNames(mode, mode.end, { key: "endScope" });
1100  mode.end = _rewriteBackreferences(mode.end, { joinWith: "" });
1101}
1102
1103/**
1104 * this exists only to allow `scope: {}` to be used beside `match:`
1105 * Otherwise `beginScope` would necessary and that would look weird
1106
1107  {
1108    match: [ /def/, /\w+/ ]
1109    scope: { 1: "keyword" , 2: "title" }
1110  }
1111
1112 * @param {CompiledMode} mode
1113 */
1114function scopeSugar(mode) {
1115  if (mode.scope && typeof mode.scope === "object" && mode.scope !== null) {
1116    mode.beginScope = mode.scope;
1117    delete mode.scope;
1118  }
1119}
1120
1121/**
1122 * @param {CompiledMode} mode
1123 */
1124function MultiClass(mode) {
1125  scopeSugar(mode);
1126
1127  if (typeof mode.beginScope === "string") {
1128    mode.beginScope = { _wrap: mode.beginScope };
1129  }
1130  if (typeof mode.endScope === "string") {
1131    mode.endScope = { _wrap: mode.endScope };
1132  }
1133
1134  beginMultiClass(mode);
1135  endMultiClass(mode);
1136}
1137
1138/**
1139@typedef {import('highlight.js').Mode} Mode
1140@typedef {import('highlight.js').CompiledMode} CompiledMode
1141@typedef {import('highlight.js').Language} Language
1142@typedef {import('highlight.js').HLJSPlugin} HLJSPlugin
1143@typedef {import('highlight.js').CompiledLanguage} CompiledLanguage
1144*/
1145
1146// compilation
1147
1148/**
1149 * Compiles a language definition result
1150 *
1151 * Given the raw result of a language definition (Language), compiles this so
1152 * that it is ready for highlighting code.
1153 * @param {Language} language
1154 * @returns {CompiledLanguage}
1155 */
1156function compileLanguage(language) {
1157  /**
1158   * Builds a regex with the case sensitivity of the current language
1159   *
1160   * @param {RegExp | string} value
1161   * @param {boolean} [global]
1162   */
1163  function langRe(value, global) {
1164    return new RegExp(
1165      source(value),
1166      'm'
1167      + (language.case_insensitive ? 'i' : '')
1168      + (language.unicodeRegex ? 'u' : '')
1169      + (global ? 'g' : '')
1170    );
1171  }
1172
1173  /**
1174    Stores multiple regular expressions and allows you to quickly search for
1175    them all in a string simultaneously - returning the first match.  It does
1176    this by creating a huge (a|b|c) regex - each individual item wrapped with ()
1177    and joined by `|` - using match groups to track position.  When a match is
1178    found checking which position in the array has content allows us to figure
1179    out which of the original regexes / match groups triggered the match.
1180
1181    The match object itself (the result of `Regex.exec`) is returned but also
1182    enhanced by merging in any meta-data that was registered with the regex.
1183    This is how we keep track of which mode matched, and what type of rule
1184    (`illegal`, `begin`, end, etc).
1185  */
1186  class MultiRegex {
1187    constructor() {
1188      this.matchIndexes = {};
1189      // @ts-ignore
1190      this.regexes = [];
1191      this.matchAt = 1;
1192      this.position = 0;
1193    }
1194
1195    // @ts-ignore
1196    addRule(re, opts) {
1197      opts.position = this.position++;
1198      // @ts-ignore
1199      this.matchIndexes[this.matchAt] = opts;
1200      this.regexes.push([opts, re]);
hooks/vendor/hljs/languages/bash.js 21 lines
1/*! `bash` grammar compiled for Highlight.js 11.12.0 */
2var hljsGrammar=(()=>{"use strict";return e=>{const s=e.regex,t={},a={
3begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]}
4;Object.assign(t,{className:"variable",variants:[{
5begin:s.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},a]});const n={
6className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]
7},c=e.inherit(e.COMMENT(),{match:[/(^|\s)/,/#.*$/],scope:{2:"comment"}}),i={
8begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,
9end:/(\w+)/,className:"string"})]}},o={className:"string",begin:/"/,end:/"/,
10contains:[e.BACKSLASH_ESCAPE,t,n]};n.contains.push(o);const r={begin:/\$?\(\(/,
11end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t]
12},l=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10
13}),m={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,
14contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{
15name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/,
16keyword:["if","then","else","elif","fi","time","for","while","until","in","do","done","case","esac","coproc","function","select"],
17literal:["true","false"],
18built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","sudo","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"]
19},contains:[l,e.SHEBANG(),m,r,c,i,{match:/(\/[a-z._-]+)+/},o,{match:/\\"/},{
20className:"string",begin:/'/,end:/'/},{match:/\\'/},t]}}})()
21;export default hljsGrammar;
hooks/vendor/hljs/languages/c.js 45 lines
1/*! `c` grammar compiled for Highlight.js 11.12.0 */
2var hljsGrammar=(()=>{"use strict";return e=>{
3const t=e.regex,n=e.COMMENT("//","$",{contains:[{begin:/\\\n/}]
4}),a="decltype\\(auto\\)",s="[a-zA-Z_]\\w*::",i="("+a+"|"+t.optional(s)+"[a-zA-Z_]\\w*"+t.optional("<[^<>]+>")+")",r={
5className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{
6match:t.concat(/\batomic_/,t.either("bool","char","schar","uchar","short","ushort","int","uint","long","ulong","llong","ullong","char16_t","char32_t","wchar_t","int_least8_t","uint_least8_t","int_least16_t","uint_least16_t","int_least32_t","uint_least32_t","int_least64_t","uint_least64_t","int_fast8_t","uint_fast8_t","int_fast16_t","uint_fast16_t","int_fast32_t","uint_fast32_t","int_fast64_t","uint_fast64_t","intptr_t","uintptr_t","size_t","ptrdiff_t","intmax_t","uintmax_t"),/\b/)
7}]},l={className:"string",variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",
8contains:[e.BACKSLASH_ESCAPE]},{
9begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",
10end:"'",illegal:"."},e.END_SAME_AS_BEGIN({
11begin:/(?:u8?|U|L)?R"([^()\\\s"]{0,16})\(/,end:/\)([^()\\\s"]{0,16})"/})]},o={
12className:"number",variants:[{match:/\b(0b[01']+)/},{
13match:/(-?)\b([\d']+(\.[\d']*)?|\.[\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)/
14},{
15match:/(-?)\b(0[xX][a-fA-F0-9]+(?:'[a-fA-F0-9]+)*(?:\.[a-fA-F0-9]*(?:'[a-fA-F0-9]*)*)?(?:[pP][-+]?[0-9]+)?(l|L)?(u|U)?)/
16},{match:/(-?)\b\d+(?:'\d+)*(?:\.\d*(?:'\d*)*)?(?:[eE][-+]?\d+)?/}],relevance:0
17},c={scope:"meta",begin:/#\s*include\b/,end:/$/,keywords:{keyword:"include"},
18contains:[{begin:/\\\n/},l,{scope:"string",begin:/<.*?>/
19},n,e.C_BLOCK_COMMENT_MODE]},_={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,
20keywords:{
21keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef elifdef elifndef include"
22},contains:[{begin:/\\\n/,relevance:0},e.inherit(l,{className:"string"
23}),n,e.C_BLOCK_COMMENT_MODE]},d=[c,_],u={className:"title",
24begin:t.optional(s)+e.IDENT_RE,relevance:0
25},m=t.optional(s)+e.IDENT_RE+"\\s*\\(",f={
26keyword:["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","typeof","typeof_unqual","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"],
27type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_BitInt","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal96","_Decimal128","_Decimal64x","_Decimal128x","_Float16","_Float32","_Float64","_Float128","_Float32x","_Float64x","_Float128x","const","static","constexpr","complex","bool","imaginary"],
28literal:"true false NULL",
29built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr"
30},p=[...d,r,n,e.C_BLOCK_COMMENT_MODE,o,l],g={variants:[{begin:/=/,end:/;/},{
31begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],
32keywords:f,contains:p.concat([{begin:/\(/,end:/\)/,keywords:f,
33contains:p.concat(["self"]),relevance:0}]),relevance:0},b={
34begin:"("+i+"[\\*&\\s]+){1,12}"+m,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,
35keywords:f,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:f,relevance:0},{
36begin:m,returnBegin:!0,contains:[e.inherit(u,{className:"title.function"})],
37relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/,
38keywords:f,relevance:0,contains:[n,e.C_BLOCK_COMMENT_MODE,l,o,r,{begin:/\(/,
39end:/\)/,keywords:f,relevance:0,contains:["self",n,e.C_BLOCK_COMMENT_MODE,l,o,r]
40}]},r,n,e.C_BLOCK_COMMENT_MODE,...d]};return{name:"C",aliases:["h"],keywords:f,
41disableAutodetect:!0,illegal:"</",contains:[].concat(g,b,p,[...d,{
42begin:e.IDENT_RE+"::",keywords:f},{className:"class",
43beginKeywords:"enum class struct union",end:/[{;:<>=]/,contains:[{
44beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:_,
45strings:l,keywords:f}}}})();export default hljsGrammar;
hooks/vendor/hljs/languages/cpp.js 49 lines
1/*! `cpp` grammar compiled for Highlight.js 11.12.0 */
2var hljsGrammar=(()=>{"use strict";return e=>{
3const t=e.regex,a=e.COMMENT("//","$",{contains:[{begin:/\\\n/}]
4}),n="decltype\\(auto\\)",r="[a-zA-Z_]\\w*::",i="(?!struct)("+n+"|"+t.optional(r)+"[a-zA-Z_]\\w*"+t.optional("<[^<>]+>")+")",s={
5className:"type",begin:"\\b[a-z\\d_]*_t\\b"},c={className:"string",variants:[{
6begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{
7begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",
8end:"'",illegal:"."},e.END_SAME_AS_BEGIN({
9begin:/(?:u8?|U|L)?R"([^()\\\s"]{0,16})\(/,end:/\)([^()\\\s"]{0,16})"/})]},o={
10className:"number",variants:[{
11begin:"[+-]?(?:(?:\\b[0-9](?:'?[0-9])*\\.(?:[0-9](?:'?[0-9])*)?|\\.[0-9](?:'?[0-9])*)(?:[Ee][+-]?[0-9](?:'?[0-9])*)?|\\b[0-9](?:'?[0-9])*[Ee][+-]?[0-9](?:'?[0-9])*|\\b0[Xx](?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*(?:\\.(?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)?)?|\\.[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)[Pp][+-]?[0-9](?:'?[0-9])*)(?:[Ff](?:16|32|64|128)?|(BF|bf)16|[Ll]|)"
12},{
13begin:"[+-]?\\b(?:0[Bb][01](?:'?[01])*|0[Xx][0-9A-Fa-f](?:'?[0-9A-Fa-f])*|0(?:'?[0-7])*|[1-9](?:'?[0-9])*)(?:[Uu](?:LL?|ll?)|[Uu][Zz]?|(?:LL?|ll?)[Uu]?|[Zz][Uu]|)"
14}],relevance:0},l=[{scope:"meta",begin:/#\s*include\b/,end:/$/,keywords:{
15keyword:"include"},contains:[{begin:/\\\n/},c,{scope:"string",begin:/<.*?>/
16},a,e.C_BLOCK_COMMENT_MODE]},{className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,
17keywords:{
18keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"
19},contains:[{begin:/\\\n/,relevance:0},e.inherit(c,{className:"string"
20}),a,e.C_BLOCK_COMMENT_MODE]}],d={className:"title",
21begin:t.optional(r)+e.IDENT_RE,relevance:0
22},u=t.optional(r)+e.IDENT_RE+"\\s*\\(",_=["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"],p={
23type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"],
24keyword:_,literal:["NULL","false","nullopt","nullptr","true"],
25built_in:["_Pragma"],
26_type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","flat_map","flat_set","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"]
27},m={className:"function.dispatch",relevance:0,keywords:{
28_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"]
29},
30begin:t.concat(/\b/,`(?!${_.join("|")})`,e.IDENT_RE,t.lookahead(/(<[^<>]+>|)\s*\(/))
31},f=[m,...l,s,a,e.C_BLOCK_COMMENT_MODE,o,c],g={variants:[{begin:/=/,end:/;/},{
32begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],
33keywords:p,contains:f.concat([{begin:/\(/,end:/\)/,keywords:p,
34contains:f.concat(["self"]),relevance:0}]),relevance:0},b={className:"function",
35begin:"("+i+"[\\*&\\s]+){1,12}"+u,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,
36keywords:p,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:n,keywords:p,relevance:0},{
37begin:u,returnBegin:!0,contains:[d],relevance:0},{begin:/::/,relevance:0},{
38begin:/:/,endsWithParent:!0,contains:[c,o]},{relevance:0,match:/,/},{
39className:"params",begin:/\(/,end:/\)/,keywords:p,relevance:0,
40contains:[a,e.C_BLOCK_COMMENT_MODE,c,o,s,{begin:/\(/,end:/\)/,keywords:p,
41relevance:0,contains:["self",a,e.C_BLOCK_COMMENT_MODE,c,o,s]}]
42},s,a,e.C_BLOCK_COMMENT_MODE,...l]};return{name:"C++",
43aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:p,illegal:"</",
44classNameAliases:{"function.dispatch":"built_in"},
45contains:[].concat(g,b,m,f,[...l,{
46begin:"\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array|tuple|optional|variant|function|flat_map|flat_set)\\s*<(?!<)",
47end:">",keywords:p,contains:["self",s]},{begin:e.IDENT_RE+"::",keywords:p},{
48match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/],
49className:{1:"keyword",3:"title.class"}}])}}})();export default hljsGrammar;
hooks/vendor/hljs/languages/csharp.js 49 lines
1/*! `csharp` grammar compiled for Highlight.js 11.12.0 */
2var hljsGrammar=(()=>{"use strict";return e=>{const n={
3keyword:["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","scoped","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","args","async","await","by","descending","dynamic","equals","file","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","record","remove","required","scoped","select","set","unmanaged","value|0","var","when","where","with","yield"]),
4built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"],
5literal:["default","false","null","true"]},a=e.inherit(e.TITLE_MODE,{
6begin:"[a-zA-Z](\\.?\\w)*"}),i="\\d(_*\\d)*",s="([uU][lL]?|[lL][uU]?)?",r={
7className:"number",variants:[{begin:"\\b0[bB]_*[01](_*[01])*"+s},{
8begin:"(-?)\\b0[xX]_*[a-fA-F0-9](_*[a-fA-F0-9])*"+s},{
9begin:"(-?)(\\b"+i+"(\\.("+i+")?)?|\\."+i+")([eE][-+]?"+i+")?([fFdDmM]|[uU][lL]?|[lL][uU]?)?"
10}],relevance:0},t={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}]
11},l=e.inherit(t,{illegal:/\n/}),c={className:"subst",begin:/\{/,end:/\}/,
12keywords:n},o=e.inherit(c,{illegal:/\n/}),d={className:"string",begin:/\$"/,
13end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/
14},e.BACKSLASH_ESCAPE,o]},g={className:"string",begin:/\$@"/,end:'"',contains:[{
15begin:/\{\{/},{begin:/\}\}/},{begin:'""'},c]},_=e.inherit(g,{illegal:/\n/,
16contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},o]})
17;c.contains=[g,d,t,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,r,e.C_BLOCK_COMMENT_MODE],
18o.contains=[_,d,l,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,r,e.inherit(e.C_BLOCK_COMMENT_MODE,{
19illegal:/\n/})];const E={variants:[{className:"string",
20begin:/"""("*)(?!")(.|\n)*?"""\1/,relevance:1
21},g,d,t,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},b={begin:"<",end:">",
22contains:[{beginKeywords:"in out"},a]
23},u=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",M={
24begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"],
25keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0,
26contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{
27begin:"\x3c!--|--\x3e"},{begin:"</?",end:">"}]}]
28}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#",
29end:"$",keywords:{
30keyword:"if else elif endif define undef warning error line region endregion pragma checksum"
31}},E,r,{beginKeywords:"class interface",relevance:0,end:/[{;=]/,
32illegal:/[^\s:,]/,contains:[{beginKeywords:"where class"
33},a,b,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace",
34relevance:0,end:/[{;=]/,illegal:/[^\s:]/,
35contains:[a,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{
36beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/,
37contains:[a,b,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta",
38begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{
39className:"string",begin:/"/,end:/"/}]},{
40beginKeywords:"new return throw await else",relevance:0},{className:"function",
41begin:"("+u+"\\s+)+"+e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0,
42end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{
43beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial",
44relevance:0},{begin:e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0,
45contains:[e.TITLE_MODE,b],relevance:0},{match:/\(\)/},{className:"params",
46begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0,
47contains:[E,r,e.C_BLOCK_COMMENT_MODE]
48},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},M]}}})()
49;export default hljsGrammar;
hooks/vendor/hljs/languages/css.js 33 lines
1/*! `css` grammar compiled for Highlight.js 11.12.0 */
2var hljsGrammar=(()=>{"use strict"
3;const e=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","optgroup","option","p","picture","q","quote","samp","section","select","source","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video","defs","g","marker","mask","pattern","svg","switch","symbol","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feFlood","feGaussianBlur","feImage","feMerge","feMorphology","feOffset","feSpecularLighting","feTile","feTurbulence","linearGradient","radialGradient","stop","circle","ellipse","image","line","path","polygon","polyline","rect","text","use","textPath","tspan","foreignObject","clipPath"],t=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"].sort().reverse(),i=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"].sort().reverse(),o=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"].sort().reverse(),r=["accent-color","align-content","align-items","align-self","alignment-baseline","all","anchor-name","animation","animation-composition","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-range","animation-range-end","animation-range-start","animation-timeline","animation-timing-function","appearance","aspect-ratio","backdrop-filter","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-position-x","background-position-y","background-repeat","background-size","baseline-shift","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-end-end-radius","border-end-start-radius","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-start-end-radius","border-start-start-radius","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-align","box-decoration-break","box-direction","box-flex","box-flex-group","box-lines","box-ordinal-group","box-orient","box-pack","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","color-scheme","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","contain-intrinsic-block-size","contain-intrinsic-height","contain-intrinsic-inline-size","contain-intrinsic-size","contain-intrinsic-width","container","container-name","container-type","content","content-visibility","corner-bottom-left-shape","corner-bottom-right-shape","corner-shape","corner-top-left-shape","corner-top-right-shape","counter-increment","counter-reset","counter-set","cue","cue-after","cue-before","cursor","cx","cy","direction","display","dominant-baseline","empty-cells","enable-background","field-sizing","fill","fill-opacity","fill-rule","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flood-color","flood-opacity","flow","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-optical-sizing","font-palette","font-size","font-size-adjust","font-smooth","font-smoothing","font-stretch","font-style","font-synthesis","font-synthesis-position","font-synthesis-small-caps","font-synthesis-style","font-synthesis-weight","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-emoji","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","forced-color-adjust","gap","glyph-orientation-horizontal","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphenate-character","hyphenate-limit-chars","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","initial-letter","initial-letter-align","inline-size","inset","inset-area","inset-block","inset-block-end","inset-block-start","inset-inline","inset-inline-end","inset-inline-start","isolation","justify-content","justify-items","justify-self","kerning","left","letter-spacing","lighting-color","line-break","line-height","line-height-step","list-style","list-style-image","list-style-position","list-style-type","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","margin-trim","marker","marker-end","marker-mid","marker-start","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","masonry-auto-flow","math-depth","math-shift","math-style","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","offset","offset-anchor","offset-distance","offset-path","offset-position","offset-rotate","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-anchor","overflow-block","overflow-clip-margin","overflow-inline","overflow-wrap","overflow-x","overflow-y","overlay","overscroll-behavior","overscroll-behavior-block","overscroll-behavior-inline","overscroll-behavior-x","overscroll-behavior-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","paint-order","pause","pause-after","pause-before","perspective","perspective-origin","place-content","place-items","place-self","pointer-events","position","position-anchor","position-visibility","print-color-adjust","quotes","r","resize","rest","rest-after","rest-before","right","rotate","row-gap","ruby-align","ruby-position","scale","scroll-behavior","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scroll-timeline","scroll-timeline-axis","scroll-timeline-name","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","shape-rendering","speak","speak-as","src","stop-color","stop-opacity","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","tab-size","table-layout","text-align","text-align-all","text-align-last","text-anchor","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-skip-ink","text-decoration-style","text-decoration-thickness","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-size-adjust","text-transform","text-underline-offset","text-underline-position","text-wrap","text-wrap-mode","text-wrap-style","timeline-scope","top","touch-action","transform","transform-box","transform-origin","transform-style","transition","transition-behavior","transition-delay","transition-duration","transition-property","transition-timing-function","translate","unicode-bidi","unicode-range","user-modify","user-select","vector-effect","vertical-align","view-timeline","view-timeline-axis","view-timeline-inset","view-timeline-name","view-transition-name","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","white-space-collapse","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","x","y","z-index","zoom"].sort().reverse()
4;return n=>{const a=n.regex,l=(e=>({IMPORTANT:{scope:"meta",begin:"!important"},
5BLOCK_COMMENT:e.C_BLOCK_COMMENT_MODE,HEXCOLOR:{scope:"number",
6begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/},UNICODE_RANGE:{
7scope:"number",
8begin:/\b[Uu]\+[0-9A-Fa-f][0-9A-Fa-f?]{0,5}(-[0-9A-Fa-f][0-9A-Fa-f]{0,5})?/},
9FUNCTION_DISPATCH:{className:"built_in",begin:/[\w-]+(?=\()/},
10ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$",
11contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{
12scope:"number",
13begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",
14relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z_][A-Za-z0-9_-]*/}
15}))(n),s=[n.APOS_STRING_MODE,n.QUOTE_STRING_MODE];return{name:"CSS",
16case_insensitive:!0,illegal:/[=|'\$]/,keywords:{keyframePosition:"from to"},
17classNameAliases:{keyframePosition:"selector-tag"},contains:[l.BLOCK_COMMENT,{
18begin:/-(webkit|moz|ms|o)-(?=[a-z])/},l.CSS_NUMBER_MODE,{
19className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0},{
20className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0
21},l.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{
22begin:":("+i.join("|")+")"},{begin:":(:)?("+o.join("|")+")"}]},l.CSS_VARIABLE,{
23className:"attribute",begin:"\\b("+r.join("|")+")\\b"},{begin:/:/,end:/[;}{]/,
24contains:[l.BLOCK_COMMENT,l.HEXCOLOR,l.IMPORTANT,l.CSS_NUMBER_MODE,l.UNICODE_RANGE,...s,{
25begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri"
26},contains:[...s,{className:"string",begin:/[^)]/,endsWithParent:!0,
27excludeEnd:!0}]},l.FUNCTION_DISPATCH]},{begin:a.lookahead(/@/),end:"[{;]",
28relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/
29},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{
30$pattern:/[a-z-]+/,keyword:"and or not only",attribute:t.join(" ")},contains:[{
31begin:/[a-z-]+(?=:)/,className:"attribute"},...s,l.CSS_NUMBER_MODE]}]},{
32className:"selector-tag",begin:"\\b("+e.join("|")+")\\b"}]}}})()
33;export default hljsGrammar;
hooks/vendor/hljs/languages/diff.js 9 lines
1/*! `diff` grammar compiled for Highlight.js 11.12.0 */
2var hljsGrammar=(()=>{"use strict";return e=>{const a=e.regex;return{
3name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10,
4match:a.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^@@ +-\d+ +\+\d+,\d+ +@@/,/^@@ +-\d+,\d+ +\+\d+ +@@/,/^@@ +-\d+ +\+\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/)
5},{className:"comment",variants:[{
6begin:a.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/),
7end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{
8className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/,
9end:/$/}]}}})();export default hljsGrammar;