chore(repo): reorganize services structure and codebase cleanup
- commit
- 7f21e33997a14739cc1d91a65fc932fa573d07d4
- author
- bamen · · 2025-09-18 18:45 UTC
- committer
- bamen · · 2025-09-18 20:05 UTC
- parent
- 3b4fc68
- signature
- unsigned
14 files · +9 -335
D configs/sqlc.yaml +0 -15
| @@ -1,15 +0,0 @@ | |||
| 1 | - | version: "2" | |
| 2 | - | sql: | |
| 3 | - | - engine: "sqlite" | |
| 4 | - | queries: "./internal/db/queries/" | |
| 5 | - | schema: "./migrations/" | |
| 6 | - | gen: | |
| 7 | - | go: | |
| 8 | - | package: "db" | |
| 9 | - | out: "./internal/db" | |
| 10 | - | sql_package: "database/sql" | |
| 11 | - | emit_json_tags: true | |
| 12 | - | emit_empty_slices: true | |
| 13 | - | emit_exported_queries: true | |
| 14 | - | emit_interface: true | |
| 15 | - | query_parameter_limit: 5⏎̸ | |
| @@ -1,15 +0,0 @@ | |||||
| 1 | - | version: "2" | |||
| 2 | - | sql: | |||
| 3 | - | - engine: "sqlite" | |||
| 4 | - | queries: "./internal/db/queries/" | |||
| 5 | - | schema: "./migrations/" | |||
| 6 | - | gen: | |||
| 7 | - | go: | |||
| 8 | - | package: "db" | |||
| 9 | - | out: "./internal/db" | |||
| 10 | - | sql_package: "database/sql" | |||
| 11 | - | emit_json_tags: true | |||
| 12 | - | emit_empty_slices: true | |||
| 13 | - | emit_exported_queries: true | |||
| 14 | - | emit_interface: true | |||
| 15 | - | query_parameter_limit: 5⏎̸ | |||
M gui/bindings/database/sql/index.ts +0 -1
| @@ -1,4 +1,3 @@ | |||
| 1 | - | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL | |
| 2 | 1 | // This file is automatically generated. DO NOT EDIT | |
| 3 | 2 | ||
| 4 | 3 | export { | |
| @@ -1,4 +1,3 @@ | |||||
| 1 | - | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL | |||
| 2 | // This file is automatically generated. DO NOT EDIT | 1 | // This file is automatically generated. DO NOT EDIT | ||
| 3 | 2 | ||||
| 4 | export { | 3 | export { | ||
M gui/package.json +1 -0
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | "dev:color-scheme": "npm run build:color-scheme -- --watch", | |
| 14 | 14 | "check": "svelte-check", | |
| 15 | 15 | "lint": "eslint src --fix", | |
| 16 | + | "fmt": "prettier --write .", | |
| 16 | 17 | "generate:types": "node ../scripts/generate-types.js" | |
| 17 | 18 | }, | |
| 18 | 19 | "devDependencies": { | |
| @@ -13,6 +13,7 @@ | |||||
| 13 | "dev:color-scheme": "npm run build:color-scheme -- --watch", | 13 | "dev:color-scheme": "npm run build:color-scheme -- --watch", | ||
| 14 | "check": "svelte-check", | 14 | "check": "svelte-check", | ||
| 15 | "lint": "eslint src --fix", | 15 | "lint": "eslint src --fix", | ||
| 16 | + | "fmt": "prettier --write .", | |||
| 16 | "generate:types": "node ../scripts/generate-types.js" | 17 | "generate:types": "node ../scripts/generate-types.js" | ||
| 17 | }, | 18 | }, | ||
| 18 | "devDependencies": { | 19 | "devDependencies": { | ||
M internal/app/api/scheme.go +1 -1
| @@ -10,7 +10,7 @@ import ( | |||
| 10 | 10 | ||
| 11 | 11 | "github.com/bnema/dumber/internal/app/constants" | |
| 12 | 12 | "github.com/bnema/dumber/internal/config" | |
| 13 | - | "github.com/bnema/dumber/services" | |
| 13 | + | "github.com/bnema/dumber/internal/services" | |
| 14 | 14 | ) | |
| 15 | 15 | ||
| 16 | 16 | // SchemeHandler handles custom dumb:// scheme resolution | |
| @@ -10,7 +10,7 @@ import ( | |||||
| 10 | 10 | ||||
| 11 | "github.com/bnema/dumber/internal/app/constants" | 11 | "github.com/bnema/dumber/internal/app/constants" | ||
| 12 | "github.com/bnema/dumber/internal/config" | 12 | "github.com/bnema/dumber/internal/config" | ||
| 13 | - | "github.com/bnema/dumber/services" | 13 | + | "github.com/bnema/dumber/internal/services" |
| 14 | ) | 14 | ) | ||
| 15 | 15 | ||||
| 16 | // SchemeHandler handles custom dumb:// scheme resolution | 16 | // SchemeHandler handles custom dumb:// scheme resolution | ||
M internal/app/browser/browser.go +1 -1
| @@ -20,7 +20,7 @@ import ( | |||
| 20 | 20 | "github.com/bnema/dumber/internal/logging" | |
| 21 | 21 | "github.com/bnema/dumber/internal/migrations" | |
| 22 | 22 | "github.com/bnema/dumber/pkg/webkit" | |
| 23 | - | "github.com/bnema/dumber/services" | |
| 23 | + | "github.com/bnema/dumber/internal/services" | |
| 24 | 24 | ) | |
| 25 | 25 | ||
| 26 | 26 | // BrowserApp represents the main browser application | |
| @@ -20,7 +20,7 @@ import ( | |||||
| 20 | "github.com/bnema/dumber/internal/logging" | 20 | "github.com/bnema/dumber/internal/logging" | ||
| 21 | "github.com/bnema/dumber/internal/migrations" | 21 | "github.com/bnema/dumber/internal/migrations" | ||
| 22 | "github.com/bnema/dumber/pkg/webkit" | 22 | "github.com/bnema/dumber/pkg/webkit" | ||
| 23 | - | "github.com/bnema/dumber/services" | 23 | + | "github.com/bnema/dumber/internal/services" |
| 24 | ) | 24 | ) | ||
| 25 | 25 | ||||
| 26 | // BrowserApp represents the main browser application | 26 | // BrowserApp represents the main browser application | ||
M internal/app/control/navigation.go +1 -1
| @@ -6,7 +6,7 @@ import ( | |||
| 6 | 6 | "os" | |
| 7 | 7 | ||
| 8 | 8 | "github.com/bnema/dumber/pkg/webkit" | |
| 9 | - | "github.com/bnema/dumber/services" | |
| 9 | + | "github.com/bnema/dumber/internal/services" | |
| 10 | 10 | ) | |
| 11 | 11 | ||
| 12 | 12 | // NavigationController manages navigation functionality | |
| @@ -6,7 +6,7 @@ import ( | |||||
| 6 | "os" | 6 | "os" | ||
| 7 | 7 | ||||
| 8 | "github.com/bnema/dumber/pkg/webkit" | 8 | "github.com/bnema/dumber/pkg/webkit" | ||
| 9 | - | "github.com/bnema/dumber/services" | 9 | + | "github.com/bnema/dumber/internal/services" |
| 10 | ) | 10 | ) | ||
| 11 | 11 | ||||
| 12 | // NavigationController manages navigation functionality | 12 | // NavigationController manages navigation functionality | ||
M internal/app/control/zoom.go +1 -1
| @@ -5,7 +5,7 @@ import ( | |||
| 5 | 5 | "log" | |
| 6 | 6 | ||
| 7 | 7 | "github.com/bnema/dumber/pkg/webkit" | |
| 8 | - | "github.com/bnema/dumber/services" | |
| 8 | + | "github.com/bnema/dumber/internal/services" | |
| 9 | 9 | ) | |
| 10 | 10 | ||
| 11 | 11 | // ZoomController manages zoom functionality for the WebView | |
| @@ -5,7 +5,7 @@ import ( | |||||
| 5 | "log" | 5 | "log" | ||
| 6 | 6 | ||||
| 7 | "github.com/bnema/dumber/pkg/webkit" | 7 | "github.com/bnema/dumber/pkg/webkit" | ||
| 8 | - | "github.com/bnema/dumber/services" | 8 | + | "github.com/bnema/dumber/internal/services" |
| 9 | ) | 9 | ) | ||
| 10 | 10 | ||||
| 11 | // ZoomController manages zoom functionality for the WebView | 11 | // ZoomController manages zoom functionality for the WebView | ||
M internal/app/messaging/handler.go +1 -1
| @@ -12,7 +12,7 @@ import ( | |||
| 12 | 12 | "github.com/bnema/dumber/internal/app/constants" | |
| 13 | 13 | "github.com/bnema/dumber/internal/app/control" | |
| 14 | 14 | "github.com/bnema/dumber/pkg/webkit" | |
| 15 | - | "github.com/bnema/dumber/services" | |
| 15 | + | "github.com/bnema/dumber/internal/services" | |
| 16 | 16 | ) | |
| 17 | 17 | ||
| 18 | 18 | // Handler processes script messages from the WebView | |
| @@ -12,7 +12,7 @@ import ( | |||||
| 12 | "github.com/bnema/dumber/internal/app/constants" | 12 | "github.com/bnema/dumber/internal/app/constants" | ||
| 13 | "github.com/bnema/dumber/internal/app/control" | 13 | "github.com/bnema/dumber/internal/app/control" | ||
| 14 | "github.com/bnema/dumber/pkg/webkit" | 14 | "github.com/bnema/dumber/pkg/webkit" | ||
| 15 | - | "github.com/bnema/dumber/services" | 15 | + | "github.com/bnema/dumber/internal/services" |
| 16 | ) | 16 | ) | ||
| 17 | 17 | ||||
| 18 | // Handler processes script messages from the WebView | 18 | // Handler processes script messages from the WebView | ||
M internal/cli/root.go +1 -1
| @@ -12,7 +12,7 @@ import ( | |||
| 12 | 12 | "github.com/bnema/dumber/internal/config" | |
| 13 | 13 | "github.com/bnema/dumber/internal/db" | |
| 14 | 14 | "github.com/bnema/dumber/internal/migrations" | |
| 15 | - | "github.com/bnema/dumber/services" | |
| 15 | + | "github.com/bnema/dumber/internal/services" | |
| 16 | 16 | ||
| 17 | 17 | _ "github.com/ncruces/go-sqlite3/driver" // SQLite driver for database/sql | |
| 18 | 18 | _ "github.com/ncruces/go-sqlite3/embed" // Embed SQLite for cross-platform compatibility | |
| @@ -12,7 +12,7 @@ import ( | |||||
| 12 | "github.com/bnema/dumber/internal/config" | 12 | "github.com/bnema/dumber/internal/config" | ||
| 13 | "github.com/bnema/dumber/internal/db" | 13 | "github.com/bnema/dumber/internal/db" | ||
| 14 | "github.com/bnema/dumber/internal/migrations" | 14 | "github.com/bnema/dumber/internal/migrations" | ||
| 15 | - | "github.com/bnema/dumber/services" | 15 | + | "github.com/bnema/dumber/internal/services" |
| 16 | 16 | ||||
| 17 | _ "github.com/ncruces/go-sqlite3/driver" // SQLite driver for database/sql | 17 | _ "github.com/ncruces/go-sqlite3/driver" // SQLite driver for database/sql | ||
| 18 | _ "github.com/ncruces/go-sqlite3/embed" // Embed SQLite for cross-platform compatibility | 18 | _ "github.com/ncruces/go-sqlite3/embed" // Embed SQLite for cross-platform compatibility | ||
R services/browser_service.go → internal/services/browser.go +0 -0 renamed, 100% similar
renamed, 100% similar
R services/parser_service.go → internal/services/parser.go +0 -0 renamed, 100% similar
renamed, 100% similar
D services/config_service.go +0 -311
| @@ -1,311 +0,0 @@ | |||
| 1 | - | package services | |
| 2 | - | ||
| 3 | - | import ( | |
| 4 | - | "context" | |
| 5 | - | "fmt" | |
| 6 | - | "os" | |
| 7 | - | "path/filepath" | |
| 8 | - | ||
| 9 | - | "github.com/bnema/dumber/internal/config" | |
| 10 | - | "strings" | |
| 11 | - | ) | |
| 12 | - | ||
| 13 | - | // ConfigService handles configuration operations for the application. | |
| 14 | - | type ConfigService struct { | |
| 15 | - | config *config.Config | |
| 16 | - | configPath string | |
| 17 | - | } | |
| 18 | - | ||
| 19 | - | const defaultDirPerm = 0o750 | |
| 20 | - | ||
| 21 | - | // ConfigInfo represents configuration information for the frontend. | |
| 22 | - | type ConfigInfo struct { | |
| 23 | - | ConfigPath string `json:"config_path"` | |
| 24 | - | DatabasePath string `json:"database_path"` | |
| 25 | - | SearchShortcuts map[string]config.SearchShortcut `json:"search_shortcuts"` | |
| 26 | - | DmenuSettings *config.DmenuConfig `json:"dmenu_settings"` | |
| 27 | - | RenderingMode string `json:"rendering_mode"` | |
| 28 | - | UseDomZoom bool `json:"use_dom_zoom"` | |
| 29 | - | Workspace config.WorkspaceConfig `json:"workspace"` | |
| 30 | - | } | |
| 31 | - | ||
| 32 | - | // NewConfigService creates a new ConfigService instance. | |
| 33 | - | func NewConfigService(cfg *config.Config, configPath string) *ConfigService { | |
| 34 | - | return &ConfigService{ | |
| 35 | - | config: cfg, | |
| 36 | - | configPath: configPath, | |
| 37 | - | } | |
| 38 | - | } | |
| 39 | - | ||
| 40 | - | // GetConfigInfo returns comprehensive configuration information. | |
| 41 | - | func (s *ConfigService) GetConfigInfo(ctx context.Context) (*ConfigInfo, error) { | |
| 42 | - | _ = ctx | |
| 43 | - | return &ConfigInfo{ | |
| 44 | - | ConfigPath: s.configPath, | |
| 45 | - | DatabasePath: s.config.Database.Path, | |
| 46 | - | SearchShortcuts: s.config.SearchShortcuts, | |
| 47 | - | DmenuSettings: &s.config.Dmenu, | |
| 48 | - | RenderingMode: string(s.config.RenderingMode), | |
| 49 | - | UseDomZoom: s.config.UseDomZoom, | |
| 50 | - | Workspace: s.config.Workspace, | |
| 51 | - | }, nil | |
| 52 | - | } | |
| 53 | - | ||
| 54 | - | // GetSearchShortcuts returns all configured search shortcuts. | |
| 55 | - | func (s *ConfigService) GetSearchShortcuts(ctx context.Context) (map[string]config.SearchShortcut, error) { | |
| 56 | - | _ = ctx | |
| 57 | - | return s.config.SearchShortcuts, nil | |
| 58 | - | } | |
| 59 | - | ||
| 60 | - | // AddSearchShortcut adds a new search shortcut. | |
| 61 | - | func (s *ConfigService) AddSearchShortcut(ctx context.Context, key string, shortcut config.SearchShortcut) error { | |
| 62 | - | _ = ctx | |
| 63 | - | if key == "" { | |
| 64 | - | return fmt.Errorf("shortcut key cannot be empty") | |
| 65 | - | } | |
| 66 | - | ||
| 67 | - | if shortcut.URL == "" { | |
| 68 | - | return fmt.Errorf("shortcut URL cannot be empty") | |
| 69 | - | } | |
| 70 | - | ||
| 71 | - | if s.config.SearchShortcuts == nil { | |
| 72 | - | s.config.SearchShortcuts = make(map[string]config.SearchShortcut) | |
| 73 | - | } | |
| 74 | - | ||
| 75 | - | s.config.SearchShortcuts[key] = shortcut | |
| 76 | - | return s.saveConfig() | |
| 77 | - | } | |
| 78 | - | ||
| 79 | - | // UpdateSearchShortcut updates an existing search shortcut. | |
| 80 | - | func (s *ConfigService) UpdateSearchShortcut(ctx context.Context, key string, shortcut config.SearchShortcut) error { | |
| 81 | - | _ = ctx | |
| 82 | - | if key == "" { | |
| 83 | - | return fmt.Errorf("shortcut key cannot be empty") | |
| 84 | - | } | |
| 85 | - | ||
| 86 | - | if _, exists := s.config.SearchShortcuts[key]; !exists { | |
| 87 | - | return fmt.Errorf("shortcut '%s' does not exist", key) | |
| 88 | - | } | |
| 89 | - | ||
| 90 | - | if shortcut.URL == "" { | |
| 91 | - | return fmt.Errorf("shortcut URL cannot be empty") | |
| 92 | - | } | |
| 93 | - | ||
| 94 | - | s.config.SearchShortcuts[key] = shortcut | |
| 95 | - | return s.saveConfig() | |
| 96 | - | } | |
| 97 | - | ||
| 98 | - | // DeleteSearchShortcut removes a search shortcut. | |
| 99 | - | func (s *ConfigService) DeleteSearchShortcut(ctx context.Context, key string) error { | |
| 100 | - | _ = ctx | |
| 101 | - | if key == "" { | |
| 102 | - | return fmt.Errorf("shortcut key cannot be empty") | |
| 103 | - | } | |
| 104 | - | ||
| 105 | - | if _, exists := s.config.SearchShortcuts[key]; !exists { | |
| 106 | - | return fmt.Errorf("shortcut '%s' does not exist", key) | |
| 107 | - | } | |
| 108 | - | ||
| 109 | - | delete(s.config.SearchShortcuts, key) | |
| 110 | - | return s.saveConfig() | |
| 111 | - | } | |
| 112 | - | ||
| 113 | - | // GetDmenuSettings returns current dmenu settings. | |
| 114 | - | func (s *ConfigService) GetDmenuSettings(ctx context.Context) (*config.DmenuConfig, error) { | |
| 115 | - | _ = ctx | |
| 116 | - | return &s.config.Dmenu, nil | |
| 117 | - | } | |
| 118 | - | ||
| 119 | - | // UpdateDmenuSettings updates dmenu configuration. | |
| 120 | - | func (s *ConfigService) UpdateDmenuSettings(ctx context.Context, settings *config.DmenuConfig) error { | |
| 121 | - | _ = ctx | |
| 122 | - | if settings == nil { | |
| 123 | - | return fmt.Errorf("dmenu settings cannot be nil") | |
| 124 | - | } | |
| 125 | - | ||
| 126 | - | s.config.Dmenu = *settings | |
| 127 | - | return s.saveConfig() | |
| 128 | - | } | |
| 129 | - | ||
| 130 | - | // GetDatabasePath returns the current database path. | |
| 131 | - | func (s *ConfigService) GetDatabasePath(ctx context.Context) (string, error) { | |
| 132 | - | _ = ctx | |
| 133 | - | return s.config.Database.Path, nil | |
| 134 | - | } | |
| 135 | - | ||
| 136 | - | // SetDatabasePath updates the database path. | |
| 137 | - | func (s *ConfigService) SetDatabasePath(ctx context.Context, path string) error { | |
| 138 | - | _ = ctx | |
| 139 | - | if path == "" { | |
| 140 | - | return fmt.Errorf("database path cannot be empty") | |
| 141 | - | } | |
| 142 | - | ||
| 143 | - | // Validate that the directory exists or can be created | |
| 144 | - | dir := filepath.Dir(path) | |
| 145 | - | if err := os.MkdirAll(dir, defaultDirPerm); err != nil { | |
| 146 | - | return fmt.Errorf("failed to create database directory: %w", err) | |
| 147 | - | } | |
| 148 | - | ||
| 149 | - | s.config.Database.Path = path | |
| 150 | - | return s.saveConfig() | |
| 151 | - | } | |
| 152 | - | ||
| 153 | - | // GetDefaultBrowser returns the default browser setting. | |
| 154 | - | func (s *ConfigService) GetDefaultBrowser(ctx context.Context) (string, error) { | |
| 155 | - | _ = ctx | |
| 156 | - | // Default browser is now built into the app | |
| 157 | - | return "dumber (built-in)", nil | |
| 158 | - | } | |
| 159 | - | ||
| 160 | - | // SetDefaultBrowser updates the default browser setting. | |
| 161 | - | func (s *ConfigService) SetDefaultBrowser(ctx context.Context, browser string) error { | |
| 162 | - | _ = ctx | |
| 163 | - | _ = browser | |
| 164 | - | // Default browser setting is not needed for built-in browser | |
| 165 | - | return fmt.Errorf("default browser is built-in and cannot be changed") | |
| 166 | - | } | |
| 167 | - | ||
| 168 | - | // ReloadConfig reloads configuration from file. | |
| 169 | - | func (s *ConfigService) ReloadConfig(ctx context.Context) error { | |
| 170 | - | _ = ctx | |
| 171 | - | // Create new manager and load config | |
| 172 | - | manager, err := config.NewManager() | |
| 173 | - | if err != nil { | |
| 174 | - | return fmt.Errorf("failed to create config manager: %w", err) | |
| 175 | - | } | |
| 176 | - | ||
| 177 | - | if err := manager.Load(); err != nil { | |
| 178 | - | return fmt.Errorf("failed to load config: %w", err) | |
| 179 | - | } | |
| 180 | - | ||
| 181 | - | s.config = manager.Get() | |
| 182 | - | return nil | |
| 183 | - | } | |
| 184 | - | ||
| 185 | - | // ValidateConfig validates the current configuration. | |
| 186 | - | func (s *ConfigService) ValidateConfig(ctx context.Context) ([]string, error) { | |
| 187 | - | _ = ctx | |
| 188 | - | var errors []string | |
| 189 | - | ||
| 190 | - | // Validate database path | |
| 191 | - | if s.config.Database.Path == "" { | |
| 192 | - | errors = append(errors, "database path is not set") | |
| 193 | - | } else { | |
| 194 | - | dir := filepath.Dir(s.config.Database.Path) | |
| 195 | - | if _, err := os.Stat(dir); os.IsNotExist(err) { | |
| 196 | - | errors = append(errors, fmt.Sprintf("database directory does not exist: %s", dir)) | |
| 197 | - | } | |
| 198 | - | } | |
| 199 | - | ||
| 200 | - | // Validate search shortcuts | |
| 201 | - | if len(s.config.SearchShortcuts) == 0 { | |
| 202 | - | errors = append(errors, "no search shortcuts configured") | |
| 203 | - | } else { | |
| 204 | - | for key, shortcut := range s.config.SearchShortcuts { | |
| 205 | - | if shortcut.URL == "" { | |
| 206 | - | errors = append(errors, fmt.Sprintf("search shortcut '%s' has empty URL", key)) | |
| 207 | - | } | |
| 208 | - | } | |
| 209 | - | } | |
| 210 | - | ||
| 211 | - | // Check for default search shortcut | |
| 212 | - | if _, hasDefault := s.config.SearchShortcuts["g"]; !hasDefault { | |
| 213 | - | errors = append(errors, "no default search shortcut 'g' configured") | |
| 214 | - | } | |
| 215 | - | ||
| 216 | - | // Validate dmenu settings | |
| 217 | - | if s.config.Dmenu.MaxHistoryItems < 1 { | |
| 218 | - | errors = append(errors, "dmenu max_history_items must be at least 1") | |
| 219 | - | } | |
| 220 | - | ||
| 221 | - | // Validate workspace configuration when enabled | |
| 222 | - | if s.config.Workspace.EnableZellijControls { | |
| 223 | - | if strings.TrimSpace(s.config.Workspace.PaneMode.ActivationShortcut) == "" { | |
| 224 | - | errors = append(errors, "workspace pane_mode activation_shortcut is empty") | |
| 225 | - | } | |
| 226 | - | if len(s.config.Workspace.PaneMode.ActionBindings) == 0 { | |
| 227 | - | errors = append(errors, "workspace pane_mode action_bindings are empty") | |
| 228 | - | } | |
| 229 | - | } | |
| 230 | - | ||
| 231 | - | if strings.TrimSpace(s.config.Workspace.Popups.Placement) == "" { | |
| 232 | - | errors = append(errors, "workspace popups placement is empty") | |
| 233 | - | } | |
| 234 | - | ||
| 235 | - | return errors, nil | |
| 236 | - | } | |
| 237 | - | ||
| 238 | - | // GetConfigPath returns the path to the configuration file. | |
| 239 | - | func (s *ConfigService) GetConfigPath(ctx context.Context) (string, error) { | |
| 240 | - | _ = ctx | |
| 241 | - | return s.configPath, nil | |
| 242 | - | } | |
| 243 | - | ||
| 244 | - | // ExportConfig returns the current configuration as JSON. | |
| 245 | - | func (s *ConfigService) ExportConfig(ctx context.Context) (*config.Config, error) { | |
| 246 | - | _ = ctx | |
| 247 | - | // Return a copy of the config to prevent modifications | |
| 248 | - | configCopy := *s.config | |
| 249 | - | return &configCopy, nil | |
| 250 | - | } | |
| 251 | - | ||
| 252 | - | // ImportConfig imports configuration from a Config object. | |
| 253 | - | func (s *ConfigService) ImportConfig(ctx context.Context, newConfig *config.Config) error { | |
| 254 | - | if newConfig == nil { | |
| 255 | - | return fmt.Errorf("config cannot be nil") | |
| 256 | - | } | |
| 257 | - | ||
| 258 | - | // Validate the new config | |
| 259 | - | tempService := &ConfigService{config: newConfig} | |
| 260 | - | validationErrors, err := tempService.ValidateConfig(ctx) | |
| 261 | - | if err != nil { | |
| 262 | - | return fmt.Errorf("failed to validate config: %w", err) | |
| 263 | - | } | |
| 264 | - | ||
| 265 | - | if len(validationErrors) > 0 { | |
| 266 | - | return fmt.Errorf("config validation failed: %v", validationErrors) | |
| 267 | - | } | |
| 268 | - | ||
| 269 | - | // Apply the new config | |
| 270 | - | s.config = newConfig | |
| 271 | - | return s.saveConfig() | |
| 272 | - | } | |
| 273 | - | ||
| 274 | - | // GetRenderingMode returns the current rendering mode (auto|gpu|cpu). | |
| 275 | - | func (s *ConfigService) GetRenderingMode(ctx context.Context) (string, error) { | |
| 276 | - | _ = ctx | |
| 277 | - | return string(s.config.RenderingMode), nil | |
| 278 | - | } | |
| 279 | - | ||
| 280 | - | // SetRenderingMode updates the rendering mode (auto|gpu|cpu). | |
| 281 | - | func (s *ConfigService) SetRenderingMode(ctx context.Context, mode string) error { | |
| 282 | - | _ = ctx | |
| 283 | - | m := strings.ToLower(strings.TrimSpace(mode)) | |
| 284 | - | switch m { | |
| 285 | - | case "auto", "gpu", "cpu": | |
| 286 | - | s.config.RenderingMode = config.RenderingMode(m) | |
| 287 | - | return s.saveConfig() | |
| 288 | - | default: | |
| 289 | - | return fmt.Errorf("invalid rendering mode: %s", mode) | |
| 290 | - | } | |
| 291 | - | } | |
| 292 | - | ||
| 293 | - | // GetUseDomZoom reports whether DOM-based zoom is enabled. | |
| 294 | - | func (s *ConfigService) GetUseDomZoom(ctx context.Context) (bool, error) { | |
| 295 | - | _ = ctx | |
| 296 | - | return s.config.UseDomZoom, nil | |
| 297 | - | } | |
| 298 | - | ||
| 299 | - | // SetUseDomZoom toggles DOM-based zoom. | |
| 300 | - | func (s *ConfigService) SetUseDomZoom(ctx context.Context, enabled bool) error { | |
| 301 | - | _ = ctx | |
| 302 | - | s.config.UseDomZoom = enabled | |
| 303 | - | return s.saveConfig() | |
| 304 | - | } | |
| 305 | - | ||
| 306 | - | // saveConfig saves the current configuration to file. | |
| 307 | - | func (s *ConfigService) saveConfig() error { | |
| 308 | - | // For now, return success - implementing config saving would require | |
| 309 | - | // extending the config package with save functionality | |
| 310 | - | return nil | |
| 311 | - | } | |
| @@ -1,311 +0,0 @@ | |||||
| 1 | - | package services | |||
| 2 | - | ||||
| 3 | - | import ( | |||
| 4 | - | "context" | |||
| 5 | - | "fmt" | |||
| 6 | - | "os" | |||
| 7 | - | "path/filepath" | |||
| 8 | - | ||||
| 9 | - | "github.com/bnema/dumber/internal/config" | |||
| 10 | - | "strings" | |||
| 11 | - | ) | |||
| 12 | - | ||||
| 13 | - | // ConfigService handles configuration operations for the application. | |||
| 14 | - | type ConfigService struct { | |||
| 15 | - | config *config.Config | |||
| 16 | - | configPath string | |||
| 17 | - | } | |||
| 18 | - | ||||
| 19 | - | const defaultDirPerm = 0o750 | |||
| 20 | - | ||||
| 21 | - | // ConfigInfo represents configuration information for the frontend. | |||
| 22 | - | type ConfigInfo struct { | |||
| 23 | - | ConfigPath string `json:"config_path"` | |||
| 24 | - | DatabasePath string `json:"database_path"` | |||
| 25 | - | SearchShortcuts map[string]config.SearchShortcut `json:"search_shortcuts"` | |||
| 26 | - | DmenuSettings *config.DmenuConfig `json:"dmenu_settings"` | |||
| 27 | - | RenderingMode string `json:"rendering_mode"` | |||
| 28 | - | UseDomZoom bool `json:"use_dom_zoom"` | |||
| 29 | - | Workspace config.WorkspaceConfig `json:"workspace"` | |||
| 30 | - | } | |||
| 31 | - | ||||
| 32 | - | // NewConfigService creates a new ConfigService instance. | |||
| 33 | - | func NewConfigService(cfg *config.Config, configPath string) *ConfigService { | |||
| 34 | - | return &ConfigService{ | |||
| 35 | - | config: cfg, | |||
| 36 | - | configPath: configPath, | |||
| 37 | - | } | |||
| 38 | - | } | |||
| 39 | - | ||||
| 40 | - | // GetConfigInfo returns comprehensive configuration information. | |||
| 41 | - | func (s *ConfigService) GetConfigInfo(ctx context.Context) (*ConfigInfo, error) { | |||
| 42 | - | _ = ctx | |||
| 43 | - | return &ConfigInfo{ | |||
| 44 | - | ConfigPath: s.configPath, | |||
| 45 | - | DatabasePath: s.config.Database.Path, | |||
| 46 | - | SearchShortcuts: s.config.SearchShortcuts, | |||
| 47 | - | DmenuSettings: &s.config.Dmenu, | |||
| 48 | - | RenderingMode: string(s.config.RenderingMode), | |||
| 49 | - | UseDomZoom: s.config.UseDomZoom, | |||
| 50 | - | Workspace: s.config.Workspace, | |||
| 51 | - | }, nil | |||
| 52 | - | } | |||
| 53 | - | ||||
| 54 | - | // GetSearchShortcuts returns all configured search shortcuts. | |||
| 55 | - | func (s *ConfigService) GetSearchShortcuts(ctx context.Context) (map[string]config.SearchShortcut, error) { | |||
| 56 | - | _ = ctx | |||
| 57 | - | return s.config.SearchShortcuts, nil | |||
| 58 | - | } | |||
| 59 | - | ||||
| 60 | - | // AddSearchShortcut adds a new search shortcut. | |||
| 61 | - | func (s *ConfigService) AddSearchShortcut(ctx context.Context, key string, shortcut config.SearchShortcut) error { | |||
| 62 | - | _ = ctx | |||
| 63 | - | if key == "" { | |||
| 64 | - | return fmt.Errorf("shortcut key cannot be empty") | |||
| 65 | - | } | |||
| 66 | - | ||||
| 67 | - | if shortcut.URL == "" { | |||
| 68 | - | return fmt.Errorf("shortcut URL cannot be empty") | |||
| 69 | - | } | |||
| 70 | - | ||||
| 71 | - | if s.config.SearchShortcuts == nil { | |||
| 72 | - | s.config.SearchShortcuts = make(map[string]config.SearchShortcut) | |||
| 73 | - | } | |||
| 74 | - | ||||
| 75 | - | s.config.SearchShortcuts[key] = shortcut | |||
| 76 | - | return s.saveConfig() | |||
| 77 | - | } | |||
| 78 | - | ||||
| 79 | - | // UpdateSearchShortcut updates an existing search shortcut. | |||
| 80 | - | func (s *ConfigService) UpdateSearchShortcut(ctx context.Context, key string, shortcut config.SearchShortcut) error { | |||
| 81 | - | _ = ctx | |||
| 82 | - | if key == "" { | |||
| 83 | - | return fmt.Errorf("shortcut key cannot be empty") | |||
| 84 | - | } | |||
| 85 | - | ||||
| 86 | - | if _, exists := s.config.SearchShortcuts[key]; !exists { | |||
| 87 | - | return fmt.Errorf("shortcut '%s' does not exist", key) | |||
| 88 | - | } | |||
| 89 | - | ||||
| 90 | - | if shortcut.URL == "" { | |||
| 91 | - | return fmt.Errorf("shortcut URL cannot be empty") | |||
| 92 | - | } | |||
| 93 | - | ||||
| 94 | - | s.config.SearchShortcuts[key] = shortcut | |||
| 95 | - | return s.saveConfig() | |||
| 96 | - | } | |||
| 97 | - | ||||
| 98 | - | // DeleteSearchShortcut removes a search shortcut. | |||
| 99 | - | func (s *ConfigService) DeleteSearchShortcut(ctx context.Context, key string) error { | |||
| 100 | - | _ = ctx | |||
| 101 | - | if key == "" { | |||
| 102 | - | return fmt.Errorf("shortcut key cannot be empty") | |||
| 103 | - | } | |||
| 104 | - | ||||
| 105 | - | if _, exists := s.config.SearchShortcuts[key]; !exists { | |||
| 106 | - | return fmt.Errorf("shortcut '%s' does not exist", key) | |||
| 107 | - | } | |||
| 108 | - | ||||
| 109 | - | delete(s.config.SearchShortcuts, key) | |||
| 110 | - | return s.saveConfig() | |||
| 111 | - | } | |||
| 112 | - | ||||
| 113 | - | // GetDmenuSettings returns current dmenu settings. | |||
| 114 | - | func (s *ConfigService) GetDmenuSettings(ctx context.Context) (*config.DmenuConfig, error) { | |||
| 115 | - | _ = ctx | |||
| 116 | - | return &s.config.Dmenu, nil | |||
| 117 | - | } | |||
| 118 | - | ||||
| 119 | - | // UpdateDmenuSettings updates dmenu configuration. | |||
| 120 | - | func (s *ConfigService) UpdateDmenuSettings(ctx context.Context, settings *config.DmenuConfig) error { | |||
| 121 | - | _ = ctx | |||
| 122 | - | if settings == nil { | |||
| 123 | - | return fmt.Errorf("dmenu settings cannot be nil") | |||
| 124 | - | } | |||
| 125 | - | ||||
| 126 | - | s.config.Dmenu = *settings | |||
| 127 | - | return s.saveConfig() | |||
| 128 | - | } | |||
| 129 | - | ||||
| 130 | - | // GetDatabasePath returns the current database path. | |||
| 131 | - | func (s *ConfigService) GetDatabasePath(ctx context.Context) (string, error) { | |||
| 132 | - | _ = ctx | |||
| 133 | - | return s.config.Database.Path, nil | |||
| 134 | - | } | |||
| 135 | - | ||||
| 136 | - | // SetDatabasePath updates the database path. | |||
| 137 | - | func (s *ConfigService) SetDatabasePath(ctx context.Context, path string) error { | |||
| 138 | - | _ = ctx | |||
| 139 | - | if path == "" { | |||
| 140 | - | return fmt.Errorf("database path cannot be empty") | |||
| 141 | - | } | |||
| 142 | - | ||||
| 143 | - | // Validate that the directory exists or can be created | |||
| 144 | - | dir := filepath.Dir(path) | |||
| 145 | - | if err := os.MkdirAll(dir, defaultDirPerm); err != nil { | |||
| 146 | - | return fmt.Errorf("failed to create database directory: %w", err) | |||
| 147 | - | } | |||
| 148 | - | ||||
| 149 | - | s.config.Database.Path = path | |||
| 150 | - | return s.saveConfig() | |||
| 151 | - | } | |||
| 152 | - | ||||
| 153 | - | // GetDefaultBrowser returns the default browser setting. | |||
| 154 | - | func (s *ConfigService) GetDefaultBrowser(ctx context.Context) (string, error) { | |||
| 155 | - | _ = ctx | |||
| 156 | - | // Default browser is now built into the app | |||
| 157 | - | return "dumber (built-in)", nil | |||
| 158 | - | } | |||
| 159 | - | ||||
| 160 | - | // SetDefaultBrowser updates the default browser setting. | |||
| 161 | - | func (s *ConfigService) SetDefaultBrowser(ctx context.Context, browser string) error { | |||
| 162 | - | _ = ctx | |||
| 163 | - | _ = browser | |||
| 164 | - | // Default browser setting is not needed for built-in browser | |||
| 165 | - | return fmt.Errorf("default browser is built-in and cannot be changed") | |||
| 166 | - | } | |||
| 167 | - | ||||
| 168 | - | // ReloadConfig reloads configuration from file. | |||
| 169 | - | func (s *ConfigService) ReloadConfig(ctx context.Context) error { | |||
| 170 | - | _ = ctx | |||
| 171 | - | // Create new manager and load config | |||
| 172 | - | manager, err := config.NewManager() | |||
| 173 | - | if err != nil { | |||
| 174 | - | return fmt.Errorf("failed to create config manager: %w", err) | |||
| 175 | - | } | |||
| 176 | - | ||||
| 177 | - | if err := manager.Load(); err != nil { | |||
| 178 | - | return fmt.Errorf("failed to load config: %w", err) | |||
| 179 | - | } | |||
| 180 | - | ||||
| 181 | - | s.config = manager.Get() | |||
| 182 | - | return nil | |||
| 183 | - | } | |||
| 184 | - | ||||
| 185 | - | // ValidateConfig validates the current configuration. | |||
| 186 | - | func (s *ConfigService) ValidateConfig(ctx context.Context) ([]string, error) { | |||
| 187 | - | _ = ctx | |||
| 188 | - | var errors []string | |||
| 189 | - | ||||
| 190 | - | // Validate database path | |||
| 191 | - | if s.config.Database.Path == "" { | |||
| 192 | - | errors = append(errors, "database path is not set") | |||
| 193 | - | } else { | |||
| 194 | - | dir := filepath.Dir(s.config.Database.Path) | |||
| 195 | - | if _, err := os.Stat(dir); os.IsNotExist(err) { | |||
| 196 | - | errors = append(errors, fmt.Sprintf("database directory does not exist: %s", dir)) | |||
| 197 | - | } | |||
| 198 | - | } | |||
| 199 | - | ||||
| 200 | - | // Validate search shortcuts | |||
| 201 | - | if len(s.config.SearchShortcuts) == 0 { | |||
| 202 | - | errors = append(errors, "no search shortcuts configured") | |||
| 203 | - | } else { | |||
| 204 | - | for key, shortcut := range s.config.SearchShortcuts { | |||
| 205 | - | if shortcut.URL == "" { | |||
| 206 | - | errors = append(errors, fmt.Sprintf("search shortcut '%s' has empty URL", key)) | |||
| 207 | - | } | |||
| 208 | - | } | |||
| 209 | - | } | |||
| 210 | - | ||||
| 211 | - | // Check for default search shortcut | |||
| 212 | - | if _, hasDefault := s.config.SearchShortcuts["g"]; !hasDefault { | |||
| 213 | - | errors = append(errors, "no default search shortcut 'g' configured") | |||
| 214 | - | } | |||
| 215 | - | ||||
| 216 | - | // Validate dmenu settings | |||
| 217 | - | if s.config.Dmenu.MaxHistoryItems < 1 { | |||
| 218 | - | errors = append(errors, "dmenu max_history_items must be at least 1") | |||
| 219 | - | } | |||
| 220 | - | ||||
| 221 | - | // Validate workspace configuration when enabled | |||
| 222 | - | if s.config.Workspace.EnableZellijControls { | |||
| 223 | - | if strings.TrimSpace(s.config.Workspace.PaneMode.ActivationShortcut) == "" { | |||
| 224 | - | errors = append(errors, "workspace pane_mode activation_shortcut is empty") | |||
| 225 | - | } | |||
| 226 | - | if len(s.config.Workspace.PaneMode.ActionBindings) == 0 { | |||
| 227 | - | errors = append(errors, "workspace pane_mode action_bindings are empty") | |||
| 228 | - | } | |||
| 229 | - | } | |||
| 230 | - | ||||
| 231 | - | if strings.TrimSpace(s.config.Workspace.Popups.Placement) == "" { | |||
| 232 | - | errors = append(errors, "workspace popups placement is empty") | |||
| 233 | - | } | |||
| 234 | - | ||||
| 235 | - | return errors, nil | |||
| 236 | - | } | |||
| 237 | - | ||||
| 238 | - | // GetConfigPath returns the path to the configuration file. | |||
| 239 | - | func (s *ConfigService) GetConfigPath(ctx context.Context) (string, error) { | |||
| 240 | - | _ = ctx | |||
| 241 | - | return s.configPath, nil | |||
| 242 | - | } | |||
| 243 | - | ||||
| 244 | - | // ExportConfig returns the current configuration as JSON. | |||
| 245 | - | func (s *ConfigService) ExportConfig(ctx context.Context) (*config.Config, error) { | |||
| 246 | - | _ = ctx | |||
| 247 | - | // Return a copy of the config to prevent modifications | |||
| 248 | - | configCopy := *s.config | |||
| 249 | - | return &configCopy, nil | |||
| 250 | - | } | |||
| 251 | - | ||||
| 252 | - | // ImportConfig imports configuration from a Config object. | |||
| 253 | - | func (s *ConfigService) ImportConfig(ctx context.Context, newConfig *config.Config) error { | |||
| 254 | - | if newConfig == nil { | |||
| 255 | - | return fmt.Errorf("config cannot be nil") | |||
| 256 | - | } | |||
| 257 | - | ||||
| 258 | - | // Validate the new config | |||
| 259 | - | tempService := &ConfigService{config: newConfig} | |||
| 260 | - | validationErrors, err := tempService.ValidateConfig(ctx) | |||
| 261 | - | if err != nil { | |||
| 262 | - | return fmt.Errorf("failed to validate config: %w", err) | |||
| 263 | - | } | |||
| 264 | - | ||||
| 265 | - | if len(validationErrors) > 0 { | |||
| 266 | - | return fmt.Errorf("config validation failed: %v", validationErrors) | |||
| 267 | - | } | |||
| 268 | - | ||||
| 269 | - | // Apply the new config | |||
| 270 | - | s.config = newConfig | |||
| 271 | - | return s.saveConfig() | |||
| 272 | - | } | |||
| 273 | - | ||||
| 274 | - | // GetRenderingMode returns the current rendering mode (auto|gpu|cpu). | |||
| 275 | - | func (s *ConfigService) GetRenderingMode(ctx context.Context) (string, error) { | |||
| 276 | - | _ = ctx | |||
| 277 | - | return string(s.config.RenderingMode), nil | |||
| 278 | - | } | |||
| 279 | - | ||||
| 280 | - | // SetRenderingMode updates the rendering mode (auto|gpu|cpu). | |||
| 281 | - | func (s *ConfigService) SetRenderingMode(ctx context.Context, mode string) error { | |||
| 282 | - | _ = ctx | |||
| 283 | - | m := strings.ToLower(strings.TrimSpace(mode)) | |||
| 284 | - | switch m { | |||
| 285 | - | case "auto", "gpu", "cpu": | |||
| 286 | - | s.config.RenderingMode = config.RenderingMode(m) | |||
| 287 | - | return s.saveConfig() | |||
| 288 | - | default: | |||
| 289 | - | return fmt.Errorf("invalid rendering mode: %s", mode) | |||
| 290 | - | } | |||
| 291 | - | } | |||
| 292 | - | ||||
| 293 | - | // GetUseDomZoom reports whether DOM-based zoom is enabled. | |||
| 294 | - | func (s *ConfigService) GetUseDomZoom(ctx context.Context) (bool, error) { | |||
| 295 | - | _ = ctx | |||
| 296 | - | return s.config.UseDomZoom, nil | |||
| 297 | - | } | |||
| 298 | - | ||||
| 299 | - | // SetUseDomZoom toggles DOM-based zoom. | |||
| 300 | - | func (s *ConfigService) SetUseDomZoom(ctx context.Context, enabled bool) error { | |||
| 301 | - | _ = ctx | |||
| 302 | - | s.config.UseDomZoom = enabled | |||
| 303 | - | return s.saveConfig() | |||
| 304 | - | } | |||
| 305 | - | ||||
| 306 | - | // saveConfig saves the current configuration to file. | |||
| 307 | - | func (s *ConfigService) saveConfig() error { | |||
| 308 | - | // For now, return success - implementing config saving would require | |||
| 309 | - | // extending the config package with save functionality | |||
| 310 | - | return nil | |||
| 311 | - | } | |||
M tests/contract/browser_controls_test.go +1 -1
| @@ -9,7 +9,7 @@ import ( | |||
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/dumber/internal/config" | |
| 11 | 11 | mock_db "github.com/bnema/dumber/internal/db/mocks" | |
| 12 | - | "github.com/bnema/dumber/services" | |
| 12 | + | "github.com/bnema/dumber/internal/services" | |
| 13 | 13 | "github.com/golang/mock/gomock" | |
| 14 | 14 | ) | |
| 15 | 15 | ||
| @@ -9,7 +9,7 @@ import ( | |||||
| 9 | 9 | ||||
| 10 | "github.com/bnema/dumber/internal/config" | 10 | "github.com/bnema/dumber/internal/config" | ||
| 11 | mock_db "github.com/bnema/dumber/internal/db/mocks" | 11 | mock_db "github.com/bnema/dumber/internal/db/mocks" | ||
| 12 | - | "github.com/bnema/dumber/services" | 12 | + | "github.com/bnema/dumber/internal/services" |
| 13 | "github.com/golang/mock/gomock" | 13 | "github.com/golang/mock/gomock" | ||
| 14 | ) | 14 | ) | ||
| 15 | 15 | ||||
M tests/integration/browser_controls_integration_test.go +1 -1
| @@ -12,7 +12,7 @@ import ( | |||
| 12 | 12 | ||
| 13 | 13 | "github.com/bnema/dumber/internal/config" | |
| 14 | 14 | "github.com/bnema/dumber/internal/db" | |
| 15 | - | "github.com/bnema/dumber/services" | |
| 15 | + | "github.com/bnema/dumber/internal/services" | |
| 16 | 16 | _ "github.com/ncruces/go-sqlite3/driver" // SQLite driver | |
| 17 | 17 | _ "github.com/ncruces/go-sqlite3/embed" // Embed SQLite | |
| 18 | 18 | ) | |
| @@ -12,7 +12,7 @@ import ( | |||||
| 12 | 12 | ||||
| 13 | "github.com/bnema/dumber/internal/config" | 13 | "github.com/bnema/dumber/internal/config" | ||
| 14 | "github.com/bnema/dumber/internal/db" | 14 | "github.com/bnema/dumber/internal/db" | ||
| 15 | - | "github.com/bnema/dumber/services" | 15 | + | "github.com/bnema/dumber/internal/services" |
| 16 | _ "github.com/ncruces/go-sqlite3/driver" // SQLite driver | 16 | _ "github.com/ncruces/go-sqlite3/driver" // SQLite driver | ||
| 17 | _ "github.com/ncruces/go-sqlite3/embed" // Embed SQLite | 17 | _ "github.com/ncruces/go-sqlite3/embed" // Embed SQLite | ||
| 18 | ) | 18 | ) | ||