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