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