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