| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057 |
- import { SyntaxStyle, RGBA, type TerminalColors } from "@opentui/core"
- import path from "path"
- import { createEffect, createMemo, onMount } from "solid-js"
- import { useSync } from "@tui/context/sync"
- import { createSimpleContext } from "./helper"
- import aura from "./theme/aura.json" with { type: "json" }
- import ayu from "./theme/ayu.json" with { type: "json" }
- import catppuccin from "./theme/catppuccin.json" with { type: "json" }
- import cobalt2 from "./theme/cobalt2.json" with { type: "json" }
- import dracula from "./theme/dracula.json" with { type: "json" }
- import everforest from "./theme/everforest.json" with { type: "json" }
- import flexoki from "./theme/flexoki.json" with { type: "json" }
- import github from "./theme/github.json" with { type: "json" }
- import gruvbox from "./theme/gruvbox.json" with { type: "json" }
- import kanagawa from "./theme/kanagawa.json" with { type: "json" }
- import material from "./theme/material.json" with { type: "json" }
- import matrix from "./theme/matrix.json" with { type: "json" }
- import monokai from "./theme/monokai.json" with { type: "json" }
- import nightowl from "./theme/nightowl.json" with { type: "json" }
- import nord from "./theme/nord.json" with { type: "json" }
- import onedark from "./theme/one-dark.json" with { type: "json" }
- import opencode from "./theme/opencode.json" with { type: "json" }
- import palenight from "./theme/palenight.json" with { type: "json" }
- import rosepine from "./theme/rosepine.json" with { type: "json" }
- import solarized from "./theme/solarized.json" with { type: "json" }
- import synthwave84 from "./theme/synthwave84.json" with { type: "json" }
- import tokyonight from "./theme/tokyonight.json" with { type: "json" }
- import vesper from "./theme/vesper.json" with { type: "json" }
- import zenburn from "./theme/zenburn.json" with { type: "json" }
- import { useKV } from "./kv"
- import { useRenderer } from "@opentui/solid"
- import { createStore, produce } from "solid-js/store"
- import { Global } from "@/global"
- import { Filesystem } from "@/util/filesystem"
- type ThemeColors = {
- primary: RGBA
- secondary: RGBA
- accent: RGBA
- error: RGBA
- warning: RGBA
- success: RGBA
- info: RGBA
- text: RGBA
- textMuted: RGBA
- selectedListItemText: RGBA
- background: RGBA
- backgroundPanel: RGBA
- backgroundElement: RGBA
- backgroundMenu: RGBA
- border: RGBA
- borderActive: RGBA
- borderSubtle: RGBA
- diffAdded: RGBA
- diffRemoved: RGBA
- diffContext: RGBA
- diffHunkHeader: RGBA
- diffHighlightAdded: RGBA
- diffHighlightRemoved: RGBA
- diffAddedBg: RGBA
- diffRemovedBg: RGBA
- diffContextBg: RGBA
- diffLineNumber: RGBA
- diffAddedLineNumberBg: RGBA
- diffRemovedLineNumberBg: RGBA
- markdownText: RGBA
- markdownHeading: RGBA
- markdownLink: RGBA
- markdownLinkText: RGBA
- markdownCode: RGBA
- markdownBlockQuote: RGBA
- markdownEmph: RGBA
- markdownStrong: RGBA
- markdownHorizontalRule: RGBA
- markdownListItem: RGBA
- markdownListEnumeration: RGBA
- markdownImage: RGBA
- markdownImageText: RGBA
- markdownCodeBlock: RGBA
- syntaxComment: RGBA
- syntaxKeyword: RGBA
- syntaxFunction: RGBA
- syntaxVariable: RGBA
- syntaxString: RGBA
- syntaxNumber: RGBA
- syntaxType: RGBA
- syntaxOperator: RGBA
- syntaxPunctuation: RGBA
- }
- type Theme = ThemeColors & {
- _hasSelectedListItemText: boolean
- }
- export function selectedForeground(theme: Theme): RGBA {
- // If theme explicitly defines selectedListItemText, use it
- if (theme._hasSelectedListItemText) {
- return theme.selectedListItemText
- }
- // For transparent backgrounds, calculate contrast based on primary color
- if (theme.background.a === 0) {
- const { r, g, b } = theme.primary
- const luminance = 0.299 * r + 0.587 * g + 0.114 * b
- return luminance > 0.5 ? RGBA.fromInts(0, 0, 0) : RGBA.fromInts(255, 255, 255)
- }
- // Fall back to background color
- return theme.background
- }
- type HexColor = `#${string}`
- type RefName = string
- type Variant = {
- dark: HexColor | RefName
- light: HexColor | RefName
- }
- type ColorValue = HexColor | RefName | Variant | RGBA
- type ThemeJson = {
- $schema?: string
- defs?: Record<string, HexColor | RefName>
- theme: Omit<Record<keyof ThemeColors, ColorValue>, "selectedListItemText" | "backgroundMenu"> & {
- selectedListItemText?: ColorValue
- backgroundMenu?: ColorValue
- }
- }
- export const DEFAULT_THEMES: Record<string, ThemeJson> = {
- aura,
- ayu,
- catppuccin,
- cobalt2,
- dracula,
- everforest,
- flexoki,
- github,
- gruvbox,
- kanagawa,
- material,
- matrix,
- monokai,
- nightowl,
- nord,
- ["one-dark"]: onedark,
- opencode,
- palenight,
- rosepine,
- solarized,
- synthwave84,
- tokyonight,
- vesper,
- zenburn,
- }
- function resolveTheme(theme: ThemeJson, mode: "dark" | "light") {
- const defs = theme.defs ?? {}
- function resolveColor(c: ColorValue): RGBA {
- if (c instanceof RGBA) return c
- if (typeof c === "string") {
- if (c === "transparent" || c === "none") return RGBA.fromInts(0, 0, 0, 0)
- if (c.startsWith("#")) return RGBA.fromHex(c)
- if (defs[c]) {
- return resolveColor(defs[c])
- } else if (theme.theme[c as keyof ThemeColors] !== undefined) {
- return resolveColor(theme.theme[c as keyof ThemeColors]!)
- } else {
- throw new Error(`Color reference "${c}" not found in defs or theme`)
- }
- }
- if (typeof c === "number") {
- return ansiToRgba(c)
- }
- return resolveColor(c[mode])
- }
- const resolved = Object.fromEntries(
- Object.entries(theme.theme)
- .filter(([key]) => key !== "selectedListItemText" && key !== "backgroundMenu")
- .map(([key, value]) => {
- return [key, resolveColor(value)]
- }),
- ) as Partial<ThemeColors>
- // Handle selectedListItemText separately since it's optional
- const hasSelectedListItemText = theme.theme.selectedListItemText !== undefined
- if (hasSelectedListItemText) {
- resolved.selectedListItemText = resolveColor(theme.theme.selectedListItemText!)
- } else {
- // Backward compatibility: if selectedListItemText is not defined, use background color
- // This preserves the current behavior for all existing themes
- resolved.selectedListItemText = resolved.background
- }
- // Handle backgroundMenu - optional with fallback to backgroundElement
- if (theme.theme.backgroundMenu !== undefined) {
- resolved.backgroundMenu = resolveColor(theme.theme.backgroundMenu)
- } else {
- resolved.backgroundMenu = resolved.backgroundElement
- }
- return {
- ...resolved,
- _hasSelectedListItemText: hasSelectedListItemText,
- } as Theme
- }
- function ansiToRgba(code: number): RGBA {
- // Standard ANSI colors (0-15)
- if (code < 16) {
- const ansiColors = [
- "#000000", // Black
- "#800000", // Red
- "#008000", // Green
- "#808000", // Yellow
- "#000080", // Blue
- "#800080", // Magenta
- "#008080", // Cyan
- "#c0c0c0", // White
- "#808080", // Bright Black
- "#ff0000", // Bright Red
- "#00ff00", // Bright Green
- "#ffff00", // Bright Yellow
- "#0000ff", // Bright Blue
- "#ff00ff", // Bright Magenta
- "#00ffff", // Bright Cyan
- "#ffffff", // Bright White
- ]
- return RGBA.fromHex(ansiColors[code] ?? "#000000")
- }
- // 6x6x6 Color Cube (16-231)
- if (code < 232) {
- const index = code - 16
- const b = index % 6
- const g = Math.floor(index / 6) % 6
- const r = Math.floor(index / 36)
- const val = (x: number) => (x === 0 ? 0 : x * 40 + 55)
- return RGBA.fromInts(val(r), val(g), val(b))
- }
- // Grayscale Ramp (232-255)
- if (code < 256) {
- const gray = (code - 232) * 10 + 8
- return RGBA.fromInts(gray, gray, gray)
- }
- // Fallback for invalid codes
- return RGBA.fromInts(0, 0, 0)
- }
- export const { use: useTheme, provider: ThemeProvider } = createSimpleContext({
- name: "Theme",
- init: (props: { mode: "dark" | "light" }) => {
- const sync = useSync()
- const kv = useKV()
- const [store, setStore] = createStore({
- themes: DEFAULT_THEMES,
- mode: kv.get("theme_mode", props.mode),
- active: (sync.data.config.theme ?? kv.get("theme", "opencode")) as string,
- ready: false,
- })
- createEffect(async () => {
- const custom = await getCustomThemes()
- setStore(
- produce((draft) => {
- Object.assign(draft.themes, custom)
- draft.ready = true
- }),
- )
- })
- const renderer = useRenderer()
- renderer
- .getPalette({
- size: 16,
- })
- .then((colors) => {
- if (!colors.palette[0]) return
- setStore("themes", "system", generateSystem(colors, store.mode))
- })
- const values = createMemo(() => {
- return resolveTheme(store.themes[store.active] ?? store.themes.opencode, store.mode)
- })
- const syntax = createMemo(() => generateSyntax(values()))
- const subtleSyntax = createMemo(() => generateSubtleSyntax(values()))
- return {
- theme: new Proxy(values(), {
- get(_target, prop) {
- // @ts-expect-error
- return values()[prop]
- },
- }),
- get selected() {
- return store.active
- },
- all() {
- return store.themes
- },
- syntax,
- subtleSyntax,
- mode() {
- return store.mode
- },
- setMode(mode: "dark" | "light") {
- setStore("mode", mode)
- kv.set("theme_mode", mode)
- },
- set(theme: string) {
- setStore("active", theme)
- kv.set("theme", theme)
- },
- get ready() {
- return store.ready
- },
- }
- },
- })
- const CUSTOM_THEME_GLOB = new Bun.Glob("themes/*.json")
- async function getCustomThemes() {
- const directories = [
- Global.Path.config,
- ...(await Array.fromAsync(
- Filesystem.up({
- targets: [".opencode"],
- start: process.cwd(),
- }),
- )),
- ]
- const result: Record<string, ThemeJson> = {}
- for (const dir of directories) {
- for await (const item of CUSTOM_THEME_GLOB.scan({
- absolute: true,
- followSymlinks: true,
- dot: true,
- cwd: dir,
- })) {
- const name = path.basename(item, ".json")
- result[name] = await Bun.file(item).json()
- }
- }
- return result
- }
- function generateSystem(colors: TerminalColors, mode: "dark" | "light"): ThemeJson {
- const bg = RGBA.fromHex(colors.defaultBackground ?? colors.palette[0]!)
- const fg = RGBA.fromHex(colors.defaultForeground ?? colors.palette[7]!)
- const palette = colors.palette.filter((x) => x !== null).map((x) => RGBA.fromHex(x))
- const isDark = mode == "dark"
- // Generate gray scale based on terminal background
- const grays = generateGrayScale(bg, isDark)
- const textMuted = generateMutedTextColor(bg, isDark)
- // ANSI color references
- const ansiColors = {
- black: palette[0],
- red: palette[1],
- green: palette[2],
- yellow: palette[3],
- blue: palette[4],
- magenta: palette[5],
- cyan: palette[6],
- white: palette[7],
- }
- return {
- theme: {
- // Primary colors using ANSI
- primary: ansiColors.cyan,
- secondary: ansiColors.magenta,
- accent: ansiColors.cyan,
- // Status colors using ANSI
- error: ansiColors.red,
- warning: ansiColors.yellow,
- success: ansiColors.green,
- info: ansiColors.cyan,
- // Text colors
- text: fg,
- textMuted,
- selectedListItemText: bg,
- // Background colors
- background: bg,
- backgroundPanel: grays[2],
- backgroundElement: grays[3],
- backgroundMenu: grays[3],
- // Border colors
- borderSubtle: grays[6],
- border: grays[7],
- borderActive: grays[8],
- // Diff colors
- diffAdded: ansiColors.green,
- diffRemoved: ansiColors.red,
- diffContext: grays[7],
- diffHunkHeader: grays[7],
- diffHighlightAdded: ansiColors.green,
- diffHighlightRemoved: ansiColors.red,
- diffAddedBg: grays[2],
- diffRemovedBg: grays[2],
- diffContextBg: grays[1],
- diffLineNumber: grays[6],
- diffAddedLineNumberBg: grays[3],
- diffRemovedLineNumberBg: grays[3],
- // Markdown colors
- markdownText: fg,
- markdownHeading: fg,
- markdownLink: ansiColors.blue,
- markdownLinkText: ansiColors.cyan,
- markdownCode: ansiColors.green,
- markdownBlockQuote: ansiColors.yellow,
- markdownEmph: ansiColors.yellow,
- markdownStrong: fg,
- markdownHorizontalRule: grays[7],
- markdownListItem: ansiColors.blue,
- markdownListEnumeration: ansiColors.cyan,
- markdownImage: ansiColors.blue,
- markdownImageText: ansiColors.cyan,
- markdownCodeBlock: fg,
- // Syntax colors
- syntaxComment: textMuted,
- syntaxKeyword: ansiColors.magenta,
- syntaxFunction: ansiColors.blue,
- syntaxVariable: fg,
- syntaxString: ansiColors.green,
- syntaxNumber: ansiColors.yellow,
- syntaxType: ansiColors.cyan,
- syntaxOperator: ansiColors.cyan,
- syntaxPunctuation: fg,
- },
- }
- }
- function generateGrayScale(bg: RGBA, isDark: boolean): Record<number, RGBA> {
- const grays: Record<number, RGBA> = {}
- // RGBA stores floats in range 0-1, convert to 0-255
- const bgR = bg.r * 255
- const bgG = bg.g * 255
- const bgB = bg.b * 255
- const luminance = 0.299 * bgR + 0.587 * bgG + 0.114 * bgB
- for (let i = 1; i <= 12; i++) {
- const factor = i / 12.0
- let grayValue: number
- let newR: number
- let newG: number
- let newB: number
- if (isDark) {
- if (luminance < 10) {
- grayValue = Math.floor(factor * 0.4 * 255)
- newR = grayValue
- newG = grayValue
- newB = grayValue
- } else {
- const newLum = luminance + (255 - luminance) * factor * 0.4
- const ratio = newLum / luminance
- newR = Math.min(bgR * ratio, 255)
- newG = Math.min(bgG * ratio, 255)
- newB = Math.min(bgB * ratio, 255)
- }
- } else {
- if (luminance > 245) {
- grayValue = Math.floor(255 - factor * 0.4 * 255)
- newR = grayValue
- newG = grayValue
- newB = grayValue
- } else {
- const newLum = luminance * (1 - factor * 0.4)
- const ratio = newLum / luminance
- newR = Math.max(bgR * ratio, 0)
- newG = Math.max(bgG * ratio, 0)
- newB = Math.max(bgB * ratio, 0)
- }
- }
- grays[i] = RGBA.fromInts(Math.floor(newR), Math.floor(newG), Math.floor(newB))
- }
- return grays
- }
- function generateMutedTextColor(bg: RGBA, isDark: boolean): RGBA {
- // RGBA stores floats in range 0-1, convert to 0-255
- const bgR = bg.r * 255
- const bgG = bg.g * 255
- const bgB = bg.b * 255
- const bgLum = 0.299 * bgR + 0.587 * bgG + 0.114 * bgB
- let grayValue: number
- if (isDark) {
- if (bgLum < 10) {
- // Very dark/black background
- grayValue = 180 // #b4b4b4
- } else {
- // Scale up for lighter dark backgrounds
- grayValue = Math.min(Math.floor(160 + bgLum * 0.3), 200)
- }
- } else {
- if (bgLum > 245) {
- // Very light/white background
- grayValue = 75 // #4b4b4b
- } else {
- // Scale down for darker light backgrounds
- grayValue = Math.max(Math.floor(100 - (255 - bgLum) * 0.2), 60)
- }
- }
- return RGBA.fromInts(grayValue, grayValue, grayValue)
- }
- function generateSyntax(theme: Theme) {
- return SyntaxStyle.fromTheme(getSyntaxRules(theme))
- }
- function generateSubtleSyntax(theme: Theme) {
- const rules = getSyntaxRules(theme)
- return SyntaxStyle.fromTheme(
- rules.map((rule) => {
- if (rule.style.foreground) {
- const fg = rule.style.foreground
- return {
- ...rule,
- style: {
- ...rule.style,
- foreground: RGBA.fromInts(
- Math.round(fg.r * 255),
- Math.round(fg.g * 255),
- Math.round(fg.b * 255),
- Math.round(0.6 * 255),
- ),
- },
- }
- }
- return rule
- }),
- )
- }
- function getSyntaxRules(theme: Theme) {
- return [
- {
- scope: ["prompt"],
- style: {
- foreground: theme.accent,
- },
- },
- {
- scope: ["extmark.file"],
- style: {
- foreground: theme.warning,
- bold: true,
- },
- },
- {
- scope: ["extmark.agent"],
- style: {
- foreground: theme.secondary,
- bold: true,
- },
- },
- {
- scope: ["extmark.paste"],
- style: {
- foreground: theme.background,
- background: theme.warning,
- bold: true,
- },
- },
- {
- scope: ["comment"],
- style: {
- foreground: theme.syntaxComment,
- italic: true,
- },
- },
- {
- scope: ["comment.documentation"],
- style: {
- foreground: theme.syntaxComment,
- italic: true,
- },
- },
- {
- scope: ["string", "symbol"],
- style: {
- foreground: theme.syntaxString,
- },
- },
- {
- scope: ["number", "boolean"],
- style: {
- foreground: theme.syntaxNumber,
- },
- },
- {
- scope: ["character.special"],
- style: {
- foreground: theme.syntaxString,
- },
- },
- {
- scope: ["keyword.return", "keyword.conditional", "keyword.repeat", "keyword.coroutine"],
- style: {
- foreground: theme.syntaxKeyword,
- italic: true,
- },
- },
- {
- scope: ["keyword.type"],
- style: {
- foreground: theme.syntaxType,
- bold: true,
- italic: true,
- },
- },
- {
- scope: ["keyword.function", "function.method"],
- style: {
- foreground: theme.syntaxFunction,
- },
- },
- {
- scope: ["keyword"],
- style: {
- foreground: theme.syntaxKeyword,
- italic: true,
- },
- },
- {
- scope: ["keyword.import"],
- style: {
- foreground: theme.syntaxKeyword,
- },
- },
- {
- scope: ["operator", "keyword.operator", "punctuation.delimiter"],
- style: {
- foreground: theme.syntaxOperator,
- },
- },
- {
- scope: ["keyword.conditional.ternary"],
- style: {
- foreground: theme.syntaxOperator,
- },
- },
- {
- scope: ["variable", "variable.parameter", "function.method.call", "function.call"],
- style: {
- foreground: theme.syntaxVariable,
- },
- },
- {
- scope: ["variable.member", "function", "constructor"],
- style: {
- foreground: theme.syntaxFunction,
- },
- },
- {
- scope: ["type", "module"],
- style: {
- foreground: theme.syntaxType,
- },
- },
- {
- scope: ["constant"],
- style: {
- foreground: theme.syntaxNumber,
- },
- },
- {
- scope: ["property"],
- style: {
- foreground: theme.syntaxVariable,
- },
- },
- {
- scope: ["class"],
- style: {
- foreground: theme.syntaxType,
- },
- },
- {
- scope: ["parameter"],
- style: {
- foreground: theme.syntaxVariable,
- },
- },
- {
- scope: ["punctuation", "punctuation.bracket"],
- style: {
- foreground: theme.syntaxPunctuation,
- },
- },
- {
- scope: ["variable.builtin", "type.builtin", "function.builtin", "module.builtin", "constant.builtin"],
- style: {
- foreground: theme.error,
- },
- },
- {
- scope: ["variable.super"],
- style: {
- foreground: theme.error,
- },
- },
- {
- scope: ["string.escape", "string.regexp"],
- style: {
- foreground: theme.syntaxKeyword,
- },
- },
- {
- scope: ["keyword.directive"],
- style: {
- foreground: theme.syntaxKeyword,
- italic: true,
- },
- },
- {
- scope: ["punctuation.special"],
- style: {
- foreground: theme.syntaxOperator,
- },
- },
- {
- scope: ["keyword.modifier"],
- style: {
- foreground: theme.syntaxKeyword,
- italic: true,
- },
- },
- {
- scope: ["keyword.exception"],
- style: {
- foreground: theme.syntaxKeyword,
- italic: true,
- },
- },
- // Markdown specific styles
- {
- scope: ["markup.heading"],
- style: {
- foreground: theme.markdownHeading,
- bold: true,
- },
- },
- {
- scope: ["markup.heading.1"],
- style: {
- foreground: theme.markdownHeading,
- bold: true,
- },
- },
- {
- scope: ["markup.heading.2"],
- style: {
- foreground: theme.markdownHeading,
- bold: true,
- },
- },
- {
- scope: ["markup.heading.3"],
- style: {
- foreground: theme.markdownHeading,
- bold: true,
- },
- },
- {
- scope: ["markup.heading.4"],
- style: {
- foreground: theme.markdownHeading,
- bold: true,
- },
- },
- {
- scope: ["markup.heading.5"],
- style: {
- foreground: theme.markdownHeading,
- bold: true,
- },
- },
- {
- scope: ["markup.heading.6"],
- style: {
- foreground: theme.markdownHeading,
- bold: true,
- },
- },
- {
- scope: ["markup.bold", "markup.strong"],
- style: {
- foreground: theme.markdownStrong,
- bold: true,
- },
- },
- {
- scope: ["markup.italic"],
- style: {
- foreground: theme.markdownEmph,
- italic: true,
- },
- },
- {
- scope: ["markup.list"],
- style: {
- foreground: theme.markdownListItem,
- },
- },
- {
- scope: ["markup.quote"],
- style: {
- foreground: theme.markdownBlockQuote,
- italic: true,
- },
- },
- {
- scope: ["markup.raw", "markup.raw.block"],
- style: {
- foreground: theme.markdownCode,
- },
- },
- {
- scope: ["markup.raw.inline"],
- style: {
- foreground: theme.markdownCode,
- background: theme.background,
- },
- },
- {
- scope: ["markup.link"],
- style: {
- foreground: theme.markdownLink,
- underline: true,
- },
- },
- {
- scope: ["markup.link.label"],
- style: {
- foreground: theme.markdownLinkText,
- underline: true,
- },
- },
- {
- scope: ["markup.link.url"],
- style: {
- foreground: theme.markdownLink,
- underline: true,
- },
- },
- {
- scope: ["label"],
- style: {
- foreground: theme.markdownLinkText,
- },
- },
- {
- scope: ["spell", "nospell"],
- style: {
- foreground: theme.text,
- },
- },
- {
- scope: ["conceal"],
- style: {
- foreground: theme.textMuted,
- },
- },
- // Additional common highlight groups
- {
- scope: ["string.special", "string.special.url"],
- style: {
- foreground: theme.markdownLink,
- underline: true,
- },
- },
- {
- scope: ["character"],
- style: {
- foreground: theme.syntaxString,
- },
- },
- {
- scope: ["float"],
- style: {
- foreground: theme.syntaxNumber,
- },
- },
- {
- scope: ["comment.error"],
- style: {
- foreground: theme.error,
- italic: true,
- bold: true,
- },
- },
- {
- scope: ["comment.warning"],
- style: {
- foreground: theme.warning,
- italic: true,
- bold: true,
- },
- },
- {
- scope: ["comment.todo", "comment.note"],
- style: {
- foreground: theme.info,
- italic: true,
- bold: true,
- },
- },
- {
- scope: ["namespace"],
- style: {
- foreground: theme.syntaxType,
- },
- },
- {
- scope: ["field"],
- style: {
- foreground: theme.syntaxVariable,
- },
- },
- {
- scope: ["type.definition"],
- style: {
- foreground: theme.syntaxType,
- bold: true,
- },
- },
- {
- scope: ["keyword.export"],
- style: {
- foreground: theme.syntaxKeyword,
- },
- },
- {
- scope: ["attribute", "annotation"],
- style: {
- foreground: theme.warning,
- },
- },
- {
- scope: ["tag"],
- style: {
- foreground: theme.error,
- },
- },
- {
- scope: ["tag.attribute"],
- style: {
- foreground: theme.syntaxKeyword,
- },
- },
- {
- scope: ["tag.delimiter"],
- style: {
- foreground: theme.syntaxOperator,
- },
- },
- {
- scope: ["markup.strikethrough"],
- style: {
- foreground: theme.textMuted,
- },
- },
- {
- scope: ["markup.underline"],
- style: {
- foreground: theme.text,
- underline: true,
- },
- },
- {
- scope: ["markup.list.checked"],
- style: {
- foreground: theme.success,
- },
- },
- {
- scope: ["markup.list.unchecked"],
- style: {
- foreground: theme.textMuted,
- },
- },
- {
- scope: ["diff.plus"],
- style: {
- foreground: theme.diffAdded,
- background: theme.diffAddedBg,
- },
- },
- {
- scope: ["diff.minus"],
- style: {
- foreground: theme.diffRemoved,
- background: theme.diffRemovedBg,
- },
- },
- {
- scope: ["diff.delta"],
- style: {
- foreground: theme.diffContext,
- background: theme.diffContextBg,
- },
- },
- {
- scope: ["error"],
- style: {
- foreground: theme.error,
- bold: true,
- },
- },
- {
- scope: ["warning"],
- style: {
- foreground: theme.warning,
- bold: true,
- },
- },
- {
- scope: ["info"],
- style: {
- foreground: theme.info,
- },
- },
- {
- scope: ["debug"],
- style: {
- foreground: theme.textMuted,
- },
- },
- ]
- }
|