Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

highlight.ts

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

highlight.tsBlame132 lines · 1 contributor
06d5ffeClaude1/**
2 * Syntax highlighting via highlight.js — server-side.
3 * Returns pre-highlighted HTML strings for code display.
4 */
5
6import hljs from "highlight.js";
7
8const EXT_TO_LANG: Record<string, string> = {
9 ts: "typescript",
10 tsx: "typescript",
11 js: "javascript",
12 jsx: "javascript",
13 py: "python",
14 rb: "ruby",
15 rs: "rust",
16 go: "go",
17 java: "java",
18 c: "c",
19 cpp: "cpp",
20 h: "c",
21 hpp: "cpp",
22 cs: "csharp",
23 php: "php",
24 swift: "swift",
25 kt: "kotlin",
26 scala: "scala",
27 sh: "bash",
28 bash: "bash",
29 zsh: "bash",
30 fish: "bash",
31 ps1: "powershell",
32 sql: "sql",
33 html: "html",
34 htm: "html",
35 css: "css",
36 scss: "scss",
37 less: "less",
38 json: "json",
39 yaml: "yaml",
40 yml: "yaml",
41 toml: "ini",
42 xml: "xml",
43 md: "markdown",
44 markdown: "markdown",
45 dockerfile: "dockerfile",
46 makefile: "makefile",
47 cmake: "cmake",
48 lua: "lua",
49 r: "r",
50 dart: "dart",
51 ex: "elixir",
52 exs: "elixir",
53 erl: "erlang",
54 hs: "haskell",
55 ml: "ocaml",
56 clj: "clojure",
57 vim: "vim",
58 tf: "hcl",
59 proto: "protobuf",
60 graphql: "graphql",
61 gql: "graphql",
62};
63
64export function highlightCode(
65 code: string,
66 filename: string
67): { html: string; language: string | null } {
68 const ext = filename.split(".").pop()?.toLowerCase() || "";
69 const lang = EXT_TO_LANG[ext];
70
71 if (lang) {
72 try {
73 const result = hljs.highlight(code, { language: lang });
74 return { html: result.value, language: lang };
75 } catch {
76 // fallback to auto-detect
77 }
78 }
79
80 // Try auto-detection for unknown extensions
81 try {
82 const result = hljs.highlightAuto(code);
83 if (result.language && result.relevance > 5) {
84 return { html: result.value, language: result.language };
85 }
86 } catch {
87 // fallback to plain
88 }
89
90 return { html: escapeHtml(code), language: null };
91}
92
93function escapeHtml(str: string): string {
94 return str
95 .replace(/&/g, "&amp;")
96 .replace(/</g, "&lt;")
97 .replace(/>/g, "&gt;")
98 .replace(/"/g, "&quot;");
99}
100
101export const hljsThemeCss = `
102 .hljs-keyword { color: #ff7b72; }
103 .hljs-built_in { color: #ffa657; }
104 .hljs-type { color: #ffa657; }
105 .hljs-literal { color: #79c0ff; }
106 .hljs-number { color: #79c0ff; }
107 .hljs-string { color: #a5d6ff; }
108 .hljs-regexp { color: #a5d6ff; }
109 .hljs-symbol { color: #79c0ff; }
110 .hljs-title { color: #d2a8ff; }
111 .hljs-title.function_ { color: #d2a8ff; }
112 .hljs-title.class_ { color: #ffa657; }
113 .hljs-params { color: #e6edf3; }
114 .hljs-comment { color: #8b949e; font-style: italic; }
115 .hljs-doctag { color: #8b949e; }
116 .hljs-meta { color: #79c0ff; }
117 .hljs-attr { color: #79c0ff; }
118 .hljs-attribute { color: #79c0ff; }
119 .hljs-selector-tag { color: #ff7b72; }
120 .hljs-selector-class { color: #d2a8ff; }
121 .hljs-selector-id { color: #79c0ff; }
122 .hljs-variable { color: #ffa657; }
123 .hljs-template-variable { color: #ffa657; }
124 .hljs-tag { color: #7ee787; }
125 .hljs-name { color: #7ee787; }
126 .hljs-section { color: #d2a8ff; font-weight: bold; }
127 .hljs-addition { color: #aff5b4; background: rgba(63, 185, 80, 0.15); }
128 .hljs-deletion { color: #ffdcd7; background: rgba(248, 81, 73, 0.1); }
129 .hljs-property { color: #79c0ff; }
130 .hljs-subst { color: #e6edf3; }
131 .hljs-punctuation { color: #8b949e; }
132`;