@brimveyn/aimux-config 0.2.5 → 0.3.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.
- package/README.md +7 -1
- package/package.json +1 -1
- package/src/actions.ts +15 -0
- package/src/defaults.ts +158 -130
- package/src/keymap-builder.ts +37 -6
- package/src/resolver.ts +1 -0
- package/src/types.ts +39 -3
package/README.md
CHANGED
|
@@ -77,7 +77,13 @@ defineConfig({
|
|
|
77
77
|
```ts
|
|
78
78
|
k.leader(keys) // default: '<Space>'
|
|
79
79
|
.timeout(ms) // default: 300
|
|
80
|
-
.mode(id, configure) // define bindings for a mode
|
|
80
|
+
.mode(id | ids[], configure) // define bindings for a mode (or several at once)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Pass an array of `ModeId`s to register the same bindings in every listed mode — handy for actions that should fire in both `navigation` and `terminal-input`, for example:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
k.mode(['navigation', 'terminal-input'], (m) => m.map('<C-s>', actions.snippetPicker))
|
|
81
87
|
```
|
|
82
88
|
|
|
83
89
|
### Mode builder
|
package/package.json
CHANGED
package/src/actions.ts
CHANGED
|
@@ -36,8 +36,13 @@ export const helpModal: KeyResult = r([{ type: 'open-help-modal' }], [], 'modal.
|
|
|
36
36
|
|
|
37
37
|
export const toggleSidebar: KeyResult = r([{ type: 'toggle-sidebar' }])
|
|
38
38
|
export const toggleGitPanel: KeyResult = r([{ type: 'toggle-git-panel' }])
|
|
39
|
+
export const toggleSessionBar: KeyResult = r([{ type: 'toggle-session-bar' }])
|
|
39
40
|
export const enterGitMode: KeyResult = r([{ type: 'enter-git-mode' }], [], 'git-mode')
|
|
40
41
|
|
|
42
|
+
export function switchSessionByIndex(index: number): KeyResult {
|
|
43
|
+
return r([], [{ index, type: 'switch-session-by-index' }])
|
|
44
|
+
}
|
|
45
|
+
|
|
41
46
|
export const splitVertical: KeyResult = r(
|
|
42
47
|
[{ direction: 'vertical', type: 'open-split-picker' }],
|
|
43
48
|
[],
|
|
@@ -237,6 +242,16 @@ export const saveSnippetEditor: KeyResult = r(
|
|
|
237
242
|
'navigation'
|
|
238
243
|
)
|
|
239
244
|
|
|
245
|
+
// ---------------------------------------------------------------------------
|
|
246
|
+
// Update-available modal
|
|
247
|
+
// ---------------------------------------------------------------------------
|
|
248
|
+
|
|
249
|
+
export const confirmUpdateSelection: KeyResult = r(
|
|
250
|
+
[{ type: 'close-modal' }],
|
|
251
|
+
[{ type: 'confirm-update-selection' }],
|
|
252
|
+
'navigation'
|
|
253
|
+
)
|
|
254
|
+
|
|
240
255
|
// Layout-specific
|
|
241
256
|
export const exitLayoutToInput: KeyResult = r(
|
|
242
257
|
[{ focusMode: 'terminal-input', type: 'set-focus-mode' }],
|
package/src/defaults.ts
CHANGED
|
@@ -12,262 +12,290 @@ export function getDefaultKeymapConfig(): ResolvedKeymapConfig {
|
|
|
12
12
|
.timeout(300)
|
|
13
13
|
|
|
14
14
|
// -----------------------------------------------------------------------
|
|
15
|
-
// Navigation mode
|
|
15
|
+
// Navigation mode
|
|
16
16
|
// -----------------------------------------------------------------------
|
|
17
17
|
.mode('navigation', (m) =>
|
|
18
18
|
m
|
|
19
|
-
.map('<C-c>', actions.quit)
|
|
20
|
-
.map('<C-n>', actions.newTab)
|
|
21
|
-
.map('<C-g>', actions.sessionPicker)
|
|
22
|
-
.map('<C-z>', actions.ctrlZSidebar)
|
|
23
|
-
.map('dd', actions.closeTab)
|
|
24
|
-
.map('<C-b>', actions.toggleSidebar)
|
|
25
|
-
.map('<C-r>', actions.restartTab)
|
|
26
|
-
.map('<C-s>', actions.snippetPicker)
|
|
27
|
-
.map('<C-t>', actions.themePicker)
|
|
28
|
-
.map('<C-h>', actions.resizeSidebar(-2))
|
|
29
|
-
.map('<C-l>', actions.resizeSidebar(2))
|
|
30
|
-
.map('G', actions.toggleGitPanel)
|
|
31
|
-
.map('<C-d>', actions.enterGitMode)
|
|
32
|
-
.map('<C-j>', actions.resizeGitPanel(-0.05))
|
|
33
|
-
.map('<C-k>', actions.resizeGitPanel(0.05))
|
|
34
|
-
.map('J', actions.reorderTab(1))
|
|
35
|
-
.map('j', actions.nextTab)
|
|
36
|
-
.map('K', actions.reorderTab(-1))
|
|
37
|
-
.map('k', actions.prevTab)
|
|
38
|
-
.map('r', actions.renameTab)
|
|
39
|
-
.map('i', actions.enterInsert)
|
|
40
|
-
.map('?', actions.helpModal)
|
|
19
|
+
.map('<C-c>', actions.quit, 'Quit')
|
|
20
|
+
.map('<C-n>', actions.newTab, 'New tab')
|
|
21
|
+
.map('<C-g>', actions.sessionPicker, 'Session picker')
|
|
22
|
+
.map('<C-z>', actions.ctrlZSidebar, 'Focus sidebar')
|
|
23
|
+
.map('dd', actions.closeTab, 'Close tab')
|
|
24
|
+
.map('<C-b>', actions.toggleSidebar, 'Toggle sidebar')
|
|
25
|
+
.map('<C-r>', actions.restartTab, 'Restart tab')
|
|
26
|
+
.map('<C-s>', actions.snippetPicker, 'Snippet picker')
|
|
27
|
+
.map('<C-t>', actions.themePicker, 'Theme picker')
|
|
28
|
+
.map('<C-h>', actions.resizeSidebar(-2), 'Sidebar narrower')
|
|
29
|
+
.map('<C-l>', actions.resizeSidebar(2), 'Sidebar wider')
|
|
30
|
+
.map('G', actions.toggleGitPanel, 'Toggle git panel')
|
|
31
|
+
.map('<C-d>', actions.enterGitMode, 'Enter git mode')
|
|
32
|
+
.map('<C-j>', actions.resizeGitPanel(-0.05), 'Git panel smaller')
|
|
33
|
+
.map('<C-k>', actions.resizeGitPanel(0.05), 'Git panel larger')
|
|
34
|
+
.map('J', actions.reorderTab(1), 'Move tab right')
|
|
35
|
+
.map('j', actions.nextTab, 'Next tab')
|
|
36
|
+
.map('K', actions.reorderTab(-1), 'Move tab left')
|
|
37
|
+
.map('k', actions.prevTab, 'Prev tab')
|
|
38
|
+
.map('r', actions.renameTab, 'Rename tab')
|
|
39
|
+
.map('i', actions.enterInsert, 'Focus terminal')
|
|
40
|
+
.map('?', actions.helpModal, 'Help')
|
|
41
41
|
)
|
|
42
42
|
|
|
43
43
|
// -----------------------------------------------------------------------
|
|
44
44
|
// Terminal-input mode
|
|
45
|
-
// Bindings here are processed by raw-input-handler.ts before bytes reach
|
|
46
|
-
// the PTY. Only single-chord <C-*> sequences are supported (no multi-key).
|
|
47
45
|
// -----------------------------------------------------------------------
|
|
48
46
|
.mode('terminal-input', (m) =>
|
|
49
47
|
m
|
|
50
|
-
.map('<C-z>', actions.leaveTerminalInput)
|
|
51
|
-
.map('<Leader>', actions.enterLayoutMode)
|
|
52
|
-
.map('<C-b>', actions.toggleSidebarFromInput)
|
|
48
|
+
.map('<C-z>', actions.leaveTerminalInput, 'Leave insert')
|
|
49
|
+
.map('<Leader>', actions.enterLayoutMode, 'Layout mode')
|
|
50
|
+
.map('<C-b>', actions.toggleSidebarFromInput, 'Toggle sidebar')
|
|
53
51
|
)
|
|
54
52
|
|
|
55
53
|
// -----------------------------------------------------------------------
|
|
56
|
-
//
|
|
54
|
+
// Session bar: same chords from nav and while typing in the terminal
|
|
55
|
+
// -----------------------------------------------------------------------
|
|
56
|
+
.mode(['navigation', 'terminal-input'], (m) =>
|
|
57
|
+
m
|
|
58
|
+
.map('<Leader>b', actions.toggleSessionBar, 'Toggle session bar')
|
|
59
|
+
.map('<Leader>1', actions.switchSessionByIndex(1), 'Session 1')
|
|
60
|
+
.map('<Leader>2', actions.switchSessionByIndex(2), 'Session 2')
|
|
61
|
+
.map('<Leader>3', actions.switchSessionByIndex(3), 'Session 3')
|
|
62
|
+
.map('<Leader>4', actions.switchSessionByIndex(4), 'Session 4')
|
|
63
|
+
.map('<Leader>5', actions.switchSessionByIndex(5), 'Session 5')
|
|
64
|
+
.map('<Leader>6', actions.switchSessionByIndex(6), 'Session 6')
|
|
65
|
+
.map('<Leader>7', actions.switchSessionByIndex(7), 'Session 7')
|
|
66
|
+
.map('<Leader>8', actions.switchSessionByIndex(8), 'Session 8')
|
|
67
|
+
.map('<Leader>9', actions.switchSessionByIndex(9), 'Session 9')
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
// -----------------------------------------------------------------------
|
|
71
|
+
// Layout mode
|
|
57
72
|
// -----------------------------------------------------------------------
|
|
58
73
|
.mode('layout', (m) =>
|
|
59
74
|
m
|
|
60
|
-
.map('<Esc>', actions.exitLayoutToInput)
|
|
61
|
-
.map('<Leader>', actions.exitLayoutToInput)
|
|
62
|
-
.map('<C-z>', actions.exitLayoutToNavigation)
|
|
63
|
-
.map('H', actions.resizePane(-1, 'vertical'))
|
|
64
|
-
.map('L', actions.resizePane(1, 'vertical'))
|
|
65
|
-
.map('K', actions.resizePane(-1, 'horizontal'))
|
|
66
|
-
.map('J', actions.resizePane(1, 'horizontal'))
|
|
67
|
-
.map('h', actions.focusPane('left'))
|
|
68
|
-
.map('j', actions.focusPane('down'))
|
|
69
|
-
.map('k', actions.focusPane('up'))
|
|
70
|
-
.map('l', actions.focusPane('right'))
|
|
71
|
-
.map('|', actions.splitVertical)
|
|
72
|
-
.map('-', actions.splitHorizontal)
|
|
73
|
-
.map('q', actions.closePane)
|
|
75
|
+
.map('<Esc>', actions.exitLayoutToInput, 'Back to insert')
|
|
76
|
+
.map('<Leader>', actions.exitLayoutToInput, 'Back to insert')
|
|
77
|
+
.map('<C-z>', actions.exitLayoutToNavigation, 'Back to nav')
|
|
78
|
+
.map('H', actions.resizePane(-1, 'vertical'), 'Shrink ←')
|
|
79
|
+
.map('L', actions.resizePane(1, 'vertical'), 'Grow →')
|
|
80
|
+
.map('K', actions.resizePane(-1, 'horizontal'), 'Shrink ↑')
|
|
81
|
+
.map('J', actions.resizePane(1, 'horizontal'), 'Grow ↓')
|
|
82
|
+
.map('h', actions.focusPane('left'), 'Focus left')
|
|
83
|
+
.map('j', actions.focusPane('down'), 'Focus down')
|
|
84
|
+
.map('k', actions.focusPane('up'), 'Focus up')
|
|
85
|
+
.map('l', actions.focusPane('right'), 'Focus right')
|
|
86
|
+
.map('|', actions.splitVertical, 'Split vertical')
|
|
87
|
+
.map('-', actions.splitHorizontal, 'Split horizontal')
|
|
88
|
+
.map('q', actions.closePane, 'Close pane')
|
|
74
89
|
)
|
|
75
90
|
|
|
76
91
|
// -----------------------------------------------------------------------
|
|
77
|
-
// Git mode
|
|
92
|
+
// Git mode
|
|
78
93
|
// -----------------------------------------------------------------------
|
|
79
94
|
.mode('git-mode', (m) =>
|
|
80
95
|
m
|
|
81
|
-
.map('<Esc>', actions.exitGitMode)
|
|
82
|
-
.map('j', actions.selectGitFile(1))
|
|
83
|
-
.map('k', actions.selectGitFile(-1))
|
|
84
|
-
.map('<C-d>', actions.scrollGitDiff(20))
|
|
85
|
-
.map('<C-u>', actions.scrollGitDiff(-20))
|
|
86
|
-
.map('<Down>', actions.scrollGitDiff(1))
|
|
87
|
-
.map('<Up>', actions.scrollGitDiff(-1))
|
|
88
|
-
.map('a', actions.gitStageSelected)
|
|
89
|
-
.map('d', actions.gitDestructiveSelected)
|
|
90
|
-
.map('c', actions.gitCommitOpen)
|
|
91
|
-
.map('p', actions.gitPush)
|
|
96
|
+
.map('<Esc>', actions.exitGitMode, 'Exit git')
|
|
97
|
+
.map('j', actions.selectGitFile(1), 'Next file')
|
|
98
|
+
.map('k', actions.selectGitFile(-1), 'Prev file')
|
|
99
|
+
.map('<C-d>', actions.scrollGitDiff(20), 'Page down')
|
|
100
|
+
.map('<C-u>', actions.scrollGitDiff(-20), 'Page up')
|
|
101
|
+
.map('<Down>', actions.scrollGitDiff(1), 'Scroll down')
|
|
102
|
+
.map('<Up>', actions.scrollGitDiff(-1), 'Scroll up')
|
|
103
|
+
.map('a', actions.gitStageSelected, 'Stage')
|
|
104
|
+
.map('d', actions.gitDestructiveSelected, 'Unstage/delete')
|
|
105
|
+
.map('c', actions.gitCommitOpen, 'Commit')
|
|
106
|
+
.map('p', actions.gitPush, 'Push')
|
|
92
107
|
)
|
|
93
108
|
|
|
94
109
|
// -----------------------------------------------------------------------
|
|
95
|
-
// Modal: help
|
|
110
|
+
// Modal: help
|
|
96
111
|
// -----------------------------------------------------------------------
|
|
97
|
-
.mode('modal.help', (m) => m.map('<Esc>', actions.closeModal))
|
|
112
|
+
.mode('modal.help', (m) => m.map('<Esc>', actions.closeModal, 'Close'))
|
|
98
113
|
|
|
99
114
|
// -----------------------------------------------------------------------
|
|
100
|
-
// Modal: theme-picker
|
|
115
|
+
// Modal: theme-picker
|
|
101
116
|
// -----------------------------------------------------------------------
|
|
102
117
|
.mode('modal.theme-picker', (m) =>
|
|
103
118
|
m
|
|
104
|
-
.map('<Esc>', actions.restoreTheme)
|
|
105
|
-
.map('j', actions.previewTheme(1))
|
|
106
|
-
.map('k', actions.previewTheme(-1))
|
|
119
|
+
.map('<Esc>', actions.restoreTheme, 'Cancel')
|
|
120
|
+
.map('j', actions.previewTheme(1), 'Next')
|
|
121
|
+
.map('k', actions.previewTheme(-1), 'Prev')
|
|
107
122
|
.map('<Down>', actions.previewTheme(1))
|
|
108
123
|
.map('<Up>', actions.previewTheme(-1))
|
|
109
|
-
.map('<CR>', actions.confirmTheme)
|
|
124
|
+
.map('<CR>', actions.confirmTheme, 'Confirm')
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
// -----------------------------------------------------------------------
|
|
128
|
+
// Modal: update-available
|
|
129
|
+
// -----------------------------------------------------------------------
|
|
130
|
+
.mode('modal.update-available', (m) =>
|
|
131
|
+
m
|
|
132
|
+
.map('<Esc>', actions.closeModal, 'Cancel')
|
|
133
|
+
.map('l', actions.moveModalSelection(1), 'Next')
|
|
134
|
+
.map('h', actions.moveModalSelection(-1), 'Prev')
|
|
135
|
+
.map('j', actions.moveModalSelection(1))
|
|
136
|
+
.map('k', actions.moveModalSelection(-1))
|
|
137
|
+
.map('<Right>', actions.moveModalSelection(1))
|
|
138
|
+
.map('<Left>', actions.moveModalSelection(-1))
|
|
139
|
+
.map('<Down>', actions.moveModalSelection(1))
|
|
140
|
+
.map('<Up>', actions.moveModalSelection(-1))
|
|
141
|
+
.map('<CR>', actions.confirmUpdateSelection, 'Confirm')
|
|
110
142
|
)
|
|
111
143
|
|
|
112
144
|
// -----------------------------------------------------------------------
|
|
113
|
-
// Modal: rename-tab
|
|
145
|
+
// Modal: rename-tab
|
|
114
146
|
// -----------------------------------------------------------------------
|
|
115
147
|
.mode('modal.rename-tab', (m) =>
|
|
116
|
-
m
|
|
148
|
+
m
|
|
149
|
+
.map('<Esc>', actions.closeModal, 'Cancel')
|
|
150
|
+
.map('<CR>', actions.confirmRenameTab, 'Confirm')
|
|
151
|
+
.passthrough()
|
|
117
152
|
)
|
|
118
153
|
|
|
119
154
|
// -----------------------------------------------------------------------
|
|
120
|
-
// Modal: new-tab
|
|
155
|
+
// Modal: new-tab
|
|
121
156
|
// -----------------------------------------------------------------------
|
|
122
157
|
.mode('modal.new-tab', (m) =>
|
|
123
158
|
m
|
|
124
|
-
.map('<Esc>', actions.closeModal)
|
|
125
|
-
.map('j', actions.moveModalSelection(1))
|
|
126
|
-
.map('k', actions.moveModalSelection(-1))
|
|
159
|
+
.map('<Esc>', actions.closeModal, 'Cancel')
|
|
160
|
+
.map('j', actions.moveModalSelection(1), 'Next')
|
|
161
|
+
.map('k', actions.moveModalSelection(-1), 'Prev')
|
|
127
162
|
.map('<Down>', actions.moveModalSelection(1))
|
|
128
163
|
.map('<Up>', actions.moveModalSelection(-1))
|
|
129
|
-
.map('<CR>', actions.launchSelectedAssistant)
|
|
130
|
-
.map('e', actions.beginCommandEdit)
|
|
164
|
+
.map('<CR>', actions.launchSelectedAssistant, 'Launch')
|
|
165
|
+
.map('e', actions.beginCommandEdit, 'Edit command')
|
|
131
166
|
)
|
|
132
167
|
|
|
133
168
|
// -----------------------------------------------------------------------
|
|
134
169
|
// Modal: new-tab command-edit
|
|
135
|
-
// (src/input/modes/handlers/modal-new-tab-command-edit.ts)
|
|
136
170
|
// -----------------------------------------------------------------------
|
|
137
171
|
.mode('modal.new-tab.command-edit', (m) =>
|
|
138
172
|
m
|
|
139
|
-
.map('<Esc>', actions.cancelCommandEdit('modal.new-tab'))
|
|
140
|
-
.map('<CR>', actions.commitCommandEdit)
|
|
141
|
-
.map('<C-n>', actions.moveModalSelection(1))
|
|
142
|
-
.map('<C-p>', actions.moveModalSelection(-1))
|
|
173
|
+
.map('<Esc>', actions.cancelCommandEdit('modal.new-tab'), 'Cancel')
|
|
174
|
+
.map('<CR>', actions.commitCommandEdit, 'Save')
|
|
175
|
+
.map('<C-n>', actions.moveModalSelection(1), 'Next')
|
|
176
|
+
.map('<C-p>', actions.moveModalSelection(-1), 'Prev')
|
|
143
177
|
.passthrough()
|
|
144
178
|
)
|
|
145
179
|
|
|
146
180
|
// -----------------------------------------------------------------------
|
|
147
|
-
// Modal: session-picker
|
|
181
|
+
// Modal: session-picker
|
|
148
182
|
// -----------------------------------------------------------------------
|
|
149
183
|
.mode('modal.session-picker', (m) =>
|
|
150
184
|
m
|
|
151
|
-
.map('<Esc>', actions.sessionPickerEscape)
|
|
152
|
-
.map('j', actions.moveModalSelection(1))
|
|
153
|
-
.map('k', actions.moveModalSelection(-1))
|
|
185
|
+
.map('<Esc>', actions.sessionPickerEscape, 'Cancel')
|
|
186
|
+
.map('j', actions.moveModalSelection(1), 'Next')
|
|
187
|
+
.map('k', actions.moveModalSelection(-1), 'Prev')
|
|
154
188
|
.map('<Down>', actions.moveModalSelection(1))
|
|
155
189
|
.map('<Up>', actions.moveModalSelection(-1))
|
|
156
|
-
.map('<CR>', actions.confirmSelectedSession)
|
|
157
|
-
.map('n', actions.openCreateSessionModal)
|
|
158
|
-
.map('r', actions.openRenameSelectedSession)
|
|
159
|
-
.map('d', actions.deleteSelectedSession)
|
|
160
|
-
.map('/', actions.beginSessionFilter)
|
|
190
|
+
.map('<CR>', actions.confirmSelectedSession, 'Open')
|
|
191
|
+
.map('n', actions.openCreateSessionModal, 'New')
|
|
192
|
+
.map('r', actions.openRenameSelectedSession, 'Rename')
|
|
193
|
+
.map('d', actions.deleteSelectedSession, 'Delete')
|
|
194
|
+
.map('/', actions.beginSessionFilter, 'Filter')
|
|
161
195
|
)
|
|
162
196
|
|
|
163
197
|
// -----------------------------------------------------------------------
|
|
164
198
|
// Modal: session-picker filtering
|
|
165
|
-
// (src/input/modes/handlers/modal-session-picker-filter.ts)
|
|
166
199
|
// -----------------------------------------------------------------------
|
|
167
200
|
.mode('modal.session-picker.filtering', (m) =>
|
|
168
201
|
m
|
|
169
|
-
.map('<Esc>', actions.cancelCommandEdit('modal.session-picker'))
|
|
170
|
-
.map('<CR>', actions.confirmSelectedSession)
|
|
171
|
-
.map('<C-n>', actions.moveModalSelection(1))
|
|
172
|
-
.map('<C-p>', actions.moveModalSelection(-1))
|
|
202
|
+
.map('<Esc>', actions.cancelCommandEdit('modal.session-picker'), 'Cancel')
|
|
203
|
+
.map('<CR>', actions.confirmSelectedSession, 'Open')
|
|
204
|
+
.map('<C-n>', actions.moveModalSelection(1), 'Next')
|
|
205
|
+
.map('<C-p>', actions.moveModalSelection(-1), 'Prev')
|
|
173
206
|
.passthrough()
|
|
174
207
|
)
|
|
175
208
|
|
|
176
209
|
// -----------------------------------------------------------------------
|
|
177
|
-
// Modal: session-name
|
|
210
|
+
// Modal: session-name
|
|
178
211
|
// -----------------------------------------------------------------------
|
|
179
212
|
.mode('modal.session-name', (m) =>
|
|
180
213
|
m
|
|
181
|
-
.map('<Esc>', actions.backToSessionPicker)
|
|
182
|
-
.map('<CR>', actions.confirmSessionRename)
|
|
214
|
+
.map('<Esc>', actions.backToSessionPicker, 'Cancel')
|
|
215
|
+
.map('<CR>', actions.confirmSessionRename, 'Confirm')
|
|
183
216
|
.passthrough()
|
|
184
217
|
)
|
|
185
218
|
|
|
186
219
|
// -----------------------------------------------------------------------
|
|
187
220
|
// Modal: create-session
|
|
188
|
-
// (src/input/modes/handlers/modal-create-session.ts)
|
|
189
221
|
// -----------------------------------------------------------------------
|
|
190
222
|
.mode('modal.create-session', (m) =>
|
|
191
223
|
m
|
|
192
|
-
.map('<Esc>', actions.backToSessionPicker)
|
|
193
|
-
.map('<Tab>', actions.switchField)
|
|
194
|
-
.map('<CR>', actions.confirmCreateSession)
|
|
195
|
-
.map('<C-n>', actions.moveModalSelection(1))
|
|
196
|
-
.map('<C-p>', actions.moveModalSelection(-1))
|
|
224
|
+
.map('<Esc>', actions.backToSessionPicker, 'Cancel')
|
|
225
|
+
.map('<Tab>', actions.switchField, 'Next field')
|
|
226
|
+
.map('<CR>', actions.confirmCreateSession, 'Confirm')
|
|
227
|
+
.map('<C-n>', actions.moveModalSelection(1), 'Next')
|
|
228
|
+
.map('<C-p>', actions.moveModalSelection(-1), 'Prev')
|
|
197
229
|
.passthrough()
|
|
198
230
|
)
|
|
199
231
|
|
|
200
232
|
// -----------------------------------------------------------------------
|
|
201
233
|
// Modal: snippet-picker
|
|
202
|
-
// (src/input/modes/handlers/modal-snippet-picker.ts)
|
|
203
234
|
// -----------------------------------------------------------------------
|
|
204
235
|
.mode('modal.snippet-picker', (m) =>
|
|
205
236
|
m
|
|
206
|
-
.map('<Esc>', actions.closeModal)
|
|
207
|
-
.map('j', actions.moveModalSelection(1))
|
|
208
|
-
.map('k', actions.moveModalSelection(-1))
|
|
237
|
+
.map('<Esc>', actions.closeModal, 'Cancel')
|
|
238
|
+
.map('j', actions.moveModalSelection(1), 'Next')
|
|
239
|
+
.map('k', actions.moveModalSelection(-1), 'Prev')
|
|
209
240
|
.map('<Down>', actions.moveModalSelection(1))
|
|
210
241
|
.map('<Up>', actions.moveModalSelection(-1))
|
|
211
|
-
.map('<CR>', actions.pasteSelectedSnippet)
|
|
212
|
-
.map('a', actions.pasteSnippetToGroup)
|
|
213
|
-
.map('n', actions.openSnippetEditor)
|
|
214
|
-
.map('r', actions.editSelectedSnippet)
|
|
242
|
+
.map('<CR>', actions.pasteSelectedSnippet, 'Send')
|
|
243
|
+
.map('a', actions.pasteSnippetToGroup, 'Send to group')
|
|
244
|
+
.map('n', actions.openSnippetEditor, 'New')
|
|
245
|
+
.map('r', actions.editSelectedSnippet, 'Edit')
|
|
215
246
|
.map('e', actions.editSelectedSnippet)
|
|
216
|
-
.map('d', actions.deleteSelectedSnippet)
|
|
217
|
-
.map('/', actions.beginSnippetFilter)
|
|
247
|
+
.map('d', actions.deleteSelectedSnippet, 'Delete')
|
|
248
|
+
.map('/', actions.beginSnippetFilter, 'Filter')
|
|
218
249
|
)
|
|
219
250
|
|
|
220
251
|
// -----------------------------------------------------------------------
|
|
221
252
|
// Modal: snippet-picker filtering
|
|
222
|
-
// (src/input/modes/handlers/modal-snippet-picker-filter.ts)
|
|
223
253
|
// -----------------------------------------------------------------------
|
|
224
254
|
.mode('modal.snippet-picker.filtering', (m) =>
|
|
225
255
|
m
|
|
226
|
-
.map('<Esc>', actions.cancelCommandEdit('modal.snippet-picker'))
|
|
227
|
-
.map('<CR>', actions.snippetFilterPaste)
|
|
228
|
-
.map('<C-a>', actions.snippetFilterPasteToGroup)
|
|
229
|
-
.map('<C-n>', actions.moveModalSelection(1))
|
|
230
|
-
.map('<C-p>', actions.moveModalSelection(-1))
|
|
256
|
+
.map('<Esc>', actions.cancelCommandEdit('modal.snippet-picker'), 'Cancel')
|
|
257
|
+
.map('<CR>', actions.snippetFilterPaste, 'Send')
|
|
258
|
+
.map('<C-a>', actions.snippetFilterPasteToGroup, 'Send to group')
|
|
259
|
+
.map('<C-n>', actions.moveModalSelection(1), 'Next')
|
|
260
|
+
.map('<C-p>', actions.moveModalSelection(-1), 'Prev')
|
|
231
261
|
.passthrough()
|
|
232
262
|
)
|
|
233
263
|
|
|
234
264
|
// -----------------------------------------------------------------------
|
|
235
265
|
// Modal: snippet-editor
|
|
236
|
-
// (src/input/modes/handlers/modal-snippet-editor.ts)
|
|
237
266
|
// -----------------------------------------------------------------------
|
|
238
267
|
.mode('modal.snippet-editor', (m) =>
|
|
239
268
|
m
|
|
240
|
-
.map('<Esc>', actions.backToSnippetPicker)
|
|
241
|
-
.map('<Tab>', actions.switchField)
|
|
242
|
-
.map('<CR>', actions.saveSnippetEditor)
|
|
243
|
-
.map('<C-n>', actions.moveModalSelection(1))
|
|
244
|
-
.map('<C-p>', actions.moveModalSelection(-1))
|
|
269
|
+
.map('<Esc>', actions.backToSnippetPicker, 'Cancel')
|
|
270
|
+
.map('<Tab>', actions.switchField, 'Next field')
|
|
271
|
+
.map('<CR>', actions.saveSnippetEditor, 'Save')
|
|
272
|
+
.map('<C-n>', actions.moveModalSelection(1), 'Next')
|
|
273
|
+
.map('<C-p>', actions.moveModalSelection(-1), 'Prev')
|
|
245
274
|
.passthrough()
|
|
246
275
|
)
|
|
247
276
|
|
|
248
277
|
// -----------------------------------------------------------------------
|
|
249
278
|
// Modal: split-picker
|
|
250
|
-
// (src/input/modes/handlers/modal-split-picker.ts)
|
|
251
279
|
// -----------------------------------------------------------------------
|
|
252
280
|
.mode('modal.split-picker', (m) =>
|
|
253
281
|
m
|
|
254
|
-
.map('<Esc>', actions.closeModal)
|
|
255
|
-
.map('j', actions.moveModalSelection(1))
|
|
256
|
-
.map('k', actions.moveModalSelection(-1))
|
|
282
|
+
.map('<Esc>', actions.closeModal, 'Cancel')
|
|
283
|
+
.map('j', actions.moveModalSelection(1), 'Next')
|
|
284
|
+
.map('k', actions.moveModalSelection(-1), 'Prev')
|
|
257
285
|
.map('<Down>', actions.moveModalSelection(1))
|
|
258
286
|
.map('<Up>', actions.moveModalSelection(-1))
|
|
259
|
-
.map('<CR>', actions.confirmSplit)
|
|
287
|
+
.map('<CR>', actions.confirmSplit, 'Confirm')
|
|
260
288
|
)
|
|
261
289
|
|
|
262
290
|
// -----------------------------------------------------------------------
|
|
263
|
-
// Modal: git-commit
|
|
291
|
+
// Modal: git-commit
|
|
264
292
|
// -----------------------------------------------------------------------
|
|
265
293
|
.mode('modal.git-commit', (m) =>
|
|
266
294
|
m
|
|
267
|
-
.map('<Esc>', actions.gitCommitCancel)
|
|
268
|
-
.map('<C-CR>', actions.gitCommitSubmit)
|
|
269
|
-
.map('<Tab>', actions.switchField)
|
|
270
|
-
.map('<CR>', actions.gitCommitReturnKey)
|
|
295
|
+
.map('<Esc>', actions.gitCommitCancel, 'Cancel')
|
|
296
|
+
.map('<C-CR>', actions.gitCommitSubmit, 'Commit')
|
|
297
|
+
.map('<Tab>', actions.switchField, 'Next field')
|
|
298
|
+
.map('<CR>', actions.gitCommitReturnKey, 'Newline / confirm')
|
|
271
299
|
.passthrough()
|
|
272
300
|
)
|
|
273
301
|
|
package/src/keymap-builder.ts
CHANGED
|
@@ -21,8 +21,13 @@ export class GroupBuilder implements GroupBuilderApi {
|
|
|
21
21
|
private readonly groupName: string
|
|
22
22
|
) {}
|
|
23
23
|
|
|
24
|
-
map(keys: string, action: Action): this {
|
|
25
|
-
this.bindings.push({
|
|
24
|
+
map(keys: string, action: Action, description?: string): this {
|
|
25
|
+
this.bindings.push({
|
|
26
|
+
description,
|
|
27
|
+
group: this.groupName,
|
|
28
|
+
keys: `${this.prefix}${keys}`,
|
|
29
|
+
result: action,
|
|
30
|
+
})
|
|
26
31
|
return this
|
|
27
32
|
}
|
|
28
33
|
|
|
@@ -43,8 +48,8 @@ export class ModeBindingBuilder implements ModeBindingBuilderApi {
|
|
|
43
48
|
private readonly removals: string[] = []
|
|
44
49
|
private _passthrough = false
|
|
45
50
|
|
|
46
|
-
map(keys: string, action: Action): this {
|
|
47
|
-
this.bindings.push({ keys, result: action })
|
|
51
|
+
map(keys: string, action: Action, description?: string): this {
|
|
52
|
+
this.bindings.push({ description, keys, result: action })
|
|
48
53
|
return this
|
|
49
54
|
}
|
|
50
55
|
|
|
@@ -94,10 +99,36 @@ export class KeymapBuilder implements KeymapBuilderApi {
|
|
|
94
99
|
return this
|
|
95
100
|
}
|
|
96
101
|
|
|
97
|
-
mode(
|
|
102
|
+
mode(
|
|
103
|
+
id: ModeId | readonly ModeId[],
|
|
104
|
+
configure: (m: ModeBindingBuilderApi) => ModeBindingBuilderApi
|
|
105
|
+
): this {
|
|
98
106
|
const builder = new ModeBindingBuilder()
|
|
99
107
|
configure(builder)
|
|
100
|
-
|
|
108
|
+
const incoming = builder._build()
|
|
109
|
+
const ids = Array.isArray(id) ? id : [id]
|
|
110
|
+
for (const modeId of ids) {
|
|
111
|
+
const existing = this.modes.get(modeId)
|
|
112
|
+
if (!existing) {
|
|
113
|
+
// Fresh mode: clone so later merges don't mutate a shared array.
|
|
114
|
+
this.modes.set(modeId, {
|
|
115
|
+
bindings: [...incoming.bindings],
|
|
116
|
+
isPassthrough: incoming.isPassthrough,
|
|
117
|
+
removals: [...incoming.removals],
|
|
118
|
+
})
|
|
119
|
+
continue
|
|
120
|
+
}
|
|
121
|
+
// Merge: later bindings win over earlier ones sharing the same keys.
|
|
122
|
+
const incomingKeys = new Set(incoming.bindings.map((b) => b.keys))
|
|
123
|
+
this.modes.set(modeId, {
|
|
124
|
+
bindings: [
|
|
125
|
+
...existing.bindings.filter((b) => !incomingKeys.has(b.keys)),
|
|
126
|
+
...incoming.bindings,
|
|
127
|
+
],
|
|
128
|
+
isPassthrough: existing.isPassthrough || incoming.isPassthrough,
|
|
129
|
+
removals: [...existing.removals, ...incoming.removals],
|
|
130
|
+
})
|
|
131
|
+
}
|
|
101
132
|
return this
|
|
102
133
|
}
|
|
103
134
|
|
package/src/resolver.ts
CHANGED
|
@@ -20,6 +20,7 @@ export function resolveConfig(userConfig: AimuxUserConfig): ResolvedConfig {
|
|
|
20
20
|
backends: userConfig.backends ?? {},
|
|
21
21
|
hooks: userConfig.hooks ?? {},
|
|
22
22
|
keymaps,
|
|
23
|
+
sessionBar: userConfig.sessionBar ?? {},
|
|
23
24
|
sidebar: userConfig.sidebar ?? {},
|
|
24
25
|
snippets: userConfig.snippets ?? [],
|
|
25
26
|
theme: userConfig.theme,
|
package/src/types.ts
CHANGED
|
@@ -27,6 +27,7 @@ export type ModeId =
|
|
|
27
27
|
| 'modal.help'
|
|
28
28
|
| 'modal.split-picker'
|
|
29
29
|
| 'modal.git-commit'
|
|
30
|
+
| 'modal.update-available'
|
|
30
31
|
|
|
31
32
|
// ─── Primitive app types ──────────────────────────────────────────────────────
|
|
32
33
|
|
|
@@ -124,6 +125,7 @@ export interface SessionRecord {
|
|
|
124
125
|
createdAt: string
|
|
125
126
|
updatedAt: string
|
|
126
127
|
lastOpenedAt: string
|
|
128
|
+
order?: number
|
|
127
129
|
workspaceSnapshot?: WorkspaceSnapshotV1
|
|
128
130
|
}
|
|
129
131
|
|
|
@@ -263,6 +265,12 @@ export interface ModalSnippetEditor extends ModalBase {
|
|
|
263
265
|
contentBuffer: string
|
|
264
266
|
}
|
|
265
267
|
|
|
268
|
+
export interface ModalUpdateAvailable extends ModalBase {
|
|
269
|
+
type: 'update-available'
|
|
270
|
+
currentVersion: string
|
|
271
|
+
latestVersion: string
|
|
272
|
+
}
|
|
273
|
+
|
|
266
274
|
export type ModalState =
|
|
267
275
|
| ModalClosed
|
|
268
276
|
| ModalNewTab
|
|
@@ -276,12 +284,20 @@ export type ModalState =
|
|
|
276
284
|
| ModalCreateSession
|
|
277
285
|
| ModalSnippetEditor
|
|
278
286
|
| ModalGitCommit
|
|
287
|
+
| ModalUpdateAvailable
|
|
279
288
|
|
|
280
289
|
export interface LayoutState {
|
|
281
290
|
terminalCols: number
|
|
282
291
|
terminalRows: number
|
|
283
292
|
}
|
|
284
293
|
|
|
294
|
+
export type SessionBarPosition = 'top' | 'bottom'
|
|
295
|
+
|
|
296
|
+
export interface SessionBarState {
|
|
297
|
+
visible: boolean
|
|
298
|
+
position: SessionBarPosition
|
|
299
|
+
}
|
|
300
|
+
|
|
285
301
|
export interface AppState {
|
|
286
302
|
tabs: TabSession[]
|
|
287
303
|
activeTabId: string | null
|
|
@@ -289,6 +305,8 @@ export interface AppState {
|
|
|
289
305
|
tabGroupMap: Record<string, string>
|
|
290
306
|
sessions: SessionRecord[]
|
|
291
307
|
currentSessionId: string | null
|
|
308
|
+
sessionsBusy: Record<string, boolean>
|
|
309
|
+
sessionBar: SessionBarState
|
|
292
310
|
snippets: SnippetRecord[]
|
|
293
311
|
focusMode: FocusMode
|
|
294
312
|
sidebar: SidebarState
|
|
@@ -324,6 +342,7 @@ export type ModalAction =
|
|
|
324
342
|
| { type: 'open-snippet-editor'; snippetId?: string }
|
|
325
343
|
| { type: 'begin-snippet-filter' }
|
|
326
344
|
| { type: 'open-theme-picker' }
|
|
345
|
+
| { type: 'open-update-available-modal'; currentVersion: string; latestVersion: string }
|
|
327
346
|
|
|
328
347
|
export type SessionAction =
|
|
329
348
|
| { type: 'load-session'; sessionId: string; workspaceSnapshot?: WorkspaceSnapshotV1 }
|
|
@@ -331,6 +350,8 @@ export type SessionAction =
|
|
|
331
350
|
| { type: 'create-session-record'; session: SessionRecord }
|
|
332
351
|
| { type: 'rename-session-record'; sessionId: string; name: string }
|
|
333
352
|
| { type: 'delete-session-record'; sessionId: string }
|
|
353
|
+
| { type: 'reorder-sessions'; orderedIds: string[] }
|
|
354
|
+
| { type: 'set-session-busy'; sessionId: string; busy: boolean }
|
|
334
355
|
|
|
335
356
|
export type TabAction =
|
|
336
357
|
| { type: 'add-tab'; tab: TabSession }
|
|
@@ -392,6 +413,8 @@ export type UIAction =
|
|
|
392
413
|
| { type: 'toggle-git-panel' }
|
|
393
414
|
| { type: 'resize-git-panel'; delta: number }
|
|
394
415
|
| { type: 'set-pending-chords'; chords: string[] | null }
|
|
416
|
+
| { type: 'toggle-session-bar' }
|
|
417
|
+
| { type: 'set-session-bar-position'; position: SessionBarPosition }
|
|
395
418
|
|
|
396
419
|
export interface GitRefreshPayload {
|
|
397
420
|
branch: string | null
|
|
@@ -467,6 +490,8 @@ export type SideEffect =
|
|
|
467
490
|
| { type: 'git-rm'; path: string }
|
|
468
491
|
| { type: 'git-commit'; title: string; body: string }
|
|
469
492
|
| { type: 'git-push' }
|
|
493
|
+
| { type: 'confirm-update-selection' }
|
|
494
|
+
| { type: 'switch-session-by-index'; index: number }
|
|
470
495
|
|
|
471
496
|
// ─── Key input / KeyResult / ModeContext ──────────────────────────────────────
|
|
472
497
|
|
|
@@ -563,7 +588,7 @@ export type Action = KeyResult | ActionFn
|
|
|
563
588
|
// ─── Keymap builder API types ─────────────────────────────────────────────────
|
|
564
589
|
|
|
565
590
|
export interface GroupBuilderApi {
|
|
566
|
-
map(keys: string, action: Action): GroupBuilderApi
|
|
591
|
+
map(keys: string, action: Action, description?: string): GroupBuilderApi
|
|
567
592
|
group(
|
|
568
593
|
prefix: string,
|
|
569
594
|
name: string,
|
|
@@ -572,7 +597,7 @@ export interface GroupBuilderApi {
|
|
|
572
597
|
}
|
|
573
598
|
|
|
574
599
|
export interface ModeBindingBuilderApi {
|
|
575
|
-
map(keys: string, action: Action): ModeBindingBuilderApi
|
|
600
|
+
map(keys: string, action: Action, description?: string): ModeBindingBuilderApi
|
|
576
601
|
unmap(keys: string): ModeBindingBuilderApi
|
|
577
602
|
group(
|
|
578
603
|
prefix: string,
|
|
@@ -585,16 +610,25 @@ export interface ModeBindingBuilderApi {
|
|
|
585
610
|
export interface KeymapBuilderApi {
|
|
586
611
|
leader(key: string): KeymapBuilderApi
|
|
587
612
|
timeout(ms: number): KeymapBuilderApi
|
|
588
|
-
mode(
|
|
613
|
+
mode(
|
|
614
|
+
id: ModeId | readonly ModeId[],
|
|
615
|
+
configure: (m: ModeBindingBuilderApi) => ModeBindingBuilderApi
|
|
616
|
+
): KeymapBuilderApi
|
|
589
617
|
}
|
|
590
618
|
|
|
591
619
|
// ─── Top-level user config ────────────────────────────────────────────────────
|
|
592
620
|
|
|
621
|
+
export interface SessionBarConfig {
|
|
622
|
+
visible?: boolean
|
|
623
|
+
position?: SessionBarPosition
|
|
624
|
+
}
|
|
625
|
+
|
|
593
626
|
export interface AimuxUserConfig {
|
|
594
627
|
theme?: ThemeId | ThemeDefinition
|
|
595
628
|
keymaps?: (k: KeymapBuilderApi) => KeymapBuilderApi
|
|
596
629
|
backends?: Record<string, BackendConfig>
|
|
597
630
|
sidebar?: SidebarConfig
|
|
631
|
+
sessionBar?: SessionBarConfig
|
|
598
632
|
hooks?: HooksConfig
|
|
599
633
|
snippets?: SnippetDef[]
|
|
600
634
|
}
|
|
@@ -605,6 +639,7 @@ export interface BindingDef {
|
|
|
605
639
|
keys: string
|
|
606
640
|
result: Action
|
|
607
641
|
group?: string
|
|
642
|
+
description?: string
|
|
608
643
|
}
|
|
609
644
|
|
|
610
645
|
export interface ModeKeymapDef {
|
|
@@ -624,6 +659,7 @@ export interface ResolvedConfig {
|
|
|
624
659
|
keymaps: ResolvedKeymapConfig
|
|
625
660
|
backends: Record<string, BackendConfig>
|
|
626
661
|
sidebar: SidebarConfig
|
|
662
|
+
sessionBar: SessionBarConfig
|
|
627
663
|
hooks: HooksConfig
|
|
628
664
|
snippets: SnippetDef[]
|
|
629
665
|
}
|