syntax.ts

 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}