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