[OCaml] Mobile-friendly clone of cgit.
1
(** Server-side syntax highlighting engine.
2
3
Tokenizes source code using TextMate grammars (via hilite) and produces
4
{!Dream_html.node} spans ready for embedding in the page. Falls back
5
gracefully to plain text when no grammar is available for the requested
6
language. *)
7
8
open Dream_html
9
10
type line = node list
11
(** A single highlighted line: a list of HTML nodes (spans with classes). *)
12
13
(** Highlight source code for the given language.
14
15
Returns a list of lines, each line being a list of [<span>] nodes with
16
appropriate CSS classes. If [lang] is [None] or the language is not
17
supported, returns plain-text lines (no spans, just escaped text).
18
19
The CSS classes follow hilite's convention:
20
[{lang_scope}-{token_scope_segments}], e.g.
21
[source.python-storage-type-function]. *)
22
let highlight ~lang source : line list =
23
let plain_lines () =
24
String.split_on_char '\n' source
25
|> List.map (fun line -> [ txt "%s\n" line ])
26
in
27
match lang with
28
| None -> plain_lines ()
29
| Some lang_name -> (
30
let scope = Grammars.scope_of_lang lang_name in
31
match scope with
32
| None -> plain_lines ()
33
| Some scope_name -> (
34
let tm = Lazy.force Grammars.registry in
35
match
36
Hilite.src_code_to_pairs ~escape:true ~lookup_method:`Scope_name ~tm
37
~lang:scope_name source
38
with
39
| Error _ -> plain_lines ()
40
| Ok pairs ->
41
List.map
42
(fun line_pairs ->
43
List.map
44
(fun (css_class, content) ->
45
if css_class = "" then txt ~raw:true "%s" content
46
else
47
HTML.span
48
[ HTML.class_ "%s" css_class ]
49
[ txt ~raw:true "%s" content ])
50
line_pairs)
51
pairs))
52