1import { withOpacity } 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, styleSet: 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", styleSet, "default", { size: "sm" }),
40 highlight_text: text(layer, "sans", styleSet, "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: withOpacity(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 foldBackground: 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 removedWidthEm: 0.275,
149 widthEm: 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 documentHighlightReadBackground: withOpacity(
156 foreground(layer, "accent"),
157 0.1
158 ),
159 documentHighlightWriteBackground: theme.ramps
160 .neutral(0.5)
161 .alpha(0.4)
162 .hex(), // TODO: This was blend * 2
163 errorColor: background(layer, "negative"),
164 gutterBackground: background(layer),
165 gutterPaddingFactor: 3.5,
166 lineNumber: withOpacity(foreground(layer), 0.35),
167 lineNumberActive: foreground(layer),
168 renameFade: 0.6,
169 unnecessaryCodeFade: 0.5,
170 selection: theme.players[0],
171 whitespace: theme.ramps.neutral(0.5).hex(),
172 guestSelections: [
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 matchHighlight: foreground(theme.middle, "accent"),
191 item: autocomplete_item,
192 hoveredItem: {
193 ...autocomplete_item,
194 matchHighlight: foreground(
195 theme.middle,
196 "accent",
197 "hovered"
198 ),
199 background: background(theme.middle, "hovered"),
200 },
201 selectedItem: {
202 ...autocomplete_item,
203 matchHighlight: foreground(
204 theme.middle,
205 "accent",
206 "active"
207 ),
208 background: background(theme.middle, "active"),
209 },
210 },
211 diagnosticHeader: {
212 background: background(theme.middle),
213 icon_widthFactor: 1.5,
214 textScaleFactor: 0.857,
215 border: border(theme.middle, {
216 bottom: true,
217 top: true,
218 }),
219 code: {
220 ...text(theme.middle, "mono", { size: "sm" }),
221 margin: {
222 left: 10,
223 },
224 },
225 source: {
226 text: text(theme.middle, "sans", {
227 size: "sm",
228 weight: "bold",
229 }),
230 },
231 message: {
232 highlightText: text(theme.middle, "sans", {
233 size: "sm",
234 weight: "bold",
235 }),
236 text: text(theme.middle, "sans", { size: "sm" }),
237 },
238 },
239 diagnosticPathHeader: {
240 background: background(theme.middle),
241 textScaleFactor: 0.857,
242 filename: text(theme.middle, "mono", { size: "sm" }),
243 path: {
244 ...text(theme.middle, "mono", { size: "sm" }),
245 margin: {
246 left: 12,
247 },
248 },
249 },
250 errorDiagnostic: diagnostic(theme.middle, "negative"),
251 warningDiagnostic: diagnostic(theme.middle, "warning"),
252 informationDiagnostic: diagnostic(theme.middle, "accent"),
253 hintDiagnostic: diagnostic(theme.middle, "warning"),
254 invalidErrorDiagnostic: diagnostic(theme.middle, "base"),
255 invalidHintDiagnostic: diagnostic(theme.middle, "base"),
256 invalidInformationDiagnostic: diagnostic(theme.middle, "base"),
257 invalidWarningDiagnostic: diagnostic(theme.middle, "base"),
258 hover_popover: hover_popover(theme),
259 linkDefinition: {
260 color: syntax.link_uri.color,
261 underline: syntax.link_uri.underline,
262 },
263 jumpIcon: interactive({
264 base: {
265 color: foreground(layer, "on"),
266 icon_width: 20,
267 button_width: 20,
268 corner_radius: 6,
269 padding: {
270 top: 6,
271 bottom: 6,
272 left: 6,
273 right: 6,
274 },
275 },
276 state: {
277 hovered: {
278 background: background(layer, "on", "hovered"),
279 },
280 },
281 }),
282
283 scrollbar: {
284 width: 12,
285 minHeightFactor: 1.0,
286 track: {
287 border: border(layer, "variant", { left: true }),
288 },
289 thumb: {
290 background: withOpacity(background(layer, "inverted"), 0.3),
291 border: {
292 width: 1,
293 color: border_color(layer, "variant"),
294 top: false,
295 right: true,
296 left: true,
297 bottom: false,
298 },
299 },
300 git: {
301 deleted: is_light
302 ? withOpacity(theme.ramps.red(0.5).hex(), 0.8)
303 : withOpacity(theme.ramps.red(0.4).hex(), 0.8),
304 modified: is_light
305 ? withOpacity(theme.ramps.yellow(0.5).hex(), 0.8)
306 : withOpacity(theme.ramps.yellow(0.4).hex(), 0.8),
307 inserted: is_light
308 ? withOpacity(theme.ramps.green(0.5).hex(), 0.8)
309 : withOpacity(theme.ramps.green(0.4).hex(), 0.8),
310 },
311 },
312 compositionMark: {
313 underline: {
314 thickness: 1.0,
315 color: border_color(layer),
316 },
317 },
318 syntax,
319 }
320}