1import deepmerge from "deepmerge"
2import { font_weights, ThemeConfigInputSyntax, RampSet } from "../common"
3import { Syntax, SyntaxHighlightStyle, allSyntaxKeys } from "../types/syntax"
4
5// Apply defaults to any missing syntax properties that are not defined manually
6function apply_defaults(ramps: RampSet, syntax_highlights: Partial<Syntax>): Syntax {
7 const restKeys: (keyof Syntax)[] = allSyntaxKeys.filter(key => !syntax_highlights[key])
8
9 const completeSyntax: Syntax = {} as Syntax
10
11 const defaults: SyntaxHighlightStyle = {
12 color: ramps.neutral(1).hex(),
13 }
14
15 for (const key of restKeys) {
16 {
17 completeSyntax[key] = {
18 ...defaults,
19 }
20 }
21 }
22
23 const mergedBaseSyntax = Object.assign(completeSyntax, syntax_highlights)
24
25 return mergedBaseSyntax
26}
27
28// Merge the base syntax with the theme syntax overrides
29// This is a deep merge, so any nested properties will be merged as well
30// This allows for a theme to only override a single property of a syntax highlight style
31const merge_syntax = (baseSyntax: Syntax, theme_syntax_overrides: ThemeConfigInputSyntax): Syntax => {
32 return deepmerge<Syntax, ThemeConfigInputSyntax>(baseSyntax, theme_syntax_overrides, {
33 arrayMerge: (destinationArray, sourceArray) => [
34 ...destinationArray,
35 ...sourceArray,
36 ],
37 })
38}
39
40/** Returns a complete Syntax object of the combined styles of a theme's syntax overrides and the default syntax styles */
41export const syntaxStyle = (ramps: RampSet, theme_syntax_overrides: ThemeConfigInputSyntax): Syntax => {
42 const syntax_highlights: Partial<Syntax> = {
43 "comment": { color: ramps.neutral(0.71).hex() },
44 "comment.doc": { color: ramps.neutral(0.71).hex() },
45 primary: { color: ramps.neutral(1).hex() },
46 emphasis: { color: ramps.blue(0.5).hex() },
47 "emphasis.strong": { color: ramps.blue(0.5).hex(), weight: font_weights.bold },
48 link_uri: { color: ramps.green(0.5).hex(), underline: true },
49 link_text: { color: ramps.orange(0.5).hex(), italic: true },
50 "text.literal": { color: ramps.orange(0.5).hex() },
51 punctuation: { color: ramps.neutral(0.86).hex() },
52 "punctuation.bracket": { color: ramps.neutral(0.86).hex() },
53 "punctuation.special": { color: ramps.neutral(0.86).hex() },
54 "punctuation.delimiter": { color: ramps.neutral(0.86).hex() },
55 "punctuation.list_marker": { color: ramps.neutral(0.86).hex() },
56 string: { color: ramps.orange(0.5).hex() },
57 "string.special": { color: ramps.orange(0.5).hex() },
58 "string.special.symbol": { color: ramps.orange(0.5).hex() },
59 "string.escape": { color: ramps.neutral(0.71).hex() },
60 "string.regex": { color: ramps.orange(0.5).hex() },
61 "method.constructor": { color: ramps.blue(0.5).hex() },
62 type: { color: ramps.cyan(0.5).hex() },
63 variable: { color: ramps.neutral(1).hex() },
64 label: { color: ramps.blue(0.5).hex() },
65 attribute: { color: ramps.blue(0.5).hex() },
66 property: { color: ramps.blue(0.5).hex() },
67 constant: { color: ramps.green(0.5).hex() },
68 keyword: { color: ramps.blue(0.5).hex() },
69 operator: { color: ramps.orange(0.5).hex() },
70 number: { color: ramps.green(0.5).hex() },
71 boolean: { color: ramps.green(0.5).hex() },
72 function: { color: ramps.yellow(0.5).hex() },
73 preproc: { color: ramps.neutral(1).hex() },
74 embedded: { color: ramps.neutral(1).hex() },
75 }
76
77 const baseSyntax = apply_defaults(ramps, syntax_highlights)
78 const mergedSyntax = merge_syntax(baseSyntax, theme_syntax_overrides)
79 return mergedSyntax
80}