Skip to content

Commit af08446

Browse files
authored
Merge pull request #184 from KubrickCode/develop/shlee/183
feat: add button sets feature
2 parents 20d8701 + 8b56171 commit af08446

32 files changed

+2497
-139
lines changed

.vscode/settings.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,5 +116,7 @@
116116
"icon": "$(refresh)",
117117
"color": "gray",
118118
"enabled": true
119-
}
119+
},
120+
"quickCommandButtons.buttonSets": [],
121+
"quickCommandButtons.activeSet": null
120122
}

CLAUDE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ The extension follows a **dependency injection pattern** with clear separation o
9191
- `TerminalManager`: Terminal creation and command execution
9292
- `ConfigManager`: Configuration reading/writing with 3-tier fallback (Local → Workspace → Global)
9393
- `ImportExportManager`: Configuration import/export with preview, conflict detection, and backup
94+
- `ButtonSetManager`: Button set CRUD, active set switching, per-scope storage
9495
4. **Providers** (`src/internal/providers/`):
9596
- `CommandTreeProvider`: Sidebar tree view data provider
9697
- `ConfigWebviewProvider`: React-based configuration UI host
@@ -185,6 +186,7 @@ src/
185186
status-bar-manager.ts # Status bar button lifecycle
186187
terminal-manager.ts # Terminal creation/execution
187188
import-export-manager.ts # Import/export with preview and conflict detection
189+
button-set-manager.ts # Button set management and switching
188190
providers/ # VS Code providers
189191
command-tree-provider.ts # Sidebar tree view
190192
webview-provider.ts # React configuration UI host

README.md

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ _Drag-and-drop configuration with real-time preview_
8989
- 🎨 **Color Picker**: Visual color selection for button customization
9090
- 🌐 **Multi-Language UI**: English and Korean interface support
9191
- 📦 **Import/Export**: Backup and restore configurations with conflict detection
92+
- 📂 **Button Sets**: Save and switch between different button configurations
9293

9394
## 🎯 Perfect For
9495

@@ -167,16 +168,18 @@ _Drag-and-drop configuration with real-time preview_
167168

168169
## 📖 Configuration Options
169170

170-
| Option | Type | Description |
171-
| -------------- | ------- | ----------------------------------------------- |
172-
| `name` | string | Button display name (supports `$(icon)` syntax) |
173-
| `command` | string | Command to execute |
174-
| `useVsCodeApi` | boolean | Use VS Code API instead of terminal |
175-
| `color` | string | Button color (hex, rgb, or CSS names) |
176-
| `shortcut` | string | Single character for quick access |
177-
| `terminalName` | string | Custom terminal session name |
178-
| `group` | array | Nested commands (supports infinite depth) |
179-
| `executeAll` | boolean | Run all group commands simultaneously |
171+
| Option | Type | Description |
172+
| -------------- | ------- | ------------------------------------------------- |
173+
| `name` | string | Button display name (supports `$(icon)` syntax) |
174+
| `command` | string | Command to execute |
175+
| `useVsCodeApi` | boolean | Use VS Code API instead of terminal |
176+
| `color` | string | Button color (hex, rgb, or CSS names) |
177+
| `shortcut` | string | Single character for quick access |
178+
| `terminalName` | string | Custom terminal session name |
179+
| `group` | array | Nested commands (supports infinite depth) |
180+
| `executeAll` | boolean | Run all group commands simultaneously |
181+
| `buttonSets` | array | Named button configurations for context switching |
182+
| `activeSet` | string | Currently active button set name (null = default) |
180183

181184
## ⚙️ Configuration Scope
182185

@@ -286,6 +289,7 @@ _Comprehensive sidebar panel for command management_
286289
| **Multi-Language Keyboards** | ✅ 15 languages (Korean, Japanese, Chinese, Hindi, etc.) | ❌ English only |
287290
| **Multi-Language UI** | ✅ English & Korean interface | ❌ English only |
288291
| **Import/Export** | ✅ Preview & conflict detection | ❌ Manual backup |
292+
| **Button Sets** | ✅ Save & switch configurations | ❌ Manual editing |
289293
| **Real-time Updates** | ✅ Instant configuration sync | ❌ Restart required |
290294

291295
## 🛠️ Commands Reference
@@ -295,6 +299,9 @@ _Comprehensive sidebar panel for command management_
295299
| `Quick Commands: Show All` | `Ctrl+Shift+;` | Open unified command palette |
296300
| `Quick Commands: Open Configuration UI` | - | Launch visual configuration editor |
297301
| `Quick Commands: Refresh Tree` | - | Reload tree view panel |
302+
| `Quick Commands: Switch Button Set` | - | Switch to a different button set |
303+
| `Quick Commands: Save Current as Set` | - | Save current buttons as a new set |
304+
| `Quick Commands: Delete Button Set` | - | Delete an existing button set |
298305

299306
## 📦 Installation
300307

l10n/bundle.l10n.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
{
2+
"action.delete": "Delete",
3+
"command.deleteButtonSet": "Delete Button Set",
4+
"command.saveAsButtonSet": "Save as Button Set",
5+
"command.switchButtonSet": "Switch Button Set",
26
"error.backupFailedAndImportCancelled": "Failed to create backup: {0}. Import cancelled for safety.",
7+
"error.buttonSetManagerNotAvailable": "Button set manager not available",
38
"error.communicationTimeout": "Communication with extension timed out. Please try again.",
49
"error.configSaveFailed": "Failed to save configuration",
510
"error.configScopeChangedSincePreview": "Configuration scope has changed since preview. Please re-preview the import.",
611
"error.contextRequired": "{0} must be used within a VscodeCommandProvider",
12+
"error.duplicateSetName": "A button set with name '{0}' already exists",
713
"error.duplicateShortcuts": "Duplicate shortcuts detected: {0}. Please ensure each shortcut is unique.",
814
"error.extensionError": "Extension error: {0}",
915
"error.importExportManagerNotAvailable": "Import/Export manager not available",
@@ -12,7 +18,22 @@
1218
"error.invalidImportConfirmationData": "Invalid import confirmation data. Please restart the import process from the preview dialog.",
1319
"error.invalidSetConfigData": "Invalid data for setConfig: data is not an array.",
1420
"error.noCommands": "No commands found",
21+
"error.setNameRequired": "Button set name is required",
1522
"error.unknownError": "Unknown error occurred",
23+
"info.buttonSet.clickToSwitch": "(Click to switch)",
24+
"info.buttonSet.confirmDelete": "Are you sure you want to delete the button set '{0}'?",
25+
"info.buttonSet.current": "(Current)",
26+
"info.buttonSet.currentSet": "Current Button Set: {0}",
27+
"info.buttonSet.default": "Default",
28+
"info.buttonSet.deleted": "Button set '{0}' deleted",
29+
"info.buttonSet.enterName": "Enter a name for the button set",
30+
"info.buttonSet.namePlaceholder": "e.g., Frontend, Backend, DevOps",
31+
"info.buttonSet.noSetsToDelete": "No button sets to delete",
32+
"info.buttonSet.saved": "Button set '{0}' saved successfully",
33+
"info.buttonSet.selectToDelete": "Select a button set to delete",
34+
"info.buttonSet.selectToSwitch": "Select a button set to switch to",
35+
"info.buttonSet.switchedTo": "Switched to button set: {0}",
36+
"info.buttonSet.tooltip": "Current Set: {0} (Click to switch)",
1637
"info.commandsCount": "{0} commands",
1738
"info.groupCommands": "{0} Commands",
1839
"info.quickCommands": "Quick Commands",

l10n/bundle.l10n.ko.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
{
2+
"action.delete": "삭제",
3+
"command.deleteButtonSet": "버튼 세트 삭제",
4+
"command.saveAsButtonSet": "버튼 세트로 저장",
5+
"command.switchButtonSet": "버튼 세트 전환",
26
"error.backupFailedAndImportCancelled": "백업 생성 실패: {0}. 안전을 위해 가져오기가 취소되었습니다.",
7+
"error.buttonSetManagerNotAvailable": "버튼 세트 관리자를 사용할 수 없습니다",
38
"error.communicationTimeout": "익스텐션과의 통신 시간이 초과되었습니다. 다시 시도해주세요.",
49
"error.configSaveFailed": "구성 저장 실패",
510
"error.configScopeChangedSincePreview": "미리보기 이후 구성 스코프가 변경되었습니다. 가져오기를 다시 미리보기 해주세요.",
611
"error.contextRequired": "{0}은(는) VscodeCommandProvider 내에서 사용해야 합니다",
12+
"error.duplicateSetName": "'{0}' 이름의 버튼 세트가 이미 존재합니다",
713
"error.duplicateShortcuts": "중복된 단축키 감지: {0}. 각 단축키가 고유한지 확인해주세요.",
814
"error.extensionError": "익스텐션 오류: {0}",
915
"error.importExportManagerNotAvailable": "가져오기/내보내기 관리자를 사용할 수 없습니다",
@@ -12,7 +18,22 @@
1218
"error.invalidImportConfirmationData": "잘못된 가져오기 확인 데이터입니다. 미리보기 대화상자에서 가져오기 프로세스를 다시 시작해주세요.",
1319
"error.invalidSetConfigData": "setConfig의 잘못된 데이터: 데이터가 배열이 아닙니다.",
1420
"error.noCommands": "명령을 찾을 수 없습니다",
21+
"error.setNameRequired": "버튼 세트 이름을 입력해주세요",
1522
"error.unknownError": "알 수 없는 오류가 발생했습니다",
23+
"info.buttonSet.clickToSwitch": "(클릭하여 전환)",
24+
"info.buttonSet.confirmDelete": "버튼 세트 '{0}'을(를) 삭제하시겠습니까?",
25+
"info.buttonSet.current": "(현재)",
26+
"info.buttonSet.currentSet": "현재 버튼 세트: {0}",
27+
"info.buttonSet.default": "기본",
28+
"info.buttonSet.deleted": "버튼 세트 '{0}'이(가) 삭제되었습니다",
29+
"info.buttonSet.enterName": "버튼 세트 이름을 입력하세요",
30+
"info.buttonSet.namePlaceholder": "예: Frontend, Backend, DevOps",
31+
"info.buttonSet.noSetsToDelete": "삭제할 버튼 세트가 없습니다",
32+
"info.buttonSet.saved": "버튼 세트 '{0}'이(가) 저장되었습니다",
33+
"info.buttonSet.selectToDelete": "삭제할 버튼 세트를 선택하세요",
34+
"info.buttonSet.selectToSwitch": "전환할 버튼 세트를 선택하세요",
35+
"info.buttonSet.switchedTo": "버튼 세트 전환됨: {0}",
36+
"info.buttonSet.tooltip": "현재 세트: {0} (클릭하여 전환)",
1637
"info.commandsCount": "{0}개 명령",
1738
"info.groupCommands": "{0}개 명령",
1839
"info.quickCommands": "빠른 명령",

package.json

Lines changed: 90 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,24 @@
7575
"title": "%command.importConfiguration%",
7676
"category": "%category.quickCommands%",
7777
"icon": "$(import)"
78+
},
79+
{
80+
"command": "quickCommandButtons.switchButtonSet",
81+
"title": "%command.switchButtonSet%",
82+
"category": "%category.quickCommands%",
83+
"icon": "$(layers)"
84+
},
85+
{
86+
"command": "quickCommandButtons.saveAsButtonSet",
87+
"title": "%command.saveAsButtonSet%",
88+
"category": "%category.quickCommands%",
89+
"icon": "$(save)"
90+
},
91+
{
92+
"command": "quickCommandButtons.deleteButtonSet",
93+
"title": "%command.deleteButtonSet%",
94+
"category": "%category.quickCommands%",
95+
"icon": "$(trash)"
7896
}
7997
],
8098
"viewsContainers": {
@@ -118,45 +136,12 @@
118136
"configuration": {
119137
"title": "%config.title%",
120138
"properties": {
121-
"quickCommandButtons.refreshButton": {
122-
"type": "object",
123-
"default": {
124-
"icon": "$(refresh)",
125-
"color": "#00BCD4",
126-
"enabled": true
127-
},
128-
"description": "%config.refreshButton.description%",
129-
"properties": {
130-
"icon": {
131-
"type": "string",
132-
"default": "$(refresh)",
133-
"description": "%config.refreshButton.icon.description%"
134-
},
135-
"color": {
136-
"type": "string",
137-
"default": "#00BCD4",
138-
"description": "%config.refreshButton.color.description%"
139-
},
140-
"enabled": {
141-
"type": "boolean",
142-
"default": true,
143-
"description": "%config.refreshButton.enabled.description%"
144-
}
145-
}
146-
},
147-
"quickCommandButtons.configurationTarget": {
148-
"type": "string",
149-
"enum": [
150-
"local",
151-
"workspace",
152-
"global"
153-
],
154-
"default": "workspace",
155-
"description": "%config.configurationTarget.description%",
156-
"enumDescriptions": [
157-
"%config.configurationTarget.local%",
158-
"%config.configurationTarget.workspace%",
159-
"%config.configurationTarget.global%"
139+
"quickCommandButtons.activeSet": {
140+
"default": null,
141+
"description": "%config.activeSet.description%",
142+
"type": [
143+
"string",
144+
"null"
160145
]
161146
},
162147
"quickCommandButtons.buttons": {
@@ -288,6 +273,72 @@
288273
}
289274
]
290275
}
276+
},
277+
"quickCommandButtons.buttonSets": {
278+
"default": [],
279+
"description": "%config.buttonSets.description%",
280+
"items": {
281+
"properties": {
282+
"buttons": {
283+
"description": "%config.buttonSets.buttons.description%",
284+
"items": {
285+
"$ref": "#/properties/quickCommandButtons.buttons/items"
286+
},
287+
"type": "array"
288+
},
289+
"name": {
290+
"description": "%config.buttonSets.name.description%",
291+
"type": "string"
292+
}
293+
},
294+
"required": [
295+
"buttons",
296+
"name"
297+
],
298+
"type": "object"
299+
},
300+
"type": "array"
301+
},
302+
"quickCommandButtons.configurationTarget": {
303+
"default": "workspace",
304+
"description": "%config.configurationTarget.description%",
305+
"enum": [
306+
"local",
307+
"workspace",
308+
"global"
309+
],
310+
"enumDescriptions": [
311+
"%config.configurationTarget.local%",
312+
"%config.configurationTarget.workspace%",
313+
"%config.configurationTarget.global%"
314+
],
315+
"type": "string"
316+
},
317+
"quickCommandButtons.refreshButton": {
318+
"default": {
319+
"color": "#00BCD4",
320+
"enabled": true,
321+
"icon": "$(refresh)"
322+
},
323+
"description": "%config.refreshButton.description%",
324+
"properties": {
325+
"color": {
326+
"default": "#00BCD4",
327+
"description": "%config.refreshButton.color.description%",
328+
"type": "string"
329+
},
330+
"enabled": {
331+
"default": true,
332+
"description": "%config.refreshButton.enabled.description%",
333+
"type": "boolean"
334+
},
335+
"icon": {
336+
"default": "$(refresh)",
337+
"description": "%config.refreshButton.icon.description%",
338+
"type": "string"
339+
}
340+
},
341+
"type": "object"
291342
}
292343
}
293344
}

package.nls.json

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,39 @@
11
{
2+
"category.quickCommands": "Quick Commands",
3+
"command.deleteButtonSet": "Delete Button Set",
4+
"command.executeFromTree": "Execute Command from Tree",
5+
"command.exportConfiguration": "Export Configuration",
6+
"command.importConfiguration": "Import Configuration",
7+
"command.openConfig": "Open Configuration UI",
28
"command.refresh": "Refresh Quick Command Buttons",
39
"command.refreshTree": "Refresh Tree View",
4-
"command.executeFromTree": "Execute Command from Tree",
10+
"command.saveAsButtonSet": "Save Current Buttons as Set",
511
"command.showAllCommands": "Show All Quick Commands",
6-
"command.openConfig": "Open Configuration UI",
12+
"command.switchButtonSet": "Switch Button Set",
713
"command.toggleConfigurationTarget": "Toggle Configuration Target (Workspace/Global)",
8-
"command.exportConfiguration": "Export Configuration",
9-
"command.importConfiguration": "Import Configuration",
10-
"category.quickCommands": "Quick Commands",
11-
"viewsContainer.title": "Quick Commands",
12-
"view.commands": "Commands",
13-
"config.title": "Quick Command Buttons",
14-
"config.refreshButton.description": "Configuration for the refresh button",
15-
"config.refreshButton.icon.description": "Icon for the refresh button (supports $(icon-name) syntax)",
16-
"config.refreshButton.color.description": "Color for the refresh button",
17-
"config.refreshButton.enabled.description": "Enable/disable the refresh button",
18-
"config.configurationTarget.description": "Where to save button configurations: 'local' saves to workspace state (Git-excluded), 'workspace' saves to .vscode/settings.json (project-specific), 'global' saves to user settings (shared across all projects)",
19-
"config.configurationTarget.local": "Save to workspace state (Git-excluded) - personal project commands",
20-
"config.configurationTarget.workspace": "Save to workspace settings (.vscode/settings.json) - project-specific commands",
21-
"config.configurationTarget.global": "Save to user settings - shared across all projects",
14+
"config.activeSet.description": "Currently active button set name (null uses default buttons)",
15+
"config.buttonSets.buttons.description": "Buttons in this set",
16+
"config.buttonSets.description": "Named button sets for quick context switching",
17+
"config.buttonSets.name.description": "Unique name for the button set",
18+
"config.buttons.color.description": "Button text color",
19+
"config.buttons.command.description": "Command to execute (for single buttons)",
2220
"config.buttons.description": "Configuration for quick command buttons",
21+
"config.buttons.executeAll.description": "Execute all commands in group simultaneously",
22+
"config.buttons.group.description": "Sub-commands for grouped buttons (supports infinite nesting)",
23+
"config.buttons.insertOnly.description": "Insert command into terminal without executing (user must press Enter manually)",
2324
"config.buttons.name.description": "Button label (supports $(icon-name) syntax)",
24-
"config.buttons.command.description": "Command to execute (for single buttons)",
25-
"config.buttons.useVsCodeApi.description": "Use VS Code API instead of terminal",
26-
"config.buttons.color.description": "Button text color",
2725
"config.buttons.shortcut.description": "Single key shortcut for quick access (e.g. 'q', '1', 'F1')",
2826
"config.buttons.terminalName.description": "Custom terminal name",
29-
"config.buttons.executeAll.description": "Execute all commands in group simultaneously",
30-
"config.buttons.group.description": "Sub-commands for grouped buttons (supports infinite nesting)",
31-
"config.buttons.insertOnly.description": "Insert command into terminal without executing (user must press Enter manually)"
27+
"config.buttons.useVsCodeApi.description": "Use VS Code API instead of terminal",
28+
"config.configurationTarget.description": "Where to save button configurations: 'local' saves to workspace state (Git-excluded), 'workspace' saves to .vscode/settings.json (project-specific), 'global' saves to user settings (shared across all projects)",
29+
"config.configurationTarget.global": "Save to user settings - shared across all projects",
30+
"config.configurationTarget.local": "Save to workspace state (Git-excluded) - personal project commands",
31+
"config.configurationTarget.workspace": "Save to workspace settings (.vscode/settings.json) - project-specific commands",
32+
"config.refreshButton.color.description": "Color for the refresh button",
33+
"config.refreshButton.description": "Configuration for the refresh button",
34+
"config.refreshButton.enabled.description": "Enable/disable the refresh button",
35+
"config.refreshButton.icon.description": "Icon for the refresh button (supports $(icon-name) syntax)",
36+
"config.title": "Quick Command Buttons",
37+
"view.commands": "Commands",
38+
"viewsContainer.title": "Quick Commands"
3239
}

0 commit comments

Comments
 (0)