detached 592167c

refactor: add browser launch ports and runtime dir

commit
592167c132570c7e1c78953a723c021a44e3ce25
author
brice · · 2026-04-14 12:06 UTC
parent
d7aff0c
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
6 files · +378 -0
M .mockery.yaml +2 -0
@@ -71,6 +71,8 @@ packages:
7171 RuntimeVersionProbe: {}
7272 ScriptRefresher: {}
7373 SnapshotService: {}
74+ BrowserWindowOpener: {}
75+ BrowserLaunchRelay: {}
7476 TextInputTargetProvider: {}
7577 Texture: {}
7678 ToolkitAvailabilityNotifier: {}
@@ -71,6 +71,8 @@ packages:
71 RuntimeVersionProbe: {}71 RuntimeVersionProbe: {}
72 ScriptRefresher: {}72 ScriptRefresher: {}
73 SnapshotService: {}73 SnapshotService: {}
74+ BrowserWindowOpener: {}
75+ BrowserLaunchRelay: {}
74 TextInputTargetProvider: {}76 TextInputTargetProvider: {}
75 Texture: {}77 Texture: {}
76 ToolkitAvailabilityNotifier: {}78 ToolkitAvailabilityNotifier: {}
A internal/application/port/browser_launch.go +17 -0
@@ -0,0 +1,17 @@
1+package port
2+
3+import (
4+ "context"
5+ "io"
6+)
7+
8+// BrowserWindowOpener opens a fresh browser window.
9+type BrowserWindowOpener interface {
10+ OpenFreshWindow(ctx context.Context, url string) error
11+}
12+
13+// BrowserLaunchRelay delivers fresh-window launch requests.
14+type BrowserLaunchRelay interface {
15+ DeliverOpenFreshWindow(ctx context.Context, url string) (bool, error)
16+ Listen(ctx context.Context, opener BrowserWindowOpener) (io.Closer, error)
17+}
@@ -0,0 +1,17 @@
1+package port
2+
3+import (
4+ "context"
5+ "io"
6+)
7+
8+// BrowserWindowOpener opens a fresh browser window.
9+type BrowserWindowOpener interface {
10+ OpenFreshWindow(ctx context.Context, url string) error
11+}
12+
13+// BrowserLaunchRelay delivers fresh-window launch requests.
14+type BrowserLaunchRelay interface {
15+ DeliverOpenFreshWindow(ctx context.Context, url string) (bool, error)
16+ Listen(ctx context.Context, opener BrowserWindowOpener) (io.Closer, error)
17+}
M internal/application/port/mocks/mocks.go +299 -0
@@ -8,6 +8,7 @@ import (
88 "context"
99 "database/sql"
1010 "encoding/json"
11+ "io"
1112 "time"
1213
1314 "github.com/bnema/dumber/internal/application/port"
@@ -172,6 +173,251 @@ func (_c *MockAccentPickerUI_Show_Call) RunAndReturn(run func(accents []rune, se
172173 return _c
173174 }
174175
176+// NewMockBrowserWindowOpener creates a new instance of MockBrowserWindowOpener. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
177+// The first argument is typically a *testing.T value.
178+func NewMockBrowserWindowOpener(t interface {
179+ mock.TestingT
180+ Cleanup(func())
181+}) *MockBrowserWindowOpener {
182+ mock := &MockBrowserWindowOpener{}
183+ mock.Mock.Test(t)
184+
185+ t.Cleanup(func() { mock.AssertExpectations(t) })
186+
187+ return mock
188+}
189+
190+// MockBrowserWindowOpener is an autogenerated mock type for the BrowserWindowOpener type
191+type MockBrowserWindowOpener struct {
192+ mock.Mock
193+}
194+
195+type MockBrowserWindowOpener_Expecter struct {
196+ mock *mock.Mock
197+}
198+
199+func (_m *MockBrowserWindowOpener) EXPECT() *MockBrowserWindowOpener_Expecter {
200+ return &MockBrowserWindowOpener_Expecter{mock: &_m.Mock}
201+}
202+
203+// OpenFreshWindow provides a mock function for the type MockBrowserWindowOpener
204+func (_mock *MockBrowserWindowOpener) OpenFreshWindow(ctx context.Context, url string) error {
205+ ret := _mock.Called(ctx, url)
206+
207+ if len(ret) == 0 {
208+ panic("no return value specified for OpenFreshWindow")
209+ }
210+
211+ var r0 error
212+ if returnFunc, ok := ret.Get(0).(func(context.Context, string) error); ok {
213+ r0 = returnFunc(ctx, url)
214+ } else {
215+ r0 = ret.Error(0)
216+ }
217+ return r0
218+}
219+
220+// MockBrowserWindowOpener_OpenFreshWindow_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OpenFreshWindow'
221+type MockBrowserWindowOpener_OpenFreshWindow_Call struct {
222+ *mock.Call
223+}
224+
225+// OpenFreshWindow is a helper method to define mock.On call
226+// - ctx context.Context
227+// - url string
228+func (_e *MockBrowserWindowOpener_Expecter) OpenFreshWindow(ctx interface{}, url interface{}) *MockBrowserWindowOpener_OpenFreshWindow_Call {
229+ return &MockBrowserWindowOpener_OpenFreshWindow_Call{Call: _e.mock.On("OpenFreshWindow", ctx, url)}
230+}
231+
232+func (_c *MockBrowserWindowOpener_OpenFreshWindow_Call) Run(run func(ctx context.Context, url string)) *MockBrowserWindowOpener_OpenFreshWindow_Call {
233+ _c.Call.Run(func(args mock.Arguments) {
234+ var arg0 context.Context
235+ if args[0] != nil {
236+ arg0 = args[0].(context.Context)
237+ }
238+ var arg1 string
239+ if args[1] != nil {
240+ arg1 = args[1].(string)
241+ }
242+ run(
243+ arg0,
244+ arg1,
245+ )
246+ })
247+ return _c
248+}
249+
250+func (_c *MockBrowserWindowOpener_OpenFreshWindow_Call) Return(err error) *MockBrowserWindowOpener_OpenFreshWindow_Call {
251+ _c.Call.Return(err)
252+ return _c
253+}
254+
255+func (_c *MockBrowserWindowOpener_OpenFreshWindow_Call) RunAndReturn(run func(ctx context.Context, url string) error) *MockBrowserWindowOpener_OpenFreshWindow_Call {
256+ _c.Call.Return(run)
257+ return _c
258+}
259+
260+// NewMockBrowserLaunchRelay creates a new instance of MockBrowserLaunchRelay. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
261+// The first argument is typically a *testing.T value.
262+func NewMockBrowserLaunchRelay(t interface {
263+ mock.TestingT
264+ Cleanup(func())
265+}) *MockBrowserLaunchRelay {
266+ mock := &MockBrowserLaunchRelay{}
267+ mock.Mock.Test(t)
268+
269+ t.Cleanup(func() { mock.AssertExpectations(t) })
270+
271+ return mock
272+}
273+
274+// MockBrowserLaunchRelay is an autogenerated mock type for the BrowserLaunchRelay type
275+type MockBrowserLaunchRelay struct {
276+ mock.Mock
277+}
278+
279+type MockBrowserLaunchRelay_Expecter struct {
280+ mock *mock.Mock
281+}
282+
283+func (_m *MockBrowserLaunchRelay) EXPECT() *MockBrowserLaunchRelay_Expecter {
284+ return &MockBrowserLaunchRelay_Expecter{mock: &_m.Mock}
285+}
286+
287+// DeliverOpenFreshWindow provides a mock function for the type MockBrowserLaunchRelay
288+func (_mock *MockBrowserLaunchRelay) DeliverOpenFreshWindow(ctx context.Context, url string) (bool, error) {
289+ ret := _mock.Called(ctx, url)
290+
291+ if len(ret) == 0 {
292+ panic("no return value specified for DeliverOpenFreshWindow")
293+ }
294+
295+ var r0 bool
296+ var r1 error
297+ if returnFunc, ok := ret.Get(0).(func(context.Context, string) (bool, error)); ok {
298+ return returnFunc(ctx, url)
299+ }
300+ if returnFunc, ok := ret.Get(0).(func(context.Context, string) bool); ok {
301+ r0 = returnFunc(ctx, url)
302+ } else {
303+ r0 = ret.Get(0).(bool)
304+ }
305+ if returnFunc, ok := ret.Get(1).(func(context.Context, string) error); ok {
306+ r1 = returnFunc(ctx, url)
307+ } else {
308+ r1 = ret.Error(1)
309+ }
310+ return r0, r1
311+}
312+
313+// MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeliverOpenFreshWindow'
314+type MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call struct {
315+ *mock.Call
316+}
317+
318+// DeliverOpenFreshWindow is a helper method to define mock.On call
319+// - ctx context.Context
320+// - url string
321+func (_e *MockBrowserLaunchRelay_Expecter) DeliverOpenFreshWindow(ctx interface{}, url interface{}) *MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call {
322+ return &MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call{Call: _e.mock.On("DeliverOpenFreshWindow", ctx, url)}
323+}
324+
325+func (_c *MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call) Run(run func(ctx context.Context, url string)) *MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call {
326+ _c.Call.Run(func(args mock.Arguments) {
327+ var arg0 context.Context
328+ if args[0] != nil {
329+ arg0 = args[0].(context.Context)
330+ }
331+ var arg1 string
332+ if args[1] != nil {
333+ arg1 = args[1].(string)
334+ }
335+ run(
336+ arg0,
337+ arg1,
338+ )
339+ })
340+ return _c
341+}
342+
343+func (_c *MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call) Return(b bool, err error) *MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call {
344+ _c.Call.Return(b, err)
345+ return _c
346+}
347+
348+func (_c *MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call) RunAndReturn(run func(ctx context.Context, url string) (bool, error)) *MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call {
349+ _c.Call.Return(run)
350+ return _c
351+}
352+
353+// Listen provides a mock function for the type MockBrowserLaunchRelay
354+func (_mock *MockBrowserLaunchRelay) Listen(ctx context.Context, opener port.BrowserWindowOpener) (io.Closer, error) {
355+ ret := _mock.Called(ctx, opener)
356+
357+ if len(ret) == 0 {
358+ panic("no return value specified for Listen")
359+ }
360+
361+ var r0 io.Closer
362+ var r1 error
363+ if returnFunc, ok := ret.Get(0).(func(context.Context, port.BrowserWindowOpener) (io.Closer, error)); ok {
364+ return returnFunc(ctx, opener)
365+ }
366+ if returnFunc, ok := ret.Get(0).(func(context.Context, port.BrowserWindowOpener) io.Closer); ok {
367+ r0 = returnFunc(ctx, opener)
368+ } else {
369+ if ret.Get(0) != nil {
370+ r0 = ret.Get(0).(io.Closer)
371+ }
372+ }
373+ if returnFunc, ok := ret.Get(1).(func(context.Context, port.BrowserWindowOpener) error); ok {
374+ r1 = returnFunc(ctx, opener)
375+ } else {
376+ r1 = ret.Error(1)
377+ }
378+ return r0, r1
379+}
380+
381+// MockBrowserLaunchRelay_Listen_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Listen'
382+type MockBrowserLaunchRelay_Listen_Call struct {
383+ *mock.Call
384+}
385+
386+// Listen is a helper method to define mock.On call
387+// - ctx context.Context
388+// - opener port.BrowserWindowOpener
389+func (_e *MockBrowserLaunchRelay_Expecter) Listen(ctx interface{}, opener interface{}) *MockBrowserLaunchRelay_Listen_Call {
390+ return &MockBrowserLaunchRelay_Listen_Call{Call: _e.mock.On("Listen", ctx, opener)}
391+}
392+
393+func (_c *MockBrowserLaunchRelay_Listen_Call) Run(run func(ctx context.Context, opener port.BrowserWindowOpener)) *MockBrowserLaunchRelay_Listen_Call {
394+ _c.Call.Run(func(args mock.Arguments) {
395+ var arg0 context.Context
396+ if args[0] != nil {
397+ arg0 = args[0].(context.Context)
398+ }
399+ var arg1 port.BrowserWindowOpener
400+ if args[1] != nil {
401+ arg1 = args[1].(port.BrowserWindowOpener)
402+ }
403+ run(
404+ arg0,
405+ arg1,
406+ )
407+ })
408+ return _c
409+}
410+
411+func (_c *MockBrowserLaunchRelay_Listen_Call) Return(closer io.Closer, err error) *MockBrowserLaunchRelay_Listen_Call {
412+ _c.Call.Return(closer, err)
413+ return _c
414+}
415+
416+func (_c *MockBrowserLaunchRelay_Listen_Call) RunAndReturn(run func(ctx context.Context, opener port.BrowserWindowOpener) (io.Closer, error)) *MockBrowserLaunchRelay_Listen_Call {
417+ _c.Call.Return(run)
418+ return _c
419+}
420+
175421 // NewMockClipboard creates a new instance of MockClipboard. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
176422 // The first argument is typically a *testing.T value.
177423 func NewMockClipboard(t interface {
@@ -14045,6 +14291,59 @@ func (_c *MockXDGPaths_ManDir_Call) RunAndReturn(run func() (string, error)) *Mo
1404514291 return _c
1404614292 }
1404714293
14294+// RuntimeDir provides a mock function for the type MockXDGPaths
14295+func (_mock *MockXDGPaths) RuntimeDir() (string, error) {
14296+ ret := _mock.Called()
14297+
14298+ if len(ret) == 0 {
14299+ panic("no return value specified for RuntimeDir")
14300+ }
14301+
14302+ var r0 string
14303+ var r1 error
14304+ if returnFunc, ok := ret.Get(0).(func() (string, error)); ok {
14305+ return returnFunc()
14306+ }
14307+ if returnFunc, ok := ret.Get(0).(func() string); ok {
14308+ r0 = returnFunc()
14309+ } else {
14310+ r0 = ret.Get(0).(string)
14311+ }
14312+ if returnFunc, ok := ret.Get(1).(func() error); ok {
14313+ r1 = returnFunc()
14314+ } else {
14315+ r1 = ret.Error(1)
14316+ }
14317+ return r0, r1
14318+}
14319+
14320+// MockXDGPaths_RuntimeDir_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RuntimeDir'
14321+type MockXDGPaths_RuntimeDir_Call struct {
14322+ *mock.Call
14323+}
14324+
14325+// RuntimeDir is a helper method to define mock.On call
14326+func (_e *MockXDGPaths_Expecter) RuntimeDir() *MockXDGPaths_RuntimeDir_Call {
14327+ return &MockXDGPaths_RuntimeDir_Call{Call: _e.mock.On("RuntimeDir")}
14328+}
14329+
14330+func (_c *MockXDGPaths_RuntimeDir_Call) Run(run func()) *MockXDGPaths_RuntimeDir_Call {
14331+ _c.Call.Run(func(args mock.Arguments) {
14332+ run()
14333+ })
14334+ return _c
14335+}
14336+
14337+func (_c *MockXDGPaths_RuntimeDir_Call) Return(s string, err error) *MockXDGPaths_RuntimeDir_Call {
14338+ _c.Call.Return(s, err)
14339+ return _c
14340+}
14341+
14342+func (_c *MockXDGPaths_RuntimeDir_Call) RunAndReturn(run func() (string, error)) *MockXDGPaths_RuntimeDir_Call {
14343+ _c.Call.Return(run)
14344+ return _c
14345+}
14346+
1404814347 // StateDir provides a mock function for the type MockXDGPaths
1404914348 func (_mock *MockXDGPaths) StateDir() (string, error) {
1405014349 ret := _mock.Called()
@@ -8,6 +8,7 @@ import (
8 "context"8 "context"
9 "database/sql"9 "database/sql"
10 "encoding/json"10 "encoding/json"
11+ "io"
11 "time"12 "time"
12 13
13 "github.com/bnema/dumber/internal/application/port"14 "github.com/bnema/dumber/internal/application/port"
@@ -172,6 +173,251 @@ func (_c *MockAccentPickerUI_Show_Call) RunAndReturn(run func(accents []rune, se
172 return _c173 return _c
173 }174 }
174 175
176+// NewMockBrowserWindowOpener creates a new instance of MockBrowserWindowOpener. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
177+// The first argument is typically a *testing.T value.
178+func NewMockBrowserWindowOpener(t interface {
179+ mock.TestingT
180+ Cleanup(func())
181+}) *MockBrowserWindowOpener {
182+ mock := &MockBrowserWindowOpener{}
183+ mock.Mock.Test(t)
184+
185+ t.Cleanup(func() { mock.AssertExpectations(t) })
186+
187+ return mock
188+}
189+
190+// MockBrowserWindowOpener is an autogenerated mock type for the BrowserWindowOpener type
191+type MockBrowserWindowOpener struct {
192+ mock.Mock
193+}
194+
195+type MockBrowserWindowOpener_Expecter struct {
196+ mock *mock.Mock
197+}
198+
199+func (_m *MockBrowserWindowOpener) EXPECT() *MockBrowserWindowOpener_Expecter {
200+ return &MockBrowserWindowOpener_Expecter{mock: &_m.Mock}
201+}
202+
203+// OpenFreshWindow provides a mock function for the type MockBrowserWindowOpener
204+func (_mock *MockBrowserWindowOpener) OpenFreshWindow(ctx context.Context, url string) error {
205+ ret := _mock.Called(ctx, url)
206+
207+ if len(ret) == 0 {
208+ panic("no return value specified for OpenFreshWindow")
209+ }
210+
211+ var r0 error
212+ if returnFunc, ok := ret.Get(0).(func(context.Context, string) error); ok {
213+ r0 = returnFunc(ctx, url)
214+ } else {
215+ r0 = ret.Error(0)
216+ }
217+ return r0
218+}
219+
220+// MockBrowserWindowOpener_OpenFreshWindow_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'OpenFreshWindow'
221+type MockBrowserWindowOpener_OpenFreshWindow_Call struct {
222+ *mock.Call
223+}
224+
225+// OpenFreshWindow is a helper method to define mock.On call
226+// - ctx context.Context
227+// - url string
228+func (_e *MockBrowserWindowOpener_Expecter) OpenFreshWindow(ctx interface{}, url interface{}) *MockBrowserWindowOpener_OpenFreshWindow_Call {
229+ return &MockBrowserWindowOpener_OpenFreshWindow_Call{Call: _e.mock.On("OpenFreshWindow", ctx, url)}
230+}
231+
232+func (_c *MockBrowserWindowOpener_OpenFreshWindow_Call) Run(run func(ctx context.Context, url string)) *MockBrowserWindowOpener_OpenFreshWindow_Call {
233+ _c.Call.Run(func(args mock.Arguments) {
234+ var arg0 context.Context
235+ if args[0] != nil {
236+ arg0 = args[0].(context.Context)
237+ }
238+ var arg1 string
239+ if args[1] != nil {
240+ arg1 = args[1].(string)
241+ }
242+ run(
243+ arg0,
244+ arg1,
245+ )
246+ })
247+ return _c
248+}
249+
250+func (_c *MockBrowserWindowOpener_OpenFreshWindow_Call) Return(err error) *MockBrowserWindowOpener_OpenFreshWindow_Call {
251+ _c.Call.Return(err)
252+ return _c
253+}
254+
255+func (_c *MockBrowserWindowOpener_OpenFreshWindow_Call) RunAndReturn(run func(ctx context.Context, url string) error) *MockBrowserWindowOpener_OpenFreshWindow_Call {
256+ _c.Call.Return(run)
257+ return _c
258+}
259+
260+// NewMockBrowserLaunchRelay creates a new instance of MockBrowserLaunchRelay. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
261+// The first argument is typically a *testing.T value.
262+func NewMockBrowserLaunchRelay(t interface {
263+ mock.TestingT
264+ Cleanup(func())
265+}) *MockBrowserLaunchRelay {
266+ mock := &MockBrowserLaunchRelay{}
267+ mock.Mock.Test(t)
268+
269+ t.Cleanup(func() { mock.AssertExpectations(t) })
270+
271+ return mock
272+}
273+
274+// MockBrowserLaunchRelay is an autogenerated mock type for the BrowserLaunchRelay type
275+type MockBrowserLaunchRelay struct {
276+ mock.Mock
277+}
278+
279+type MockBrowserLaunchRelay_Expecter struct {
280+ mock *mock.Mock
281+}
282+
283+func (_m *MockBrowserLaunchRelay) EXPECT() *MockBrowserLaunchRelay_Expecter {
284+ return &MockBrowserLaunchRelay_Expecter{mock: &_m.Mock}
285+}
286+
287+// DeliverOpenFreshWindow provides a mock function for the type MockBrowserLaunchRelay
288+func (_mock *MockBrowserLaunchRelay) DeliverOpenFreshWindow(ctx context.Context, url string) (bool, error) {
289+ ret := _mock.Called(ctx, url)
290+
291+ if len(ret) == 0 {
292+ panic("no return value specified for DeliverOpenFreshWindow")
293+ }
294+
295+ var r0 bool
296+ var r1 error
297+ if returnFunc, ok := ret.Get(0).(func(context.Context, string) (bool, error)); ok {
298+ return returnFunc(ctx, url)
299+ }
300+ if returnFunc, ok := ret.Get(0).(func(context.Context, string) bool); ok {
301+ r0 = returnFunc(ctx, url)
302+ } else {
303+ r0 = ret.Get(0).(bool)
304+ }
305+ if returnFunc, ok := ret.Get(1).(func(context.Context, string) error); ok {
306+ r1 = returnFunc(ctx, url)
307+ } else {
308+ r1 = ret.Error(1)
309+ }
310+ return r0, r1
311+}
312+
313+// MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeliverOpenFreshWindow'
314+type MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call struct {
315+ *mock.Call
316+}
317+
318+// DeliverOpenFreshWindow is a helper method to define mock.On call
319+// - ctx context.Context
320+// - url string
321+func (_e *MockBrowserLaunchRelay_Expecter) DeliverOpenFreshWindow(ctx interface{}, url interface{}) *MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call {
322+ return &MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call{Call: _e.mock.On("DeliverOpenFreshWindow", ctx, url)}
323+}
324+
325+func (_c *MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call) Run(run func(ctx context.Context, url string)) *MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call {
326+ _c.Call.Run(func(args mock.Arguments) {
327+ var arg0 context.Context
328+ if args[0] != nil {
329+ arg0 = args[0].(context.Context)
330+ }
331+ var arg1 string
332+ if args[1] != nil {
333+ arg1 = args[1].(string)
334+ }
335+ run(
336+ arg0,
337+ arg1,
338+ )
339+ })
340+ return _c
341+}
342+
343+func (_c *MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call) Return(b bool, err error) *MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call {
344+ _c.Call.Return(b, err)
345+ return _c
346+}
347+
348+func (_c *MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call) RunAndReturn(run func(ctx context.Context, url string) (bool, error)) *MockBrowserLaunchRelay_DeliverOpenFreshWindow_Call {
349+ _c.Call.Return(run)
350+ return _c
351+}
352+
353+// Listen provides a mock function for the type MockBrowserLaunchRelay
354+func (_mock *MockBrowserLaunchRelay) Listen(ctx context.Context, opener port.BrowserWindowOpener) (io.Closer, error) {
355+ ret := _mock.Called(ctx, opener)
356+
357+ if len(ret) == 0 {
358+ panic("no return value specified for Listen")
359+ }
360+
361+ var r0 io.Closer
362+ var r1 error
363+ if returnFunc, ok := ret.Get(0).(func(context.Context, port.BrowserWindowOpener) (io.Closer, error)); ok {
364+ return returnFunc(ctx, opener)
365+ }
366+ if returnFunc, ok := ret.Get(0).(func(context.Context, port.BrowserWindowOpener) io.Closer); ok {
367+ r0 = returnFunc(ctx, opener)
368+ } else {
369+ if ret.Get(0) != nil {
370+ r0 = ret.Get(0).(io.Closer)
371+ }
372+ }
373+ if returnFunc, ok := ret.Get(1).(func(context.Context, port.BrowserWindowOpener) error); ok {
374+ r1 = returnFunc(ctx, opener)
375+ } else {
376+ r1 = ret.Error(1)
377+ }
378+ return r0, r1
379+}
380+
381+// MockBrowserLaunchRelay_Listen_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Listen'
382+type MockBrowserLaunchRelay_Listen_Call struct {
383+ *mock.Call
384+}
385+
386+// Listen is a helper method to define mock.On call
387+// - ctx context.Context
388+// - opener port.BrowserWindowOpener
389+func (_e *MockBrowserLaunchRelay_Expecter) Listen(ctx interface{}, opener interface{}) *MockBrowserLaunchRelay_Listen_Call {
390+ return &MockBrowserLaunchRelay_Listen_Call{Call: _e.mock.On("Listen", ctx, opener)}
391+}
392+
393+func (_c *MockBrowserLaunchRelay_Listen_Call) Run(run func(ctx context.Context, opener port.BrowserWindowOpener)) *MockBrowserLaunchRelay_Listen_Call {
394+ _c.Call.Run(func(args mock.Arguments) {
395+ var arg0 context.Context
396+ if args[0] != nil {
397+ arg0 = args[0].(context.Context)
398+ }
399+ var arg1 port.BrowserWindowOpener
400+ if args[1] != nil {
401+ arg1 = args[1].(port.BrowserWindowOpener)
402+ }
403+ run(
404+ arg0,
405+ arg1,
406+ )
407+ })
408+ return _c
409+}
410+
411+func (_c *MockBrowserLaunchRelay_Listen_Call) Return(closer io.Closer, err error) *MockBrowserLaunchRelay_Listen_Call {
412+ _c.Call.Return(closer, err)
413+ return _c
414+}
415+
416+func (_c *MockBrowserLaunchRelay_Listen_Call) RunAndReturn(run func(ctx context.Context, opener port.BrowserWindowOpener) (io.Closer, error)) *MockBrowserLaunchRelay_Listen_Call {
417+ _c.Call.Return(run)
418+ return _c
419+}
420+
175 // NewMockClipboard creates a new instance of MockClipboard. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.421 // NewMockClipboard creates a new instance of MockClipboard. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
176 // The first argument is typically a *testing.T value.422 // The first argument is typically a *testing.T value.
177 func NewMockClipboard(t interface {423 func NewMockClipboard(t interface {
@@ -14045,6 +14291,59 @@ func (_c *MockXDGPaths_ManDir_Call) RunAndReturn(run func() (string, error)) *Mo
14045 return _c14291 return _c
14046 }14292 }
14047 14293
14294+// RuntimeDir provides a mock function for the type MockXDGPaths
14295+func (_mock *MockXDGPaths) RuntimeDir() (string, error) {
14296+ ret := _mock.Called()
14297+
14298+ if len(ret) == 0 {
14299+ panic("no return value specified for RuntimeDir")
14300+ }
14301+
14302+ var r0 string
14303+ var r1 error
14304+ if returnFunc, ok := ret.Get(0).(func() (string, error)); ok {
14305+ return returnFunc()
14306+ }
14307+ if returnFunc, ok := ret.Get(0).(func() string); ok {
14308+ r0 = returnFunc()
14309+ } else {
14310+ r0 = ret.Get(0).(string)
14311+ }
14312+ if returnFunc, ok := ret.Get(1).(func() error); ok {
14313+ r1 = returnFunc()
14314+ } else {
14315+ r1 = ret.Error(1)
14316+ }
14317+ return r0, r1
14318+}
14319+
14320+// MockXDGPaths_RuntimeDir_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RuntimeDir'
14321+type MockXDGPaths_RuntimeDir_Call struct {
14322+ *mock.Call
14323+}
14324+
14325+// RuntimeDir is a helper method to define mock.On call
14326+func (_e *MockXDGPaths_Expecter) RuntimeDir() *MockXDGPaths_RuntimeDir_Call {
14327+ return &MockXDGPaths_RuntimeDir_Call{Call: _e.mock.On("RuntimeDir")}
14328+}
14329+
14330+func (_c *MockXDGPaths_RuntimeDir_Call) Run(run func()) *MockXDGPaths_RuntimeDir_Call {
14331+ _c.Call.Run(func(args mock.Arguments) {
14332+ run()
14333+ })
14334+ return _c
14335+}
14336+
14337+func (_c *MockXDGPaths_RuntimeDir_Call) Return(s string, err error) *MockXDGPaths_RuntimeDir_Call {
14338+ _c.Call.Return(s, err)
14339+ return _c
14340+}
14341+
14342+func (_c *MockXDGPaths_RuntimeDir_Call) RunAndReturn(run func() (string, error)) *MockXDGPaths_RuntimeDir_Call {
14343+ _c.Call.Return(run)
14344+ return _c
14345+}
14346+
14048 // StateDir provides a mock function for the type MockXDGPaths14347 // StateDir provides a mock function for the type MockXDGPaths
14049 func (_mock *MockXDGPaths) StateDir() (string, error) {14348 func (_mock *MockXDGPaths) StateDir() (string, error) {
14050 ret := _mock.Called()14349 ret := _mock.Called()
M internal/application/port/xdg.go +1 -0
@@ -5,6 +5,7 @@ type XDGPaths interface {
55 ConfigDir() (string, error)
66 DataDir() (string, error)
77 StateDir() (string, error)
8+ RuntimeDir() (string, error)
89 CacheDir() (string, error)
910
1011 FilterJSONDir() (string, error)
@@ -5,6 +5,7 @@ type XDGPaths interface {
5 ConfigDir() (string, error)5 ConfigDir() (string, error)
6 DataDir() (string, error)6 DataDir() (string, error)
7 StateDir() (string, error)7 StateDir() (string, error)
8+ RuntimeDir() (string, error)
8 CacheDir() (string, error)9 CacheDir() (string, error)
9 10
10 FilterJSONDir() (string, error)11 FilterJSONDir() (string, error)
M internal/infrastructure/xdg/adapter.go +12 -0
@@ -28,6 +28,18 @@ func (a *Adapter) StateDir() (string, error) {
2828 return config.GetStateDir()
2929 }
3030
31+func (a *Adapter) RuntimeDir() (string, error) {
32+ if dir := os.Getenv("XDG_RUNTIME_DIR"); dir != "" {
33+ return dir, nil
34+ }
35+
36+ stateDir, err := a.StateDir()
37+ if err != nil {
38+ return "", err
39+ }
40+ return filepath.Join(stateDir, "runtime"), nil
41+}
42+
3143 func (a *Adapter) CacheDir() (string, error) {
3244 dirs, err := config.GetXDGDirs()
3345 if err != nil {
@@ -28,6 +28,18 @@ func (a *Adapter) StateDir() (string, error) {
28 return config.GetStateDir()28 return config.GetStateDir()
29 }29 }
30 30
31+func (a *Adapter) RuntimeDir() (string, error) {
32+ if dir := os.Getenv("XDG_RUNTIME_DIR"); dir != "" {
33+ return dir, nil
34+ }
35+
36+ stateDir, err := a.StateDir()
37+ if err != nil {
38+ return "", err
39+ }
40+ return filepath.Join(stateDir, "runtime"), nil
41+}
42+
31 func (a *Adapter) CacheDir() (string, error) {43 func (a *Adapter) CacheDir() (string, error) {
32 dirs, err := config.GetXDGDirs()44 dirs, err := config.GetXDGDirs()
33 if err != nil {45 if err != nil {
M internal/infrastructure/xdg/adapter_test.go +47 -0
@@ -56,6 +56,53 @@ func TestAdapter_DownloadDir(t *testing.T) {
5656 })
5757 }
5858
59+func TestAdapter_RuntimeDir(t *testing.T) {
60+ adapter := New()
61+
62+ t.Run("returns XDG_RUNTIME_DIR when set", func(t *testing.T) {
63+ original := os.Getenv("XDG_RUNTIME_DIR")
64+ defer func() {
65+ if original == "" {
66+ os.Unsetenv("XDG_RUNTIME_DIR")
67+ } else {
68+ os.Setenv("XDG_RUNTIME_DIR", original)
69+ }
70+ }()
71+
72+ os.Setenv("XDG_RUNTIME_DIR", "/custom/runtime")
73+
74+ dir, err := adapter.RuntimeDir()
75+
76+ require.NoError(t, err)
77+ assert.Equal(t, "/custom/runtime", dir)
78+ })
79+
80+ t.Run("falls back to state runtime dir when XDG_RUNTIME_DIR not set", func(t *testing.T) {
81+ originalRuntime := os.Getenv("XDG_RUNTIME_DIR")
82+ originalState := os.Getenv("XDG_STATE_HOME")
83+ defer func() {
84+ if originalRuntime == "" {
85+ os.Unsetenv("XDG_RUNTIME_DIR")
86+ } else {
87+ os.Setenv("XDG_RUNTIME_DIR", originalRuntime)
88+ }
89+ if originalState == "" {
90+ os.Unsetenv("XDG_STATE_HOME")
91+ } else {
92+ os.Setenv("XDG_STATE_HOME", originalState)
93+ }
94+ }()
95+
96+ os.Unsetenv("XDG_RUNTIME_DIR")
97+ os.Setenv("XDG_STATE_HOME", "/tmp/dumber-state")
98+
99+ dir, err := adapter.RuntimeDir()
100+
101+ require.NoError(t, err)
102+ assert.Equal(t, filepath.Join("/tmp/dumber-state", "dumber", "runtime"), dir)
103+ })
104+}
105+
59106 func TestNew(t *testing.T) {
60107 adapter := New()
61108
@@ -56,6 +56,53 @@ func TestAdapter_DownloadDir(t *testing.T) {
56 })56 })
57 }57 }
58 58
59+func TestAdapter_RuntimeDir(t *testing.T) {
60+ adapter := New()
61+
62+ t.Run("returns XDG_RUNTIME_DIR when set", func(t *testing.T) {
63+ original := os.Getenv("XDG_RUNTIME_DIR")
64+ defer func() {
65+ if original == "" {
66+ os.Unsetenv("XDG_RUNTIME_DIR")
67+ } else {
68+ os.Setenv("XDG_RUNTIME_DIR", original)
69+ }
70+ }()
71+
72+ os.Setenv("XDG_RUNTIME_DIR", "/custom/runtime")
73+
74+ dir, err := adapter.RuntimeDir()
75+
76+ require.NoError(t, err)
77+ assert.Equal(t, "/custom/runtime", dir)
78+ })
79+
80+ t.Run("falls back to state runtime dir when XDG_RUNTIME_DIR not set", func(t *testing.T) {
81+ originalRuntime := os.Getenv("XDG_RUNTIME_DIR")
82+ originalState := os.Getenv("XDG_STATE_HOME")
83+ defer func() {
84+ if originalRuntime == "" {
85+ os.Unsetenv("XDG_RUNTIME_DIR")
86+ } else {
87+ os.Setenv("XDG_RUNTIME_DIR", originalRuntime)
88+ }
89+ if originalState == "" {
90+ os.Unsetenv("XDG_STATE_HOME")
91+ } else {
92+ os.Setenv("XDG_STATE_HOME", originalState)
93+ }
94+ }()
95+
96+ os.Unsetenv("XDG_RUNTIME_DIR")
97+ os.Setenv("XDG_STATE_HOME", "/tmp/dumber-state")
98+
99+ dir, err := adapter.RuntimeDir()
100+
101+ require.NoError(t, err)
102+ assert.Equal(t, filepath.Join("/tmp/dumber-state", "dumber", "runtime"), dir)
103+ })
104+}
105+
59 func TestNew(t *testing.T) {106 func TestNew(t *testing.T) {
60 adapter := New()107 adapter := New()
61 108

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