1import { withOpacity } from "../theme/color"
2import { ColorScheme, Layer, StyleSets } from "../theme/colorScheme"
3import { background, border, borderColor, foreground, text } from "./components"
4import hoverPopover from "./hoverPopover"
5
6import { buildSyntax } from "../theme/syntax"
7import { interactive, toggleable } from "../element"
8
9export default function editor(colorScheme: ColorScheme) {
10 const { isLight } = colorScheme
11
12 let layer = colorScheme.highest
13
14 const autocompleteItem = {
15 cornerRadius: 6,
16 padding: {
17 bottom: 2,
18 left: 6,
19 right: 6,
20 top: 2,
21 },
22 }
23
24 function diagnostic(layer: Layer, styleSet: StyleSets) {
25 return {
26 textScaleFactor: 0.857,
27 header: {
28 border: border(layer, {
29 top: true,
30 }),
31 },
32 message: {
33 text: text(layer, "sans", styleSet, "default", { size: "sm" }),
34 highlightText: text(layer, "sans", styleSet, "default", {
35 size: "sm",
36 weight: "bold",
37 }),
38 },
39 }
40 }
41
42 const syntax = buildSyntax(colorScheme)
43
44 return {
45 textColor: syntax.primary.color,
46 background: background(layer),
47 activeLineBackground: withOpacity(background(layer, "on"), 0.75),
48 highlightedLineBackground: background(layer, "on"),
49 // Inline autocomplete suggestions, Co-pilot suggestions, etc.
50 suggestion: syntax.predictive,
51 codeActions: {
52 indicator: toggleable({
53 base:
54 interactive({
55 base: {
56 color: foreground(layer, "variant"),
57 },
58 state: {
59 clicked: {
60 color: foreground(layer, "base"),
61 },
62 hovered: {
63 color: foreground(layer, "on"),
64 },
65 },
66 }),
67 state: {
68 active: {
69 default: {
70 color: foreground(layer, "on"),
71 },
72 }
73 }
74 }
75 ),
76
77 verticalScale: 0.55,
78 },
79 folds: {
80 iconMarginScale: 2.5,
81 foldedIcon: "icons/chevron_right_8.svg",
82 foldableIcon: "icons/chevron_down_8.svg",
83 indicator: toggleable({
84 base:
85 interactive({
86 base: {
87 color: foreground(layer, "variant"),
88 },
89 state: {
90 clicked: {
91 color: foreground(layer, "base"),
92 },
93 hovered: {
94 color: foreground(layer, "on"),
95 },
96 },
97 }),
98 state: {
99 active: {
100 default: {
101 color: foreground(layer, "on"),
102 },
103 }
104 }
105 }
106 ),
107 ellipses: {
108 textColor: colorScheme.ramps.neutral(0.71).hex(),
109 cornerRadiusFactor: 0.15,
110 background: {
111 // Copied from hover_popover highlight
112 default: {
113 color: colorScheme.ramps.neutral(0.5).alpha(0.0).hex(),
114 },
115
116 hovered: {
117 color: colorScheme.ramps.neutral(0.5).alpha(0.5).hex(),
118 },
119
120 clicked: {
121 color: colorScheme.ramps.neutral(0.5).alpha(0.7).hex(),
122 },
123 },
124 },
125 foldBackground: foreground(layer, "variant"),
126 },
127 diff: {
128 deleted: isLight
129 ? colorScheme.ramps.red(0.5).hex()
130 : colorScheme.ramps.red(0.4).hex(),
131 modified: isLight
132 ? colorScheme.ramps.yellow(0.5).hex()
133 : colorScheme.ramps.yellow(0.5).hex(),
134 inserted: isLight
135 ? colorScheme.ramps.green(0.4).hex()
136 : colorScheme.ramps.green(0.5).hex(),
137 removedWidthEm: 0.275,
138 widthEm: 0.15,
139 cornerRadius: 0.05,
140 },
141 /** Highlights matching occurrences of what is under the cursor
142 * as well as matched brackets
143 */
144 documentHighlightReadBackground: withOpacity(
145 foreground(layer, "accent"),
146 0.1
147 ),
148 documentHighlightWriteBackground: colorScheme.ramps
149 .neutral(0.5)
150 .alpha(0.4)
151 .hex(), // TODO: This was blend * 2
152 errorColor: background(layer, "negative"),
153 gutterBackground: background(layer),
154 gutterPaddingFactor: 3.5,
155 lineNumber: withOpacity(foreground(layer), 0.35),
156 lineNumberActive: foreground(layer),
157 renameFade: 0.6,
158 unnecessaryCodeFade: 0.5,
159 selection: colorScheme.players[0],
160 whitespace: colorScheme.ramps.neutral(0.5).hex(),
161 guestSelections: [
162 colorScheme.players[1],
163 colorScheme.players[2],
164 colorScheme.players[3],
165 colorScheme.players[4],
166 colorScheme.players[5],
167 colorScheme.players[6],
168 colorScheme.players[7],
169 ],
170 autocomplete: {
171 background: background(colorScheme.middle),
172 cornerRadius: 8,
173 padding: 4,
174 margin: {
175 left: -14,
176 },
177 border: border(colorScheme.middle),
178 shadow: colorScheme.popoverShadow,
179 matchHighlight: foreground(colorScheme.middle, "accent"),
180 item: autocompleteItem,
181 hoveredItem: {
182 ...autocompleteItem,
183 matchHighlight: foreground(
184 colorScheme.middle,
185 "accent",
186 "hovered"
187 ),
188 background: background(colorScheme.middle, "hovered"),
189 },
190 selectedItem: {
191 ...autocompleteItem,
192 matchHighlight: foreground(
193 colorScheme.middle,
194 "accent",
195 "active"
196 ),
197 background: background(colorScheme.middle, "active"),
198 },
199 },
200 diagnosticHeader: {
201 background: background(colorScheme.middle),
202 iconWidthFactor: 1.5,
203 textScaleFactor: 0.857,
204 border: border(colorScheme.middle, {
205 bottom: true,
206 top: true,
207 }),
208 code: {
209 ...text(colorScheme.middle, "mono", { size: "sm" }),
210 margin: {
211 left: 10,
212 },
213 },
214 source: {
215 text: text(colorScheme.middle, "sans", {
216 size: "sm",
217 weight: "bold",
218 }),
219 },
220 message: {
221 highlightText: text(colorScheme.middle, "sans", {
222 size: "sm",
223 weight: "bold",
224 }),
225 text: text(colorScheme.middle, "sans", { size: "sm" }),
226 },
227 },
228 diagnosticPathHeader: {
229 background: background(colorScheme.middle),
230 textScaleFactor: 0.857,
231 filename: text(colorScheme.middle, "mono", { size: "sm" }),
232 path: {
233 ...text(colorScheme.middle, "mono", { size: "sm" }),
234 margin: {
235 left: 12,
236 },
237 },
238 },
239 errorDiagnostic: diagnostic(colorScheme.middle, "negative"),
240 warningDiagnostic: diagnostic(colorScheme.middle, "warning"),
241 informationDiagnostic: diagnostic(colorScheme.middle, "accent"),
242 hintDiagnostic: diagnostic(colorScheme.middle, "warning"),
243 invalidErrorDiagnostic: diagnostic(colorScheme.middle, "base"),
244 invalidHintDiagnostic: diagnostic(colorScheme.middle, "base"),
245 invalidInformationDiagnostic: diagnostic(colorScheme.middle, "base"),
246 invalidWarningDiagnostic: diagnostic(colorScheme.middle, "base"),
247 hoverPopover: hoverPopover(colorScheme),
248 linkDefinition: {
249 color: syntax.linkUri.color,
250 underline: syntax.linkUri.underline,
251 },
252 jumpIcon: interactive({
253 base: {
254 color: foreground(layer, "on"),
255 iconWidth: 20,
256 buttonWidth: 20,
257 cornerRadius: 6,
258 padding: {
259 top: 6,
260 bottom: 6,
261 left: 6,
262 right: 6,
263 },
264 },
265 state: {
266 hovered: {
267 background: background(layer, "on", "hovered"),
268 },
269 },
270 }),
271
272 scrollbar: {
273 width: 12,
274 minHeightFactor: 1.0,
275 track: {
276 border: border(layer, "variant", { left: true }),
277 },
278 thumb: {
279 background: withOpacity(background(layer, "inverted"), 0.3),
280 border: {
281 width: 1,
282 color: borderColor(layer, "variant"),
283 top: false,
284 right: true,
285 left: true,
286 bottom: false,
287 },
288 },
289 git: {
290 deleted: isLight
291 ? withOpacity(colorScheme.ramps.red(0.5).hex(), 0.8)
292 : withOpacity(colorScheme.ramps.red(0.4).hex(), 0.8),
293 modified: isLight
294 ? withOpacity(colorScheme.ramps.yellow(0.5).hex(), 0.8)
295 : withOpacity(colorScheme.ramps.yellow(0.4).hex(), 0.8),
296 inserted: isLight
297 ? withOpacity(colorScheme.ramps.green(0.5).hex(), 0.8)
298 : withOpacity(colorScheme.ramps.green(0.4).hex(), 0.8),
299 },
300 },
301 compositionMark: {
302 underline: {
303 thickness: 1.0,
304 color: borderColor(layer),
305 },
306 },
307 syntax,
308 }
309}