detached f95a7fa

fix(lint): resolve funlen, rangeValCopy, magic numbers and line length issues

commit
f95a7fad48dd4a0c09f70bed5dd42d3402e963b7
author
bnema · · 2025-12-22 21:52 UTC
parent
ab84ac9
signature
unsigned
3 files · +112 -110
M cmd/dumber/main.go +80 -91
@@ -20,10 +20,8 @@ import (
2020 "github.com/bnema/dumber/internal/infrastructure/config"
2121 "github.com/bnema/dumber/internal/infrastructure/deps"
2222 "github.com/bnema/dumber/internal/infrastructure/favicon"
23- "github.com/bnema/dumber/internal/infrastructure/filtering"
2423 "github.com/bnema/dumber/internal/infrastructure/media"
2524 "github.com/bnema/dumber/internal/infrastructure/persistence/sqlite"
26- "github.com/bnema/dumber/internal/infrastructure/webkit"
2725 "github.com/bnema/dumber/internal/logging"
2826 "github.com/bnema/dumber/internal/ui"
2927 "github.com/bnema/dumber/internal/ui/theme"
@@ -107,61 +105,11 @@ func runGUI() int {
107105 checkRuntimeRequirements(ctx, cfg, logger)
108106 checkMediaRequirements(ctx, cfg, logger)
109107
110- // Create repositories
111- historyRepo := sqlite.NewHistoryRepository(db)
112- favoriteRepo := sqlite.NewFavoriteRepository(db)
113- folderRepo := sqlite.NewFolderRepository(db)
114- tagRepo := sqlite.NewTagRepository(db)
115- zoomRepo := sqlite.NewZoomRepository(db)
116-
117- // Theme management
118108 themeManager := theme.NewManager(ctx, cfg)
119-
120109 stack := bootstrap.BuildWebKitStack(ctx, cfg, dataDir, cacheDir, themeManager, logger)
121-
122- // Create use cases
123- const idAlphabetSize = 26
124- idCounter := uint64(0)
125- idGenerator := func() string {
126- idCounter++
127- return fmt.Sprintf("%c%d", 'a'+rune(idCounter%idAlphabetSize), idCounter/idAlphabetSize)
128- }
129- tabsUC := usecase.NewManageTabsUseCase(idGenerator)
130- panesUC := usecase.NewManagePanesUseCase(idGenerator)
131- historyUC := usecase.NewSearchHistoryUseCase(historyRepo)
132- favoritesUC := usecase.NewManageFavoritesUseCase(favoriteRepo, folderRepo, tagRepo)
133- zoomUC := usecase.NewManageZoomUseCase(zoomRepo, cfg.DefaultWebpageZoom)
134- navigateUC := usecase.NewNavigateUseCase(historyRepo, zoomRepo, cfg.DefaultWebpageZoom)
135- clipboardAdapter := clipboard.New()
136- copyURLUC := usecase.NewCopyURLUseCase(clipboardAdapter)
137-
138- // Create favicon service
139- faviconCacheDir, _ := config.GetFaviconCacheDir()
140- faviconService := favicon.NewService(faviconCacheDir)
141-
142- uiDeps := buildUIDependencies(
143- ctx,
144- cfg,
145- themeManager,
146- stack.Context,
147- stack.Pool,
148- stack.Settings,
149- stack.Injector,
150- stack.MessageRouter,
151- stack.FilterManager,
152- historyRepo,
153- favoriteRepo,
154- zoomRepo,
155- tabsUC,
156- panesUC,
157- historyUC,
158- favoritesUC,
159- zoomUC,
160- navigateUC,
161- copyURLUC,
162- clipboardAdapter,
163- faviconService,
164- )
110+ repos := createRepositories(db)
111+ useCases := createUseCases(repos, cfg.DefaultWebpageZoom)
112+ uiDeps := buildUIDependencies(ctx, cfg, themeManager, &stack, repos, useCases)
165113
166114 app, err := ui.New(uiDeps)
167115 if err != nil {
@@ -267,51 +215,92 @@ func openDatabase(ctx context.Context, logger zerolog.Logger, dataDir string) (*
267215 return db, cleanup
268216 }
269217
218+// repositories groups infrastructure layer repository implementations.
219+type repositories struct {
220+ history repository.HistoryRepository
221+ favorite repository.FavoriteRepository
222+ folder repository.FolderRepository
223+ tag repository.TagRepository
224+ zoom repository.ZoomRepository
225+}
226+
227+func createRepositories(db *sql.DB) *repositories {
228+ return &repositories{
229+ history: sqlite.NewHistoryRepository(db),
230+ favorite: sqlite.NewFavoriteRepository(db),
231+ folder: sqlite.NewFolderRepository(db),
232+ tag: sqlite.NewTagRepository(db),
233+ zoom: sqlite.NewZoomRepository(db),
234+ }
235+}
236+
237+// useCases groups application layer use case implementations.
238+type useCases struct {
239+ tabs *usecase.ManageTabsUseCase
240+ panes *usecase.ManagePanesUseCase
241+ history *usecase.SearchHistoryUseCase
242+ favorites *usecase.ManageFavoritesUseCase
243+ zoom *usecase.ManageZoomUseCase
244+ navigate *usecase.NavigateUseCase
245+ copyURL *usecase.CopyURLUseCase
246+ clipboard port.Clipboard
247+ favicon *favicon.Service
248+}
249+
250+func createUseCases(repos *repositories, defaultZoom float64) *useCases {
251+ const idAlphabetSize = 26
252+ idCounter := uint64(0)
253+ idGenerator := func() string {
254+ idCounter++
255+ return fmt.Sprintf("%c%d", 'a'+rune(idCounter%idAlphabetSize), idCounter/idAlphabetSize)
256+ }
257+
258+ clipboardAdapter := clipboard.New()
259+ faviconCacheDir, _ := config.GetFaviconCacheDir()
260+
261+ return &useCases{
262+ tabs: usecase.NewManageTabsUseCase(idGenerator),
263+ panes: usecase.NewManagePanesUseCase(idGenerator),
264+ history: usecase.NewSearchHistoryUseCase(repos.history),
265+ favorites: usecase.NewManageFavoritesUseCase(repos.favorite, repos.folder, repos.tag),
266+ zoom: usecase.NewManageZoomUseCase(repos.zoom, defaultZoom),
267+ navigate: usecase.NewNavigateUseCase(repos.history, repos.zoom, defaultZoom),
268+ copyURL: usecase.NewCopyURLUseCase(clipboardAdapter),
269+ clipboard: clipboardAdapter,
270+ favicon: favicon.NewService(faviconCacheDir),
271+ }
272+}
273+
270274 func buildUIDependencies(
271275 ctx context.Context,
272276 cfg *config.Config,
273277 themeManager *theme.Manager,
274- wkCtx *webkit.WebKitContext,
275- pool *webkit.WebViewPool,
276- settings *webkit.SettingsManager,
277- injector *webkit.ContentInjector,
278- messageRouter *webkit.MessageRouter,
279- filterManager *filtering.Manager,
280- historyRepo repository.HistoryRepository,
281- favoriteRepo repository.FavoriteRepository,
282- zoomRepo repository.ZoomRepository,
283- tabsUC *usecase.ManageTabsUseCase,
284- panesUC *usecase.ManagePanesUseCase,
285- historyUC *usecase.SearchHistoryUseCase,
286- favoritesUC *usecase.ManageFavoritesUseCase,
287- zoomUC *usecase.ManageZoomUseCase,
288- navigateUC *usecase.NavigateUseCase,
289- copyURLUC *usecase.CopyURLUseCase,
290- clipboardAdapter port.Clipboard,
291- faviconService *favicon.Service,
278+ stack *bootstrap.WebKitStack,
279+ repos *repositories,
280+ uc *useCases,
292281 ) *ui.Dependencies {
293282 return &ui.Dependencies{
294283 Ctx: ctx,
295284 Config: cfg,
296285 InitialURL: initialURL,
297286 Theme: themeManager,
298- WebContext: wkCtx,
299- Pool: pool,
300- Settings: settings,
301- Injector: injector,
302- MessageRouter: messageRouter,
303- HistoryRepo: historyRepo,
304- FavoriteRepo: favoriteRepo,
305- ZoomRepo: zoomRepo,
306- TabsUC: tabsUC,
307- PanesUC: panesUC,
308- HistoryUC: historyUC,
309- FavoritesUC: favoritesUC,
310- ZoomUC: zoomUC,
311- NavigateUC: navigateUC,
312- CopyURLUC: copyURLUC,
313- Clipboard: clipboardAdapter,
314- FaviconService: faviconService,
315- FilterManager: filterManager,
287+ WebContext: stack.Context,
288+ Pool: stack.Pool,
289+ Settings: stack.Settings,
290+ Injector: stack.Injector,
291+ MessageRouter: stack.MessageRouter,
292+ FilterManager: stack.FilterManager,
293+ HistoryRepo: repos.history,
294+ FavoriteRepo: repos.favorite,
295+ ZoomRepo: repos.zoom,
296+ TabsUC: uc.tabs,
297+ PanesUC: uc.panes,
298+ HistoryUC: uc.history,
299+ FavoritesUC: uc.favorites,
300+ ZoomUC: uc.zoom,
301+ NavigateUC: uc.navigate,
302+ CopyURLUC: uc.copyURL,
303+ Clipboard: uc.clipboard,
304+ FaviconService: uc.favicon,
316305 }
317306 }
@@ -20,10 +20,8 @@ import (
20 "github.com/bnema/dumber/internal/infrastructure/config"20 "github.com/bnema/dumber/internal/infrastructure/config"
21 "github.com/bnema/dumber/internal/infrastructure/deps"21 "github.com/bnema/dumber/internal/infrastructure/deps"
22 "github.com/bnema/dumber/internal/infrastructure/favicon"22 "github.com/bnema/dumber/internal/infrastructure/favicon"
23- "github.com/bnema/dumber/internal/infrastructure/filtering"
24 "github.com/bnema/dumber/internal/infrastructure/media"23 "github.com/bnema/dumber/internal/infrastructure/media"
25 "github.com/bnema/dumber/internal/infrastructure/persistence/sqlite"24 "github.com/bnema/dumber/internal/infrastructure/persistence/sqlite"
26- "github.com/bnema/dumber/internal/infrastructure/webkit"
27 "github.com/bnema/dumber/internal/logging"25 "github.com/bnema/dumber/internal/logging"
28 "github.com/bnema/dumber/internal/ui"26 "github.com/bnema/dumber/internal/ui"
29 "github.com/bnema/dumber/internal/ui/theme"27 "github.com/bnema/dumber/internal/ui/theme"
@@ -107,61 +105,11 @@ func runGUI() int {
107 checkRuntimeRequirements(ctx, cfg, logger)105 checkRuntimeRequirements(ctx, cfg, logger)
108 checkMediaRequirements(ctx, cfg, logger)106 checkMediaRequirements(ctx, cfg, logger)
109 107
110- // Create repositories
111- historyRepo := sqlite.NewHistoryRepository(db)
112- favoriteRepo := sqlite.NewFavoriteRepository(db)
113- folderRepo := sqlite.NewFolderRepository(db)
114- tagRepo := sqlite.NewTagRepository(db)
115- zoomRepo := sqlite.NewZoomRepository(db)
116-
117- // Theme management
118 themeManager := theme.NewManager(ctx, cfg)108 themeManager := theme.NewManager(ctx, cfg)
119-
120 stack := bootstrap.BuildWebKitStack(ctx, cfg, dataDir, cacheDir, themeManager, logger)109 stack := bootstrap.BuildWebKitStack(ctx, cfg, dataDir, cacheDir, themeManager, logger)
121-110+ repos := createRepositories(db)
122- // Create use cases111+ useCases := createUseCases(repos, cfg.DefaultWebpageZoom)
123- const idAlphabetSize = 26112+ uiDeps := buildUIDependencies(ctx, cfg, themeManager, &stack, repos, useCases)
124- idCounter := uint64(0)
125- idGenerator := func() string {
126- idCounter++
127- return fmt.Sprintf("%c%d", 'a'+rune(idCounter%idAlphabetSize), idCounter/idAlphabetSize)
128- }
129- tabsUC := usecase.NewManageTabsUseCase(idGenerator)
130- panesUC := usecase.NewManagePanesUseCase(idGenerator)
131- historyUC := usecase.NewSearchHistoryUseCase(historyRepo)
132- favoritesUC := usecase.NewManageFavoritesUseCase(favoriteRepo, folderRepo, tagRepo)
133- zoomUC := usecase.NewManageZoomUseCase(zoomRepo, cfg.DefaultWebpageZoom)
134- navigateUC := usecase.NewNavigateUseCase(historyRepo, zoomRepo, cfg.DefaultWebpageZoom)
135- clipboardAdapter := clipboard.New()
136- copyURLUC := usecase.NewCopyURLUseCase(clipboardAdapter)
137-
138- // Create favicon service
139- faviconCacheDir, _ := config.GetFaviconCacheDir()
140- faviconService := favicon.NewService(faviconCacheDir)
141-
142- uiDeps := buildUIDependencies(
143- ctx,
144- cfg,
145- themeManager,
146- stack.Context,
147- stack.Pool,
148- stack.Settings,
149- stack.Injector,
150- stack.MessageRouter,
151- stack.FilterManager,
152- historyRepo,
153- favoriteRepo,
154- zoomRepo,
155- tabsUC,
156- panesUC,
157- historyUC,
158- favoritesUC,
159- zoomUC,
160- navigateUC,
161- copyURLUC,
162- clipboardAdapter,
163- faviconService,
164- )
165 113
166 app, err := ui.New(uiDeps)114 app, err := ui.New(uiDeps)
167 if err != nil {115 if err != nil {
@@ -267,51 +215,92 @@ func openDatabase(ctx context.Context, logger zerolog.Logger, dataDir string) (*
267 return db, cleanup215 return db, cleanup
268 }216 }
269 217
218+// repositories groups infrastructure layer repository implementations.
219+type repositories struct {
220+ history repository.HistoryRepository
221+ favorite repository.FavoriteRepository
222+ folder repository.FolderRepository
223+ tag repository.TagRepository
224+ zoom repository.ZoomRepository
225+}
226+
227+func createRepositories(db *sql.DB) *repositories {
228+ return &repositories{
229+ history: sqlite.NewHistoryRepository(db),
230+ favorite: sqlite.NewFavoriteRepository(db),
231+ folder: sqlite.NewFolderRepository(db),
232+ tag: sqlite.NewTagRepository(db),
233+ zoom: sqlite.NewZoomRepository(db),
234+ }
235+}
236+
237+// useCases groups application layer use case implementations.
238+type useCases struct {
239+ tabs *usecase.ManageTabsUseCase
240+ panes *usecase.ManagePanesUseCase
241+ history *usecase.SearchHistoryUseCase
242+ favorites *usecase.ManageFavoritesUseCase
243+ zoom *usecase.ManageZoomUseCase
244+ navigate *usecase.NavigateUseCase
245+ copyURL *usecase.CopyURLUseCase
246+ clipboard port.Clipboard
247+ favicon *favicon.Service
248+}
249+
250+func createUseCases(repos *repositories, defaultZoom float64) *useCases {
251+ const idAlphabetSize = 26
252+ idCounter := uint64(0)
253+ idGenerator := func() string {
254+ idCounter++
255+ return fmt.Sprintf("%c%d", 'a'+rune(idCounter%idAlphabetSize), idCounter/idAlphabetSize)
256+ }
257+
258+ clipboardAdapter := clipboard.New()
259+ faviconCacheDir, _ := config.GetFaviconCacheDir()
260+
261+ return &useCases{
262+ tabs: usecase.NewManageTabsUseCase(idGenerator),
263+ panes: usecase.NewManagePanesUseCase(idGenerator),
264+ history: usecase.NewSearchHistoryUseCase(repos.history),
265+ favorites: usecase.NewManageFavoritesUseCase(repos.favorite, repos.folder, repos.tag),
266+ zoom: usecase.NewManageZoomUseCase(repos.zoom, defaultZoom),
267+ navigate: usecase.NewNavigateUseCase(repos.history, repos.zoom, defaultZoom),
268+ copyURL: usecase.NewCopyURLUseCase(clipboardAdapter),
269+ clipboard: clipboardAdapter,
270+ favicon: favicon.NewService(faviconCacheDir),
271+ }
272+}
273+
270 func buildUIDependencies(274 func buildUIDependencies(
271 ctx context.Context,275 ctx context.Context,
272 cfg *config.Config,276 cfg *config.Config,
273 themeManager *theme.Manager,277 themeManager *theme.Manager,
274- wkCtx *webkit.WebKitContext,278+ stack *bootstrap.WebKitStack,
275- pool *webkit.WebViewPool,279+ repos *repositories,
276- settings *webkit.SettingsManager,280+ uc *useCases,
277- injector *webkit.ContentInjector,
278- messageRouter *webkit.MessageRouter,
279- filterManager *filtering.Manager,
280- historyRepo repository.HistoryRepository,
281- favoriteRepo repository.FavoriteRepository,
282- zoomRepo repository.ZoomRepository,
283- tabsUC *usecase.ManageTabsUseCase,
284- panesUC *usecase.ManagePanesUseCase,
285- historyUC *usecase.SearchHistoryUseCase,
286- favoritesUC *usecase.ManageFavoritesUseCase,
287- zoomUC *usecase.ManageZoomUseCase,
288- navigateUC *usecase.NavigateUseCase,
289- copyURLUC *usecase.CopyURLUseCase,
290- clipboardAdapter port.Clipboard,
291- faviconService *favicon.Service,
292 ) *ui.Dependencies {281 ) *ui.Dependencies {
293 return &ui.Dependencies{282 return &ui.Dependencies{
294 Ctx: ctx,283 Ctx: ctx,
295 Config: cfg,284 Config: cfg,
296 InitialURL: initialURL,285 InitialURL: initialURL,
297 Theme: themeManager,286 Theme: themeManager,
298- WebContext: wkCtx,287+ WebContext: stack.Context,
299- Pool: pool,288+ Pool: stack.Pool,
300- Settings: settings,289+ Settings: stack.Settings,
301- Injector: injector,290+ Injector: stack.Injector,
302- MessageRouter: messageRouter,291+ MessageRouter: stack.MessageRouter,
303- HistoryRepo: historyRepo,292+ FilterManager: stack.FilterManager,
304- FavoriteRepo: favoriteRepo,293+ HistoryRepo: repos.history,
305- ZoomRepo: zoomRepo,294+ FavoriteRepo: repos.favorite,
306- TabsUC: tabsUC,295+ ZoomRepo: repos.zoom,
307- PanesUC: panesUC,296+ TabsUC: uc.tabs,
308- HistoryUC: historyUC,297+ PanesUC: uc.panes,
309- FavoritesUC: favoritesUC,298+ HistoryUC: uc.history,
310- ZoomUC: zoomUC,299+ FavoritesUC: uc.favorites,
311- NavigateUC: navigateUC,300+ ZoomUC: uc.zoom,
312- CopyURLUC: copyURLUC,301+ NavigateUC: uc.navigate,
313- Clipboard: clipboardAdapter,302+ CopyURLUC: uc.copyURL,
314- FaviconService: faviconService,303+ Clipboard: uc.clipboard,
315- FilterManager: filterManager,304+ FaviconService: uc.favicon,
316 }305 }
317 }306 }
M internal/bootstrap/session.go +13 -5
@@ -20,6 +20,12 @@ import (
2020 "github.com/rs/zerolog"
2121 )
2222
23+const (
24+ recentSessionsLimit = 200
25+ lockDirPerm = 0o755
26+ lockFilePerm = 0o600
27+)
28+
2329 type BrowserSession struct {
2430 Session *entity.Session
2531 Logger zerolog.Logger
@@ -92,9 +98,11 @@ func StartBrowserSession(ctx context.Context, cfg *config.Config, db *sql.DB) (*
9298 }, sessionCtx, nil
9399 }
94100
95-func endStaleActiveBrowserSessions(ctx context.Context, sessionUC *usecase.ManageSessionUseCase, lockDir string, log *zerolog.Logger) error {
101+func endStaleActiveBrowserSessions(
102+ ctx context.Context, sessionUC *usecase.ManageSessionUseCase, lockDir string, log *zerolog.Logger,
103+) error {
96104 // We only have GetRecentSessions; fetch enough to cover likely actives.
97- recent, err := sessionUC.GetRecentSessions(ctx, 200)
105+ recent, err := sessionUC.GetRecentSessions(ctx, recentSessionsLimit)
98106 if err != nil {
99107 return err
100108 }
@@ -111,7 +119,7 @@ func endStaleActiveBrowserSessions(ctx context.Context, sessionUC *usecase.Manag
111119 continue
112120 }
113121
114- f, err := os.OpenFile(lockPath, os.O_RDWR, 0o600)
122+ f, err := os.OpenFile(lockPath, os.O_RDWR, lockFilePerm)
115123 if err != nil {
116124 continue
117125 }
@@ -148,12 +156,12 @@ func lockSessionFile(lockDir string, sessionID entity.SessionID) (*os.File, stri
148156 if lockDir == "" {
149157 return nil, "", errors.New("lock dir is empty")
150158 }
151- if err := os.MkdirAll(lockDir, 0o755); err != nil {
159+ if err := os.MkdirAll(lockDir, lockDirPerm); err != nil {
152160 return nil, "", err
153161 }
154162
155163 lockPath := sessionLockPath(lockDir, sessionID)
156- f, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0o600)
164+ f, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, lockFilePerm)
157165 if err != nil {
158166 return nil, "", err
159167 }
@@ -20,6 +20,12 @@ import (
20 "github.com/rs/zerolog"20 "github.com/rs/zerolog"
21 )21 )
22 22
23+const (
24+ recentSessionsLimit = 200
25+ lockDirPerm = 0o755
26+ lockFilePerm = 0o600
27+)
28+
23 type BrowserSession struct {29 type BrowserSession struct {
24 Session *entity.Session30 Session *entity.Session
25 Logger zerolog.Logger31 Logger zerolog.Logger
@@ -92,9 +98,11 @@ func StartBrowserSession(ctx context.Context, cfg *config.Config, db *sql.DB) (*
92 }, sessionCtx, nil98 }, sessionCtx, nil
93 }99 }
94 100
95-func endStaleActiveBrowserSessions(ctx context.Context, sessionUC *usecase.ManageSessionUseCase, lockDir string, log *zerolog.Logger) error {101+func endStaleActiveBrowserSessions(
102+ ctx context.Context, sessionUC *usecase.ManageSessionUseCase, lockDir string, log *zerolog.Logger,
103+) error {
96 // We only have GetRecentSessions; fetch enough to cover likely actives.104 // We only have GetRecentSessions; fetch enough to cover likely actives.
97- recent, err := sessionUC.GetRecentSessions(ctx, 200)105+ recent, err := sessionUC.GetRecentSessions(ctx, recentSessionsLimit)
98 if err != nil {106 if err != nil {
99 return err107 return err
100 }108 }
@@ -111,7 +119,7 @@ func endStaleActiveBrowserSessions(ctx context.Context, sessionUC *usecase.Manag
111 continue119 continue
112 }120 }
113 121
114- f, err := os.OpenFile(lockPath, os.O_RDWR, 0o600)122+ f, err := os.OpenFile(lockPath, os.O_RDWR, lockFilePerm)
115 if err != nil {123 if err != nil {
116 continue124 continue
117 }125 }
@@ -148,12 +156,12 @@ func lockSessionFile(lockDir string, sessionID entity.SessionID) (*os.File, stri
148 if lockDir == "" {156 if lockDir == "" {
149 return nil, "", errors.New("lock dir is empty")157 return nil, "", errors.New("lock dir is empty")
150 }158 }
151- if err := os.MkdirAll(lockDir, 0o755); err != nil {159+ if err := os.MkdirAll(lockDir, lockDirPerm); err != nil {
152 return nil, "", err160 return nil, "", err
153 }161 }
154 162
155 lockPath := sessionLockPath(lockDir, sessionID)163 lockPath := sessionLockPath(lockDir, sessionID)
156- f, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, 0o600)164+ f, err := os.OpenFile(lockPath, os.O_CREATE|os.O_RDWR, lockFilePerm)
157 if err != nil {165 if err != nil {
158 return nil, "", err166 return nil, "", err
159 }167 }
M internal/cli/cmd/logs.go +19 -14
@@ -26,7 +26,10 @@ var (
2626 logsClearAll bool
2727 )
2828
29-const defaultLogsLines = 50
29+const (
30+ defaultLogsLines = 50
31+ recentSessionsLimit = 200
32+)
3033
3134 var logsCmd = &cobra.Command{
3235 Use: "logs [session]",
@@ -138,8 +141,9 @@ func listSessions(ctx context.Context, sessionMgr sessionManager, logDir string,
138141 fmt.Println()
139142
140143 // Table format: ShortID | DateTime | Status | Size
141- for _, s := range sessions {
142- timeStr := sessionSortTime(s).Format("2006-01-02 15:04:05")
144+ for i := range sessions {
145+ s := &sessions[i]
146+ timeStr := sessionSortTime(*s).Format("2006-01-02 15:04:05")
143147
144148 status := ""
145149 if s.FromDB {
@@ -222,7 +226,7 @@ func getSessionsMerged(ctx context.Context, sessionMgr sessionManager, logDir st
222226 return fsSessions, nil
223227 }
224228
225- dbSessions, err := sessionMgr.GetRecentSessions(ctx, 200)
229+ dbSessions, err := sessionMgr.GetRecentSessions(ctx, recentSessionsLimit)
226230 if err != nil {
227231 if isMissingSessionsTable(err) {
228232 return fsSessions, nil
@@ -256,11 +260,11 @@ func getSessionsMerged(ctx context.Context, sessionMgr sessionManager, logDir st
256260 merged = append(merged, info)
257261 }
258262
259- for _, s := range fsSessions {
260- if _, ok := byID[s.SessionID]; ok {
263+ for i := range fsSessions {
264+ if _, ok := byID[fsSessions[i].SessionID]; ok {
261265 continue
262266 }
263- merged = append(merged, s)
267+ merged = append(merged, fsSessions[i])
264268 }
265269
266270 sort.Slice(merged, func(i, j int) bool {
@@ -304,16 +308,16 @@ func findSession(ctx context.Context, sessionMgr sessionManager, logDir, query s
304308 if shortID == "" {
305309 shortID = logging.ShortSessionID(sessions[i].SessionID)
306310 }
307- if strings.ToLower(shortID) == queryNormalized {
311+ if strings.EqualFold(shortID, queryNormalized) {
308312 return &sessions[i], nil
309313 }
310314 }
311315
312316 // Try partial match on full session ID
313317 var matches []SessionInfo
314- for _, s := range sessions {
315- if strings.Contains(strings.ToLower(s.SessionID), queryNormalized) {
316- matches = append(matches, s)
318+ for i := range sessions {
319+ if strings.Contains(strings.ToLower(sessions[i].SessionID), queryNormalized) {
320+ matches = append(matches, sessions[i])
317321 }
318322 }
319323
@@ -325,8 +329,8 @@ func findSession(ctx context.Context, sessionMgr sessionManager, logDir, query s
325329 default:
326330 // Multiple matches - show them and ask user to be more specific
327331 var ids []string
328- for _, m := range matches {
329- ids = append(ids, m.ShortID)
332+ for i := range matches {
333+ ids = append(ids, matches[i].ShortID)
330334 }
331335 return nil, fmt.Errorf("multiple sessions match '%s': %s", query, strings.Join(ids, ", "))
332336 }
@@ -523,7 +527,8 @@ func runLogsClear(_ *cobra.Command, _ []string) error {
523527 cutoff := time.Now().AddDate(0, 0, -maxAge)
524528 var removed int
525529
526- for _, s := range sessions {
530+ for i := range sessions {
531+ s := &sessions[i]
527532 shouldRemove := logsClearAll || s.ModTime.Before(cutoff)
528533 if !shouldRemove {
529534 continue
@@ -26,7 +26,10 @@ var (
26 logsClearAll bool26 logsClearAll bool
27 )27 )
28 28
29-const defaultLogsLines = 5029+const (
30+ defaultLogsLines = 50
31+ recentSessionsLimit = 200
32+)
30 33
31 var logsCmd = &cobra.Command{34 var logsCmd = &cobra.Command{
32 Use: "logs [session]",35 Use: "logs [session]",
@@ -138,8 +141,9 @@ func listSessions(ctx context.Context, sessionMgr sessionManager, logDir string,
138 fmt.Println()141 fmt.Println()
139 142
140 // Table format: ShortID | DateTime | Status | Size143 // Table format: ShortID | DateTime | Status | Size
141- for _, s := range sessions {144+ for i := range sessions {
142- timeStr := sessionSortTime(s).Format("2006-01-02 15:04:05")145+ s := &sessions[i]
146+ timeStr := sessionSortTime(*s).Format("2006-01-02 15:04:05")
143 147
144 status := ""148 status := ""
145 if s.FromDB {149 if s.FromDB {
@@ -222,7 +226,7 @@ func getSessionsMerged(ctx context.Context, sessionMgr sessionManager, logDir st
222 return fsSessions, nil226 return fsSessions, nil
223 }227 }
224 228
225- dbSessions, err := sessionMgr.GetRecentSessions(ctx, 200)229+ dbSessions, err := sessionMgr.GetRecentSessions(ctx, recentSessionsLimit)
226 if err != nil {230 if err != nil {
227 if isMissingSessionsTable(err) {231 if isMissingSessionsTable(err) {
228 return fsSessions, nil232 return fsSessions, nil
@@ -256,11 +260,11 @@ func getSessionsMerged(ctx context.Context, sessionMgr sessionManager, logDir st
256 merged = append(merged, info)260 merged = append(merged, info)
257 }261 }
258 262
259- for _, s := range fsSessions {263+ for i := range fsSessions {
260- if _, ok := byID[s.SessionID]; ok {264+ if _, ok := byID[fsSessions[i].SessionID]; ok {
261 continue265 continue
262 }266 }
263- merged = append(merged, s)267+ merged = append(merged, fsSessions[i])
264 }268 }
265 269
266 sort.Slice(merged, func(i, j int) bool {270 sort.Slice(merged, func(i, j int) bool {
@@ -304,16 +308,16 @@ func findSession(ctx context.Context, sessionMgr sessionManager, logDir, query s
304 if shortID == "" {308 if shortID == "" {
305 shortID = logging.ShortSessionID(sessions[i].SessionID)309 shortID = logging.ShortSessionID(sessions[i].SessionID)
306 }310 }
307- if strings.ToLower(shortID) == queryNormalized {311+ if strings.EqualFold(shortID, queryNormalized) {
308 return &sessions[i], nil312 return &sessions[i], nil
309 }313 }
310 }314 }
311 315
312 // Try partial match on full session ID316 // Try partial match on full session ID
313 var matches []SessionInfo317 var matches []SessionInfo
314- for _, s := range sessions {318+ for i := range sessions {
315- if strings.Contains(strings.ToLower(s.SessionID), queryNormalized) {319+ if strings.Contains(strings.ToLower(sessions[i].SessionID), queryNormalized) {
316- matches = append(matches, s)320+ matches = append(matches, sessions[i])
317 }321 }
318 }322 }
319 323
@@ -325,8 +329,8 @@ func findSession(ctx context.Context, sessionMgr sessionManager, logDir, query s
325 default:329 default:
326 // Multiple matches - show them and ask user to be more specific330 // Multiple matches - show them and ask user to be more specific
327 var ids []string331 var ids []string
328- for _, m := range matches {332+ for i := range matches {
329- ids = append(ids, m.ShortID)333+ ids = append(ids, matches[i].ShortID)
330 }334 }
331 return nil, fmt.Errorf("multiple sessions match '%s': %s", query, strings.Join(ids, ", "))335 return nil, fmt.Errorf("multiple sessions match '%s': %s", query, strings.Join(ids, ", "))
332 }336 }
@@ -523,7 +527,8 @@ func runLogsClear(_ *cobra.Command, _ []string) error {
523 cutoff := time.Now().AddDate(0, 0, -maxAge)527 cutoff := time.Now().AddDate(0, 0, -maxAge)
524 var removed int528 var removed int
525 529
526- for _, s := range sessions {530+ for i := range sessions {
531+ s := &sessions[i]
527 shouldRemove := logsClearAll || s.ModTime.Before(cutoff)532 shouldRemove := logsClearAll || s.ModTime.Before(cutoff)
528 if !shouldRemove {533 if !shouldRemove {
529 continue534 continue

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