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