detached e787fc1

feat(usecase): add keybindings port types and use cases

commit
e787fc17b8b62888ae0039071c3df6689f654eef
author
bnema · · 2026-01-11 14:21 UTC
committer
brice · · 2026-01-24 06:22 UTC
parent
d701001
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
5 files · +828 -0
M .mockery.yaml +2 -0
@@ -27,6 +27,8 @@ packages:
2727 FocusedInputProvider: {}
2828 AccentPickerUI: {}
2929 FontDetector: {}
30+ KeybindingsProvider: {}
31+ KeybindingsSaver: {}
3032 github.com/bnema/dumber/internal/domain/repository:
3133 config:
3234 dir: '{{.InterfaceDir}}/mocks'
@@ -27,6 +27,8 @@ packages:
27 FocusedInputProvider: {}27 FocusedInputProvider: {}
28 AccentPickerUI: {}28 AccentPickerUI: {}
29 FontDetector: {}29 FontDetector: {}
30+ KeybindingsProvider: {}
31+ KeybindingsSaver: {}
30 github.com/bnema/dumber/internal/domain/repository:32 github.com/bnema/dumber/internal/domain/repository:
31 config:33 config:
32 dir: '{{.InterfaceDir}}/mocks'34 dir: '{{.InterfaceDir}}/mocks'
A internal/application/port/keybindings.go +60 -0
@@ -0,0 +1,60 @@
1+package port
2+
3+import "context"
4+
5+// KeybindingEntry represents a single keybinding for the UI.
6+type KeybindingEntry struct {
7+ Action string `json:"action"`
8+ Description string `json:"description"`
9+ Keys []string `json:"keys"`
10+ DefaultKeys []string `json:"default_keys"`
11+ IsCustom bool `json:"is_custom"`
12+}
13+
14+// KeybindingGroup represents keybindings for a mode.
15+type KeybindingGroup struct {
16+ Mode string `json:"mode"`
17+ DisplayName string `json:"display_name"`
18+ Bindings []KeybindingEntry `json:"bindings"`
19+ Activation string `json:"activation,omitempty"`
20+}
21+
22+// KeybindingsConfig represents all keybindings for the UI.
23+type KeybindingsConfig struct {
24+ Groups []KeybindingGroup `json:"groups"`
25+}
26+
27+// SetKeybindingRequest represents a request to update a keybinding.
28+type SetKeybindingRequest struct {
29+ RequestID string `json:"requestId"`
30+ Mode string `json:"mode"`
31+ Action string `json:"action"`
32+ Keys []string `json:"keys"`
33+}
34+
35+// ResetKeybindingRequest represents a request to reset a keybinding.
36+type ResetKeybindingRequest struct {
37+ RequestID string `json:"requestId"`
38+ Mode string `json:"mode"`
39+ Action string `json:"action"`
40+}
41+
42+// KeybindingConflict represents a detected conflict.
43+type KeybindingConflict struct {
44+ ConflictingAction string `json:"conflicting_action"`
45+ ConflictingMode string `json:"conflicting_mode"`
46+ Key string `json:"key"`
47+}
48+
49+// KeybindingsProvider provides keybinding configuration data.
50+type KeybindingsProvider interface {
51+ GetKeybindings(ctx context.Context) (KeybindingsConfig, error)
52+ GetDefaultKeybindings(ctx context.Context) (KeybindingsConfig, error)
53+}
54+
55+// KeybindingsSaver persists keybinding changes.
56+type KeybindingsSaver interface {
57+ SetKeybinding(ctx context.Context, req SetKeybindingRequest) error
58+ ResetKeybinding(ctx context.Context, req ResetKeybindingRequest) error
59+ ResetAllKeybindings(ctx context.Context) error
60+}
@@ -0,0 +1,60 @@
1+package port
2+
3+import "context"
4+
5+// KeybindingEntry represents a single keybinding for the UI.
6+type KeybindingEntry struct {
7+ Action string `json:"action"`
8+ Description string `json:"description"`
9+ Keys []string `json:"keys"`
10+ DefaultKeys []string `json:"default_keys"`
11+ IsCustom bool `json:"is_custom"`
12+}
13+
14+// KeybindingGroup represents keybindings for a mode.
15+type KeybindingGroup struct {
16+ Mode string `json:"mode"`
17+ DisplayName string `json:"display_name"`
18+ Bindings []KeybindingEntry `json:"bindings"`
19+ Activation string `json:"activation,omitempty"`
20+}
21+
22+// KeybindingsConfig represents all keybindings for the UI.
23+type KeybindingsConfig struct {
24+ Groups []KeybindingGroup `json:"groups"`
25+}
26+
27+// SetKeybindingRequest represents a request to update a keybinding.
28+type SetKeybindingRequest struct {
29+ RequestID string `json:"requestId"`
30+ Mode string `json:"mode"`
31+ Action string `json:"action"`
32+ Keys []string `json:"keys"`
33+}
34+
35+// ResetKeybindingRequest represents a request to reset a keybinding.
36+type ResetKeybindingRequest struct {
37+ RequestID string `json:"requestId"`
38+ Mode string `json:"mode"`
39+ Action string `json:"action"`
40+}
41+
42+// KeybindingConflict represents a detected conflict.
43+type KeybindingConflict struct {
44+ ConflictingAction string `json:"conflicting_action"`
45+ ConflictingMode string `json:"conflicting_mode"`
46+ Key string `json:"key"`
47+}
48+
49+// KeybindingsProvider provides keybinding configuration data.
50+type KeybindingsProvider interface {
51+ GetKeybindings(ctx context.Context) (KeybindingsConfig, error)
52+ GetDefaultKeybindings(ctx context.Context) (KeybindingsConfig, error)
53+}
54+
55+// KeybindingsSaver persists keybinding changes.
56+type KeybindingsSaver interface {
57+ SetKeybinding(ctx context.Context, req SetKeybindingRequest) error
58+ ResetKeybinding(ctx context.Context, req ResetKeybindingRequest) error
59+ ResetAllKeybindings(ctx context.Context) error
60+}
M internal/application/port/mocks/mocks.go +339 -0
@@ -1495,6 +1495,345 @@ func (_c *MockHardwareSurveyor_Survey_Call) RunAndReturn(run func(ctx context.Co
14951495 return _c
14961496 }
14971497
1498+// NewMockKeybindingsProvider creates a new instance of MockKeybindingsProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
1499+// The first argument is typically a *testing.T value.
1500+func NewMockKeybindingsProvider(t interface {
1501+ mock.TestingT
1502+ Cleanup(func())
1503+}) *MockKeybindingsProvider {
1504+ mock := &MockKeybindingsProvider{}
1505+ mock.Mock.Test(t)
1506+
1507+ t.Cleanup(func() { mock.AssertExpectations(t) })
1508+
1509+ return mock
1510+}
1511+
1512+// MockKeybindingsProvider is an autogenerated mock type for the KeybindingsProvider type
1513+type MockKeybindingsProvider struct {
1514+ mock.Mock
1515+}
1516+
1517+type MockKeybindingsProvider_Expecter struct {
1518+ mock *mock.Mock
1519+}
1520+
1521+func (_m *MockKeybindingsProvider) EXPECT() *MockKeybindingsProvider_Expecter {
1522+ return &MockKeybindingsProvider_Expecter{mock: &_m.Mock}
1523+}
1524+
1525+// GetDefaultKeybindings provides a mock function for the type MockKeybindingsProvider
1526+func (_mock *MockKeybindingsProvider) GetDefaultKeybindings(ctx context.Context) (port.KeybindingsConfig, error) {
1527+ ret := _mock.Called(ctx)
1528+
1529+ if len(ret) == 0 {
1530+ panic("no return value specified for GetDefaultKeybindings")
1531+ }
1532+
1533+ var r0 port.KeybindingsConfig
1534+ var r1 error
1535+ if returnFunc, ok := ret.Get(0).(func(context.Context) (port.KeybindingsConfig, error)); ok {
1536+ return returnFunc(ctx)
1537+ }
1538+ if returnFunc, ok := ret.Get(0).(func(context.Context) port.KeybindingsConfig); ok {
1539+ r0 = returnFunc(ctx)
1540+ } else {
1541+ r0 = ret.Get(0).(port.KeybindingsConfig)
1542+ }
1543+ if returnFunc, ok := ret.Get(1).(func(context.Context) error); ok {
1544+ r1 = returnFunc(ctx)
1545+ } else {
1546+ r1 = ret.Error(1)
1547+ }
1548+ return r0, r1
1549+}
1550+
1551+// MockKeybindingsProvider_GetDefaultKeybindings_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDefaultKeybindings'
1552+type MockKeybindingsProvider_GetDefaultKeybindings_Call struct {
1553+ *mock.Call
1554+}
1555+
1556+// GetDefaultKeybindings is a helper method to define mock.On call
1557+// - ctx context.Context
1558+func (_e *MockKeybindingsProvider_Expecter) GetDefaultKeybindings(ctx interface{}) *MockKeybindingsProvider_GetDefaultKeybindings_Call {
1559+ return &MockKeybindingsProvider_GetDefaultKeybindings_Call{Call: _e.mock.On("GetDefaultKeybindings", ctx)}
1560+}
1561+
1562+func (_c *MockKeybindingsProvider_GetDefaultKeybindings_Call) Run(run func(ctx context.Context)) *MockKeybindingsProvider_GetDefaultKeybindings_Call {
1563+ _c.Call.Run(func(args mock.Arguments) {
1564+ var arg0 context.Context
1565+ if args[0] != nil {
1566+ arg0 = args[0].(context.Context)
1567+ }
1568+ run(
1569+ arg0,
1570+ )
1571+ })
1572+ return _c
1573+}
1574+
1575+func (_c *MockKeybindingsProvider_GetDefaultKeybindings_Call) Return(keybindingsConfig port.KeybindingsConfig, err error) *MockKeybindingsProvider_GetDefaultKeybindings_Call {
1576+ _c.Call.Return(keybindingsConfig, err)
1577+ return _c
1578+}
1579+
1580+func (_c *MockKeybindingsProvider_GetDefaultKeybindings_Call) RunAndReturn(run func(ctx context.Context) (port.KeybindingsConfig, error)) *MockKeybindingsProvider_GetDefaultKeybindings_Call {
1581+ _c.Call.Return(run)
1582+ return _c
1583+}
1584+
1585+// GetKeybindings provides a mock function for the type MockKeybindingsProvider
1586+func (_mock *MockKeybindingsProvider) GetKeybindings(ctx context.Context) (port.KeybindingsConfig, error) {
1587+ ret := _mock.Called(ctx)
1588+
1589+ if len(ret) == 0 {
1590+ panic("no return value specified for GetKeybindings")
1591+ }
1592+
1593+ var r0 port.KeybindingsConfig
1594+ var r1 error
1595+ if returnFunc, ok := ret.Get(0).(func(context.Context) (port.KeybindingsConfig, error)); ok {
1596+ return returnFunc(ctx)
1597+ }
1598+ if returnFunc, ok := ret.Get(0).(func(context.Context) port.KeybindingsConfig); ok {
1599+ r0 = returnFunc(ctx)
1600+ } else {
1601+ r0 = ret.Get(0).(port.KeybindingsConfig)
1602+ }
1603+ if returnFunc, ok := ret.Get(1).(func(context.Context) error); ok {
1604+ r1 = returnFunc(ctx)
1605+ } else {
1606+ r1 = ret.Error(1)
1607+ }
1608+ return r0, r1
1609+}
1610+
1611+// MockKeybindingsProvider_GetKeybindings_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetKeybindings'
1612+type MockKeybindingsProvider_GetKeybindings_Call struct {
1613+ *mock.Call
1614+}
1615+
1616+// GetKeybindings is a helper method to define mock.On call
1617+// - ctx context.Context
1618+func (_e *MockKeybindingsProvider_Expecter) GetKeybindings(ctx interface{}) *MockKeybindingsProvider_GetKeybindings_Call {
1619+ return &MockKeybindingsProvider_GetKeybindings_Call{Call: _e.mock.On("GetKeybindings", ctx)}
1620+}
1621+
1622+func (_c *MockKeybindingsProvider_GetKeybindings_Call) Run(run func(ctx context.Context)) *MockKeybindingsProvider_GetKeybindings_Call {
1623+ _c.Call.Run(func(args mock.Arguments) {
1624+ var arg0 context.Context
1625+ if args[0] != nil {
1626+ arg0 = args[0].(context.Context)
1627+ }
1628+ run(
1629+ arg0,
1630+ )
1631+ })
1632+ return _c
1633+}
1634+
1635+func (_c *MockKeybindingsProvider_GetKeybindings_Call) Return(keybindingsConfig port.KeybindingsConfig, err error) *MockKeybindingsProvider_GetKeybindings_Call {
1636+ _c.Call.Return(keybindingsConfig, err)
1637+ return _c
1638+}
1639+
1640+func (_c *MockKeybindingsProvider_GetKeybindings_Call) RunAndReturn(run func(ctx context.Context) (port.KeybindingsConfig, error)) *MockKeybindingsProvider_GetKeybindings_Call {
1641+ _c.Call.Return(run)
1642+ return _c
1643+}
1644+
1645+// NewMockKeybindingsSaver creates a new instance of MockKeybindingsSaver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
1646+// The first argument is typically a *testing.T value.
1647+func NewMockKeybindingsSaver(t interface {
1648+ mock.TestingT
1649+ Cleanup(func())
1650+}) *MockKeybindingsSaver {
1651+ mock := &MockKeybindingsSaver{}
1652+ mock.Mock.Test(t)
1653+
1654+ t.Cleanup(func() { mock.AssertExpectations(t) })
1655+
1656+ return mock
1657+}
1658+
1659+// MockKeybindingsSaver is an autogenerated mock type for the KeybindingsSaver type
1660+type MockKeybindingsSaver struct {
1661+ mock.Mock
1662+}
1663+
1664+type MockKeybindingsSaver_Expecter struct {
1665+ mock *mock.Mock
1666+}
1667+
1668+func (_m *MockKeybindingsSaver) EXPECT() *MockKeybindingsSaver_Expecter {
1669+ return &MockKeybindingsSaver_Expecter{mock: &_m.Mock}
1670+}
1671+
1672+// ResetAllKeybindings provides a mock function for the type MockKeybindingsSaver
1673+func (_mock *MockKeybindingsSaver) ResetAllKeybindings(ctx context.Context) error {
1674+ ret := _mock.Called(ctx)
1675+
1676+ if len(ret) == 0 {
1677+ panic("no return value specified for ResetAllKeybindings")
1678+ }
1679+
1680+ var r0 error
1681+ if returnFunc, ok := ret.Get(0).(func(context.Context) error); ok {
1682+ r0 = returnFunc(ctx)
1683+ } else {
1684+ r0 = ret.Error(0)
1685+ }
1686+ return r0
1687+}
1688+
1689+// MockKeybindingsSaver_ResetAllKeybindings_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResetAllKeybindings'
1690+type MockKeybindingsSaver_ResetAllKeybindings_Call struct {
1691+ *mock.Call
1692+}
1693+
1694+// ResetAllKeybindings is a helper method to define mock.On call
1695+// - ctx context.Context
1696+func (_e *MockKeybindingsSaver_Expecter) ResetAllKeybindings(ctx interface{}) *MockKeybindingsSaver_ResetAllKeybindings_Call {
1697+ return &MockKeybindingsSaver_ResetAllKeybindings_Call{Call: _e.mock.On("ResetAllKeybindings", ctx)}
1698+}
1699+
1700+func (_c *MockKeybindingsSaver_ResetAllKeybindings_Call) Run(run func(ctx context.Context)) *MockKeybindingsSaver_ResetAllKeybindings_Call {
1701+ _c.Call.Run(func(args mock.Arguments) {
1702+ var arg0 context.Context
1703+ if args[0] != nil {
1704+ arg0 = args[0].(context.Context)
1705+ }
1706+ run(
1707+ arg0,
1708+ )
1709+ })
1710+ return _c
1711+}
1712+
1713+func (_c *MockKeybindingsSaver_ResetAllKeybindings_Call) Return(err error) *MockKeybindingsSaver_ResetAllKeybindings_Call {
1714+ _c.Call.Return(err)
1715+ return _c
1716+}
1717+
1718+func (_c *MockKeybindingsSaver_ResetAllKeybindings_Call) RunAndReturn(run func(ctx context.Context) error) *MockKeybindingsSaver_ResetAllKeybindings_Call {
1719+ _c.Call.Return(run)
1720+ return _c
1721+}
1722+
1723+// ResetKeybinding provides a mock function for the type MockKeybindingsSaver
1724+func (_mock *MockKeybindingsSaver) ResetKeybinding(ctx context.Context, req port.ResetKeybindingRequest) error {
1725+ ret := _mock.Called(ctx, req)
1726+
1727+ if len(ret) == 0 {
1728+ panic("no return value specified for ResetKeybinding")
1729+ }
1730+
1731+ var r0 error
1732+ if returnFunc, ok := ret.Get(0).(func(context.Context, port.ResetKeybindingRequest) error); ok {
1733+ r0 = returnFunc(ctx, req)
1734+ } else {
1735+ r0 = ret.Error(0)
1736+ }
1737+ return r0
1738+}
1739+
1740+// MockKeybindingsSaver_ResetKeybinding_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResetKeybinding'
1741+type MockKeybindingsSaver_ResetKeybinding_Call struct {
1742+ *mock.Call
1743+}
1744+
1745+// ResetKeybinding is a helper method to define mock.On call
1746+// - ctx context.Context
1747+// - req port.ResetKeybindingRequest
1748+func (_e *MockKeybindingsSaver_Expecter) ResetKeybinding(ctx interface{}, req interface{}) *MockKeybindingsSaver_ResetKeybinding_Call {
1749+ return &MockKeybindingsSaver_ResetKeybinding_Call{Call: _e.mock.On("ResetKeybinding", ctx, req)}
1750+}
1751+
1752+func (_c *MockKeybindingsSaver_ResetKeybinding_Call) Run(run func(ctx context.Context, req port.ResetKeybindingRequest)) *MockKeybindingsSaver_ResetKeybinding_Call {
1753+ _c.Call.Run(func(args mock.Arguments) {
1754+ var arg0 context.Context
1755+ if args[0] != nil {
1756+ arg0 = args[0].(context.Context)
1757+ }
1758+ var arg1 port.ResetKeybindingRequest
1759+ if args[1] != nil {
1760+ arg1 = args[1].(port.ResetKeybindingRequest)
1761+ }
1762+ run(
1763+ arg0,
1764+ arg1,
1765+ )
1766+ })
1767+ return _c
1768+}
1769+
1770+func (_c *MockKeybindingsSaver_ResetKeybinding_Call) Return(err error) *MockKeybindingsSaver_ResetKeybinding_Call {
1771+ _c.Call.Return(err)
1772+ return _c
1773+}
1774+
1775+func (_c *MockKeybindingsSaver_ResetKeybinding_Call) RunAndReturn(run func(ctx context.Context, req port.ResetKeybindingRequest) error) *MockKeybindingsSaver_ResetKeybinding_Call {
1776+ _c.Call.Return(run)
1777+ return _c
1778+}
1779+
1780+// SetKeybinding provides a mock function for the type MockKeybindingsSaver
1781+func (_mock *MockKeybindingsSaver) SetKeybinding(ctx context.Context, req port.SetKeybindingRequest) error {
1782+ ret := _mock.Called(ctx, req)
1783+
1784+ if len(ret) == 0 {
1785+ panic("no return value specified for SetKeybinding")
1786+ }
1787+
1788+ var r0 error
1789+ if returnFunc, ok := ret.Get(0).(func(context.Context, port.SetKeybindingRequest) error); ok {
1790+ r0 = returnFunc(ctx, req)
1791+ } else {
1792+ r0 = ret.Error(0)
1793+ }
1794+ return r0
1795+}
1796+
1797+// MockKeybindingsSaver_SetKeybinding_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetKeybinding'
1798+type MockKeybindingsSaver_SetKeybinding_Call struct {
1799+ *mock.Call
1800+}
1801+
1802+// SetKeybinding is a helper method to define mock.On call
1803+// - ctx context.Context
1804+// - req port.SetKeybindingRequest
1805+func (_e *MockKeybindingsSaver_Expecter) SetKeybinding(ctx interface{}, req interface{}) *MockKeybindingsSaver_SetKeybinding_Call {
1806+ return &MockKeybindingsSaver_SetKeybinding_Call{Call: _e.mock.On("SetKeybinding", ctx, req)}
1807+}
1808+
1809+func (_c *MockKeybindingsSaver_SetKeybinding_Call) Run(run func(ctx context.Context, req port.SetKeybindingRequest)) *MockKeybindingsSaver_SetKeybinding_Call {
1810+ _c.Call.Run(func(args mock.Arguments) {
1811+ var arg0 context.Context
1812+ if args[0] != nil {
1813+ arg0 = args[0].(context.Context)
1814+ }
1815+ var arg1 port.SetKeybindingRequest
1816+ if args[1] != nil {
1817+ arg1 = args[1].(port.SetKeybindingRequest)
1818+ }
1819+ run(
1820+ arg0,
1821+ arg1,
1822+ )
1823+ })
1824+ return _c
1825+}
1826+
1827+func (_c *MockKeybindingsSaver_SetKeybinding_Call) Return(err error) *MockKeybindingsSaver_SetKeybinding_Call {
1828+ _c.Call.Return(err)
1829+ return _c
1830+}
1831+
1832+func (_c *MockKeybindingsSaver_SetKeybinding_Call) RunAndReturn(run func(ctx context.Context, req port.SetKeybindingRequest) error) *MockKeybindingsSaver_SetKeybinding_Call {
1833+ _c.Call.Return(run)
1834+ return _c
1835+}
1836+
14981837 // NewMockSessionLogger creates a new instance of MockSessionLogger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
14991838 // The first argument is typically a *testing.T value.
15001839 func NewMockSessionLogger(t interface {
@@ -1495,6 +1495,345 @@ func (_c *MockHardwareSurveyor_Survey_Call) RunAndReturn(run func(ctx context.Co
1495 return _c1495 return _c
1496 }1496 }
1497 1497
1498+// NewMockKeybindingsProvider creates a new instance of MockKeybindingsProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
1499+// The first argument is typically a *testing.T value.
1500+func NewMockKeybindingsProvider(t interface {
1501+ mock.TestingT
1502+ Cleanup(func())
1503+}) *MockKeybindingsProvider {
1504+ mock := &MockKeybindingsProvider{}
1505+ mock.Mock.Test(t)
1506+
1507+ t.Cleanup(func() { mock.AssertExpectations(t) })
1508+
1509+ return mock
1510+}
1511+
1512+// MockKeybindingsProvider is an autogenerated mock type for the KeybindingsProvider type
1513+type MockKeybindingsProvider struct {
1514+ mock.Mock
1515+}
1516+
1517+type MockKeybindingsProvider_Expecter struct {
1518+ mock *mock.Mock
1519+}
1520+
1521+func (_m *MockKeybindingsProvider) EXPECT() *MockKeybindingsProvider_Expecter {
1522+ return &MockKeybindingsProvider_Expecter{mock: &_m.Mock}
1523+}
1524+
1525+// GetDefaultKeybindings provides a mock function for the type MockKeybindingsProvider
1526+func (_mock *MockKeybindingsProvider) GetDefaultKeybindings(ctx context.Context) (port.KeybindingsConfig, error) {
1527+ ret := _mock.Called(ctx)
1528+
1529+ if len(ret) == 0 {
1530+ panic("no return value specified for GetDefaultKeybindings")
1531+ }
1532+
1533+ var r0 port.KeybindingsConfig
1534+ var r1 error
1535+ if returnFunc, ok := ret.Get(0).(func(context.Context) (port.KeybindingsConfig, error)); ok {
1536+ return returnFunc(ctx)
1537+ }
1538+ if returnFunc, ok := ret.Get(0).(func(context.Context) port.KeybindingsConfig); ok {
1539+ r0 = returnFunc(ctx)
1540+ } else {
1541+ r0 = ret.Get(0).(port.KeybindingsConfig)
1542+ }
1543+ if returnFunc, ok := ret.Get(1).(func(context.Context) error); ok {
1544+ r1 = returnFunc(ctx)
1545+ } else {
1546+ r1 = ret.Error(1)
1547+ }
1548+ return r0, r1
1549+}
1550+
1551+// MockKeybindingsProvider_GetDefaultKeybindings_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDefaultKeybindings'
1552+type MockKeybindingsProvider_GetDefaultKeybindings_Call struct {
1553+ *mock.Call
1554+}
1555+
1556+// GetDefaultKeybindings is a helper method to define mock.On call
1557+// - ctx context.Context
1558+func (_e *MockKeybindingsProvider_Expecter) GetDefaultKeybindings(ctx interface{}) *MockKeybindingsProvider_GetDefaultKeybindings_Call {
1559+ return &MockKeybindingsProvider_GetDefaultKeybindings_Call{Call: _e.mock.On("GetDefaultKeybindings", ctx)}
1560+}
1561+
1562+func (_c *MockKeybindingsProvider_GetDefaultKeybindings_Call) Run(run func(ctx context.Context)) *MockKeybindingsProvider_GetDefaultKeybindings_Call {
1563+ _c.Call.Run(func(args mock.Arguments) {
1564+ var arg0 context.Context
1565+ if args[0] != nil {
1566+ arg0 = args[0].(context.Context)
1567+ }
1568+ run(
1569+ arg0,
1570+ )
1571+ })
1572+ return _c
1573+}
1574+
1575+func (_c *MockKeybindingsProvider_GetDefaultKeybindings_Call) Return(keybindingsConfig port.KeybindingsConfig, err error) *MockKeybindingsProvider_GetDefaultKeybindings_Call {
1576+ _c.Call.Return(keybindingsConfig, err)
1577+ return _c
1578+}
1579+
1580+func (_c *MockKeybindingsProvider_GetDefaultKeybindings_Call) RunAndReturn(run func(ctx context.Context) (port.KeybindingsConfig, error)) *MockKeybindingsProvider_GetDefaultKeybindings_Call {
1581+ _c.Call.Return(run)
1582+ return _c
1583+}
1584+
1585+// GetKeybindings provides a mock function for the type MockKeybindingsProvider
1586+func (_mock *MockKeybindingsProvider) GetKeybindings(ctx context.Context) (port.KeybindingsConfig, error) {
1587+ ret := _mock.Called(ctx)
1588+
1589+ if len(ret) == 0 {
1590+ panic("no return value specified for GetKeybindings")
1591+ }
1592+
1593+ var r0 port.KeybindingsConfig
1594+ var r1 error
1595+ if returnFunc, ok := ret.Get(0).(func(context.Context) (port.KeybindingsConfig, error)); ok {
1596+ return returnFunc(ctx)
1597+ }
1598+ if returnFunc, ok := ret.Get(0).(func(context.Context) port.KeybindingsConfig); ok {
1599+ r0 = returnFunc(ctx)
1600+ } else {
1601+ r0 = ret.Get(0).(port.KeybindingsConfig)
1602+ }
1603+ if returnFunc, ok := ret.Get(1).(func(context.Context) error); ok {
1604+ r1 = returnFunc(ctx)
1605+ } else {
1606+ r1 = ret.Error(1)
1607+ }
1608+ return r0, r1
1609+}
1610+
1611+// MockKeybindingsProvider_GetKeybindings_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetKeybindings'
1612+type MockKeybindingsProvider_GetKeybindings_Call struct {
1613+ *mock.Call
1614+}
1615+
1616+// GetKeybindings is a helper method to define mock.On call
1617+// - ctx context.Context
1618+func (_e *MockKeybindingsProvider_Expecter) GetKeybindings(ctx interface{}) *MockKeybindingsProvider_GetKeybindings_Call {
1619+ return &MockKeybindingsProvider_GetKeybindings_Call{Call: _e.mock.On("GetKeybindings", ctx)}
1620+}
1621+
1622+func (_c *MockKeybindingsProvider_GetKeybindings_Call) Run(run func(ctx context.Context)) *MockKeybindingsProvider_GetKeybindings_Call {
1623+ _c.Call.Run(func(args mock.Arguments) {
1624+ var arg0 context.Context
1625+ if args[0] != nil {
1626+ arg0 = args[0].(context.Context)
1627+ }
1628+ run(
1629+ arg0,
1630+ )
1631+ })
1632+ return _c
1633+}
1634+
1635+func (_c *MockKeybindingsProvider_GetKeybindings_Call) Return(keybindingsConfig port.KeybindingsConfig, err error) *MockKeybindingsProvider_GetKeybindings_Call {
1636+ _c.Call.Return(keybindingsConfig, err)
1637+ return _c
1638+}
1639+
1640+func (_c *MockKeybindingsProvider_GetKeybindings_Call) RunAndReturn(run func(ctx context.Context) (port.KeybindingsConfig, error)) *MockKeybindingsProvider_GetKeybindings_Call {
1641+ _c.Call.Return(run)
1642+ return _c
1643+}
1644+
1645+// NewMockKeybindingsSaver creates a new instance of MockKeybindingsSaver. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
1646+// The first argument is typically a *testing.T value.
1647+func NewMockKeybindingsSaver(t interface {
1648+ mock.TestingT
1649+ Cleanup(func())
1650+}) *MockKeybindingsSaver {
1651+ mock := &MockKeybindingsSaver{}
1652+ mock.Mock.Test(t)
1653+
1654+ t.Cleanup(func() { mock.AssertExpectations(t) })
1655+
1656+ return mock
1657+}
1658+
1659+// MockKeybindingsSaver is an autogenerated mock type for the KeybindingsSaver type
1660+type MockKeybindingsSaver struct {
1661+ mock.Mock
1662+}
1663+
1664+type MockKeybindingsSaver_Expecter struct {
1665+ mock *mock.Mock
1666+}
1667+
1668+func (_m *MockKeybindingsSaver) EXPECT() *MockKeybindingsSaver_Expecter {
1669+ return &MockKeybindingsSaver_Expecter{mock: &_m.Mock}
1670+}
1671+
1672+// ResetAllKeybindings provides a mock function for the type MockKeybindingsSaver
1673+func (_mock *MockKeybindingsSaver) ResetAllKeybindings(ctx context.Context) error {
1674+ ret := _mock.Called(ctx)
1675+
1676+ if len(ret) == 0 {
1677+ panic("no return value specified for ResetAllKeybindings")
1678+ }
1679+
1680+ var r0 error
1681+ if returnFunc, ok := ret.Get(0).(func(context.Context) error); ok {
1682+ r0 = returnFunc(ctx)
1683+ } else {
1684+ r0 = ret.Error(0)
1685+ }
1686+ return r0
1687+}
1688+
1689+// MockKeybindingsSaver_ResetAllKeybindings_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResetAllKeybindings'
1690+type MockKeybindingsSaver_ResetAllKeybindings_Call struct {
1691+ *mock.Call
1692+}
1693+
1694+// ResetAllKeybindings is a helper method to define mock.On call
1695+// - ctx context.Context
1696+func (_e *MockKeybindingsSaver_Expecter) ResetAllKeybindings(ctx interface{}) *MockKeybindingsSaver_ResetAllKeybindings_Call {
1697+ return &MockKeybindingsSaver_ResetAllKeybindings_Call{Call: _e.mock.On("ResetAllKeybindings", ctx)}
1698+}
1699+
1700+func (_c *MockKeybindingsSaver_ResetAllKeybindings_Call) Run(run func(ctx context.Context)) *MockKeybindingsSaver_ResetAllKeybindings_Call {
1701+ _c.Call.Run(func(args mock.Arguments) {
1702+ var arg0 context.Context
1703+ if args[0] != nil {
1704+ arg0 = args[0].(context.Context)
1705+ }
1706+ run(
1707+ arg0,
1708+ )
1709+ })
1710+ return _c
1711+}
1712+
1713+func (_c *MockKeybindingsSaver_ResetAllKeybindings_Call) Return(err error) *MockKeybindingsSaver_ResetAllKeybindings_Call {
1714+ _c.Call.Return(err)
1715+ return _c
1716+}
1717+
1718+func (_c *MockKeybindingsSaver_ResetAllKeybindings_Call) RunAndReturn(run func(ctx context.Context) error) *MockKeybindingsSaver_ResetAllKeybindings_Call {
1719+ _c.Call.Return(run)
1720+ return _c
1721+}
1722+
1723+// ResetKeybinding provides a mock function for the type MockKeybindingsSaver
1724+func (_mock *MockKeybindingsSaver) ResetKeybinding(ctx context.Context, req port.ResetKeybindingRequest) error {
1725+ ret := _mock.Called(ctx, req)
1726+
1727+ if len(ret) == 0 {
1728+ panic("no return value specified for ResetKeybinding")
1729+ }
1730+
1731+ var r0 error
1732+ if returnFunc, ok := ret.Get(0).(func(context.Context, port.ResetKeybindingRequest) error); ok {
1733+ r0 = returnFunc(ctx, req)
1734+ } else {
1735+ r0 = ret.Error(0)
1736+ }
1737+ return r0
1738+}
1739+
1740+// MockKeybindingsSaver_ResetKeybinding_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ResetKeybinding'
1741+type MockKeybindingsSaver_ResetKeybinding_Call struct {
1742+ *mock.Call
1743+}
1744+
1745+// ResetKeybinding is a helper method to define mock.On call
1746+// - ctx context.Context
1747+// - req port.ResetKeybindingRequest
1748+func (_e *MockKeybindingsSaver_Expecter) ResetKeybinding(ctx interface{}, req interface{}) *MockKeybindingsSaver_ResetKeybinding_Call {
1749+ return &MockKeybindingsSaver_ResetKeybinding_Call{Call: _e.mock.On("ResetKeybinding", ctx, req)}
1750+}
1751+
1752+func (_c *MockKeybindingsSaver_ResetKeybinding_Call) Run(run func(ctx context.Context, req port.ResetKeybindingRequest)) *MockKeybindingsSaver_ResetKeybinding_Call {
1753+ _c.Call.Run(func(args mock.Arguments) {
1754+ var arg0 context.Context
1755+ if args[0] != nil {
1756+ arg0 = args[0].(context.Context)
1757+ }
1758+ var arg1 port.ResetKeybindingRequest
1759+ if args[1] != nil {
1760+ arg1 = args[1].(port.ResetKeybindingRequest)
1761+ }
1762+ run(
1763+ arg0,
1764+ arg1,
1765+ )
1766+ })
1767+ return _c
1768+}
1769+
1770+func (_c *MockKeybindingsSaver_ResetKeybinding_Call) Return(err error) *MockKeybindingsSaver_ResetKeybinding_Call {
1771+ _c.Call.Return(err)
1772+ return _c
1773+}
1774+
1775+func (_c *MockKeybindingsSaver_ResetKeybinding_Call) RunAndReturn(run func(ctx context.Context, req port.ResetKeybindingRequest) error) *MockKeybindingsSaver_ResetKeybinding_Call {
1776+ _c.Call.Return(run)
1777+ return _c
1778+}
1779+
1780+// SetKeybinding provides a mock function for the type MockKeybindingsSaver
1781+func (_mock *MockKeybindingsSaver) SetKeybinding(ctx context.Context, req port.SetKeybindingRequest) error {
1782+ ret := _mock.Called(ctx, req)
1783+
1784+ if len(ret) == 0 {
1785+ panic("no return value specified for SetKeybinding")
1786+ }
1787+
1788+ var r0 error
1789+ if returnFunc, ok := ret.Get(0).(func(context.Context, port.SetKeybindingRequest) error); ok {
1790+ r0 = returnFunc(ctx, req)
1791+ } else {
1792+ r0 = ret.Error(0)
1793+ }
1794+ return r0
1795+}
1796+
1797+// MockKeybindingsSaver_SetKeybinding_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetKeybinding'
1798+type MockKeybindingsSaver_SetKeybinding_Call struct {
1799+ *mock.Call
1800+}
1801+
1802+// SetKeybinding is a helper method to define mock.On call
1803+// - ctx context.Context
1804+// - req port.SetKeybindingRequest
1805+func (_e *MockKeybindingsSaver_Expecter) SetKeybinding(ctx interface{}, req interface{}) *MockKeybindingsSaver_SetKeybinding_Call {
1806+ return &MockKeybindingsSaver_SetKeybinding_Call{Call: _e.mock.On("SetKeybinding", ctx, req)}
1807+}
1808+
1809+func (_c *MockKeybindingsSaver_SetKeybinding_Call) Run(run func(ctx context.Context, req port.SetKeybindingRequest)) *MockKeybindingsSaver_SetKeybinding_Call {
1810+ _c.Call.Run(func(args mock.Arguments) {
1811+ var arg0 context.Context
1812+ if args[0] != nil {
1813+ arg0 = args[0].(context.Context)
1814+ }
1815+ var arg1 port.SetKeybindingRequest
1816+ if args[1] != nil {
1817+ arg1 = args[1].(port.SetKeybindingRequest)
1818+ }
1819+ run(
1820+ arg0,
1821+ arg1,
1822+ )
1823+ })
1824+ return _c
1825+}
1826+
1827+func (_c *MockKeybindingsSaver_SetKeybinding_Call) Return(err error) *MockKeybindingsSaver_SetKeybinding_Call {
1828+ _c.Call.Return(err)
1829+ return _c
1830+}
1831+
1832+func (_c *MockKeybindingsSaver_SetKeybinding_Call) RunAndReturn(run func(ctx context.Context, req port.SetKeybindingRequest) error) *MockKeybindingsSaver_SetKeybinding_Call {
1833+ _c.Call.Return(run)
1834+ return _c
1835+}
1836+
1498 // NewMockSessionLogger creates a new instance of MockSessionLogger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.1837 // NewMockSessionLogger creates a new instance of MockSessionLogger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
1499 // The first argument is typically a *testing.T value.1838 // The first argument is typically a *testing.T value.
1500 func NewMockSessionLogger(t interface {1839 func NewMockSessionLogger(t interface {
A internal/application/usecase/keybindings.go +118 -0
@@ -0,0 +1,118 @@
1+package usecase
2+
3+import (
4+ "context"
5+ "fmt"
6+
7+ "github.com/bnema/dumber/internal/application/port"
8+)
9+
10+// GetKeybindingsUseCase retrieves all keybindings.
11+type GetKeybindingsUseCase struct {
12+ provider port.KeybindingsProvider
13+}
14+
15+// NewGetKeybindingsUseCase creates a new GetKeybindingsUseCase.
16+func NewGetKeybindingsUseCase(provider port.KeybindingsProvider) *GetKeybindingsUseCase {
17+ return &GetKeybindingsUseCase{provider: provider}
18+}
19+
20+// Execute retrieves all keybindings.
21+func (uc *GetKeybindingsUseCase) Execute(ctx context.Context) (port.KeybindingsConfig, error) {
22+ if uc == nil || uc.provider == nil {
23+ return port.KeybindingsConfig{}, fmt.Errorf("keybindings provider is nil")
24+ }
25+ return uc.provider.GetKeybindings(ctx)
26+}
27+
28+// SetKeybindingUseCase updates a single keybinding.
29+type SetKeybindingUseCase struct {
30+ saver port.KeybindingsSaver
31+}
32+
33+// NewSetKeybindingUseCase creates a new SetKeybindingUseCase.
34+func NewSetKeybindingUseCase(saver port.KeybindingsSaver) *SetKeybindingUseCase {
35+ return &SetKeybindingUseCase{saver: saver}
36+}
37+
38+// Execute updates a keybinding.
39+func (uc *SetKeybindingUseCase) Execute(ctx context.Context, req port.SetKeybindingRequest) error {
40+ if uc == nil || uc.saver == nil {
41+ return fmt.Errorf("keybindings saver is nil")
42+ }
43+
44+ if err := validateSetKeybindingRequest(req); err != nil {
45+ return err
46+ }
47+
48+ return uc.saver.SetKeybinding(ctx, req)
49+}
50+
51+// ResetKeybindingUseCase resets a keybinding to default.
52+type ResetKeybindingUseCase struct {
53+ saver port.KeybindingsSaver
54+}
55+
56+// NewResetKeybindingUseCase creates a new ResetKeybindingUseCase.
57+func NewResetKeybindingUseCase(saver port.KeybindingsSaver) *ResetKeybindingUseCase {
58+ return &ResetKeybindingUseCase{saver: saver}
59+}
60+
61+// Execute resets a keybinding to default.
62+func (uc *ResetKeybindingUseCase) Execute(ctx context.Context, req port.ResetKeybindingRequest) error {
63+ if uc == nil || uc.saver == nil {
64+ return fmt.Errorf("keybindings saver is nil")
65+ }
66+
67+ if err := validateResetKeybindingRequest(req); err != nil {
68+ return err
69+ }
70+
71+ return uc.saver.ResetKeybinding(ctx, req)
72+}
73+
74+// ResetAllKeybindingsUseCase resets all keybindings to defaults.
75+type ResetAllKeybindingsUseCase struct {
76+ saver port.KeybindingsSaver
77+}
78+
79+// NewResetAllKeybindingsUseCase creates a new ResetAllKeybindingsUseCase.
80+func NewResetAllKeybindingsUseCase(saver port.KeybindingsSaver) *ResetAllKeybindingsUseCase {
81+ return &ResetAllKeybindingsUseCase{saver: saver}
82+}
83+
84+// Execute resets all keybindings to defaults.
85+func (uc *ResetAllKeybindingsUseCase) Execute(ctx context.Context) error {
86+ if uc == nil || uc.saver == nil {
87+ return fmt.Errorf("keybindings saver is nil")
88+ }
89+ return uc.saver.ResetAllKeybindings(ctx)
90+}
91+
92+func validateSetKeybindingRequest(req port.SetKeybindingRequest) error {
93+ if req.Mode == "" {
94+ return fmt.Errorf("mode is required")
95+ }
96+ if req.Action == "" {
97+ return fmt.Errorf("action is required")
98+ }
99+ validModes := map[string]bool{"global": true, "pane": true, "tab": true, "resize": true, "session": true}
100+ if !validModes[req.Mode] {
101+ return fmt.Errorf("invalid mode: %s", req.Mode)
102+ }
103+ return nil
104+}
105+
106+func validateResetKeybindingRequest(req port.ResetKeybindingRequest) error {
107+ if req.Mode == "" {
108+ return fmt.Errorf("mode is required")
109+ }
110+ if req.Action == "" {
111+ return fmt.Errorf("action is required")
112+ }
113+ validModes := map[string]bool{"global": true, "pane": true, "tab": true, "resize": true, "session": true}
114+ if !validModes[req.Mode] {
115+ return fmt.Errorf("invalid mode: %s", req.Mode)
116+ }
117+ return nil
118+}
@@ -0,0 +1,118 @@
1+package usecase
2+
3+import (
4+ "context"
5+ "fmt"
6+
7+ "github.com/bnema/dumber/internal/application/port"
8+)
9+
10+// GetKeybindingsUseCase retrieves all keybindings.
11+type GetKeybindingsUseCase struct {
12+ provider port.KeybindingsProvider
13+}
14+
15+// NewGetKeybindingsUseCase creates a new GetKeybindingsUseCase.
16+func NewGetKeybindingsUseCase(provider port.KeybindingsProvider) *GetKeybindingsUseCase {
17+ return &GetKeybindingsUseCase{provider: provider}
18+}
19+
20+// Execute retrieves all keybindings.
21+func (uc *GetKeybindingsUseCase) Execute(ctx context.Context) (port.KeybindingsConfig, error) {
22+ if uc == nil || uc.provider == nil {
23+ return port.KeybindingsConfig{}, fmt.Errorf("keybindings provider is nil")
24+ }
25+ return uc.provider.GetKeybindings(ctx)
26+}
27+
28+// SetKeybindingUseCase updates a single keybinding.
29+type SetKeybindingUseCase struct {
30+ saver port.KeybindingsSaver
31+}
32+
33+// NewSetKeybindingUseCase creates a new SetKeybindingUseCase.
34+func NewSetKeybindingUseCase(saver port.KeybindingsSaver) *SetKeybindingUseCase {
35+ return &SetKeybindingUseCase{saver: saver}
36+}
37+
38+// Execute updates a keybinding.
39+func (uc *SetKeybindingUseCase) Execute(ctx context.Context, req port.SetKeybindingRequest) error {
40+ if uc == nil || uc.saver == nil {
41+ return fmt.Errorf("keybindings saver is nil")
42+ }
43+
44+ if err := validateSetKeybindingRequest(req); err != nil {
45+ return err
46+ }
47+
48+ return uc.saver.SetKeybinding(ctx, req)
49+}
50+
51+// ResetKeybindingUseCase resets a keybinding to default.
52+type ResetKeybindingUseCase struct {
53+ saver port.KeybindingsSaver
54+}
55+
56+// NewResetKeybindingUseCase creates a new ResetKeybindingUseCase.
57+func NewResetKeybindingUseCase(saver port.KeybindingsSaver) *ResetKeybindingUseCase {
58+ return &ResetKeybindingUseCase{saver: saver}
59+}
60+
61+// Execute resets a keybinding to default.
62+func (uc *ResetKeybindingUseCase) Execute(ctx context.Context, req port.ResetKeybindingRequest) error {
63+ if uc == nil || uc.saver == nil {
64+ return fmt.Errorf("keybindings saver is nil")
65+ }
66+
67+ if err := validateResetKeybindingRequest(req); err != nil {
68+ return err
69+ }
70+
71+ return uc.saver.ResetKeybinding(ctx, req)
72+}
73+
74+// ResetAllKeybindingsUseCase resets all keybindings to defaults.
75+type ResetAllKeybindingsUseCase struct {
76+ saver port.KeybindingsSaver
77+}
78+
79+// NewResetAllKeybindingsUseCase creates a new ResetAllKeybindingsUseCase.
80+func NewResetAllKeybindingsUseCase(saver port.KeybindingsSaver) *ResetAllKeybindingsUseCase {
81+ return &ResetAllKeybindingsUseCase{saver: saver}
82+}
83+
84+// Execute resets all keybindings to defaults.
85+func (uc *ResetAllKeybindingsUseCase) Execute(ctx context.Context) error {
86+ if uc == nil || uc.saver == nil {
87+ return fmt.Errorf("keybindings saver is nil")
88+ }
89+ return uc.saver.ResetAllKeybindings(ctx)
90+}
91+
92+func validateSetKeybindingRequest(req port.SetKeybindingRequest) error {
93+ if req.Mode == "" {
94+ return fmt.Errorf("mode is required")
95+ }
96+ if req.Action == "" {
97+ return fmt.Errorf("action is required")
98+ }
99+ validModes := map[string]bool{"global": true, "pane": true, "tab": true, "resize": true, "session": true}
100+ if !validModes[req.Mode] {
101+ return fmt.Errorf("invalid mode: %s", req.Mode)
102+ }
103+ return nil
104+}
105+
106+func validateResetKeybindingRequest(req port.ResetKeybindingRequest) error {
107+ if req.Mode == "" {
108+ return fmt.Errorf("mode is required")
109+ }
110+ if req.Action == "" {
111+ return fmt.Errorf("action is required")
112+ }
113+ validModes := map[string]bool{"global": true, "pane": true, "tab": true, "resize": true, "session": true}
114+ if !validModes[req.Mode] {
115+ return fmt.Errorf("invalid mode: %s", req.Mode)
116+ }
117+ return nil
118+}
A internal/application/usecase/keybindings_test.go +309 -0
@@ -0,0 +1,309 @@
1+package usecase_test
2+
3+import (
4+ "context"
5+ "errors"
6+ "testing"
7+
8+ "github.com/stretchr/testify/assert"
9+ "github.com/stretchr/testify/mock"
10+ "github.com/stretchr/testify/require"
11+
12+ "github.com/bnema/dumber/internal/application/port"
13+ "github.com/bnema/dumber/internal/application/port/mocks"
14+ "github.com/bnema/dumber/internal/application/usecase"
15+)
16+
17+func TestGetKeybindingsUseCase_Execute(t *testing.T) {
18+ t.Run("returns keybindings from provider", func(t *testing.T) {
19+ // Arrange
20+ mockProvider := mocks.NewMockKeybindingsProvider(t)
21+ expected := port.KeybindingsConfig{
22+ Groups: []port.KeybindingGroup{
23+ {
24+ Mode: "global",
25+ DisplayName: "Global Shortcuts",
26+ Bindings: []port.KeybindingEntry{
27+ {Action: "close_pane", Keys: []string{"ctrl+w"}},
28+ },
29+ },
30+ },
31+ }
32+ mockProvider.EXPECT().GetKeybindings(mock.Anything).Return(expected, nil)
33+
34+ uc := usecase.NewGetKeybindingsUseCase(mockProvider)
35+
36+ // Act
37+ result, err := uc.Execute(context.Background())
38+
39+ // Assert
40+ require.NoError(t, err)
41+ assert.Equal(t, expected, result)
42+ mock.AssertExpectationsForObjects(t, mockProvider)
43+ })
44+
45+ t.Run("returns error when provider fails", func(t *testing.T) {
46+ // Arrange
47+ mockProvider := mocks.NewMockKeybindingsProvider(t)
48+ mockProvider.EXPECT().GetKeybindings(mock.Anything).Return(port.KeybindingsConfig{}, errors.New("provider error"))
49+
50+ uc := usecase.NewGetKeybindingsUseCase(mockProvider)
51+
52+ // Act
53+ _, err := uc.Execute(context.Background())
54+
55+ // Assert
56+ require.Error(t, err)
57+ assert.Contains(t, err.Error(), "provider error")
58+ mock.AssertExpectationsForObjects(t, mockProvider)
59+ })
60+
61+ t.Run("returns error when provider is nil", func(t *testing.T) {
62+ // Arrange
63+ uc := usecase.NewGetKeybindingsUseCase(nil)
64+
65+ // Act
66+ _, err := uc.Execute(context.Background())
67+
68+ // Assert
69+ require.Error(t, err)
70+ assert.Contains(t, err.Error(), "provider is nil")
71+ })
72+}
73+
74+func TestSetKeybindingUseCase_Execute(t *testing.T) {
75+ t.Run("successfully sets keybinding", func(t *testing.T) {
76+ // Arrange
77+ mockSaver := mocks.NewMockKeybindingsSaver(t)
78+ req := port.SetKeybindingRequest{
79+ Mode: "pane",
80+ Action: "split-right",
81+ Keys: []string{"r"},
82+ }
83+ mockSaver.EXPECT().SetKeybinding(mock.Anything, req).Return(nil)
84+
85+ uc := usecase.NewSetKeybindingUseCase(mockSaver)
86+
87+ // Act
88+ err := uc.Execute(context.Background(), req)
89+
90+ // Assert
91+ require.NoError(t, err)
92+ mock.AssertExpectationsForObjects(t, mockSaver)
93+ })
94+
95+ t.Run("returns error when saver fails", func(t *testing.T) {
96+ // Arrange
97+ mockSaver := mocks.NewMockKeybindingsSaver(t)
98+ req := port.SetKeybindingRequest{
99+ Mode: "pane",
100+ Action: "split-right",
101+ Keys: []string{"r"},
102+ }
103+ mockSaver.EXPECT().SetKeybinding(mock.Anything, req).Return(errors.New("save error"))
104+
105+ uc := usecase.NewSetKeybindingUseCase(mockSaver)
106+
107+ // Act
108+ err := uc.Execute(context.Background(), req)
109+
110+ // Assert
111+ require.Error(t, err)
112+ assert.Contains(t, err.Error(), "save error")
113+ mock.AssertExpectationsForObjects(t, mockSaver)
114+ })
115+
116+ t.Run("returns error when saver is nil", func(t *testing.T) {
117+ // Arrange
118+ uc := usecase.NewSetKeybindingUseCase(nil)
119+ req := port.SetKeybindingRequest{
120+ Mode: "pane",
121+ Action: "split-right",
122+ Keys: []string{"r"},
123+ }
124+
125+ // Act
126+ err := uc.Execute(context.Background(), req)
127+
128+ // Assert
129+ require.Error(t, err)
130+ assert.Contains(t, err.Error(), "saver is nil")
131+ })
132+
133+ t.Run("returns error when mode is empty", func(t *testing.T) {
134+ // Arrange
135+ mockSaver := mocks.NewMockKeybindingsSaver(t)
136+ req := port.SetKeybindingRequest{
137+ Mode: "",
138+ Action: "split-right",
139+ Keys: []string{"r"},
140+ }
141+
142+ uc := usecase.NewSetKeybindingUseCase(mockSaver)
143+
144+ // Act
145+ err := uc.Execute(context.Background(), req)
146+
147+ // Assert
148+ require.Error(t, err)
149+ assert.Contains(t, err.Error(), "mode is required")
150+ })
151+
152+ t.Run("returns error when action is empty", func(t *testing.T) {
153+ // Arrange
154+ mockSaver := mocks.NewMockKeybindingsSaver(t)
155+ req := port.SetKeybindingRequest{
156+ Mode: "pane",
157+ Action: "",
158+ Keys: []string{"r"},
159+ }
160+
161+ uc := usecase.NewSetKeybindingUseCase(mockSaver)
162+
163+ // Act
164+ err := uc.Execute(context.Background(), req)
165+
166+ // Assert
167+ require.Error(t, err)
168+ assert.Contains(t, err.Error(), "action is required")
169+ })
170+
171+ t.Run("returns error for invalid mode", func(t *testing.T) {
172+ // Arrange
173+ mockSaver := mocks.NewMockKeybindingsSaver(t)
174+ req := port.SetKeybindingRequest{
175+ Mode: "invalid",
176+ Action: "split-right",
177+ Keys: []string{"r"},
178+ }
179+
180+ uc := usecase.NewSetKeybindingUseCase(mockSaver)
181+
182+ // Act
183+ err := uc.Execute(context.Background(), req)
184+
185+ // Assert
186+ require.Error(t, err)
187+ assert.Contains(t, err.Error(), "invalid mode")
188+ })
189+}
190+
191+func TestResetKeybindingUseCase_Execute(t *testing.T) {
192+ t.Run("successfully resets keybinding", func(t *testing.T) {
193+ // Arrange
194+ mockSaver := mocks.NewMockKeybindingsSaver(t)
195+ req := port.ResetKeybindingRequest{
196+ Mode: "pane",
197+ Action: "split-right",
198+ }
199+ mockSaver.EXPECT().ResetKeybinding(mock.Anything, req).Return(nil)
200+
201+ uc := usecase.NewResetKeybindingUseCase(mockSaver)
202+
203+ // Act
204+ err := uc.Execute(context.Background(), req)
205+
206+ // Assert
207+ require.NoError(t, err)
208+ mock.AssertExpectationsForObjects(t, mockSaver)
209+ })
210+
211+ t.Run("returns error when saver fails", func(t *testing.T) {
212+ // Arrange
213+ mockSaver := mocks.NewMockKeybindingsSaver(t)
214+ req := port.ResetKeybindingRequest{
215+ Mode: "pane",
216+ Action: "split-right",
217+ }
218+ mockSaver.EXPECT().ResetKeybinding(mock.Anything, req).Return(errors.New("reset error"))
219+
220+ uc := usecase.NewResetKeybindingUseCase(mockSaver)
221+
222+ // Act
223+ err := uc.Execute(context.Background(), req)
224+
225+ // Assert
226+ require.Error(t, err)
227+ assert.Contains(t, err.Error(), "reset error")
228+ mock.AssertExpectationsForObjects(t, mockSaver)
229+ })
230+
231+ t.Run("returns error when saver is nil", func(t *testing.T) {
232+ // Arrange
233+ uc := usecase.NewResetKeybindingUseCase(nil)
234+ req := port.ResetKeybindingRequest{
235+ Mode: "pane",
236+ Action: "split-right",
237+ }
238+
239+ // Act
240+ err := uc.Execute(context.Background(), req)
241+
242+ // Assert
243+ require.Error(t, err)
244+ assert.Contains(t, err.Error(), "saver is nil")
245+ })
246+
247+ t.Run("returns error when mode is empty", func(t *testing.T) {
248+ // Arrange
249+ mockSaver := mocks.NewMockKeybindingsSaver(t)
250+ req := port.ResetKeybindingRequest{
251+ Mode: "",
252+ Action: "split-right",
253+ }
254+
255+ uc := usecase.NewResetKeybindingUseCase(mockSaver)
256+
257+ // Act
258+ err := uc.Execute(context.Background(), req)
259+
260+ // Assert
261+ require.Error(t, err)
262+ assert.Contains(t, err.Error(), "mode is required")
263+ })
264+}
265+
266+func TestResetAllKeybindingsUseCase_Execute(t *testing.T) {
267+ t.Run("successfully resets all keybindings", func(t *testing.T) {
268+ // Arrange
269+ mockSaver := mocks.NewMockKeybindingsSaver(t)
270+ mockSaver.EXPECT().ResetAllKeybindings(mock.Anything).Return(nil)
271+
272+ uc := usecase.NewResetAllKeybindingsUseCase(mockSaver)
273+
274+ // Act
275+ err := uc.Execute(context.Background())
276+
277+ // Assert
278+ require.NoError(t, err)
279+ mock.AssertExpectationsForObjects(t, mockSaver)
280+ })
281+
282+ t.Run("returns error when saver fails", func(t *testing.T) {
283+ // Arrange
284+ mockSaver := mocks.NewMockKeybindingsSaver(t)
285+ mockSaver.EXPECT().ResetAllKeybindings(mock.Anything).Return(errors.New("reset all error"))
286+
287+ uc := usecase.NewResetAllKeybindingsUseCase(mockSaver)
288+
289+ // Act
290+ err := uc.Execute(context.Background())
291+
292+ // Assert
293+ require.Error(t, err)
294+ assert.Contains(t, err.Error(), "reset all error")
295+ mock.AssertExpectationsForObjects(t, mockSaver)
296+ })
297+
298+ t.Run("returns error when saver is nil", func(t *testing.T) {
299+ // Arrange
300+ uc := usecase.NewResetAllKeybindingsUseCase(nil)
301+
302+ // Act
303+ err := uc.Execute(context.Background())
304+
305+ // Assert
306+ require.Error(t, err)
307+ assert.Contains(t, err.Error(), "saver is nil")
308+ })
309+}
@@ -0,0 +1,309 @@
1+package usecase_test
2+
3+import (
4+ "context"
5+ "errors"
6+ "testing"
7+
8+ "github.com/stretchr/testify/assert"
9+ "github.com/stretchr/testify/mock"
10+ "github.com/stretchr/testify/require"
11+
12+ "github.com/bnema/dumber/internal/application/port"
13+ "github.com/bnema/dumber/internal/application/port/mocks"
14+ "github.com/bnema/dumber/internal/application/usecase"
15+)
16+
17+func TestGetKeybindingsUseCase_Execute(t *testing.T) {
18+ t.Run("returns keybindings from provider", func(t *testing.T) {
19+ // Arrange
20+ mockProvider := mocks.NewMockKeybindingsProvider(t)
21+ expected := port.KeybindingsConfig{
22+ Groups: []port.KeybindingGroup{
23+ {
24+ Mode: "global",
25+ DisplayName: "Global Shortcuts",
26+ Bindings: []port.KeybindingEntry{
27+ {Action: "close_pane", Keys: []string{"ctrl+w"}},
28+ },
29+ },
30+ },
31+ }
32+ mockProvider.EXPECT().GetKeybindings(mock.Anything).Return(expected, nil)
33+
34+ uc := usecase.NewGetKeybindingsUseCase(mockProvider)
35+
36+ // Act
37+ result, err := uc.Execute(context.Background())
38+
39+ // Assert
40+ require.NoError(t, err)
41+ assert.Equal(t, expected, result)
42+ mock.AssertExpectationsForObjects(t, mockProvider)
43+ })
44+
45+ t.Run("returns error when provider fails", func(t *testing.T) {
46+ // Arrange
47+ mockProvider := mocks.NewMockKeybindingsProvider(t)
48+ mockProvider.EXPECT().GetKeybindings(mock.Anything).Return(port.KeybindingsConfig{}, errors.New("provider error"))
49+
50+ uc := usecase.NewGetKeybindingsUseCase(mockProvider)
51+
52+ // Act
53+ _, err := uc.Execute(context.Background())
54+
55+ // Assert
56+ require.Error(t, err)
57+ assert.Contains(t, err.Error(), "provider error")
58+ mock.AssertExpectationsForObjects(t, mockProvider)
59+ })
60+
61+ t.Run("returns error when provider is nil", func(t *testing.T) {
62+ // Arrange
63+ uc := usecase.NewGetKeybindingsUseCase(nil)
64+
65+ // Act
66+ _, err := uc.Execute(context.Background())
67+
68+ // Assert
69+ require.Error(t, err)
70+ assert.Contains(t, err.Error(), "provider is nil")
71+ })
72+}
73+
74+func TestSetKeybindingUseCase_Execute(t *testing.T) {
75+ t.Run("successfully sets keybinding", func(t *testing.T) {
76+ // Arrange
77+ mockSaver := mocks.NewMockKeybindingsSaver(t)
78+ req := port.SetKeybindingRequest{
79+ Mode: "pane",
80+ Action: "split-right",
81+ Keys: []string{"r"},
82+ }
83+ mockSaver.EXPECT().SetKeybinding(mock.Anything, req).Return(nil)
84+
85+ uc := usecase.NewSetKeybindingUseCase(mockSaver)
86+
87+ // Act
88+ err := uc.Execute(context.Background(), req)
89+
90+ // Assert
91+ require.NoError(t, err)
92+ mock.AssertExpectationsForObjects(t, mockSaver)
93+ })
94+
95+ t.Run("returns error when saver fails", func(t *testing.T) {
96+ // Arrange
97+ mockSaver := mocks.NewMockKeybindingsSaver(t)
98+ req := port.SetKeybindingRequest{
99+ Mode: "pane",
100+ Action: "split-right",
101+ Keys: []string{"r"},
102+ }
103+ mockSaver.EXPECT().SetKeybinding(mock.Anything, req).Return(errors.New("save error"))
104+
105+ uc := usecase.NewSetKeybindingUseCase(mockSaver)
106+
107+ // Act
108+ err := uc.Execute(context.Background(), req)
109+
110+ // Assert
111+ require.Error(t, err)
112+ assert.Contains(t, err.Error(), "save error")
113+ mock.AssertExpectationsForObjects(t, mockSaver)
114+ })
115+
116+ t.Run("returns error when saver is nil", func(t *testing.T) {
117+ // Arrange
118+ uc := usecase.NewSetKeybindingUseCase(nil)
119+ req := port.SetKeybindingRequest{
120+ Mode: "pane",
121+ Action: "split-right",
122+ Keys: []string{"r"},
123+ }
124+
125+ // Act
126+ err := uc.Execute(context.Background(), req)
127+
128+ // Assert
129+ require.Error(t, err)
130+ assert.Contains(t, err.Error(), "saver is nil")
131+ })
132+
133+ t.Run("returns error when mode is empty", func(t *testing.T) {
134+ // Arrange
135+ mockSaver := mocks.NewMockKeybindingsSaver(t)
136+ req := port.SetKeybindingRequest{
137+ Mode: "",
138+ Action: "split-right",
139+ Keys: []string{"r"},
140+ }
141+
142+ uc := usecase.NewSetKeybindingUseCase(mockSaver)
143+
144+ // Act
145+ err := uc.Execute(context.Background(), req)
146+
147+ // Assert
148+ require.Error(t, err)
149+ assert.Contains(t, err.Error(), "mode is required")
150+ })
151+
152+ t.Run("returns error when action is empty", func(t *testing.T) {
153+ // Arrange
154+ mockSaver := mocks.NewMockKeybindingsSaver(t)
155+ req := port.SetKeybindingRequest{
156+ Mode: "pane",
157+ Action: "",
158+ Keys: []string{"r"},
159+ }
160+
161+ uc := usecase.NewSetKeybindingUseCase(mockSaver)
162+
163+ // Act
164+ err := uc.Execute(context.Background(), req)
165+
166+ // Assert
167+ require.Error(t, err)
168+ assert.Contains(t, err.Error(), "action is required")
169+ })
170+
171+ t.Run("returns error for invalid mode", func(t *testing.T) {
172+ // Arrange
173+ mockSaver := mocks.NewMockKeybindingsSaver(t)
174+ req := port.SetKeybindingRequest{
175+ Mode: "invalid",
176+ Action: "split-right",
177+ Keys: []string{"r"},
178+ }
179+
180+ uc := usecase.NewSetKeybindingUseCase(mockSaver)
181+
182+ // Act
183+ err := uc.Execute(context.Background(), req)
184+
185+ // Assert
186+ require.Error(t, err)
187+ assert.Contains(t, err.Error(), "invalid mode")
188+ })
189+}
190+
191+func TestResetKeybindingUseCase_Execute(t *testing.T) {
192+ t.Run("successfully resets keybinding", func(t *testing.T) {
193+ // Arrange
194+ mockSaver := mocks.NewMockKeybindingsSaver(t)
195+ req := port.ResetKeybindingRequest{
196+ Mode: "pane",
197+ Action: "split-right",
198+ }
199+ mockSaver.EXPECT().ResetKeybinding(mock.Anything, req).Return(nil)
200+
201+ uc := usecase.NewResetKeybindingUseCase(mockSaver)
202+
203+ // Act
204+ err := uc.Execute(context.Background(), req)
205+
206+ // Assert
207+ require.NoError(t, err)
208+ mock.AssertExpectationsForObjects(t, mockSaver)
209+ })
210+
211+ t.Run("returns error when saver fails", func(t *testing.T) {
212+ // Arrange
213+ mockSaver := mocks.NewMockKeybindingsSaver(t)
214+ req := port.ResetKeybindingRequest{
215+ Mode: "pane",
216+ Action: "split-right",
217+ }
218+ mockSaver.EXPECT().ResetKeybinding(mock.Anything, req).Return(errors.New("reset error"))
219+
220+ uc := usecase.NewResetKeybindingUseCase(mockSaver)
221+
222+ // Act
223+ err := uc.Execute(context.Background(), req)
224+
225+ // Assert
226+ require.Error(t, err)
227+ assert.Contains(t, err.Error(), "reset error")
228+ mock.AssertExpectationsForObjects(t, mockSaver)
229+ })
230+
231+ t.Run("returns error when saver is nil", func(t *testing.T) {
232+ // Arrange
233+ uc := usecase.NewResetKeybindingUseCase(nil)
234+ req := port.ResetKeybindingRequest{
235+ Mode: "pane",
236+ Action: "split-right",
237+ }
238+
239+ // Act
240+ err := uc.Execute(context.Background(), req)
241+
242+ // Assert
243+ require.Error(t, err)
244+ assert.Contains(t, err.Error(), "saver is nil")
245+ })
246+
247+ t.Run("returns error when mode is empty", func(t *testing.T) {
248+ // Arrange
249+ mockSaver := mocks.NewMockKeybindingsSaver(t)
250+ req := port.ResetKeybindingRequest{
251+ Mode: "",
252+ Action: "split-right",
253+ }
254+
255+ uc := usecase.NewResetKeybindingUseCase(mockSaver)
256+
257+ // Act
258+ err := uc.Execute(context.Background(), req)
259+
260+ // Assert
261+ require.Error(t, err)
262+ assert.Contains(t, err.Error(), "mode is required")
263+ })
264+}
265+
266+func TestResetAllKeybindingsUseCase_Execute(t *testing.T) {
267+ t.Run("successfully resets all keybindings", func(t *testing.T) {
268+ // Arrange
269+ mockSaver := mocks.NewMockKeybindingsSaver(t)
270+ mockSaver.EXPECT().ResetAllKeybindings(mock.Anything).Return(nil)
271+
272+ uc := usecase.NewResetAllKeybindingsUseCase(mockSaver)
273+
274+ // Act
275+ err := uc.Execute(context.Background())
276+
277+ // Assert
278+ require.NoError(t, err)
279+ mock.AssertExpectationsForObjects(t, mockSaver)
280+ })
281+
282+ t.Run("returns error when saver fails", func(t *testing.T) {
283+ // Arrange
284+ mockSaver := mocks.NewMockKeybindingsSaver(t)
285+ mockSaver.EXPECT().ResetAllKeybindings(mock.Anything).Return(errors.New("reset all error"))
286+
287+ uc := usecase.NewResetAllKeybindingsUseCase(mockSaver)
288+
289+ // Act
290+ err := uc.Execute(context.Background())
291+
292+ // Assert
293+ require.Error(t, err)
294+ assert.Contains(t, err.Error(), "reset all error")
295+ mock.AssertExpectationsForObjects(t, mockSaver)
296+ })
297+
298+ t.Run("returns error when saver is nil", func(t *testing.T) {
299+ // Arrange
300+ uc := usecase.NewResetAllKeybindingsUseCase(nil)
301+
302+ // Act
303+ err := uc.Execute(context.Background())
304+
305+ // Assert
306+ require.Error(t, err)
307+ assert.Contains(t, err.Error(), "saver is nil")
308+ })
309+}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close