@brimveyn/aimux-config 0.4.4 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/actions.ts +11 -8
- package/src/defaults.ts +3 -2
- package/src/house-themes.ts +44 -302
- package/src/index.ts +20 -16
- package/src/palette-to-shiki.ts +134 -0
- package/src/palette-utils.ts +92 -0
- package/src/resolver.ts +0 -1
- package/src/themes/opencode.ts +1460 -0
- package/src/themes.ts +18 -88
- package/src/types.ts +46 -131
- package/src/normalize-theme.ts +0 -260
- package/src/themes/generated/andromeeda.ts +0 -346
- package/src/themes/generated/aurora-x.ts +0 -603
- package/src/themes/generated/ayu-dark.ts +0 -817
- package/src/themes/generated/ayu-light.ts +0 -817
- package/src/themes/generated/ayu-mirage.ts +0 -817
- package/src/themes/generated/catppuccin-frappe.ts +0 -2041
- package/src/themes/generated/catppuccin-latte.ts +0 -2041
- package/src/themes/generated/catppuccin-macchiato.ts +0 -2041
- package/src/themes/generated/catppuccin-mocha.ts +0 -2041
- package/src/themes/generated/dark-plus.ts +0 -614
- package/src/themes/generated/dracula-soft.ts +0 -947
- package/src/themes/generated/dracula.ts +0 -947
- package/src/themes/generated/everforest-dark.ts +0 -2246
- package/src/themes/generated/everforest-light.ts +0 -2246
- package/src/themes/generated/github-dark-default.ts +0 -605
- package/src/themes/generated/github-dark-dimmed.ts +0 -605
- package/src/themes/generated/github-dark-high-contrast.ts +0 -608
- package/src/themes/generated/github-dark.ts +0 -519
- package/src/themes/generated/github-light-default.ts +0 -602
- package/src/themes/generated/github-light-high-contrast.ts +0 -604
- package/src/themes/generated/github-light.ts +0 -515
- package/src/themes/generated/gruvbox-dark-hard.ts +0 -1124
- package/src/themes/generated/gruvbox-dark-medium.ts +0 -1124
- package/src/themes/generated/gruvbox-dark-soft.ts +0 -1124
- package/src/themes/generated/gruvbox-light-hard.ts +0 -1124
- package/src/themes/generated/gruvbox-light-medium.ts +0 -1124
- package/src/themes/generated/gruvbox-light-soft.ts +0 -1124
- package/src/themes/generated/horizon-bright.ts +0 -420
- package/src/themes/generated/horizon.ts +0 -418
- package/src/themes/generated/houston.ts +0 -1819
- package/src/themes/generated/index.ts +0 -140
- package/src/themes/generated/kanagawa-dragon.ts +0 -753
- package/src/themes/generated/kanagawa-lotus.ts +0 -753
- package/src/themes/generated/kanagawa-wave.ts +0 -753
- package/src/themes/generated/laserwave.ts +0 -489
- package/src/themes/generated/light-plus.ts +0 -639
- package/src/themes/generated/material-theme-darker.ts +0 -759
- package/src/themes/generated/material-theme-lighter.ts +0 -759
- package/src/themes/generated/material-theme-ocean.ts +0 -759
- package/src/themes/generated/material-theme-palenight.ts +0 -759
- package/src/themes/generated/material-theme.ts +0 -759
- package/src/themes/generated/min-dark.ts +0 -326
- package/src/themes/generated/min-light.ts +0 -331
- package/src/themes/generated/monokai.ts +0 -463
- package/src/themes/generated/night-owl-light.ts +0 -1526
- package/src/themes/generated/night-owl.ts +0 -1628
- package/src/themes/generated/nord.ts +0 -1277
- package/src/themes/generated/one-dark-pro.ts +0 -1920
- package/src/themes/generated/one-light.ts +0 -1599
- package/src/themes/generated/plastic.ts +0 -315
- package/src/themes/generated/poimandres.ts +0 -1233
- package/src/themes/generated/red.ts +0 -395
- package/src/themes/generated/rose-pine-dawn.ts +0 -696
- package/src/themes/generated/rose-pine-moon.ts +0 -696
- package/src/themes/generated/rose-pine.ts +0 -696
- package/src/themes/generated/slack-dark.ts +0 -594
- package/src/themes/generated/slack-ochin.ts +0 -461
- package/src/themes/generated/snazzy-light.ts +0 -1254
- package/src/themes/generated/solarized-dark.ts +0 -387
- package/src/themes/generated/solarized-light.ts +0 -379
- package/src/themes/generated/synthwave-84.ts +0 -751
- package/src/themes/generated/tokyo-night.ts +0 -1420
- package/src/themes/generated/vesper.ts +0 -578
- package/src/themes/generated/vitesse-black.ts +0 -629
- package/src/themes/generated/vitesse-dark.ts +0 -629
- package/src/themes/generated/vitesse-light.ts +0 -627
package/src/themes.ts
CHANGED
|
@@ -1,100 +1,30 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
NamedTheme,
|
|
3
|
-
NamedThemeDefinition,
|
|
4
|
-
Theme,
|
|
5
|
-
ThemeColorMap,
|
|
6
|
-
ThemeDefinition,
|
|
7
|
-
ThemeId,
|
|
8
|
-
UserThemeInput,
|
|
9
|
-
} from './types'
|
|
1
|
+
import type { AimuxTheme, ThemeId } from './types'
|
|
10
2
|
|
|
11
3
|
import { HOUSE_THEME_IDS, HOUSE_THEMES } from './house-themes'
|
|
12
|
-
import {
|
|
13
|
-
import { GENERATED_THEME_IDS, GENERATED_THEMES } from './themes/generated'
|
|
4
|
+
import { OPENCODE_THEME_IDS, OPENCODE_THEMES } from './themes/opencode'
|
|
14
5
|
|
|
15
|
-
export const THEMES: Record<string,
|
|
16
|
-
export const THEME_IDS: ThemeId[] = [...
|
|
6
|
+
export const THEMES: Record<string, AimuxTheme> = { ...HOUSE_THEMES, ...OPENCODE_THEMES }
|
|
7
|
+
export const THEME_IDS: ThemeId[] = [...HOUSE_THEME_IDS, ...OPENCODE_THEME_IDS]
|
|
17
8
|
|
|
18
|
-
const DEFAULT_THEME_ID: ThemeId = 'aimux'
|
|
9
|
+
const DEFAULT_THEME_ID: ThemeId = 'aimux-dark'
|
|
19
10
|
|
|
20
|
-
const
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
'one-dark': 'one-dark-pro',
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function migrateThemeId(id: string | undefined): ThemeId {
|
|
28
|
-
if (id !== undefined && id in THEMES) return id as ThemeId
|
|
29
|
-
if (id !== undefined) {
|
|
30
|
-
const alias = LEGACY_THEME_ALIASES[id]
|
|
31
|
-
if (alias !== undefined) return alias
|
|
32
|
-
}
|
|
33
|
-
return DEFAULT_THEME_ID
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function isKnownThemeId(id: string): boolean {
|
|
37
|
-
return id in THEMES
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function isFullTheme(
|
|
41
|
-
def: NamedTheme | NamedThemeDefinition | UserThemeInput
|
|
42
|
-
): def is NamedTheme | UserThemeInput {
|
|
43
|
-
return 'settings' in def || 'fg' in def || 'bg' in def
|
|
11
|
+
const LEGACY_MODE_HINTS: Record<string, ThemeId> = {
|
|
12
|
+
'aimux': 'aimux-dark',
|
|
13
|
+
'aimux-dark': 'aimux-dark',
|
|
14
|
+
'aimux-light': 'aimux-light',
|
|
44
15
|
}
|
|
45
16
|
|
|
46
17
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
18
|
+
* Migrate a legacy persisted theme id (anything from the old wide registry)
|
|
19
|
+
* to the new light/dark identifier. Anything we don't recognize lands on the
|
|
20
|
+
* dark default — modes are the only knob now.
|
|
50
21
|
*/
|
|
51
|
-
export function
|
|
52
|
-
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
const fallback = THEMES[DEFAULT_THEME_ID]
|
|
56
|
-
if (!fallback) return
|
|
57
|
-
for (const [id, def] of Object.entries(defs)) {
|
|
58
|
-
if (isFullTheme(def)) {
|
|
59
|
-
THEMES[id] = normalizeTheme({ ...def, name: def.name ?? id })
|
|
60
|
-
} else {
|
|
61
|
-
const base = def.base ? (THEMES[def.base] ?? fallback) : fallback
|
|
62
|
-
const colors: Record<string, string> = { ...base.colors }
|
|
63
|
-
for (const [k, v] of Object.entries(def.colors ?? {})) {
|
|
64
|
-
if (typeof v === 'string') colors[k] = v
|
|
65
|
-
}
|
|
66
|
-
THEMES[id] = normalizeTheme({
|
|
67
|
-
bg: base.bg,
|
|
68
|
-
colors,
|
|
69
|
-
displayName: def.name,
|
|
70
|
-
fg: base.fg,
|
|
71
|
-
name: id,
|
|
72
|
-
settings: base.settings,
|
|
73
|
-
type: base.type,
|
|
74
|
-
})
|
|
75
|
-
}
|
|
76
|
-
if (!THEME_IDS.includes(id)) THEME_IDS.push(id)
|
|
77
|
-
}
|
|
22
|
+
export function migrateThemeId(id: string | undefined): ThemeId {
|
|
23
|
+
if (id === undefined) return DEFAULT_THEME_ID
|
|
24
|
+
if (id in THEMES) return id as ThemeId
|
|
25
|
+
return LEGACY_MODE_HINTS[id] ?? DEFAULT_THEME_ID
|
|
78
26
|
}
|
|
79
27
|
|
|
80
|
-
export
|
|
81
|
-
|
|
82
|
-
* Palette shortcut. Patches VSCode color keys on top of an existing theme;
|
|
83
|
-
* token settings inherit from the base unchanged.
|
|
84
|
-
*/
|
|
85
|
-
define(name: string, base: ThemeId, overrides: Partial<ThemeColorMap>): NamedThemeDefinition {
|
|
86
|
-
return { base, colors: overrides, name }
|
|
87
|
-
},
|
|
88
|
-
/** Unnamed variant of `define`. Prefer `define` in config. */
|
|
89
|
-
extend(base: ThemeId, overrides: Partial<ThemeColorMap>): ThemeDefinition {
|
|
90
|
-
return { base, colors: overrides }
|
|
91
|
-
},
|
|
92
|
-
/**
|
|
93
|
-
* Passthrough for a raw Shiki / VSCode-shape theme. Missing
|
|
94
|
-
* `AIMUX_COLOR_KEYS` are filled at registration via the same fallback chain
|
|
95
|
-
* the shipped themes go through.
|
|
96
|
-
*/
|
|
97
|
-
full(theme: UserThemeInput): UserThemeInput {
|
|
98
|
-
return theme
|
|
99
|
-
},
|
|
28
|
+
export function isKnownThemeId(id: string): id is ThemeId {
|
|
29
|
+
return id in THEMES
|
|
100
30
|
}
|
package/src/types.ts
CHANGED
|
@@ -168,7 +168,8 @@ export interface GitPaneState {
|
|
|
168
168
|
visible: boolean
|
|
169
169
|
mode: 'embedded' | 'pane'
|
|
170
170
|
position: 'top' | 'bottom' | 'left' | 'right'
|
|
171
|
-
|
|
171
|
+
paneRatio: number
|
|
172
|
+
embeddedRatio: number
|
|
172
173
|
diffModeRatio: number
|
|
173
174
|
fileListMode: GitFileListMode
|
|
174
175
|
treeCompaction: boolean
|
|
@@ -257,6 +258,7 @@ export interface ModalSessionPicker extends ModalBase {
|
|
|
257
258
|
}
|
|
258
259
|
export interface ModalSessionName extends ModalBase {
|
|
259
260
|
type: 'session-name'
|
|
261
|
+
returnToSessionPicker: boolean
|
|
260
262
|
}
|
|
261
263
|
export interface ModalRenameTab extends ModalBase {
|
|
262
264
|
type: 'rename-tab'
|
|
@@ -357,7 +359,12 @@ export type ModalAction =
|
|
|
357
359
|
| { type: 'open-help-modal'; scope?: ModeId }
|
|
358
360
|
| { type: 'open-split-picker'; direction: SplitDirection }
|
|
359
361
|
| { type: 'open-session-picker' }
|
|
360
|
-
| {
|
|
362
|
+
| {
|
|
363
|
+
type: 'open-session-name-modal'
|
|
364
|
+
sessionTargetId?: string
|
|
365
|
+
initialName?: string
|
|
366
|
+
returnToSessionPicker?: boolean
|
|
367
|
+
}
|
|
361
368
|
| { type: 'close-modal' }
|
|
362
369
|
| { type: 'move-modal-selection'; delta: number }
|
|
363
370
|
| { type: 'update-command-edit'; char: string }
|
|
@@ -437,10 +444,12 @@ export type LayoutAction =
|
|
|
437
444
|
export type UIAction =
|
|
438
445
|
| { type: 'toggle-sidebar' }
|
|
439
446
|
| { type: 'resize-sidebar'; delta: number }
|
|
447
|
+
| { type: 'set-sidebar-width'; width: number }
|
|
440
448
|
| { type: 'set-focus-mode'; focusMode: FocusMode }
|
|
441
449
|
| { type: 'set-terminal-size'; cols: number; rows: number }
|
|
442
450
|
| { type: 'toggle-git-pane' }
|
|
443
451
|
| { type: 'resize-git-pane'; delta: number }
|
|
452
|
+
| { type: 'set-git-pane-ratio'; target: 'pane' | 'embedded'; ratio: number }
|
|
444
453
|
| { type: 'resize-git-diff-pane'; delta: number }
|
|
445
454
|
| { type: 'set-git-pane-mode'; mode: 'embedded' | 'pane' }
|
|
446
455
|
| { type: 'set-git-pane-position'; position: 'top' | 'bottom' | 'left' | 'right' }
|
|
@@ -532,7 +541,7 @@ export type SideEffect =
|
|
|
532
541
|
| { type: 'apply-theme'; action: 'confirm' }
|
|
533
542
|
| { type: 'apply-theme'; action: 'preview'; delta: 1 | -1 }
|
|
534
543
|
| { type: 'rename-session'; sessionId: string; name: string }
|
|
535
|
-
| { type: 'split-pane'; direction: SplitDirection }
|
|
544
|
+
| { type: 'split-pane'; direction: SplitDirection; sourceTabId?: string }
|
|
536
545
|
| { type: 'confirm-split' }
|
|
537
546
|
| { type: 'scroll-git-diff'; delta: number }
|
|
538
547
|
| { type: 'persist-git-diff-mode-ratio'; ratio: number }
|
|
@@ -546,6 +555,7 @@ export type SideEffect =
|
|
|
546
555
|
| { type: 'git-push' }
|
|
547
556
|
| { type: 'confirm-update-selection' }
|
|
548
557
|
| { type: 'switch-session-by-index'; index: number }
|
|
558
|
+
| { type: 'delete-session'; sessionId: string }
|
|
549
559
|
| { type: 'toggle-transparent' }
|
|
550
560
|
|
|
551
561
|
// ─── Key input / KeyResult / ModeContext ──────────────────────────────────────
|
|
@@ -571,138 +581,40 @@ export interface ModeContext {
|
|
|
571
581
|
|
|
572
582
|
// ─── Themes ───────────────────────────────────────────────────────────────────
|
|
573
583
|
|
|
574
|
-
import type { BundledTheme } from 'shiki'
|
|
575
|
-
|
|
576
|
-
export type ThemeId = BundledTheme | (string & {})
|
|
577
|
-
|
|
578
584
|
/**
|
|
579
|
-
*
|
|
580
|
-
*
|
|
585
|
+
* Compact opencode-style semantic palette. Required tokens cover every UI role;
|
|
586
|
+
* optional tokens fall back via helpers in `palette-utils.ts`.
|
|
581
587
|
*/
|
|
582
|
-
export
|
|
583
|
-
//
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
// lists
|
|
604
|
-
'list.activeSelectionBackground',
|
|
605
|
-
'list.activeSelectionForeground',
|
|
606
|
-
'list.hoverBackground',
|
|
607
|
-
// text & links
|
|
608
|
-
'foreground',
|
|
609
|
-
'descriptionForeground',
|
|
610
|
-
'textLink.foreground',
|
|
611
|
-
'textLink.activeForeground',
|
|
612
|
-
// status
|
|
613
|
-
'errorForeground',
|
|
614
|
-
'editorError.foreground',
|
|
615
|
-
'editorWarning.foreground',
|
|
616
|
-
// terminal ANSI
|
|
617
|
-
'terminal.ansiRed',
|
|
618
|
-
'terminal.ansiGreen',
|
|
619
|
-
'terminal.ansiYellow',
|
|
620
|
-
'terminal.ansiBlue',
|
|
621
|
-
'terminal.ansiMagenta',
|
|
622
|
-
'terminal.ansiCyan',
|
|
623
|
-
// git decorations
|
|
624
|
-
'gitDecoration.addedResourceForeground',
|
|
625
|
-
'gitDecoration.modifiedResourceForeground',
|
|
626
|
-
'gitDecoration.deletedResourceForeground',
|
|
627
|
-
'gitDecoration.untrackedResourceForeground',
|
|
628
|
-
// diff editor
|
|
629
|
-
'diffEditor.insertedLineBackground',
|
|
630
|
-
'diffEditor.removedLineBackground',
|
|
631
|
-
// input
|
|
632
|
-
'input.background',
|
|
633
|
-
'input.foreground',
|
|
634
|
-
'input.border',
|
|
635
|
-
] as const
|
|
636
|
-
|
|
637
|
-
export type AimuxColorKey = (typeof AIMUX_COLOR_KEYS)[number]
|
|
638
|
-
|
|
639
|
-
export type ThemeColorMap = Record<AimuxColorKey, string> & Record<string, string>
|
|
640
|
-
|
|
641
|
-
export interface ThemeSettings {
|
|
642
|
-
fontStyle?: string
|
|
643
|
-
foreground?: string
|
|
644
|
-
background?: string
|
|
645
|
-
// Some bundled shiki themes include non-standard keys (e.g. `content`); allow passthrough.
|
|
646
|
-
[key: string]: string | undefined
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
export interface ThemeTokenRule {
|
|
650
|
-
name?: string
|
|
651
|
-
scope?: string | string[]
|
|
652
|
-
// `foreground` at the top level is used by a handful of shiki themes as a
|
|
653
|
-
// shorthand for `settings.foreground` — accept both forms.
|
|
654
|
-
foreground?: string
|
|
655
|
-
settings?: ThemeSettings
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
export interface Theme {
|
|
588
|
+
export interface AimuxPalette {
|
|
589
|
+
// required
|
|
590
|
+
neutral: string
|
|
591
|
+
ink: string
|
|
592
|
+
primary: string
|
|
593
|
+
success: string
|
|
594
|
+
warning: string
|
|
595
|
+
error: string
|
|
596
|
+
info: string
|
|
597
|
+
// optional
|
|
598
|
+
accent?: string
|
|
599
|
+
interactive?: string
|
|
600
|
+
diffAdd?: string
|
|
601
|
+
diffDelete?: string
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
export type ThemeMode = 'light' | 'dark'
|
|
605
|
+
// eslint-disable-next-line typescript/no-redundant-type-constituents
|
|
606
|
+
export type ThemeId = 'aimux-light' | 'aimux-dark' | (string & {})
|
|
607
|
+
|
|
608
|
+
export interface AimuxTheme {
|
|
659
609
|
name: string
|
|
610
|
+
mode: ThemeMode
|
|
660
611
|
displayName: string
|
|
661
|
-
|
|
612
|
+
palette: AimuxPalette
|
|
662
613
|
fg: string
|
|
663
614
|
bg: string
|
|
664
|
-
colors: ThemeColorMap
|
|
665
|
-
settings: ThemeTokenRule[]
|
|
666
|
-
tokenColors?: ThemeTokenRule[]
|
|
667
|
-
colorReplacements?: Record<string, string>
|
|
668
|
-
semanticHighlighting?: boolean
|
|
669
|
-
semanticTokenColors?: Record<
|
|
670
|
-
string,
|
|
671
|
-
| string
|
|
672
|
-
| {
|
|
673
|
-
foreground?: string
|
|
674
|
-
fontStyle?: string
|
|
675
|
-
bold?: boolean
|
|
676
|
-
italic?: boolean
|
|
677
|
-
underline?: boolean
|
|
678
|
-
}
|
|
679
|
-
>
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
/** Partial-override shape for `themes.define(name, base, overrides)`. */
|
|
683
|
-
export interface ThemeDefinition {
|
|
684
|
-
base?: ThemeId
|
|
685
|
-
colors: Partial<ThemeColorMap>
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
export interface NamedThemeDefinition extends ThemeDefinition {
|
|
689
|
-
name: string
|
|
690
615
|
}
|
|
691
616
|
|
|
692
|
-
export
|
|
693
|
-
displayName: string
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
/**
|
|
697
|
-
* Input shape accepted by `themes.full(...)` — lets users paste a shiki /
|
|
698
|
-
* VSCode theme JSON without typing every AIMUX_COLOR_KEY. `registerUserThemes`
|
|
699
|
-
* runs it through `normalizeTheme` to produce a complete `Theme`.
|
|
700
|
-
*/
|
|
701
|
-
export interface UserThemeInput extends Partial<Omit<Theme, 'colors' | 'name' | 'displayName'>> {
|
|
702
|
-
name: string
|
|
703
|
-
displayName: string
|
|
704
|
-
colors?: Partial<ThemeColorMap> & Record<string, string | undefined>
|
|
705
|
-
}
|
|
617
|
+
export type Theme = AimuxTheme
|
|
706
618
|
|
|
707
619
|
// ─── Backend config (stub) ────────────────────────────────────────────────────
|
|
708
620
|
|
|
@@ -816,9 +728,13 @@ export interface GitPanePaneConfig extends GitPaneBaseConfig {
|
|
|
816
728
|
|
|
817
729
|
export type GitPaneConfig = GitPaneEmbeddedConfig | GitPanePaneConfig
|
|
818
730
|
|
|
731
|
+
export interface AimuxThemeConfig {
|
|
732
|
+
mode?: ThemeMode
|
|
733
|
+
paletteOverrides?: Partial<AimuxPalette>
|
|
734
|
+
}
|
|
735
|
+
|
|
819
736
|
export interface AimuxUserConfig {
|
|
820
|
-
theme?:
|
|
821
|
-
themes?: Record<string, NamedThemeDefinition | UserThemeInput>
|
|
737
|
+
theme?: AimuxThemeConfig
|
|
822
738
|
keymaps?: (k: KeymapBuilderApi) => KeymapBuilderApi
|
|
823
739
|
backends?: Record<string, BackendConfig>
|
|
824
740
|
sidebar?: SidebarConfig
|
|
@@ -851,8 +767,7 @@ export interface ResolvedKeymapConfig {
|
|
|
851
767
|
}
|
|
852
768
|
|
|
853
769
|
export interface ResolvedConfig {
|
|
854
|
-
theme:
|
|
855
|
-
themes: Record<string, NamedThemeDefinition | UserThemeInput>
|
|
770
|
+
theme: AimuxThemeConfig | undefined
|
|
856
771
|
keymaps: ResolvedKeymapConfig
|
|
857
772
|
backends: Record<string, BackendConfig>
|
|
858
773
|
sidebar: SidebarConfig
|
package/src/normalize-theme.ts
DELETED
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
// Normalize a partial theme input into a full aimux `Theme` where every
|
|
2
|
-
// AIMUX_COLOR_KEY is guaranteed to have a value. Used at build time by the
|
|
3
|
-
// generator script and at runtime by registerUserThemes — same code path, same
|
|
4
|
-
// guarantees.
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
AIMUX_COLOR_KEYS,
|
|
8
|
-
type AimuxColorKey,
|
|
9
|
-
type Theme,
|
|
10
|
-
type ThemeColorMap,
|
|
11
|
-
type ThemeTokenRule,
|
|
12
|
-
} from './types'
|
|
13
|
-
|
|
14
|
-
export interface NormalizeInput {
|
|
15
|
-
name: string
|
|
16
|
-
displayName?: string
|
|
17
|
-
type?: 'dark' | 'light'
|
|
18
|
-
fg?: string
|
|
19
|
-
bg?: string
|
|
20
|
-
colors?: Record<string, string | null | undefined>
|
|
21
|
-
settings?: ThemeTokenRule[]
|
|
22
|
-
tokenColors?: ThemeTokenRule[]
|
|
23
|
-
colorReplacements?: Record<string, string>
|
|
24
|
-
semanticHighlighting?: boolean
|
|
25
|
-
semanticTokenColors?: Theme['semanticTokenColors']
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function stripAlpha(hex: string | null | undefined): string {
|
|
29
|
-
if (!hex || typeof hex !== 'string') return '#000000'
|
|
30
|
-
if (hex.length === 9) return hex.slice(0, 7)
|
|
31
|
-
if (hex.length === 5) return hex.slice(0, 4)
|
|
32
|
-
return hex
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function expand3(hex: string): string {
|
|
36
|
-
if (hex.length === 4) {
|
|
37
|
-
return `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`
|
|
38
|
-
}
|
|
39
|
-
return hex
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function parseHex(hex: string): { r: number; g: number; b: number } {
|
|
43
|
-
const clean = expand3(stripAlpha(hex))
|
|
44
|
-
return {
|
|
45
|
-
b: parseInt(clean.slice(5, 7), 16),
|
|
46
|
-
g: parseInt(clean.slice(3, 5), 16),
|
|
47
|
-
r: parseInt(clean.slice(1, 3), 16),
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function toHex({ b, g, r }: { b: number; g: number; r: number }): string {
|
|
52
|
-
const clamp = (n: number): number => Math.max(0, Math.min(255, Math.round(n)))
|
|
53
|
-
const h = (n: number): string => clamp(n).toString(16).padStart(2, '0')
|
|
54
|
-
return `#${h(r)}${h(g)}${h(b)}`
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function shade(hex: string, amount: number): string {
|
|
58
|
-
const { b, g, r } = parseHex(hex)
|
|
59
|
-
const d = amount * 255
|
|
60
|
-
return toHex({ b: b + d, g: g + d, r: r + d })
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function mix(a: string, b: string, t: number): string {
|
|
64
|
-
const ca = parseHex(a)
|
|
65
|
-
const cb = parseHex(b)
|
|
66
|
-
return toHex({
|
|
67
|
-
b: ca.b + (cb.b - ca.b) * t,
|
|
68
|
-
g: ca.g + (cb.g - ca.g) * t,
|
|
69
|
-
r: ca.r + (cb.r - ca.r) * t,
|
|
70
|
-
})
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function first(map: Record<string, string | null | undefined>, keys: string[]): string | undefined {
|
|
74
|
-
for (const k of keys) {
|
|
75
|
-
const v = map[k]
|
|
76
|
-
if (v && typeof v === 'string') return stripAlpha(v)
|
|
77
|
-
}
|
|
78
|
-
return undefined
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const FALLBACKS: Record<AimuxColorKey, string[]> = {
|
|
82
|
-
'contrastBorder': ['editorGroup.border'],
|
|
83
|
-
'descriptionForeground': ['editorLineNumber.foreground', 'foreground'],
|
|
84
|
-
'diffEditor.insertedLineBackground': [],
|
|
85
|
-
'diffEditor.removedLineBackground': [],
|
|
86
|
-
'editor.background': [],
|
|
87
|
-
'editor.foreground': [],
|
|
88
|
-
'editor.lineHighlightBackground': [],
|
|
89
|
-
'editor.selectionBackground': ['selection.background'],
|
|
90
|
-
'editorCursor.foreground': ['editor.foreground'],
|
|
91
|
-
'editorError.foreground': ['errorForeground', 'terminal.ansiRed'],
|
|
92
|
-
'editorGroup.border': ['contrastBorder', 'panel.border'],
|
|
93
|
-
'editorGroupHeader.tabsBackground': ['sideBar.background'],
|
|
94
|
-
'editorLineNumber.foreground': ['descriptionForeground'],
|
|
95
|
-
'editorWarning.foreground': ['terminal.ansiYellow'],
|
|
96
|
-
'editorWidget.background': ['sideBar.background', 'editor.background'],
|
|
97
|
-
'errorForeground': ['editorError.foreground', 'terminal.ansiRed'],
|
|
98
|
-
'focusBorder': ['textLink.foreground'],
|
|
99
|
-
'foreground': ['editor.foreground'],
|
|
100
|
-
'gitDecoration.addedResourceForeground': ['terminal.ansiGreen'],
|
|
101
|
-
'gitDecoration.deletedResourceForeground': ['terminal.ansiRed', 'editorError.foreground'],
|
|
102
|
-
'gitDecoration.modifiedResourceForeground': ['terminal.ansiYellow'],
|
|
103
|
-
'gitDecoration.untrackedResourceForeground': ['gitDecoration.addedResourceForeground'],
|
|
104
|
-
'input.background': ['editorWidget.background'],
|
|
105
|
-
'input.border': ['focusBorder', 'editorGroup.border'],
|
|
106
|
-
'input.foreground': ['editor.foreground'],
|
|
107
|
-
'list.activeSelectionBackground': ['editor.selectionBackground'],
|
|
108
|
-
'list.activeSelectionForeground': ['editor.foreground'],
|
|
109
|
-
'list.hoverBackground': ['list.activeSelectionBackground'],
|
|
110
|
-
'panel.background': ['editor.background'],
|
|
111
|
-
'panel.border': ['editorGroup.border', 'contrastBorder'],
|
|
112
|
-
'sideBar.background': ['editorGroupHeader.tabsBackground', 'panel.background'],
|
|
113
|
-
'sideBar.foreground': ['editor.foreground', 'foreground'],
|
|
114
|
-
'sideBarSectionHeader.background': ['sideBar.background'],
|
|
115
|
-
'sideBarSectionHeader.foreground': ['sideBar.foreground'],
|
|
116
|
-
'terminal.ansiBlue': ['textLink.foreground'],
|
|
117
|
-
'terminal.ansiCyan': [],
|
|
118
|
-
'terminal.ansiGreen': ['gitDecoration.addedResourceForeground'],
|
|
119
|
-
'terminal.ansiMagenta': [],
|
|
120
|
-
'terminal.ansiRed': ['editorError.foreground'],
|
|
121
|
-
'terminal.ansiYellow': ['editorWarning.foreground'],
|
|
122
|
-
'textLink.activeForeground': ['textLink.foreground'],
|
|
123
|
-
'textLink.foreground': ['editorLink.activeForeground', 'terminal.ansiBlue'],
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function computeFallback(
|
|
127
|
-
key: AimuxColorKey,
|
|
128
|
-
bg: string,
|
|
129
|
-
fg: string,
|
|
130
|
-
resolved: ThemeColorMap
|
|
131
|
-
): string {
|
|
132
|
-
switch (key) {
|
|
133
|
-
case 'editor.background':
|
|
134
|
-
return bg
|
|
135
|
-
case 'editor.foreground':
|
|
136
|
-
return fg
|
|
137
|
-
case 'editor.lineHighlightBackground':
|
|
138
|
-
return shade(bg, 0.03)
|
|
139
|
-
case 'editor.selectionBackground':
|
|
140
|
-
return shade(bg, 0.1)
|
|
141
|
-
case 'editorCursor.foreground':
|
|
142
|
-
return fg
|
|
143
|
-
case 'editorLineNumber.foreground':
|
|
144
|
-
return mix(fg, bg, 0.55)
|
|
145
|
-
case 'sideBar.background':
|
|
146
|
-
return shade(bg, -0.04)
|
|
147
|
-
case 'sideBar.foreground':
|
|
148
|
-
return fg
|
|
149
|
-
case 'sideBarSectionHeader.background':
|
|
150
|
-
return shade(bg, -0.02)
|
|
151
|
-
case 'sideBarSectionHeader.foreground':
|
|
152
|
-
return mix(fg, bg, 0.35)
|
|
153
|
-
case 'editorGroupHeader.tabsBackground':
|
|
154
|
-
return shade(bg, -0.04)
|
|
155
|
-
case 'editorWidget.background':
|
|
156
|
-
return shade(bg, -0.08)
|
|
157
|
-
case 'panel.background':
|
|
158
|
-
return bg
|
|
159
|
-
case 'panel.border':
|
|
160
|
-
return shade(bg, 0.15)
|
|
161
|
-
case 'focusBorder':
|
|
162
|
-
return resolved['textLink.foreground'] ?? fg
|
|
163
|
-
case 'editorGroup.border':
|
|
164
|
-
return shade(bg, 0.15)
|
|
165
|
-
case 'contrastBorder':
|
|
166
|
-
return shade(bg, 0.2)
|
|
167
|
-
case 'list.activeSelectionBackground':
|
|
168
|
-
return shade(bg, 0.1)
|
|
169
|
-
case 'list.activeSelectionForeground':
|
|
170
|
-
return fg
|
|
171
|
-
case 'list.hoverBackground':
|
|
172
|
-
return shade(bg, 0.05)
|
|
173
|
-
case 'foreground':
|
|
174
|
-
return fg
|
|
175
|
-
case 'descriptionForeground':
|
|
176
|
-
return mix(fg, bg, 0.55)
|
|
177
|
-
case 'textLink.foreground':
|
|
178
|
-
case 'textLink.activeForeground':
|
|
179
|
-
return resolved['terminal.ansiBlue'] ?? fg
|
|
180
|
-
case 'errorForeground':
|
|
181
|
-
case 'editorError.foreground':
|
|
182
|
-
return '#f38ba8'
|
|
183
|
-
case 'editorWarning.foreground':
|
|
184
|
-
return '#f6c177'
|
|
185
|
-
case 'terminal.ansiRed':
|
|
186
|
-
return '#f38ba8'
|
|
187
|
-
case 'terminal.ansiGreen':
|
|
188
|
-
return '#8bd5ca'
|
|
189
|
-
case 'terminal.ansiYellow':
|
|
190
|
-
return '#f6c177'
|
|
191
|
-
case 'terminal.ansiBlue':
|
|
192
|
-
return '#7cd1b8'
|
|
193
|
-
case 'terminal.ansiMagenta':
|
|
194
|
-
return resolved['textLink.activeForeground'] ?? '#c4a7e7'
|
|
195
|
-
case 'terminal.ansiCyan':
|
|
196
|
-
return resolved['terminal.ansiBlue'] ?? '#89dceb'
|
|
197
|
-
case 'gitDecoration.addedResourceForeground':
|
|
198
|
-
return resolved['terminal.ansiGreen'] ?? '#8bd5ca'
|
|
199
|
-
case 'gitDecoration.modifiedResourceForeground':
|
|
200
|
-
return resolved['terminal.ansiYellow'] ?? '#f6c177'
|
|
201
|
-
case 'gitDecoration.deletedResourceForeground':
|
|
202
|
-
return resolved['terminal.ansiRed'] ?? '#f38ba8'
|
|
203
|
-
case 'gitDecoration.untrackedResourceForeground':
|
|
204
|
-
return resolved['gitDecoration.addedResourceForeground'] ?? '#8bd5ca'
|
|
205
|
-
case 'diffEditor.insertedLineBackground':
|
|
206
|
-
return mix(bg, resolved['gitDecoration.addedResourceForeground'] ?? '#8bd5ca', 0.18)
|
|
207
|
-
case 'diffEditor.removedLineBackground':
|
|
208
|
-
return mix(bg, resolved['gitDecoration.deletedResourceForeground'] ?? '#f38ba8', 0.18)
|
|
209
|
-
case 'input.background':
|
|
210
|
-
return shade(bg, -0.04)
|
|
211
|
-
case 'input.foreground':
|
|
212
|
-
return fg
|
|
213
|
-
case 'input.border':
|
|
214
|
-
return shade(bg, 0.15)
|
|
215
|
-
default:
|
|
216
|
-
return fg
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
export function normalizeTheme(raw: NormalizeInput): Theme {
|
|
221
|
-
const srcColors = raw.colors ?? {}
|
|
222
|
-
const bg = stripAlpha(srcColors['editor.background'] ?? raw.bg ?? '#000000')
|
|
223
|
-
const fg = stripAlpha(srcColors['editor.foreground'] ?? raw.fg ?? '#ffffff')
|
|
224
|
-
|
|
225
|
-
const resolved: ThemeColorMap = {} as ThemeColorMap
|
|
226
|
-
for (const key of AIMUX_COLOR_KEYS) {
|
|
227
|
-
const direct = srcColors[key]
|
|
228
|
-
if (direct && typeof direct === 'string') {
|
|
229
|
-
resolved[key] = stripAlpha(direct)
|
|
230
|
-
continue
|
|
231
|
-
}
|
|
232
|
-
const alt = first(srcColors, FALLBACKS[key])
|
|
233
|
-
if (alt) resolved[key] = alt
|
|
234
|
-
}
|
|
235
|
-
for (const key of AIMUX_COLOR_KEYS) {
|
|
236
|
-
if (!resolved[key]) resolved[key] = computeFallback(key, bg, fg, resolved)
|
|
237
|
-
}
|
|
238
|
-
for (const [k, v] of Object.entries(srcColors)) {
|
|
239
|
-
if (!resolved[k] && v && typeof v === 'string') resolved[k] = stripAlpha(v)
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const out: Theme = {
|
|
243
|
-
bg,
|
|
244
|
-
colors: resolved,
|
|
245
|
-
displayName: raw.displayName ?? raw.name,
|
|
246
|
-
fg,
|
|
247
|
-
name: raw.name,
|
|
248
|
-
settings: raw.settings ?? [],
|
|
249
|
-
type: raw.type ?? 'dark',
|
|
250
|
-
}
|
|
251
|
-
if (raw.colorReplacements && Object.keys(raw.colorReplacements).length > 0) {
|
|
252
|
-
out.colorReplacements = raw.colorReplacements
|
|
253
|
-
}
|
|
254
|
-
if (raw.semanticHighlighting) out.semanticHighlighting = raw.semanticHighlighting
|
|
255
|
-
if (raw.semanticTokenColors && Object.keys(raw.semanticTokenColors).length > 0) {
|
|
256
|
-
out.semanticTokenColors = raw.semanticTokenColors
|
|
257
|
-
}
|
|
258
|
-
if (raw.tokenColors && raw.tokenColors !== raw.settings) out.tokenColors = raw.tokenColors
|
|
259
|
-
return out
|
|
260
|
-
}
|