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}