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