-
Notifications
You must be signed in to change notification settings - Fork 62
Expand file tree
/
Copy pathhighlight-plugin.ts
More file actions
136 lines (125 loc) · 3.52 KB
/
highlight-plugin.ts
File metadata and controls
136 lines (125 loc) · 3.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import { highlightPlugin } from "prosemirror-highlightjs";
import { Node as ProsemirrorNode } from "prosemirror-model";
import { Plugin } from "prosemirror-state";
import { getHljsInstance } from "./hljs-instance";
/*
* Register the languages we're going to use here so we can strongly type our inputs
*/
//TODO missing: regex
const SUPPORTED_LANGS = [
"plaintext",
"markdown",
"bash",
"cpp",
"csharp",
"coffeescript",
"xml",
"java",
"json",
"perl",
"python",
"ruby",
"clojure",
"css",
"dart",
"erlang",
"go",
"haskell",
"javascript",
"kotlin",
"tex",
"lisp",
"scheme",
"lua",
"matlab",
"mathematica",
"ocaml",
"pascal",
"protobuf",
"r",
"rust",
"scala",
"sql",
"swift",
"vhdl",
"vbscript",
"yml",
] as const;
type Language = typeof SUPPORTED_LANGS[number];
// Aliases are neatly grouped onto the same line, so tell prettier not to format
// prettier-ignore
/**
* A mapping of all known language aliases to their proper definition name
* @see https://meta.stackexchange.com/questions/184108/what-is-syntax-highlighting-and-how-does-it-work
*/
const languageAliases: { [key: string]: string } = {
bsh: "bash", csh: "bash", sh: "bash",
// TODO is cpp appropriate or is there a better c-like?
c: "cpp", cc: "cpp", cxx: "cpp", cyc: "cpp", m: "cpp",
cs: "csharp",
coffee: "coffeescript",
html: "xml", xsl: "xml",
js: "javascript",
pl: "perl",
py: "python", cv: "python",
rb: "ruby",
clj: "clojure",
erl: "erlang",
hs: "haskell",
mma: "mathematica",
tex: "latex",
cl: "lisp", el: "lisp", lsp: "lisp", scm: "scheme", ss: "scheme", rkt: "scheme",
fs: "ocaml", ml: "ocaml",
s: "r",
rc: "rust", rs: "rust",
vhd: "vhdl",
none: "plaintext"
};
/**
* Attempts to dealias a language's name into a name we can load/register under
* @param rawLanguage
*/
function dealiasLanguage(rawLanguage: string): Language {
return (languageAliases[rawLanguage] || rawLanguage) as Language;
}
/**
* Gets the language string from a code_block node
* @param block The block to get the language string from
*/
export function getBlockLanguage(
block: ProsemirrorNode,
fallback = "none"
): string {
// commonmark spec suggests that the "first word" in a fence's info string is the language
// https://spec.commonmark.org/0.29/#info-string
// https://spec.commonmark.org/0.29/#example-112
const rawInfoString = (block.attrs.params as string) || "";
const rawLanguage =
rawInfoString.split(/\s/)[0].toLowerCase() || fallback || null;
// attempt to dealias the language before sending out to the highlighter
return dealiasLanguage(rawLanguage);
}
/** Returns all supported language codes */
export function getLoadedLanguages() {
return SUPPORTED_LANGS;
}
/**
* Plugin that highlights all code within all code_blocks in the parent
*/
export function CodeBlockHighlightPlugin(
defaultFallbackLanguage: string
): Plugin {
const extractor = (block: ProsemirrorNode) => {
const detectedLanguage = block.attrs
.detectedHighlightLanguage as string;
return (
detectedLanguage || getBlockLanguage(block, defaultFallbackLanguage)
);
};
const hljs = getHljsInstance();
// if hljs fails to instantiate (optional dependency), don't crash the entire editor
if (!hljs) {
return new Plugin({});
}
return highlightPlugin(hljs, ["code_block"], extractor);
}