editor.ts

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