@brimveyn/aimux-config 0.8.5 → 0.10.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 +78 -7
- package/package.json +1 -1
- package/src/actions.ts +260 -162
- package/src/defaults.ts +111 -49
- package/src/index.ts +2 -5
- package/src/resolver.ts +17 -50
- package/src/status-bar-runtime.ts +1 -1
- package/src/types.ts +328 -244
package/src/actions.ts
CHANGED
|
@@ -20,16 +20,17 @@ function r(
|
|
|
20
20
|
export const nextTab: KeyResult = r([{ delta: 1, type: 'move-active-tab' }])
|
|
21
21
|
export const prevTab: KeyResult = r([{ delta: -1, type: 'move-active-tab' }])
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Routed through an effect rather than opening the modal directly: tabs only
|
|
25
|
+
* exist inside a workspace, and whether the project has one is the app's
|
|
26
|
+
* business, not the keymap's. The effect opens the picker or explains why not.
|
|
27
|
+
*/
|
|
28
|
+
export const newTab: KeyResult = r([], [{ type: 'open-new-tab' }])
|
|
28
29
|
export const renameTab: KeyResult = r([{ type: 'open-rename-tab-modal' }], [], 'modal.rename-tab')
|
|
29
|
-
export const
|
|
30
|
-
[{ type: 'open-
|
|
30
|
+
export const projectPicker: KeyResult = r(
|
|
31
|
+
[{ type: 'open-project-picker' }],
|
|
31
32
|
[],
|
|
32
|
-
'modal.
|
|
33
|
+
'modal.project-picker.filtering'
|
|
33
34
|
)
|
|
34
35
|
export const snippetPicker: KeyResult = r(
|
|
35
36
|
[{ type: 'open-snippet-picker' }],
|
|
@@ -51,9 +52,15 @@ export const openFlashJump: KeyResult = r(
|
|
|
51
52
|
'modal.flash-jump'
|
|
52
53
|
)
|
|
53
54
|
|
|
54
|
-
export
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
export function toggleBar(side: 'left' | 'right'): KeyResult {
|
|
56
|
+
return r([{ side, type: 'toggle-bar' }])
|
|
57
|
+
}
|
|
58
|
+
export const toggleSidebar: KeyResult = toggleBar('left')
|
|
59
|
+
export function toggleWidget(widgetId: string): KeyResult {
|
|
60
|
+
return r([{ type: 'toggle-widget', widgetId }])
|
|
61
|
+
}
|
|
62
|
+
export const toggleGitPane: KeyResult = toggleWidget('git')
|
|
63
|
+
export const toggleProjectBar: KeyResult = r([{ type: 'toggle-project-bar' }])
|
|
57
64
|
export const toggleAIUsage: ActionFn = (ctx: ModeContext) => {
|
|
58
65
|
if (ctx.state.modal.type === 'ai-usage') {
|
|
59
66
|
return r([{ type: 'close-modal' }], [], 'navigation')
|
|
@@ -61,17 +68,10 @@ export const toggleAIUsage: ActionFn = (ctx: ModeContext) => {
|
|
|
61
68
|
return r([{ type: 'open-ai-usage-modal' }], [], 'modal.ai-usage')
|
|
62
69
|
}
|
|
63
70
|
|
|
64
|
-
export function setGitPaneMode(mode: 'embedded' | 'pane'): KeyResult {
|
|
65
|
-
return r([{ mode, type: 'set-git-pane-mode' }])
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function setGitPanePosition(position: 'top' | 'bottom' | 'left' | 'right'): KeyResult {
|
|
69
|
-
return r([{ position, type: 'set-git-pane-position' }])
|
|
70
|
-
}
|
|
71
71
|
export const enterGitMode: KeyResult = r([{ type: 'enter-git-mode' }], [], 'git-mode')
|
|
72
72
|
|
|
73
|
-
export function
|
|
74
|
-
return r([], [{ index, type: 'switch-
|
|
73
|
+
export function switchProjectByIndex(index: number): KeyResult {
|
|
74
|
+
return r([], [{ index, type: 'switch-project-by-index' }])
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
export function switchTabByIndex(index: number): KeyResult {
|
|
@@ -135,16 +135,24 @@ export function reorderTab(delta: number): KeyResult {
|
|
|
135
135
|
return r([{ delta, type: 'reorder-active-tab' }])
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
export function
|
|
139
|
-
return r([{ delta, type: 'reorder-active-
|
|
138
|
+
export function reorderProject(delta: number): KeyResult {
|
|
139
|
+
return r([{ delta, type: 'reorder-active-project' }])
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function resizeBar(side: 'left' | 'right', delta: number): KeyResult {
|
|
143
|
+
return r([{ delta, side, type: 'resize-bar' }])
|
|
140
144
|
}
|
|
141
145
|
|
|
142
146
|
export function resizeSidebar(delta: number): KeyResult {
|
|
143
|
-
return
|
|
147
|
+
return resizeBar('left', delta)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function resizeWidget(widgetId: string, delta: number): KeyResult {
|
|
151
|
+
return r([{ delta, type: 'resize-widget', widgetId }])
|
|
144
152
|
}
|
|
145
153
|
|
|
146
154
|
export function resizeGitPane(delta: number): KeyResult {
|
|
147
|
-
return
|
|
155
|
+
return resizeWidget('git', delta)
|
|
148
156
|
}
|
|
149
157
|
|
|
150
158
|
export function resizeGitDiffPane(delta: number): ActionFn {
|
|
@@ -192,70 +200,20 @@ export function moveModalSelectionWithPreview(
|
|
|
192
200
|
// Modal-specific actions
|
|
193
201
|
// ---------------------------------------------------------------------------
|
|
194
202
|
|
|
195
|
-
export const launchSelectedAssistant:
|
|
196
|
-
if (ctx.state.modal.type === 'new-tab' && ctx.state.modal.step === 'assistant') {
|
|
197
|
-
return r([{ type: 'select-new-tab-assistant' }])
|
|
198
|
-
}
|
|
199
|
-
if (
|
|
200
|
-
ctx.state.modal.type === 'new-tab' &&
|
|
201
|
-
ctx.state.modal.step === 'worktree' &&
|
|
202
|
-
ctx.state.modal.createWorktree
|
|
203
|
-
) {
|
|
204
|
-
return r([{ type: 'enter-new-tab-worktree-create' }], [{ type: 'load-new-tab-base-branches' }])
|
|
205
|
-
}
|
|
206
|
-
return r([], [{ type: 'launch-selected-assistant' }])
|
|
207
|
-
}
|
|
203
|
+
export const launchSelectedAssistant: KeyResult = r([], [{ type: 'launch-selected-assistant' }])
|
|
208
204
|
|
|
209
|
-
export const
|
|
210
|
-
|
|
211
|
-
export const deleteSelectedWorktree: ActionFn = (ctx: ModeContext) => {
|
|
205
|
+
export const confirmWorkspaceDeleteModal: ActionFn = (ctx: ModeContext) => {
|
|
212
206
|
const modal = ctx.state.modal
|
|
213
|
-
|
|
214
|
-
if (modal.type !== 'new-tab' || modal.step !== 'worktree' || modal.createWorktree) return null
|
|
215
|
-
if (!(sessionId != null && sessionId !== '')) return null
|
|
216
|
-
const session = ctx.state.sessions.find((entry) => entry.id === sessionId)
|
|
217
|
-
const worktree = session?.worktrees?.[modal.selectedIndex]
|
|
218
|
-
if (!worktree) return null
|
|
219
|
-
// First attempt is never forced — a recoverable failure opens the confirm
|
|
220
|
-
// dialog (see set-new-tab-worktree-delete-prompt), where confirmDeleteWorktree
|
|
221
|
-
// retries with force.
|
|
222
|
-
return r(
|
|
223
|
-
[{ index: modal.selectedIndex, type: 'set-modal-selection-index' }],
|
|
224
|
-
[{ force: false, sessionId, type: 'delete-worktree', worktreeId: worktree.id }]
|
|
225
|
-
)
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
export const confirmDeleteWorktree: ActionFn = (ctx: ModeContext) => {
|
|
229
|
-
const modal = ctx.state.modal
|
|
230
|
-
const sessionId = ctx.state.currentSessionId
|
|
231
|
-
if (modal.type !== 'new-tab' || modal.worktreeDeletePrompt == null) return null
|
|
232
|
-
if (!(sessionId != null && sessionId !== '')) return null
|
|
233
|
-
const { worktreeId } = modal.worktreeDeletePrompt
|
|
234
|
-
return r(
|
|
235
|
-
[{ prompt: null, type: 'set-new-tab-worktree-delete-prompt' }],
|
|
236
|
-
[{ force: true, sessionId, type: 'delete-worktree', worktreeId }],
|
|
237
|
-
'modal.new-tab.command-edit'
|
|
238
|
-
)
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
export const cancelDeleteWorktree: KeyResult = r(
|
|
242
|
-
[{ prompt: null, type: 'set-new-tab-worktree-delete-prompt' }],
|
|
243
|
-
[],
|
|
244
|
-
'modal.new-tab.command-edit'
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
export const confirmWorktreeDeleteModal: ActionFn = (ctx: ModeContext) => {
|
|
248
|
-
const modal = ctx.state.modal
|
|
249
|
-
if (modal.type !== 'worktree-delete-confirm') return null
|
|
207
|
+
if (modal.type !== 'workspace-delete-confirm') return null
|
|
250
208
|
return r(
|
|
251
209
|
[{ type: 'close-modal' }],
|
|
252
210
|
[
|
|
253
211
|
{
|
|
254
212
|
closeTabs: modal.closeTabs,
|
|
255
213
|
force: modal.force,
|
|
256
|
-
|
|
257
|
-
type: 'delete-
|
|
258
|
-
|
|
214
|
+
projectId: modal.projectId,
|
|
215
|
+
type: 'delete-workspace',
|
|
216
|
+
workspaceId: modal.workspaceId,
|
|
259
217
|
},
|
|
260
218
|
],
|
|
261
219
|
'navigation'
|
|
@@ -265,20 +223,52 @@ export const confirmWorktreeDeleteModal: ActionFn = (ctx: ModeContext) => {
|
|
|
265
223
|
export const cancelCommandEdit = (returnTo: KeyResult['transition']): KeyResult =>
|
|
266
224
|
r([{ type: 'cancel-command-edit' }], [], returnTo)
|
|
267
225
|
|
|
268
|
-
export const
|
|
226
|
+
export const confirmSelectedProject: KeyResult = r([], [{ type: 'confirm-selected-project' }])
|
|
269
227
|
|
|
270
|
-
export const
|
|
271
|
-
[{
|
|
228
|
+
export const openCreateProjectModal: KeyResult = r(
|
|
229
|
+
[{ returnToProjectPicker: true, type: 'open-create-project-modal' }],
|
|
272
230
|
[],
|
|
273
|
-
'modal.create-
|
|
231
|
+
'modal.create-project'
|
|
274
232
|
)
|
|
275
233
|
|
|
276
|
-
export const
|
|
234
|
+
export const createWorkspaceModal: KeyResult = r(
|
|
235
|
+
[{ type: 'open-create-workspace-modal' }],
|
|
236
|
+
[{ type: 'load-create-workspace-base-branches' }],
|
|
237
|
+
'modal.create-workspace'
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
export const switchCreateWorkspaceField: KeyResult = r([{ type: 'switch-create-workspace-field' }])
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* An empty prompt is not a workspace: it names nothing, branches nothing and
|
|
244
|
+
* gives the assistant nothing to do, so Enter is simply inert until it is typed.
|
|
245
|
+
*/
|
|
246
|
+
export const confirmCreateWorkspace: ActionFn = (ctx: ModeContext) => {
|
|
247
|
+
const { modal } = ctx.state
|
|
248
|
+
if (modal.type === 'create-workspace' && modal.prompt.trim() === '') return r([])
|
|
249
|
+
return r([], [{ type: 'create-workspace' }])
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* `Enter` creates, so the prompt needs another way to break a line. Inverted
|
|
254
|
+
* from the commit modal on purpose: there the body is the whole point, here
|
|
255
|
+
* most prompts are one line and creating must stay the cheapest keystroke.
|
|
256
|
+
*/
|
|
257
|
+
export const createWorkspaceNewline: ActionFn = (ctx: ModeContext) => {
|
|
258
|
+
const { modal } = ctx.state
|
|
259
|
+
if (modal.type !== 'create-workspace') return r([])
|
|
260
|
+
if (modal.activeField !== 'prompt') return r([])
|
|
261
|
+
return r([{ char: '\n', type: 'update-command-edit' }])
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export const createWorkspaceEscape: KeyResult = r([{ type: 'close-modal' }], [], 'navigation')
|
|
265
|
+
|
|
266
|
+
export const openRenameSelectedProject: KeyResult = r(
|
|
277
267
|
[],
|
|
278
|
-
[{ type: 'open-rename-selected-
|
|
268
|
+
[{ type: 'open-rename-selected-project' }]
|
|
279
269
|
)
|
|
280
270
|
|
|
281
|
-
export const
|
|
271
|
+
export const deleteSelectedProject: KeyResult = r([], [{ type: 'delete-selected-project' }])
|
|
282
272
|
|
|
283
273
|
export const openSnippetEditor: KeyResult = r(
|
|
284
274
|
[{ type: 'open-snippet-editor' }],
|
|
@@ -329,20 +319,20 @@ export function previewTheme(delta: 1 | -1): KeyResult {
|
|
|
329
319
|
export const toggleTransparent: KeyResult = r([], [{ type: 'toggle-transparent' }])
|
|
330
320
|
export const toggleMode: KeyResult = r([], [{ type: 'toggle-mode' }])
|
|
331
321
|
|
|
332
|
-
export const switchField: KeyResult = r([{ type: 'switch-create-
|
|
322
|
+
export const switchField: KeyResult = r([{ type: 'switch-create-project-field' }])
|
|
333
323
|
export const selectDirectory: KeyResult = r([{ type: 'select-directory' }])
|
|
334
324
|
|
|
335
|
-
export const
|
|
336
|
-
[{ type: 'open-
|
|
325
|
+
export const backToProjectPicker: KeyResult = r(
|
|
326
|
+
[{ type: 'open-project-picker' }],
|
|
337
327
|
[],
|
|
338
|
-
'modal.
|
|
328
|
+
'modal.project-picker.filtering'
|
|
339
329
|
)
|
|
340
330
|
|
|
341
|
-
export const
|
|
342
|
-
if (ctx.state.modal.type === 'create-
|
|
331
|
+
export const createProjectEscape: ActionFn = (ctx: ModeContext) => {
|
|
332
|
+
if (ctx.state.modal.type === 'create-project' && !ctx.state.modal.returnToProjectPicker) {
|
|
343
333
|
return r([{ type: 'close-modal' }], [], 'navigation')
|
|
344
334
|
}
|
|
345
|
-
return r([{ type: 'open-
|
|
335
|
+
return r([{ type: 'open-project-picker' }], [], 'modal.project-picker.filtering')
|
|
346
336
|
}
|
|
347
337
|
|
|
348
338
|
export const backToSnippetPicker: KeyResult = r(
|
|
@@ -386,10 +376,10 @@ export const confirmUpdateSelection: KeyResult = r(
|
|
|
386
376
|
)
|
|
387
377
|
|
|
388
378
|
// ---------------------------------------------------------------------------
|
|
389
|
-
//
|
|
379
|
+
// Workspace-move modal
|
|
390
380
|
// ---------------------------------------------------------------------------
|
|
391
381
|
|
|
392
|
-
export const
|
|
382
|
+
export const openWorkspaceMove: ActionFn = (ctx: ModeContext) => {
|
|
393
383
|
if (ctx.state.gitMode.headOffset > 0) {
|
|
394
384
|
return r([
|
|
395
385
|
{
|
|
@@ -398,35 +388,35 @@ export const openWorktreeMove: ActionFn = (ctx: ModeContext) => {
|
|
|
398
388
|
},
|
|
399
389
|
])
|
|
400
390
|
}
|
|
401
|
-
const
|
|
402
|
-
const
|
|
403
|
-
// From git mode, the source is the active
|
|
404
|
-
const source =
|
|
391
|
+
const project = ctx.state.projects.find((entry) => entry.id === ctx.state.currentProjectId)
|
|
392
|
+
const workspaces = project?.workspaces ?? []
|
|
393
|
+
// From git mode, the source is the active workspace (the one being reviewed).
|
|
394
|
+
const source = workspaces.find((w) => w.id === project?.activeWorkspaceId) ?? workspaces[0]
|
|
405
395
|
const hasBranch = source != null && source.branch != null && source.branch !== ''
|
|
406
|
-
const others =
|
|
396
|
+
const others = workspaces.filter((w) => w.id !== source?.id)
|
|
407
397
|
if (!hasBranch || source == null || others.length < 1) {
|
|
408
|
-
return r([{ message: 'no other
|
|
398
|
+
return r([{ message: 'no other workspace to move into', type: 'git-mode-set-message' }])
|
|
409
399
|
}
|
|
410
400
|
// Overlay: no mode transition — deriveModeId routes input to the picker and
|
|
411
401
|
// focusMode stays 'git' so the git view remains mounted underneath.
|
|
412
402
|
return r(
|
|
413
|
-
[{
|
|
414
|
-
[{ type: 'load-
|
|
403
|
+
[{ sourceWorkspaceId: source.id, type: 'open-workspace-move-modal' }],
|
|
404
|
+
[{ type: 'load-workspace-move-stats' }]
|
|
415
405
|
)
|
|
416
406
|
}
|
|
417
407
|
|
|
418
|
-
export const
|
|
408
|
+
export const toggleWorkspaceMoveDelete: KeyResult = r([{ type: 'toggle-workspace-move-delete' }])
|
|
419
409
|
|
|
420
|
-
export const
|
|
410
|
+
export const confirmWorkspaceMove: ActionFn = (ctx: ModeContext) => {
|
|
421
411
|
const modal = ctx.state.modal
|
|
422
|
-
const
|
|
423
|
-
const
|
|
424
|
-
const sourceId = modal.type === '
|
|
425
|
-
const source =
|
|
426
|
-
const targets =
|
|
427
|
-
const selectedIndex = modal.type === '
|
|
412
|
+
const project = ctx.state.projects.find((entry) => entry.id === ctx.state.currentProjectId)
|
|
413
|
+
const workspaces = project?.workspaces ?? []
|
|
414
|
+
const sourceId = modal.type === 'workspace-move' ? modal.sourceWorkspaceId : undefined
|
|
415
|
+
const source = workspaces.find((w) => w.id === sourceId)
|
|
416
|
+
const targets = workspaces.filter((w) => w.id !== sourceId)
|
|
417
|
+
const selectedIndex = modal.type === 'workspace-move' ? modal.selectedIndex : 0
|
|
428
418
|
const target = targets[selectedIndex]
|
|
429
|
-
if (!target || !
|
|
419
|
+
if (!target || !project || !source || modal.type !== 'workspace-move') {
|
|
430
420
|
return r([{ type: 'close-modal' }])
|
|
431
421
|
}
|
|
432
422
|
// Overlay close keeps focusMode 'git' (see close-modal reducer), so the move
|
|
@@ -436,10 +426,10 @@ export const confirmWorktreeMove: ActionFn = (ctx: ModeContext) => {
|
|
|
436
426
|
[
|
|
437
427
|
{
|
|
438
428
|
deleteSource: modal.deleteSource,
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
type: 'move-
|
|
429
|
+
projectId: project.id,
|
|
430
|
+
sourceWorkspaceId: source.id,
|
|
431
|
+
targetWorkspaceId: target.id,
|
|
432
|
+
type: 'move-workspace',
|
|
443
433
|
},
|
|
444
434
|
]
|
|
445
435
|
)
|
|
@@ -447,18 +437,18 @@ export const confirmWorktreeMove: ActionFn = (ctx: ModeContext) => {
|
|
|
447
437
|
|
|
448
438
|
// Confirms the dialog opened after a recoverable move failure: re-runs the
|
|
449
439
|
// move with the flag matching the failure (stash the target / keep conflicts).
|
|
450
|
-
export const
|
|
440
|
+
export const confirmWorkspaceMoveRetry: ActionFn = (ctx: ModeContext) => {
|
|
451
441
|
const modal = ctx.state.modal
|
|
452
|
-
if (modal.type !== '
|
|
442
|
+
if (modal.type !== 'workspace-move-confirm') return null
|
|
453
443
|
return r(
|
|
454
444
|
[{ type: 'close-modal' }],
|
|
455
445
|
[
|
|
456
446
|
{
|
|
457
447
|
deleteSource: modal.deleteSource,
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
type: 'move-
|
|
448
|
+
projectId: modal.projectId,
|
|
449
|
+
sourceWorkspaceId: modal.sourceWorkspaceId,
|
|
450
|
+
targetWorkspaceId: modal.targetWorkspaceId,
|
|
451
|
+
type: 'move-workspace',
|
|
462
452
|
...(modal.variant === 'stash-target' ? { stashTarget: true } : { keepConflicts: true }),
|
|
463
453
|
},
|
|
464
454
|
],
|
|
@@ -480,9 +470,11 @@ export const closePane: ActionFn = (ctx: ModeContext) => {
|
|
|
480
470
|
}
|
|
481
471
|
|
|
482
472
|
// Navigation-specific dynamic actions
|
|
473
|
+
// Reveals whichever bar hosts the project list — it is not pinned to the left.
|
|
483
474
|
export const ctrlZSidebar: ActionFn = (ctx: ModeContext) => {
|
|
484
|
-
|
|
485
|
-
|
|
475
|
+
const side = ctx.state.bars.left.widgets.some((w) => w.id === 'projects') ? 'left' : 'right'
|
|
476
|
+
if (!ctx.state.bars[side].visible) {
|
|
477
|
+
return r([{ side, type: 'toggle-bar' }])
|
|
486
478
|
}
|
|
487
479
|
return r([])
|
|
488
480
|
}
|
|
@@ -498,23 +490,23 @@ export const leaveTerminalInput: KeyResult = r(
|
|
|
498
490
|
'navigation'
|
|
499
491
|
)
|
|
500
492
|
|
|
501
|
-
export const toggleSidebarFromInput: KeyResult =
|
|
493
|
+
export const toggleSidebarFromInput: KeyResult = toggleBar('left')
|
|
502
494
|
|
|
503
|
-
//
|
|
504
|
-
export const
|
|
495
|
+
// Project name modal
|
|
496
|
+
export const confirmProjectRename: ActionFn = (ctx: ModeContext) => {
|
|
505
497
|
const trimmed = (ctx.state.modal.editBuffer ?? '').trim()
|
|
506
|
-
const
|
|
498
|
+
const projectId = ctx.state.modal.projectTargetId
|
|
507
499
|
const returnToPicker =
|
|
508
|
-
ctx.state.modal.type === '
|
|
500
|
+
ctx.state.modal.type === 'project-name' ? ctx.state.modal.returnToProjectPicker : true
|
|
509
501
|
const closeAction: AppAction = returnToPicker
|
|
510
|
-
? { type: 'open-
|
|
502
|
+
? { type: 'open-project-picker' }
|
|
511
503
|
: { type: 'close-modal' }
|
|
512
504
|
const transition: KeyResult['transition'] = returnToPicker
|
|
513
|
-
? 'modal.
|
|
505
|
+
? 'modal.project-picker.filtering'
|
|
514
506
|
: 'navigation'
|
|
515
507
|
const effects: KeyResult['effects'] =
|
|
516
|
-
trimmed &&
|
|
517
|
-
? [{ name: trimmed,
|
|
508
|
+
trimmed && projectId != null && projectId !== ''
|
|
509
|
+
? [{ name: trimmed, projectId, type: 'rename-project' }]
|
|
518
510
|
: []
|
|
519
511
|
return r([closeAction], effects, transition)
|
|
520
512
|
}
|
|
@@ -522,7 +514,7 @@ export const confirmSessionRename: ActionFn = (ctx: ModeContext) => {
|
|
|
522
514
|
// Rename tab modal
|
|
523
515
|
export const confirmRenameTab: ActionFn = (ctx: ModeContext) => {
|
|
524
516
|
const trimmed = (ctx.state.modal.editBuffer ?? '').trim()
|
|
525
|
-
const tabId = ctx.state.modal.
|
|
517
|
+
const tabId = ctx.state.modal.projectTargetId
|
|
526
518
|
const actions: KeyResult['actions'] = []
|
|
527
519
|
const effects: KeyResult['effects'] = []
|
|
528
520
|
if (trimmed && tabId != null && tabId !== '') {
|
|
@@ -532,27 +524,33 @@ export const confirmRenameTab: ActionFn = (ctx: ModeContext) => {
|
|
|
532
524
|
return r(actions, effects, 'navigation')
|
|
533
525
|
}
|
|
534
526
|
|
|
535
|
-
// Rename
|
|
536
|
-
export const
|
|
527
|
+
// Rename workspace modal
|
|
528
|
+
export const confirmRenameWorkspace: ActionFn = (ctx: ModeContext) => {
|
|
537
529
|
const { modal } = ctx.state
|
|
538
530
|
const trimmed = (modal.editBuffer ?? '').trim()
|
|
539
|
-
const
|
|
540
|
-
const
|
|
531
|
+
const workspaceId = modal.projectTargetId
|
|
532
|
+
const projectId = modal.type === 'rename-workspace' ? modal.workspaceProjectId : null
|
|
541
533
|
const actions: KeyResult['actions'] = []
|
|
542
|
-
if (
|
|
534
|
+
if (
|
|
535
|
+
trimmed &&
|
|
536
|
+
workspaceId != null &&
|
|
537
|
+
workspaceId !== '' &&
|
|
538
|
+
projectId != null &&
|
|
539
|
+
projectId !== ''
|
|
540
|
+
) {
|
|
543
541
|
actions.push({
|
|
544
542
|
patch: { name: trimmed },
|
|
545
|
-
|
|
546
|
-
type: 'update-
|
|
547
|
-
|
|
543
|
+
projectId,
|
|
544
|
+
type: 'update-workspace-record',
|
|
545
|
+
workspaceId,
|
|
548
546
|
})
|
|
549
547
|
}
|
|
550
548
|
actions.push({ type: 'close-modal' })
|
|
551
549
|
return r(actions, [], 'navigation')
|
|
552
550
|
}
|
|
553
551
|
|
|
554
|
-
// Create
|
|
555
|
-
export const
|
|
552
|
+
// Create project modal
|
|
553
|
+
export const confirmCreateProject: ActionFn = (ctx: ModeContext) => {
|
|
556
554
|
const modal = ctx.state.modal as {
|
|
557
555
|
activeField?: string
|
|
558
556
|
editBuffer?: string
|
|
@@ -565,26 +563,26 @@ export const confirmCreateSession: ActionFn = (ctx: ModeContext) => {
|
|
|
565
563
|
|
|
566
564
|
const trimmed = (modal.editBuffer ?? '').trim()
|
|
567
565
|
const projectPath = modal.pendingProjectPath ?? undefined
|
|
568
|
-
const
|
|
569
|
-
if (
|
|
566
|
+
const projectName = trimmed || getDefaultProjectName(projectPath)
|
|
567
|
+
if (projectName) {
|
|
570
568
|
return r(
|
|
571
569
|
[{ type: 'close-modal' }],
|
|
572
|
-
[{ name:
|
|
570
|
+
[{ name: projectName, projectPath, type: 'create-project' }],
|
|
573
571
|
'navigation'
|
|
574
572
|
)
|
|
575
573
|
}
|
|
576
574
|
return r([{ type: 'close-modal' }], [], 'navigation')
|
|
577
575
|
}
|
|
578
576
|
|
|
579
|
-
function
|
|
577
|
+
function getDefaultProjectName(projectPath?: string): string {
|
|
580
578
|
if (!(projectPath != null && projectPath !== '')) return ''
|
|
581
579
|
const segments = projectPath.split('/').filter(Boolean)
|
|
582
580
|
return segments.at(-1) ?? ''
|
|
583
581
|
}
|
|
584
582
|
|
|
585
|
-
//
|
|
586
|
-
export const
|
|
587
|
-
if (!(ctx.state.
|
|
583
|
+
// Project picker escape (conditional)
|
|
584
|
+
export const projectPickerEscape: ActionFn = (ctx: ModeContext) => {
|
|
585
|
+
if (!(ctx.state.currentProjectId != null && ctx.state.currentProjectId !== '')) return null
|
|
588
586
|
return r([{ type: 'close-modal' }], [], 'navigation')
|
|
589
587
|
}
|
|
590
588
|
|
|
@@ -824,9 +822,9 @@ export const gitCommitOpen: ActionFn = (ctx: ModeContext) => {
|
|
|
824
822
|
},
|
|
825
823
|
])
|
|
826
824
|
}
|
|
827
|
-
const
|
|
825
|
+
const projectId = ctx.state.currentProjectId ?? undefined
|
|
828
826
|
return r(
|
|
829
|
-
[...clearPendingDelete(ctx), {
|
|
827
|
+
[...clearPendingDelete(ctx), { projectId, type: 'open-git-commit-modal' }],
|
|
830
828
|
[],
|
|
831
829
|
'modal.git-commit'
|
|
832
830
|
)
|
|
@@ -885,13 +883,13 @@ export const gitCommitEnterConfirm: ActionFn = (ctx: ModeContext) => {
|
|
|
885
883
|
if (hasTitle) {
|
|
886
884
|
return r([{ type: 'git-commit-enter-confirm' }], [], 'modal.git-commit.confirm')
|
|
887
885
|
}
|
|
888
|
-
const
|
|
889
|
-
if (!(
|
|
886
|
+
const projectId = ctx.state.currentProjectId
|
|
887
|
+
if (!(projectId != null && projectId !== '')) {
|
|
890
888
|
return r([{ type: 'git-commit-enter-confirm' }], [], 'modal.git-commit.confirm')
|
|
891
889
|
}
|
|
892
890
|
return r(
|
|
893
|
-
[{
|
|
894
|
-
[{
|
|
891
|
+
[{ projectId, type: 'git-commit-enter-generating' }],
|
|
892
|
+
[{ projectId, type: 'generate-auto-commit-now' }],
|
|
895
893
|
'modal.git-commit.generating'
|
|
896
894
|
)
|
|
897
895
|
}
|
|
@@ -903,10 +901,10 @@ export const gitCommitLeaveConfirm: KeyResult = r(
|
|
|
903
901
|
)
|
|
904
902
|
|
|
905
903
|
export const gitCommitLeaveGenerating: ActionFn = (ctx: ModeContext) => {
|
|
906
|
-
const
|
|
904
|
+
const projectId = ctx.state.currentProjectId
|
|
907
905
|
const actionsList: AppAction[] = [{ type: 'git-commit-leave-generating' }]
|
|
908
|
-
if (
|
|
909
|
-
actionsList.push({
|
|
906
|
+
if (projectId != null && projectId !== '') {
|
|
907
|
+
actionsList.push({ projectId, type: 'auto-commit-clear' })
|
|
910
908
|
}
|
|
911
909
|
return r(actionsList, [], 'modal.git-commit')
|
|
912
910
|
}
|
|
@@ -943,5 +941,105 @@ export const gitCommitReturnKey: ActionFn = (ctx: ModeContext) => {
|
|
|
943
941
|
if (modal.type === 'git-commit' && modal.activeField === 'body') {
|
|
944
942
|
return r([{ char: '\n', type: 'update-command-edit' }])
|
|
945
943
|
}
|
|
946
|
-
return r([{ type: 'switch-create-
|
|
944
|
+
return r([{ type: 'switch-create-project-field' }])
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
// ---------------------------------------------------------------------------
|
|
948
|
+
// Settings screen
|
|
949
|
+
// ---------------------------------------------------------------------------
|
|
950
|
+
|
|
951
|
+
export const enterSettings: KeyResult = r([{ type: 'enter-settings' }], [], 'settings')
|
|
952
|
+
export const exitSettings: KeyResult = r([{ type: 'exit-settings' }], [], 'navigation')
|
|
953
|
+
|
|
954
|
+
export function focusSettingsPane(pane: 'nav' | 'rows'): KeyResult {
|
|
955
|
+
return r([{ pane, type: 'settings-focus-pane' }])
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
export function moveSettingsSelection(delta: -1 | 1): KeyResult {
|
|
959
|
+
return r([{ delta, type: 'settings-move-selection' }])
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* One key for every kind of row: it toggles a checkbox, advances an enum, or runs
|
|
964
|
+
* whatever the row does. Which one is the row's business, not the keymap's — so
|
|
965
|
+
* there is no per-kind binding to keep in sync with the schema.
|
|
966
|
+
*/
|
|
967
|
+
export const activateSettingsRow: ActionFn = (ctx: ModeContext) => {
|
|
968
|
+
if (ctx.state.settings.pane !== 'rows') return r([{ pane: 'rows', type: 'settings-focus-pane' }])
|
|
969
|
+
return r([], [{ type: 'activate-settings-row' }])
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
export function adjustSettingsRow(delta: 1 | -1): KeyResult {
|
|
973
|
+
return r([], [{ delta, type: 'adjust-settings-row' }])
|
|
947
974
|
}
|
|
975
|
+
|
|
976
|
+
export const resetSettingsRow: KeyResult = r([], [{ type: 'reset-settings-row' }])
|
|
977
|
+
|
|
978
|
+
/**
|
|
979
|
+
* Closing a modal the settings screen opened. `closeModal` declares `navigation`,
|
|
980
|
+
* which is where every other modal goes and is not where these go — the screen is
|
|
981
|
+
* still drawn behind them, and `returnTo` puts the focus back on it.
|
|
982
|
+
*/
|
|
983
|
+
export const closeSettingsModal: KeyResult = r([{ type: 'close-modal' }], [], 'settings')
|
|
984
|
+
|
|
985
|
+
export const openSettingsSearch: KeyResult = r(
|
|
986
|
+
[{ type: 'open-settings-search' }],
|
|
987
|
+
[],
|
|
988
|
+
'modal.settings-search.filtering'
|
|
989
|
+
)
|
|
990
|
+
|
|
991
|
+
/** Jumps the screen to the highlighted setting, wherever it lives. */
|
|
992
|
+
export const confirmSettingsSearch: KeyResult = r(
|
|
993
|
+
[],
|
|
994
|
+
[{ type: 'confirm-settings-search' }],
|
|
995
|
+
'settings'
|
|
996
|
+
)
|
|
997
|
+
|
|
998
|
+
/**
|
|
999
|
+
* The value is carried in the effect rather than read from the store by it: the
|
|
1000
|
+
* `close-modal` action runs first and clears the buffer it would have read.
|
|
1001
|
+
*/
|
|
1002
|
+
export const confirmSettingText: ActionFn = (ctx: ModeContext) => {
|
|
1003
|
+
const modal = ctx.state.modal
|
|
1004
|
+
if (modal.type !== 'setting-text') return r([{ type: 'close-modal' }], [], 'settings')
|
|
1005
|
+
return r(
|
|
1006
|
+
[{ type: 'close-modal' }],
|
|
1007
|
+
[{ settingId: modal.settingId, type: 'commit-setting-text', value: modal.editBuffer ?? '' }],
|
|
1008
|
+
'settings'
|
|
1009
|
+
)
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
// ---------------------------------------------------------------------------
|
|
1013
|
+
// Deprecated aliases — 0.8.x names kept working for one release.
|
|
1014
|
+
//
|
|
1015
|
+
// The project/workspace/worktree rename moved every one of these. Aliases only
|
|
1016
|
+
// exist where the old name still has a target: `toggleNewTabWorktree`,
|
|
1017
|
+
// `deleteSelectedWorktree` and `confirmDeleteWorktree` were deleted outright
|
|
1018
|
+
// when <C-n> stopped creating worktrees, so a config referencing them is a
|
|
1019
|
+
// compile error on purpose.
|
|
1020
|
+
//
|
|
1021
|
+
// ponytail: drop these with the other rename shims.
|
|
1022
|
+
// ---------------------------------------------------------------------------
|
|
1023
|
+
|
|
1024
|
+
/** @deprecated renamed to `projectPicker`. */
|
|
1025
|
+
export const sessionPicker = projectPicker
|
|
1026
|
+
/** @deprecated renamed to `openCreateProjectModal`. */
|
|
1027
|
+
export const openCreateSessionModal = openCreateProjectModal
|
|
1028
|
+
/** @deprecated renamed to `createProjectEscape`. */
|
|
1029
|
+
export const createSessionEscape = createProjectEscape
|
|
1030
|
+
/** @deprecated renamed to `confirmCreateProject`. */
|
|
1031
|
+
export const confirmCreateSession = confirmCreateProject
|
|
1032
|
+
/** @deprecated renamed to `reorderProject`. */
|
|
1033
|
+
export const reorderSession = reorderProject
|
|
1034
|
+
/** @deprecated renamed to `switchProjectByIndex`. */
|
|
1035
|
+
export const switchSessionByIndex = switchProjectByIndex
|
|
1036
|
+
/** @deprecated renamed to `toggleProjectBar`. */
|
|
1037
|
+
export const toggleSessionBar = toggleProjectBar
|
|
1038
|
+
/** @deprecated renamed to `openWorkspaceMove`. */
|
|
1039
|
+
export const openWorktreeMove = openWorkspaceMove
|
|
1040
|
+
/** @deprecated renamed to `toggleWorkspaceMoveDelete`. */
|
|
1041
|
+
export const toggleWorktreeMoveDelete = toggleWorkspaceMoveDelete
|
|
1042
|
+
/** @deprecated renamed to `confirmWorkspaceMove`. */
|
|
1043
|
+
export const confirmWorktreeMove = confirmWorkspaceMove
|
|
1044
|
+
/** @deprecated renamed to `confirmWorkspaceDeleteModal`. */
|
|
1045
|
+
export const confirmWorktreeDeleteModal = confirmWorkspaceDeleteModal
|