editor.ts

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