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"
  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}