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