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