editor.ts

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