@brimveyn/aimux 1.5.0 → 1.6.0

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.
Files changed (67) hide show
  1. package/README.md +14 -2
  2. package/package.json +5 -3
  3. package/src/app-runtime/side-effects.ts +41 -6
  4. package/src/app-runtime/use-renderer-bindings.ts +1 -1
  5. package/src/app.tsx +17 -5
  6. package/src/config.ts +29 -4
  7. package/src/diff-parser/clean-last-newline.ts +5 -0
  8. package/src/diff-parser/constants.ts +13 -0
  9. package/src/diff-parser/index.ts +12 -0
  10. package/src/diff-parser/parse-line-type.ts +29 -0
  11. package/src/diff-parser/parse-patch-files.ts +369 -0
  12. package/src/diff-parser/types.ts +75 -0
  13. package/src/index.tsx +2 -2
  14. package/src/input/modes/bridge.ts +8 -0
  15. package/src/input/modes/transitions.ts +2 -1
  16. package/src/input/modes/types.ts +4 -1
  17. package/src/pty/terminal-snapshot.ts +4 -4
  18. package/src/state/git-tree.ts +220 -0
  19. package/src/state/reducers/git-mode-state.ts +232 -35
  20. package/src/state/reducers/git-panel-state.ts +29 -3
  21. package/src/state/reducers/modal-state.ts +43 -10
  22. package/src/state/store.ts +5 -1
  23. package/src/state/types.ts +41 -5
  24. package/src/state/workspace-save.ts +2 -0
  25. package/src/ui/components/create-session-modal.tsx +23 -7
  26. package/src/ui/components/diff-renderer/build-rows.ts +349 -0
  27. package/src/ui/components/diff-renderer/filetype.ts +29 -0
  28. package/src/ui/components/diff-renderer/fold-strip.tsx +84 -0
  29. package/src/ui/components/diff-renderer/highlight.ts +48 -0
  30. package/src/ui/components/diff-renderer/index.ts +1 -0
  31. package/src/ui/components/diff-renderer/pierre-diff.tsx +170 -0
  32. package/src/ui/components/diff-renderer/split-view.tsx +207 -0
  33. package/src/ui/components/diff-renderer/stacked-view.tsx +166 -0
  34. package/src/ui/components/git-commit-modal.tsx +14 -2
  35. package/src/ui/components/git-pane-widget.tsx +5 -0
  36. package/src/ui/components/git-panel.tsx +176 -79
  37. package/src/ui/components/git-view.tsx +89 -87
  38. package/src/ui/components/help-modal.tsx +43 -11
  39. package/src/ui/components/input-field.tsx +2 -2
  40. package/src/ui/components/list-item.tsx +9 -1
  41. package/src/ui/components/modal-filter-bar.tsx +1 -1
  42. package/src/ui/components/modal-keybinds-overlay.tsx +2 -2
  43. package/src/ui/components/modal-shell.tsx +3 -3
  44. package/src/ui/components/new-tab-modal.tsx +15 -3
  45. package/src/ui/components/pending-chord-overlay.tsx +3 -3
  46. package/src/ui/components/session-bar.tsx +10 -5
  47. package/src/ui/components/session-picker-modal.tsx +26 -9
  48. package/src/ui/components/sidebar.tsx +22 -10
  49. package/src/ui/components/snippet-editor-modal.tsx +16 -2
  50. package/src/ui/components/snippet-picker-modal.tsx +11 -3
  51. package/src/ui/components/split-layout.tsx +1 -1
  52. package/src/ui/components/status-bar.tsx +12 -9
  53. package/src/ui/components/surface.tsx +5 -5
  54. package/src/ui/components/tab-item.tsx +22 -16
  55. package/src/ui/components/terminal-pane.tsx +25 -15
  56. package/src/ui/components/theme-picker-modal.tsx +111 -16
  57. package/src/ui/components/update-available-modal.tsx +11 -1
  58. package/src/ui/filter-themes.ts +10 -0
  59. package/src/ui/house-themes.ts +313 -0
  60. package/src/ui/keymap-context.ts +10 -2
  61. package/src/ui/root.tsx +26 -6
  62. package/src/ui/shiki.ts +49 -0
  63. package/src/ui/status-bar-model.ts +19 -1
  64. package/src/ui/theme.ts +22 -10
  65. package/src/ui/themes.generated.ts +59794 -0
  66. package/src/ui/themes.ts +68 -274
  67. package/src/ui/syntax.ts +0 -102
package/src/ui/themes.ts CHANGED
@@ -1,279 +1,73 @@
1
- export interface ThemeColors {
2
- background: string
3
- panel: string
4
- panelMuted: string
5
- panelHighlight: string
6
- overlay: string
7
- border: string
8
- borderActive: string
9
- text: string
10
- textMuted: string
11
- accent: string
12
- accentAlt: string
13
- warning: string
14
- danger: string
15
- success: string
16
- dim: string
17
- diffAddBg: string
18
- diffRemoveBg: string
1
+ import type { BundledTheme } from 'shiki'
2
+
3
+ import {
4
+ AIMUX_COLOR_KEYS,
5
+ type AimuxColorKey,
6
+ type NamedTheme,
7
+ type NamedThemeDefinition,
8
+ type Theme,
9
+ type ThemeColorMap,
10
+ type ThemeSettings,
11
+ type ThemeTokenRule,
12
+ } from '@brimveyn/aimux-config'
13
+
14
+ import { HOUSE_THEME_IDS, HOUSE_THEMES } from './house-themes'
15
+ import { GENERATED_THEME_IDS, GENERATED_THEMES } from './themes.generated'
16
+
17
+ export type {
18
+ AimuxColorKey,
19
+ NamedTheme,
20
+ NamedThemeDefinition,
21
+ Theme,
22
+ ThemeColorMap,
23
+ ThemeSettings,
24
+ ThemeTokenRule,
25
+ }
26
+ export { AIMUX_COLOR_KEYS }
27
+
28
+ export type ThemeId = BundledTheme | (string & {})
29
+
30
+ export const THEMES: Record<string, Theme> = { ...GENERATED_THEMES, ...HOUSE_THEMES }
31
+ export const THEME_IDS: ThemeId[] = [...GENERATED_THEME_IDS, ...HOUSE_THEME_IDS]
32
+
33
+ const DEFAULT_THEME_ID: ThemeId = 'aimux'
34
+
35
+ /**
36
+ * Merge user-declared themes into the registry. Themes declared via
37
+ * `themes.full(...)` arrive as complete `NamedTheme` objects; themes declared
38
+ * via `themes.define(...)` arrive as `NamedThemeDefinition` (partial overrides
39
+ * over a base) and are expanded here.
40
+ */
41
+ export function registerUserThemes(
42
+ defs: Record<string, NamedTheme | NamedThemeDefinition> | undefined
43
+ ): void {
44
+ if (!defs) return
45
+ const fallback = THEMES[DEFAULT_THEME_ID]
46
+ if (!fallback) return
47
+ for (const [id, def] of Object.entries(defs)) {
48
+ THEMES[id] = isFullTheme(def) ? def : expandDefinition(id, def, fallback)
49
+ if (!THEME_IDS.includes(id)) THEME_IDS.push(id)
50
+ }
19
51
  }
20
52
 
21
- export type ThemeId =
22
- | 'aimux'
23
- | 'dracula'
24
- | 'dracula-at-night'
25
- | 'everforest'
26
- | 'tokyo-night'
27
- | 'gruvbox-dark'
28
- | 'catppuccin-mocha'
29
- | 'nord'
30
- | 'solarized-dark'
31
- | 'one-dark'
32
- | 'kanagawa'
53
+ function isFullTheme(def: NamedTheme | NamedThemeDefinition): def is NamedTheme {
54
+ return 'settings' in def && Array.isArray((def as Theme).settings)
55
+ }
33
56
 
34
- export const THEMES: Record<ThemeId, { name: string; colors: ThemeColors }> = {
35
- 'aimux': {
36
- colors: {
37
- accent: '#7cd1b8',
38
- accentAlt: '#c4a7e7',
39
- background: '#11151b',
40
- border: '#2d3f52',
41
- borderActive: '#7cd1b8',
42
- danger: '#f38ba8',
43
- diffAddBg: '#1e3d2b',
44
- diffRemoveBg: '#3b1e27',
45
- dim: '#243242',
46
- overlay: '#0b1016',
47
- panel: '#16202b',
48
- panelHighlight: '#1f3344',
49
- panelMuted: '#1c2734',
50
- success: '#8bd5ca',
51
- text: '#edf4ff',
52
- textMuted: '#6b829a',
53
- warning: '#f6c177',
54
- },
55
- name: 'Aimux',
56
- },
57
- 'catppuccin-mocha': {
58
- colors: {
59
- accent: '#cba6f7',
60
- accentAlt: '#f5c2e7',
61
- background: '#1e1e2e',
62
- border: '#45475a',
63
- borderActive: '#cba6f7',
64
- danger: '#f38ba8',
65
- diffAddBg: '#273c32',
66
- diffRemoveBg: '#3b2838',
67
- dim: '#313244',
68
- overlay: '#181825',
69
- panel: '#232334',
70
- panelHighlight: '#313244',
71
- panelMuted: '#2a2a3c',
72
- success: '#a6e3a1',
73
- text: '#cdd6f4',
74
- textMuted: '#6c7086',
75
- warning: '#f9e2af',
76
- },
77
- name: 'Catppuccin Mocha',
78
- },
79
- 'dracula': {
80
- colors: {
81
- accent: '#bd93f9',
82
- accentAlt: '#ff79c6',
83
- background: '#282a36',
84
- border: '#44475a',
85
- borderActive: '#bd93f9',
86
- danger: '#ff5555',
87
- diffAddBg: '#2f4630',
88
- diffRemoveBg: '#4a2f3b',
89
- dim: '#383a4a',
90
- overlay: '#1f2029',
91
- panel: '#2d2f3d',
92
- panelHighlight: '#3d4056',
93
- panelMuted: '#343746',
94
- success: '#50fa7b',
95
- text: '#f8f8f2',
96
- textMuted: '#6272a4',
97
- warning: '#f1fa8c',
98
- },
99
- name: 'Dracula',
100
- },
101
- 'dracula-at-night': {
102
- colors: {
103
- accent: '#bd93f9',
104
- accentAlt: '#ff79c6',
105
- background: '#0e1419',
106
- border: '#2a3440',
107
- borderActive: '#bd93f9',
108
- danger: '#ff5555',
109
- diffAddBg: '#162b1d',
110
- diffRemoveBg: '#2a1820',
111
- dim: '#1e2630',
112
- overlay: '#090d11',
113
- panel: '#131920',
114
- panelHighlight: '#222a33',
115
- panelMuted: '#1a2129',
116
- success: '#50fa7b',
117
- text: '#f8f8f2',
118
- textMuted: '#6272a4',
119
- warning: '#f1fa8c',
120
- },
121
- name: 'Dracula At Night',
122
- },
123
- 'everforest': {
124
- colors: {
125
- accent: '#a7c080',
126
- accentAlt: '#d699b6',
127
- background: '#2d353b',
128
- border: '#4f585e',
129
- borderActive: '#a7c080',
130
- danger: '#e67e80',
131
- diffAddBg: '#35473a',
132
- diffRemoveBg: '#45353a',
133
- dim: '#3d484d',
134
- overlay: '#232a2e',
135
- panel: '#343f44',
136
- panelHighlight: '#475258',
137
- panelMuted: '#3d484d',
138
- success: '#a7c080',
139
- text: '#d3c6aa',
140
- textMuted: '#859289',
141
- warning: '#dbbc7f',
142
- },
143
- name: 'Everforest',
144
- },
145
- 'gruvbox-dark': {
146
- colors: {
147
- accent: '#b8bb26',
148
- accentAlt: '#d3869b',
149
- background: '#282828',
150
- border: '#504945',
151
- borderActive: '#b8bb26',
152
- danger: '#fb4934',
153
- diffAddBg: '#2f3a28',
154
- diffRemoveBg: '#3a2828',
155
- dim: '#3c3836',
156
- overlay: '#1f1d1b',
157
- panel: '#2e2e2e',
158
- panelHighlight: '#504945',
159
- panelMuted: '#3c3836',
160
- success: '#b8bb26',
161
- text: '#ebdbb2',
162
- textMuted: '#928374',
163
- warning: '#fabd2f',
164
- },
165
- name: 'Gruvbox Dark',
166
- },
167
- 'kanagawa': {
168
- colors: {
169
- accent: '#7e9cd8',
170
- accentAlt: '#957fb8',
171
- background: '#1f1f28',
172
- border: '#363646',
173
- borderActive: '#7e9cd8',
174
- danger: '#e82424',
175
- diffAddBg: '#28332a',
176
- diffRemoveBg: '#35252b',
177
- dim: '#2a2a37',
178
- overlay: '#171720',
179
- panel: '#24242e',
180
- panelHighlight: '#363646',
181
- panelMuted: '#2a2a37',
182
- success: '#76946a',
183
- text: '#dcd7ba',
184
- textMuted: '#727169',
185
- warning: '#e6c384',
186
- },
187
- name: 'Kanagawa',
188
- },
189
- 'nord': {
190
- colors: {
191
- accent: '#88c0d0',
192
- accentAlt: '#b48ead',
193
- background: '#2e3440',
194
- border: '#434c5e',
195
- borderActive: '#88c0d0',
196
- danger: '#bf616a',
197
- diffAddBg: '#2f3d38',
198
- diffRemoveBg: '#3d3035',
199
- dim: '#3b4252',
200
- overlay: '#252a33',
201
- panel: '#333a47',
202
- panelHighlight: '#434c5e',
203
- panelMuted: '#3b4252',
204
- success: '#a3be8c',
205
- text: '#eceff4',
206
- textMuted: '#7b88a1',
207
- warning: '#ebcb8b',
208
- },
209
- name: 'Nord',
210
- },
211
- 'one-dark': {
212
- colors: {
213
- accent: '#61afef',
214
- accentAlt: '#c678dd',
215
- background: '#282c34',
216
- border: '#3e4452',
217
- borderActive: '#61afef',
218
- danger: '#e06c75',
219
- diffAddBg: '#2c3b2f',
220
- diffRemoveBg: '#3d2c33',
221
- dim: '#3b4048',
222
- overlay: '#1f2329',
223
- panel: '#2c313a',
224
- panelHighlight: '#3b4048',
225
- panelMuted: '#333842',
226
- success: '#98c379',
227
- text: '#abb2bf',
228
- textMuted: '#636d83',
229
- warning: '#e5c07b',
230
- },
231
- name: 'One Dark',
232
- },
233
- 'solarized-dark': {
234
- colors: {
235
- accent: '#268bd2',
236
- accentAlt: '#d33682',
237
- background: '#002b36',
238
- border: '#2e5560',
239
- borderActive: '#268bd2',
240
- danger: '#dc322f',
241
- diffAddBg: '#1a3a30',
242
- diffRemoveBg: '#3a1f28',
243
- dim: '#073642',
244
- overlay: '#00242c',
245
- panel: '#003340',
246
- panelHighlight: '#0a4050',
247
- panelMuted: '#073642',
248
- success: '#859900',
249
- text: '#fdf6e3',
250
- textMuted: '#657b83',
251
- warning: '#b58900',
252
- },
253
- name: 'Solarized Dark',
254
- },
255
- 'tokyo-night': {
256
- colors: {
257
- accent: '#7aa2f7',
258
- accentAlt: '#bb9af7',
259
- background: '#1a1b26',
260
- border: '#3b4261',
261
- borderActive: '#7aa2f7',
262
- danger: '#f7768e',
263
- diffAddBg: '#22362d',
264
- diffRemoveBg: '#362330',
265
- dim: '#292e42',
266
- overlay: '#141722',
267
- panel: '#1f2335',
268
- panelHighlight: '#292e42',
269
- panelMuted: '#24283b',
270
- success: '#9ece6a',
271
- text: '#c0caf5',
272
- textMuted: '#565f89',
273
- warning: '#e0af68',
274
- },
275
- name: 'Tokyo Night',
276
- },
57
+ function expandDefinition(id: string, def: NamedThemeDefinition, fallback: Theme): Theme {
58
+ const base = def.base ? (THEMES[def.base] ?? fallback) : fallback
59
+ const colors: ThemeColorMap = { ...base.colors }
60
+ for (const [k, v] of Object.entries(def.colors ?? {})) {
61
+ if (typeof v === 'string') colors[k] = v
62
+ }
63
+ return {
64
+ ...base,
65
+ colors,
66
+ displayName: def.name,
67
+ name: id,
68
+ }
277
69
  }
278
70
 
279
- export const THEME_IDS = Object.keys(THEMES) as ThemeId[]
71
+ export function isKnownThemeId(id: string): boolean {
72
+ return id in THEMES
73
+ }
package/src/ui/syntax.ts DELETED
@@ -1,102 +0,0 @@
1
- import { getTreeSitterClient, SyntaxStyle, type ThemeTokenStyle } from '@opentui/core'
2
-
3
- import { onThemeChange, theme } from './theme'
4
-
5
- let cachedStyle: SyntaxStyle | null = null
6
- let clientInitPromise: Promise<void> | null = null
7
-
8
- onThemeChange(() => {
9
- cachedStyle = null
10
- })
11
-
12
- function buildTokens(): ThemeTokenStyle[] {
13
- return [
14
- {
15
- scope: ['comment', 'spell'],
16
- style: { dim: true, foreground: theme.textMuted, italic: true },
17
- },
18
- { scope: ['comment.documentation'], style: { foreground: theme.textMuted, italic: true } },
19
-
20
- {
21
- scope: ['string', 'character', 'character.special', 'string.special'],
22
- style: { foreground: theme.warning },
23
- },
24
- {
25
- scope: ['string.escape', 'string.regexp', 'string.special.url'],
26
- style: { foreground: theme.accentAlt },
27
- },
28
-
29
- {
30
- scope: ['number', 'boolean', 'constant.builtin', 'constant.numeric'],
31
- style: { foreground: theme.danger },
32
- },
33
- { scope: ['constant', 'constant.character'], style: { foreground: theme.danger } },
34
-
35
- { scope: ['keyword'], style: { bold: true, foreground: theme.accentAlt } },
36
- {
37
- scope: [
38
- 'keyword.conditional',
39
- 'keyword.exception',
40
- 'keyword.import',
41
- 'keyword.modifier',
42
- 'keyword.repeat',
43
- ],
44
- style: { bold: true, foreground: theme.accentAlt },
45
- },
46
- {
47
- scope: [
48
- 'keyword.coroutine',
49
- 'keyword.directive',
50
- 'keyword.function',
51
- 'keyword.return',
52
- 'keyword.type',
53
- ],
54
- style: { bold: true, foreground: theme.accentAlt, italic: true },
55
- },
56
- { scope: ['keyword.operator', 'operator'], style: { foreground: theme.accent } },
57
-
58
- {
59
- scope: ['function', 'function.call', 'function.method', 'function.method.call'],
60
- style: { foreground: theme.success },
61
- },
62
- { scope: ['function.builtin'], style: { foreground: theme.success, italic: true } },
63
- { scope: ['constructor'], style: { bold: true, foreground: theme.success } },
64
-
65
- { scope: ['type', 'type.definition'], style: { foreground: theme.accent, italic: true } },
66
- { scope: ['type.builtin'], style: { bold: true, foreground: theme.accent } },
67
-
68
- { scope: ['variable'], style: { foreground: theme.text } },
69
- { scope: ['variable.builtin'], style: { foreground: theme.danger, italic: true } },
70
- { scope: ['variable.parameter', 'parameter'], style: { foreground: theme.text, italic: true } },
71
- { scope: ['variable.member', 'property', 'field'], style: { foreground: theme.accent } },
72
-
73
- { scope: ['attribute'], style: { foreground: theme.warning, italic: true } },
74
- { scope: ['tag'], style: { foreground: theme.danger } },
75
- { scope: ['tag.attribute'], style: { foreground: theme.warning, italic: true } },
76
-
77
- { scope: ['label'], style: { foreground: theme.warning } },
78
- { scope: ['module', 'namespace'], style: { foreground: theme.accentAlt, italic: true } },
79
- { scope: ['module.builtin'], style: { bold: true, foreground: theme.accentAlt, italic: true } },
80
-
81
- {
82
- scope: ['punctuation.bracket', 'punctuation.delimiter'],
83
- style: { foreground: theme.textMuted },
84
- },
85
- { scope: ['punctuation.special'], style: { foreground: theme.warning } },
86
- ]
87
- }
88
-
89
- export function getSyntaxStyle(): SyntaxStyle {
90
- if (!cachedStyle) {
91
- cachedStyle = SyntaxStyle.fromTheme(buildTokens())
92
- }
93
- return cachedStyle
94
- }
95
-
96
- export function getSyntaxClient() {
97
- const client = getTreeSitterClient()
98
- if (!clientInitPromise) {
99
- clientInitPromise = client.initialize().catch(() => {})
100
- }
101
- return client
102
- }