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