editor.ts

  1import { with_opacity } from "../theme/color"
  2import { Layer, StyleSets } from "../theme/create_theme"
  3import {
  4    background,
  5    border,
  6    border_color,
  7    foreground,
  8    text,
  9} from "./components"
 10import hover_popover from "./hover_popover"
 11
 12import { interactive, toggleable } from "../element"
 13import { useTheme } from "../theme"
 14import chroma from "chroma-js"
 15
 16export default function editor(): any {
 17    const theme = useTheme()
 18
 19    const { is_light } = theme
 20
 21    const layer = theme.highest
 22
 23    const autocomplete_item = {
 24        corner_radius: 6,
 25        padding: {
 26            bottom: 2,
 27            left: 6,
 28            right: 6,
 29            top: 2,
 30        },
 31    }
 32
 33    function diagnostic(layer: Layer, style_set: StyleSets) {
 34        return {
 35            text_scale_factor: 0.857,
 36            header: {
 37                border: border(layer, {
 38                    top: true,
 39                }),
 40            },
 41            message: {
 42                text: text(layer, "sans", style_set, "default", { size: "sm" }),
 43                highlight_text: text(layer, "sans", style_set, "default", {
 44                    size: "sm",
 45                    weight: "bold",
 46                }),
 47            },
 48        }
 49    }
 50
 51    return {
 52        text_color: theme.syntax.primary.color,
 53        background: background(layer),
 54        active_line_background: with_opacity(background(layer, "on"), 0.75),
 55        highlighted_line_background: background(layer, "on"),
 56        // Inline autocomplete suggestions, Co-pilot suggestions, etc.
 57        hint: chroma
 58            .mix(
 59                theme.ramps.neutral(0.6).hex(),
 60                theme.ramps.blue(0.4).hex(),
 61                0.45,
 62                "lch"
 63            )
 64            .hex(),
 65        suggestion: chroma
 66            .mix(
 67                theme.ramps.neutral(0.4).hex(),
 68                theme.ramps.blue(0.4).hex(),
 69                0.45,
 70                "lch"
 71            )
 72            .hex(),
 73        code_actions: {
 74            indicator: toggleable({
 75                base: interactive({
 76                    base: {
 77                        color: foreground(layer, "variant"),
 78                    },
 79                    state: {
 80                        hovered: {
 81                            color: foreground(layer, "variant", "hovered"),
 82                        },
 83                        clicked: {
 84                            color: foreground(layer, "variant", "pressed"),
 85                        },
 86                    },
 87                }),
 88                state: {
 89                    active: {
 90                        default: {
 91                            color: foreground(layer, "accent"),
 92                        },
 93                        hovered: {
 94                            color: foreground(layer, "accent", "hovered"),
 95                        },
 96                        clicked: {
 97                            color: foreground(layer, "accent", "pressed"),
 98                        },
 99                    },
100                },
101            }),
102
103            vertical_scale: 0.55,
104        },
105        folds: {
106            icon_margin_scale: 2.5,
107            folded_icon: "icons/chevron_right_8.svg",
108            foldable_icon: "icons/chevron_down_8.svg",
109            indicator: toggleable({
110                base: interactive({
111                    base: {
112                        color: foreground(layer, "variant"),
113                    },
114                    state: {
115                        hovered: {
116                            color: foreground(layer, "on"),
117                        },
118                        clicked: {
119                            color: foreground(layer, "base"),
120                        },
121                    },
122                }),
123                state: {
124                    active: {
125                        default: {
126                            color: foreground(layer, "default"),
127                        },
128                        hovered: {
129                            color: foreground(layer, "on"),
130                        },
131                    },
132                },
133            }),
134            ellipses: {
135                text_color: theme.ramps.neutral(0.71).hex(),
136                corner_radius_factor: 0.15,
137                background: {
138                    // Copied from hover_popover highlight
139                    default: {
140                        color: theme.ramps.neutral(0.5).alpha(0.0).hex(),
141                    },
142
143                    hovered: {
144                        color: theme.ramps.neutral(0.5).alpha(0.5).hex(),
145                    },
146
147                    clicked: {
148                        color: theme.ramps.neutral(0.5).alpha(0.7).hex(),
149                    },
150                },
151            },
152            fold_background: foreground(layer, "variant"),
153        },
154        diff: {
155            deleted: is_light
156                ? theme.ramps.red(0.5).hex()
157                : theme.ramps.red(0.4).hex(),
158            modified: is_light
159                ? theme.ramps.yellow(0.5).hex()
160                : theme.ramps.yellow(0.5).hex(),
161            inserted: is_light
162                ? theme.ramps.green(0.4).hex()
163                : theme.ramps.green(0.5).hex(),
164            removed_width_em: 0.275,
165            width_em: 0.15,
166            corner_radius: 0.05,
167        },
168        /** Highlights matching occurrences of what is under the cursor
169         * as well as matched brackets
170         */
171        document_highlight_read_background: with_opacity(
172            foreground(layer, "accent"),
173            0.1
174        ),
175        document_highlight_write_background: theme.ramps
176            .neutral(0.5)
177            .alpha(0.4)
178            .hex(), // TODO: This was blend * 2
179        error_color: background(layer, "negative"),
180        gutter_background: background(layer),
181        gutter_padding_factor: 3.5,
182        line_number: with_opacity(foreground(layer), 0.35),
183        line_number_active: foreground(layer),
184        rename_fade: 0.6,
185        wrap_guide: with_opacity(foreground(layer), 0.05),
186        active_wrap_guide: with_opacity(foreground(layer), 0.1),
187        unnecessary_code_fade: 0.5,
188        selection: theme.players[0],
189        whitespace: theme.ramps.neutral(0.5).hex(),
190        guest_selections: [
191            theme.players[1],
192            theme.players[2],
193            theme.players[3],
194            theme.players[4],
195            theme.players[5],
196            theme.players[6],
197            theme.players[7],
198        ],
199        autocomplete: {
200            background: background(theme.middle),
201            corner_radius: 8,
202            padding: 4,
203            margin: {
204                left: -14,
205            },
206            border: border(theme.middle),
207            shadow: theme.popover_shadow,
208            match_highlight: foreground(theme.middle, "accent"),
209            item: autocomplete_item,
210            hovered_item: {
211                ...autocomplete_item,
212                match_highlight: foreground(theme.middle, "accent", "hovered"),
213                background: background(theme.middle, "hovered"),
214            },
215            selected_item: {
216                ...autocomplete_item,
217                match_highlight: foreground(theme.middle, "accent", "active"),
218                background: background(theme.middle, "active"),
219            },
220        },
221        diagnostic_header: {
222            background: background(theme.middle),
223            icon_width_factor: 1.5,
224            text_scale_factor: 0.857,
225            border: border(theme.middle, {
226                bottom: true,
227                top: true,
228            }),
229            code: {
230                ...text(theme.middle, "mono", { size: "sm" }),
231                margin: {
232                    left: 10,
233                },
234            },
235            source: {
236                text: text(theme.middle, "sans", {
237                    size: "sm",
238                    weight: "bold",
239                }),
240            },
241            message: {
242                highlight_text: text(theme.middle, "sans", {
243                    size: "sm",
244                    weight: "bold",
245                }),
246                text: text(theme.middle, "sans", { size: "sm" }),
247            },
248        },
249        diagnostic_path_header: {
250            background: background(theme.middle),
251            text_scale_factor: 0.857,
252            filename: text(theme.middle, "mono", { size: "sm" }),
253            path: {
254                ...text(theme.middle, "mono", { size: "sm" }),
255                margin: {
256                    left: 12,
257                },
258            },
259        },
260        error_diagnostic: diagnostic(theme.middle, "negative"),
261        warning_diagnostic: diagnostic(theme.middle, "warning"),
262        information_diagnostic: diagnostic(theme.middle, "accent"),
263        hint_diagnostic: diagnostic(theme.middle, "warning"),
264        invalid_error_diagnostic: diagnostic(theme.middle, "base"),
265        invalid_hint_diagnostic: diagnostic(theme.middle, "base"),
266        invalid_information_diagnostic: diagnostic(theme.middle, "base"),
267        invalid_warning_diagnostic: diagnostic(theme.middle, "base"),
268        hover_popover: hover_popover(),
269        link_definition: {
270            color: theme.syntax.link_uri.color,
271            underline: theme.syntax.link_uri.underline,
272        },
273        jump_icon: interactive({
274            base: {
275                color: foreground(layer, "on"),
276                icon_width: 20,
277                button_width: 20,
278                corner_radius: 6,
279                padding: {
280                    top: 6,
281                    bottom: 6,
282                    left: 6,
283                    right: 6,
284                },
285            },
286            state: {
287                hovered: {
288                    background: background(layer, "on", "hovered"),
289                },
290            },
291        }),
292
293        scrollbar: {
294            width: 12,
295            min_height_factor: 1.0,
296            track: {
297                border: border(layer, "variant", { left: true }),
298            },
299            thumb: {
300                background: with_opacity(background(layer, "inverted"), 0.3),
301                border: {
302                    width: 1,
303                    color: border_color(layer, "variant"),
304                    top: false,
305                    right: true,
306                    left: true,
307                    bottom: false,
308                },
309            },
310            git: {
311                deleted: is_light
312                    ? with_opacity(theme.ramps.red(0.5).hex(), 0.8)
313                    : with_opacity(theme.ramps.red(0.4).hex(), 0.8),
314                modified: is_light
315                    ? with_opacity(theme.ramps.yellow(0.5).hex(), 0.8)
316                    : with_opacity(theme.ramps.yellow(0.4).hex(), 0.8),
317                inserted: is_light
318                    ? with_opacity(theme.ramps.green(0.5).hex(), 0.8)
319                    : with_opacity(theme.ramps.green(0.4).hex(), 0.8),
320            },
321            selections: foreground(layer, "accent"),
322        },
323        composition_mark: {
324            underline: {
325                thickness: 1.0,
326                color: border_color(layer),
327            },
328        },
329        syntax: theme.syntax,
330    }
331}