editor.ts

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