ccmanager 0.1.14 → 0.1.15
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.
|
@@ -1,31 +1,32 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { Box, Text } from 'ink';
|
|
2
|
+
import { Box, Text, useInput } from 'ink';
|
|
3
3
|
import SelectInput from 'ink-select-input';
|
|
4
4
|
import ConfigureShortcuts from './ConfigureShortcuts.js';
|
|
5
5
|
import ConfigureHooks from './ConfigureHooks.js';
|
|
6
6
|
import ConfigureWorktree from './ConfigureWorktree.js';
|
|
7
7
|
import ConfigureCommand from './ConfigureCommand.js';
|
|
8
|
+
import { shortcutManager } from '../services/shortcutManager.js';
|
|
8
9
|
const Configuration = ({ onComplete }) => {
|
|
9
10
|
const [view, setView] = useState('menu');
|
|
10
11
|
const menuItems = [
|
|
11
12
|
{
|
|
12
|
-
label: '⌨ Configure Shortcuts',
|
|
13
|
+
label: 'S ⌨ Configure Shortcuts',
|
|
13
14
|
value: 'shortcuts',
|
|
14
15
|
},
|
|
15
16
|
{
|
|
16
|
-
label: '🔧 Configure Status Hooks',
|
|
17
|
+
label: 'H 🔧 Configure Status Hooks',
|
|
17
18
|
value: 'hooks',
|
|
18
19
|
},
|
|
19
20
|
{
|
|
20
|
-
label: '📁 Configure Worktree Settings',
|
|
21
|
+
label: 'W 📁 Configure Worktree Settings',
|
|
21
22
|
value: 'worktree',
|
|
22
23
|
},
|
|
23
24
|
{
|
|
24
|
-
label: '🚀 Configure Command',
|
|
25
|
+
label: 'C 🚀 Configure Command',
|
|
25
26
|
value: 'command',
|
|
26
27
|
},
|
|
27
28
|
{
|
|
28
|
-
label: '← Back to Main Menu',
|
|
29
|
+
label: 'B ← Back to Main Menu',
|
|
29
30
|
value: 'back',
|
|
30
31
|
},
|
|
31
32
|
];
|
|
@@ -49,6 +50,33 @@ const Configuration = ({ onComplete }) => {
|
|
|
49
50
|
const handleSubMenuComplete = () => {
|
|
50
51
|
setView('menu');
|
|
51
52
|
};
|
|
53
|
+
// Handle hotkeys (only when in menu view)
|
|
54
|
+
useInput((input, key) => {
|
|
55
|
+
if (view !== 'menu')
|
|
56
|
+
return; // Only handle hotkeys in menu view
|
|
57
|
+
const keyPressed = input.toLowerCase();
|
|
58
|
+
switch (keyPressed) {
|
|
59
|
+
case 's':
|
|
60
|
+
setView('shortcuts');
|
|
61
|
+
break;
|
|
62
|
+
case 'h':
|
|
63
|
+
setView('hooks');
|
|
64
|
+
break;
|
|
65
|
+
case 'w':
|
|
66
|
+
setView('worktree');
|
|
67
|
+
break;
|
|
68
|
+
case 'c':
|
|
69
|
+
setView('command');
|
|
70
|
+
break;
|
|
71
|
+
case 'b':
|
|
72
|
+
onComplete();
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
// Handle escape key
|
|
76
|
+
if (shortcutManager.matchesShortcut('cancel', input, key)) {
|
|
77
|
+
onComplete();
|
|
78
|
+
}
|
|
79
|
+
});
|
|
52
80
|
if (view === 'shortcuts') {
|
|
53
81
|
return React.createElement(ConfigureShortcuts, { onComplete: handleSubMenuComplete });
|
|
54
82
|
}
|
package/dist/components/Menu.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import { Box, Text } from 'ink';
|
|
2
|
+
import { Box, Text, useInput } from 'ink';
|
|
3
3
|
import SelectInput from 'ink-select-input';
|
|
4
4
|
import { WorktreeService } from '../services/worktreeService.js';
|
|
5
5
|
import { STATUS_ICONS, STATUS_LABELS, MENU_ICONS, getStatusDisplay, } from '../constants/statusIcons.js';
|
|
@@ -35,7 +35,7 @@ const Menu = ({ sessionManager, onSelectWorktree }) => {
|
|
|
35
35
|
}, [sessionManager]);
|
|
36
36
|
useEffect(() => {
|
|
37
37
|
// Build menu items
|
|
38
|
-
const menuItems = worktrees.map(wt => {
|
|
38
|
+
const menuItems = worktrees.map((wt, index) => {
|
|
39
39
|
const session = sessions.find(s => s.worktreePath === wt.path);
|
|
40
40
|
let status = '';
|
|
41
41
|
if (session) {
|
|
@@ -45,8 +45,10 @@ const Menu = ({ sessionManager, onSelectWorktree }) => {
|
|
|
45
45
|
? wt.branch.replace('refs/heads/', '')
|
|
46
46
|
: 'detached';
|
|
47
47
|
const isMain = wt.isMainWorktree ? ' (main)' : '';
|
|
48
|
+
// Only show numbers for first 10 worktrees (0-9)
|
|
49
|
+
const numberPrefix = index < 10 ? `${index} ❯ ` : '❯ ';
|
|
48
50
|
return {
|
|
49
|
-
label: `${branchName}${isMain}${status}`,
|
|
51
|
+
label: `${numberPrefix}${branchName}${isMain}${status}`,
|
|
50
52
|
value: wt.path,
|
|
51
53
|
worktree: wt,
|
|
52
54
|
};
|
|
@@ -57,27 +59,87 @@ const Menu = ({ sessionManager, onSelectWorktree }) => {
|
|
|
57
59
|
value: 'separator',
|
|
58
60
|
});
|
|
59
61
|
menuItems.push({
|
|
60
|
-
label:
|
|
62
|
+
label: `N ${MENU_ICONS.NEW_WORKTREE} New Worktree`,
|
|
61
63
|
value: 'new-worktree',
|
|
62
64
|
});
|
|
63
65
|
menuItems.push({
|
|
64
|
-
label:
|
|
66
|
+
label: `M ${MENU_ICONS.MERGE_WORKTREE} Merge Worktree`,
|
|
65
67
|
value: 'merge-worktree',
|
|
66
68
|
});
|
|
67
69
|
menuItems.push({
|
|
68
|
-
label:
|
|
70
|
+
label: `D ${MENU_ICONS.DELETE_WORKTREE} Delete Worktree`,
|
|
69
71
|
value: 'delete-worktree',
|
|
70
72
|
});
|
|
71
73
|
menuItems.push({
|
|
72
|
-
label:
|
|
74
|
+
label: `C ${MENU_ICONS.CONFIGURE_SHORTCUTS} Configuration`,
|
|
73
75
|
value: 'configuration',
|
|
74
76
|
});
|
|
75
77
|
menuItems.push({
|
|
76
|
-
label:
|
|
78
|
+
label: `Q ${MENU_ICONS.EXIT} Exit`,
|
|
77
79
|
value: 'exit',
|
|
78
80
|
});
|
|
79
81
|
setItems(menuItems);
|
|
80
82
|
}, [worktrees, sessions]);
|
|
83
|
+
// Handle hotkeys
|
|
84
|
+
useInput((input, _key) => {
|
|
85
|
+
const keyPressed = input.toLowerCase();
|
|
86
|
+
// Handle number keys 0-9 for worktree selection (first 10 only)
|
|
87
|
+
if (/^[0-9]$/.test(keyPressed)) {
|
|
88
|
+
const index = parseInt(keyPressed);
|
|
89
|
+
if (index < Math.min(10, worktrees.length) && worktrees[index]) {
|
|
90
|
+
onSelectWorktree(worktrees[index]);
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
switch (keyPressed) {
|
|
95
|
+
case 'n':
|
|
96
|
+
// Trigger new worktree action
|
|
97
|
+
onSelectWorktree({
|
|
98
|
+
path: '',
|
|
99
|
+
branch: '',
|
|
100
|
+
isMainWorktree: false,
|
|
101
|
+
hasSession: false,
|
|
102
|
+
});
|
|
103
|
+
break;
|
|
104
|
+
case 'm':
|
|
105
|
+
// Trigger merge worktree action
|
|
106
|
+
onSelectWorktree({
|
|
107
|
+
path: 'MERGE_WORKTREE',
|
|
108
|
+
branch: '',
|
|
109
|
+
isMainWorktree: false,
|
|
110
|
+
hasSession: false,
|
|
111
|
+
});
|
|
112
|
+
break;
|
|
113
|
+
case 'd':
|
|
114
|
+
// Trigger delete worktree action
|
|
115
|
+
onSelectWorktree({
|
|
116
|
+
path: 'DELETE_WORKTREE',
|
|
117
|
+
branch: '',
|
|
118
|
+
isMainWorktree: false,
|
|
119
|
+
hasSession: false,
|
|
120
|
+
});
|
|
121
|
+
break;
|
|
122
|
+
case 'c':
|
|
123
|
+
// Trigger configuration action
|
|
124
|
+
onSelectWorktree({
|
|
125
|
+
path: 'CONFIGURATION',
|
|
126
|
+
branch: '',
|
|
127
|
+
isMainWorktree: false,
|
|
128
|
+
hasSession: false,
|
|
129
|
+
});
|
|
130
|
+
break;
|
|
131
|
+
case 'q':
|
|
132
|
+
case 'x':
|
|
133
|
+
// Trigger exit action
|
|
134
|
+
onSelectWorktree({
|
|
135
|
+
path: 'EXIT_APPLICATION',
|
|
136
|
+
branch: '',
|
|
137
|
+
isMainWorktree: false,
|
|
138
|
+
hasSession: false,
|
|
139
|
+
});
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
81
143
|
const handleSelect = (item) => {
|
|
82
144
|
if (item.value === 'separator') {
|
|
83
145
|
// Do nothing for separator
|
|
@@ -151,6 +213,6 @@ const Menu = ({ sessionManager, onSelectWorktree }) => {
|
|
|
151
213
|
STATUS_ICONS.IDLE,
|
|
152
214
|
' ',
|
|
153
215
|
STATUS_LABELS.IDLE),
|
|
154
|
-
React.createElement(Text, { dimColor: true }, "Controls: \u2191\u2193 Navigate Enter Select"))));
|
|
216
|
+
React.createElement(Text, { dimColor: true }, "Controls: \u2191\u2193 Navigate Enter Select | Hotkeys: 0-9 Quick Select (first 10) N-New M-Merge D-Delete C-Config Q-Quit"))));
|
|
155
217
|
};
|
|
156
218
|
export default Menu;
|