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