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