editor.ts

  1import { fontWeights } from "../common"
  2import { withOpacity } from "../utils/color"
  3import { ColorScheme, Layer, StyleSets, Syntax, ThemeSyntax } from "../themes/common/colorScheme"
  4import { background, border, borderColor, foreground, text } from "./components"
  5import hoverPopover from "./hoverPopover"
  6
  7import deepmerge from 'deepmerge';
  8
  9
 10export default function editor(colorScheme: ColorScheme) {
 11    let layer = colorScheme.highest
 12
 13    const autocompleteItem = {
 14        cornerRadius: 6,
 15        padding: {
 16            bottom: 2,
 17            left: 6,
 18            right: 6,
 19            top: 2,
 20        },
 21    }
 22
 23    function diagnostic(layer: Layer, styleSet: StyleSets) {
 24        return {
 25            textScaleFactor: 0.857,
 26            header: {
 27                border: border(layer, {
 28                    top: true,
 29                }),
 30            },
 31            message: {
 32                text: text(layer, "sans", styleSet, "default", { size: "sm" }),
 33                highlightText: text(layer, "sans", styleSet, "default", {
 34                    size: "sm",
 35                    weight: "bold",
 36                }),
 37            },
 38        }
 39    }
 40
 41    const defaultSyntax: Syntax = {
 42        primary: {
 43            color: colorScheme.ramps.neutral(1).hex(),
 44            weight: fontWeights.normal,
 45        },
 46        "variable.special": {
 47            // Highlights for self, this, etc
 48            color: colorScheme.ramps.blue(0.7).hex(),
 49            weight: fontWeights.normal,
 50        },
 51        comment: {
 52            color: colorScheme.ramps.neutral(0.71).hex(),
 53            weight: fontWeights.normal,
 54        },
 55        punctuation: {
 56            color: colorScheme.ramps.neutral(0.86).hex(),
 57            weight: fontWeights.normal,
 58        },
 59        constant: {
 60            color: colorScheme.ramps.green(0.5).hex(),
 61            weight: fontWeights.normal,
 62        },
 63        keyword: {
 64            color: colorScheme.ramps.blue(0.5).hex(),
 65            weight: fontWeights.normal,
 66        },
 67        function: {
 68            color: colorScheme.ramps.yellow(0.5).hex(),
 69            weight: fontWeights.normal,
 70        },
 71        type: {
 72            color: colorScheme.ramps.cyan(0.5).hex(),
 73            weight: fontWeights.normal,
 74        },
 75        constructor: {
 76            color: colorScheme.ramps.blue(0.5).hex(),
 77            weight: fontWeights.normal,
 78        },
 79        variant: {
 80            color: colorScheme.ramps.blue(0.5).hex(),
 81            weight: fontWeights.normal,
 82        },
 83        property: {
 84            color: colorScheme.ramps.blue(0.5).hex(),
 85            weight: fontWeights.normal,
 86        },
 87        enum: {
 88            color: colorScheme.ramps.orange(0.5).hex(),
 89            weight: fontWeights.normal,
 90        },
 91        operator: {
 92            color: colorScheme.ramps.orange(0.5).hex(),
 93            weight: fontWeights.normal,
 94        },
 95        string: {
 96            color: colorScheme.ramps.orange(0.5).hex(),
 97            weight: fontWeights.normal,
 98        },
 99        number: {
100            color: colorScheme.ramps.green(0.5).hex(),
101            weight: fontWeights.normal,
102        },
103        boolean: {
104            color: colorScheme.ramps.green(0.5).hex(),
105            weight: fontWeights.normal,
106        },
107        predictive: {
108            color: colorScheme.ramps.neutral(0.57).hex(),
109            weight: fontWeights.normal,
110        },
111        title: {
112            color: colorScheme.ramps.yellow(0.5).hex(),
113            weight: fontWeights.bold,
114        },
115        emphasis: {
116            color: colorScheme.ramps.blue(0.5).hex(),
117            weight: fontWeights.normal,
118        },
119        "emphasis.strong": {
120            color: colorScheme.ramps.blue(0.5).hex(),
121            weight: fontWeights.bold,
122        },
123        linkUri: {
124            color: colorScheme.ramps.green(0.5).hex(),
125            weight: fontWeights.normal,
126            underline: true,
127        },
128        linkText: {
129            color: colorScheme.ramps.orange(0.5).hex(),
130            weight: fontWeights.normal,
131            italic: true,
132        },
133    }
134
135    function createSyntax(colorScheme: ColorScheme): Syntax {
136        if (!colorScheme.syntax) {
137            return defaultSyntax
138        }
139
140        return deepmerge<Syntax, Partial<ThemeSyntax>>(defaultSyntax, colorScheme.syntax, {
141            arrayMerge: (destinationArray, sourceArray) => [
142                ...destinationArray,
143                ...sourceArray,
144            ],
145        });
146    }
147
148    const syntax = createSyntax(colorScheme)
149
150    return {
151        textColor: syntax.primary.color,
152        background: background(layer),
153        activeLineBackground: withOpacity(background(layer, "on"), 0.75),
154        highlightedLineBackground: background(layer, "on"),
155        codeActions: {
156            indicator: foreground(layer, "variant"),
157            verticalScale: 0.55,
158        },
159        diff: {
160            deleted: foreground(layer, "negative"),
161            modified: foreground(layer, "warning"),
162            inserted: foreground(layer, "positive"),
163            removedWidthEm: 0.275,
164            widthEm: 0.16,
165            cornerRadius: 0.05,
166        },
167        /** Highlights matching occurences of what is under the cursor
168         * as well as matched brackets
169         */
170        documentHighlightReadBackground: withOpacity(
171            foreground(layer, "accent"),
172            0.1
173        ),
174        documentHighlightWriteBackground: colorScheme.ramps
175            .neutral(0.5)
176            .alpha(0.4)
177            .hex(), // TODO: This was blend * 2
178        errorColor: background(layer, "negative"),
179        gutterBackground: background(layer),
180        gutterPaddingFactor: 3.5,
181        lineNumber: withOpacity(foreground(layer), 0.35),
182        lineNumberActive: foreground(layer),
183        renameFade: 0.6,
184        unnecessaryCodeFade: 0.5,
185        selection: colorScheme.players[0],
186        guestSelections: [
187            colorScheme.players[1],
188            colorScheme.players[2],
189            colorScheme.players[3],
190            colorScheme.players[4],
191            colorScheme.players[5],
192            colorScheme.players[6],
193            colorScheme.players[7],
194        ],
195        autocomplete: {
196            background: background(colorScheme.middle),
197            cornerRadius: 8,
198            padding: 4,
199            margin: {
200                left: -14,
201            },
202            border: border(colorScheme.middle),
203            shadow: colorScheme.popoverShadow,
204            matchHighlight: foreground(colorScheme.middle, "accent"),
205            item: autocompleteItem,
206            hoveredItem: {
207                ...autocompleteItem,
208                matchHighlight: foreground(
209                    colorScheme.middle,
210                    "accent",
211                    "hovered"
212                ),
213                background: background(colorScheme.middle, "hovered"),
214            },
215            selectedItem: {
216                ...autocompleteItem,
217                matchHighlight: foreground(
218                    colorScheme.middle,
219                    "accent",
220                    "active"
221                ),
222                background: background(colorScheme.middle, "active"),
223            },
224        },
225        diagnosticHeader: {
226            background: background(colorScheme.middle),
227            iconWidthFactor: 1.5,
228            textScaleFactor: 0.857,
229            border: border(colorScheme.middle, {
230                bottom: true,
231                top: true,
232            }),
233            code: {
234                ...text(colorScheme.middle, "mono", { size: "sm" }),
235                margin: {
236                    left: 10,
237                },
238            },
239            message: {
240                highlightText: text(colorScheme.middle, "sans", {
241                    size: "sm",
242                    weight: "bold",
243                }),
244                text: text(colorScheme.middle, "sans", { size: "sm" }),
245            },
246        },
247        diagnosticPathHeader: {
248            background: background(colorScheme.middle),
249            textScaleFactor: 0.857,
250            filename: text(colorScheme.middle, "mono", { size: "sm" }),
251            path: {
252                ...text(colorScheme.middle, "mono", { size: "sm" }),
253                margin: {
254                    left: 12,
255                },
256            },
257        },
258        errorDiagnostic: diagnostic(colorScheme.middle, "negative"),
259        warningDiagnostic: diagnostic(colorScheme.middle, "warning"),
260        informationDiagnostic: diagnostic(colorScheme.middle, "accent"),
261        hintDiagnostic: diagnostic(colorScheme.middle, "warning"),
262        invalidErrorDiagnostic: diagnostic(colorScheme.middle, "base"),
263        invalidHintDiagnostic: diagnostic(colorScheme.middle, "base"),
264        invalidInformationDiagnostic: diagnostic(colorScheme.middle, "base"),
265        invalidWarningDiagnostic: diagnostic(colorScheme.middle, "base"),
266        hoverPopover: hoverPopover(colorScheme),
267        linkDefinition: {
268            color: syntax.linkUri.color,
269            underline: syntax.linkUri.underline,
270        },
271        jumpIcon: {
272            color: foreground(layer, "on"),
273            iconWidth: 20,
274            buttonWidth: 20,
275            cornerRadius: 6,
276            padding: {
277                top: 6,
278                bottom: 6,
279                left: 6,
280                right: 6,
281            },
282            hover: {
283                background: background(layer, "on", "hovered"),
284            },
285        },
286        scrollbar: {
287            width: 12,
288            minHeightFactor: 1.0,
289            track: {
290                border: border(layer, "variant", { left: true }),
291            },
292            thumb: {
293                background: withOpacity(background(layer, "inverted"), 0.4),
294                border: {
295                    width: 1,
296                    color: borderColor(layer, "variant"),
297                },
298            },
299        },
300        compositionMark: {
301            underline: {
302                thickness: 1.0,
303                color: borderColor(layer),
304            },
305        },
306        syntax,
307    }
308}