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