feat(dmenu): integrate DmenuConfig into CLI command with formatting support
- commit
- 40983c7d77da3f0163cbdb7df57d7ee982ffbe35
- author
- brice · · 2025-12-18 17:21 UTC
- parent
- 6bf5e05
- signature
- unsigned
2 files · +57 -75
M docs/CONFIG.md +25 -70
| @@ -68,17 +68,31 @@ description = "YouTube" | |||
| 68 | 68 | ||
| 69 | 69 | ## Dmenu / Launcher | |
| 70 | 70 | ||
| 71 | + | These settings control the `dumber dmenu` CLI command for rofi/fuzzel integration. | |
| 72 | + | ||
| 71 | 73 | | Key | Type | Default | Description | | |
| 72 | 74 | |-----|------|---------|-------------| | |
| 73 | 75 | | `dmenu.max_history_items` | int | `20` | Max items shown in launcher | | |
| 74 | - | | `dmenu.show_visit_count` | bool | `true` | Show visit counts | | |
| 75 | - | | `dmenu.show_last_visited` | bool | `true` | Show last visited dates | | |
| 76 | + | | `dmenu.show_visit_count` | bool | `true` | Show visit counts in output | | |
| 77 | + | | `dmenu.show_last_visited` | bool | `true` | Show last visited dates in output | | |
| 76 | 78 | | `dmenu.history_prefix` | string | `"🕒"` | Prefix for history items | | |
| 77 | 79 | | `dmenu.shortcut_prefix` | string | `"🔍"` | Prefix for shortcuts | | |
| 78 | 80 | | `dmenu.url_prefix` | string | `"🌐"` | Prefix for URLs | | |
| 79 | 81 | | `dmenu.date_format` | string | `"2006-01-02 15:04"` | Go time format string | | |
| 80 | 82 | | `dmenu.sort_by_visit_count` | bool | `true` | Sort by popularity | | |
| 81 | 83 | ||
| 84 | + | **CLI Usage:** | |
| 85 | + | ```bash | |
| 86 | + | # Pipe mode (default) - outputs history for rofi/fuzzel | |
| 87 | + | dumber dmenu | rofi -dmenu -p "Browse: " | dumber dmenu --select | |
| 88 | + | ||
| 89 | + | # Interactive TUI mode | |
| 90 | + | dumber dmenu --interactive | |
| 91 | + | ||
| 92 | + | # Override max items via CLI flag | |
| 93 | + | dumber dmenu --max 50 | |
| 94 | + | ``` | |
| 95 | + | ||
| 82 | 96 | ## Omnibox | |
| 83 | 97 | ||
| 84 | 98 | | Key | Type | Default | Valid Values | Description | | |
| @@ -101,19 +115,10 @@ initial_behavior = "recent" # Show recent history when omnibox opens | |||
| 101 | 115 | |-----|------|---------|--------------|-------------| | |
| 102 | 116 | | `logging.level` | string | `"info"` | `debug`, `info`, `warn`, `error` | Log level | | |
| 103 | 117 | | `logging.format` | string | `"text"` | `text`, `json` | Log format | | |
| 104 | - | | `logging.filename` | string | `""` | any | Empty = stdout | | |
| 105 | - | | `logging.max_size` | int | `100` | > 0 | Max log size in MB | | |
| 106 | - | | `logging.max_backups` | int | `3` | >= 0 | Number of log backups | | |
| 107 | 118 | | `logging.max_age` | int | `7` | >= 0 | Days to keep logs | | |
| 108 | - | | `logging.compress` | bool | `true` | - | Compress old logs | | |
| 109 | 119 | | `logging.log_dir` | string | `~/.local/state/dumber/logs/` | any | Log directory | | |
| 110 | 120 | | `logging.enable_file_log` | bool | `true` | - | Enable file logging | | |
| 111 | - | | `logging.capture_stdout` | bool | `false` | - | Capture stdout to log | | |
| 112 | - | | `logging.capture_stderr` | bool | `false` | - | Capture stderr to log | | |
| 113 | - | | `logging.capture_c_output` | bool | `false` | - | Capture C/CGO output | | |
| 114 | - | | `logging.capture_console` | bool | `false` | - | Capture browser console | | |
| 115 | - | | `logging.debug_file` | string | `"debug.log"` | any | Debug log filename | | |
| 116 | - | | `logging.verbose_webkit` | bool | `false` | - | Verbose WebKit logs | | |
| 121 | + | | `logging.capture_console` | bool | `false` | - | Capture browser console to logs | | |
| 117 | 122 | ||
| 118 | 123 | ## Appearance | |
| 119 | 124 | ||
| @@ -151,48 +156,11 @@ accent = "#a8a8a8" | |||
| 151 | 156 | border = "#363636" | |
| 152 | 157 | ``` | |
| 153 | 158 | ||
| 154 | - | ## Video Acceleration | |
| 155 | - | ||
| 156 | - | | Key | Type | Default | Description | | |
| 157 | - | |-----|------|---------|-------------| | |
| 158 | - | | `video_acceleration.enable_vaapi` | bool | `true` | Enable VA-API hardware accel | | |
| 159 | - | | `video_acceleration.auto_detect_gpu` | bool | `true` | Auto-detect GPU driver | | |
| 160 | - | | `video_acceleration.vaapi_driver_name` | string | `""` | Driver name (auto-detected) | | |
| 161 | - | | `video_acceleration.enable_all_drivers` | bool | `true` | Enable all VA-API drivers | | |
| 162 | - | | `video_acceleration.legacy_vaapi` | bool | `false` | Legacy VA-API mode | | |
| 163 | - | ||
| 164 | - | ## Codec Preferences | |
| 165 | - | ||
| 166 | - | | Key | Type | Default | Valid Values | Description | | |
| 167 | - | |-----|------|---------|--------------|-------------| | |
| 168 | - | | `codec_preferences.preferred_codecs` | string | `"av1,h264"` | Comma-separated | Codec priority order | | |
| 169 | - | | `codec_preferences.force_av1` | bool | `false` | - | Force AV1 codec | | |
| 170 | - | | `codec_preferences.block_vp9` | bool | `false` | - | Block VP9 codec | | |
| 171 | - | | `codec_preferences.block_vp8` | bool | `false` | - | Block VP8 codec | | |
| 172 | - | | `codec_preferences.av1_hardware_only` | bool | `false` | - | Disable AV1 software fallback | | |
| 173 | - | | `codec_preferences.disable_vp9_hardware` | bool | `false` | - | Disable VP9 hardware accel | | |
| 174 | - | | `codec_preferences.video_buffer_size_mb` | int | `64` | > 0 | Video buffer size in MB | | |
| 175 | - | | `codec_preferences.queue_buffer_time_sec` | int | `20` | > 0 | Queue buffer time in seconds | | |
| 176 | - | | `codec_preferences.custom_user_agent` | string | Chrome UA | any | Custom user agent string | | |
| 177 | - | | `codec_preferences.av1_max_resolution` | string | `"1080p"` | `720p`, `1080p`, `1440p`, `4k`, `unlimited` | Max AV1 resolution | | |
| 178 | - | | `codec_preferences.disable_twitch_codec_control` | bool | `true` | - | Disable codec control on Twitch | | |
| 179 | - | ||
| 180 | 159 | ## Debug Options | |
| 181 | 160 | ||
| 182 | 161 | | Key | Type | Default | Description | | |
| 183 | 162 | |-----|------|---------|-------------| | |
| 184 | - | | `debug.enable_webkit_debug` | bool | `false` | Enable WebKit debug logs | | |
| 185 | - | | `debug.webkit_debug_categories` | string | `"Network:preconnectTo,ContentFilters"` | Debug categories | | |
| 186 | - | | `debug.enable_filtering_debug` | bool | `false` | Content filter debug | | |
| 187 | - | | `debug.enable_webview_debug` | bool | `false` | WebView state debug | | |
| 188 | - | | `debug.log_webkit_crashes` | bool | `true` | Log WebKit crashes | | |
| 189 | - | | `debug.enable_script_debug` | bool | `false` | Script injection debug | | |
| 190 | - | | `debug.enable_general_debug` | bool | `false` | General debug mode | | |
| 191 | - | | `debug.enable_workspace_debug` | bool | `false` | Workspace navigation debug | | |
| 192 | - | | `debug.enable_focus_debug` | bool | `false` | Focus state debug | | |
| 193 | - | | `debug.enable_css_debug` | bool | `false` | CSS reconciler debug | | |
| 194 | - | | `debug.enable_focus_metrics` | bool | `false` | Focus metrics tracking | | |
| 195 | - | | `debug.enable_pane_close_debug` | bool | `false` | Pane close debug | | |
| 163 | + | | `debug.enable_devtools` | bool | `true` | Enable browser developer tools (F12, Inspect Element) | | |
| 196 | 164 | ||
| 197 | 165 | ## Rendering & Zoom | |
| 198 | 166 | ||
| @@ -287,19 +255,9 @@ cancel = ["escape"] | |||
| 287 | 255 | | Key | Type | Default | Description | | |
| 288 | 256 | |-----|------|---------|-------------| | |
| 289 | 257 | | `content_filtering.enabled` | bool | `true` | Enable ad blocking | | |
| 290 | - | | `content_filtering.whitelist` | array | See below | Domains to skip ad blocking | | |
| 291 | 258 | | `content_filtering.filter_lists` | array | See below | Filter list URLs to use | | |
| 292 | 259 | ||
| 293 | - | **Default whitelist:** | |
| 294 | - | ```toml | |
| 295 | - | [content_filtering] | |
| 296 | - | enabled = true | |
| 297 | - | whitelist = [ | |
| 298 | - | "twitch.tv", | |
| 299 | - | "passport.twitch.tv", | |
| 300 | - | "gql.twitch.tv" | |
| 301 | - | ] | |
| 302 | - | ``` | |
| 260 | + | > **Note:** Domain whitelist is managed via the database (`content_whitelist` table), not the config file. | |
| 303 | 261 | ||
| 304 | 262 | **Default filter lists:** | |
| 305 | 263 | ```toml | |
| @@ -329,20 +287,17 @@ filter_lists = [ | |||
| 329 | 287 | ||
| 330 | 288 | ## Environment Variables | |
| 331 | 289 | ||
| 332 | - | All config values can be overridden via environment variables with the prefix `DUMB_BROWSER_`: | |
| 290 | + | All config values can be overridden via environment variables with the prefix `DUMBER_`: | |
| 333 | 291 | ||
| 334 | 292 | ```bash | |
| 335 | 293 | # Database | |
| 336 | - | DUMB_BROWSER_DATABASE_PATH=/custom/path/db.sqlite | |
| 294 | + | DUMBER_DATABASE_PATH=/custom/path/db.sqlite | |
| 337 | 295 | ||
| 338 | 296 | # Rendering | |
| 339 | 297 | DUMBER_RENDERING_MODE=cpu | |
| 340 | - | DUMBER_DEFAULT_ZOOM=1.5 | |
| 298 | + | DUMBER_DEFAULT_WEBPAGE_ZOOM=1.5 | |
| 341 | 299 | ||
| 342 | - | # Video/Codec | |
| 343 | - | DUMBER_VIDEO_ACCELERATION_ENABLE=true | |
| 344 | - | LIBVA_DRIVER_NAME=iHD | |
| 345 | - | DUMBER_PREFERRED_CODECS=av1,vp9,h264 | |
| 300 | + | # Logging | |
| 301 | + | DUMBER_LOG_LEVEL=debug | |
| 302 | + | DUMBER_LOG_FORMAT=json | |
| 346 | 303 | ``` | |
| 347 | - | ||
| 348 | - | **Note:** Some video/codec env vars use `DUMBER_*` prefix and match GStreamer/VA-API conventions. | |
| @@ -68,17 +68,31 @@ description = "YouTube" | |||||
| 68 | 68 | ||||
| 69 | ## Dmenu / Launcher | 69 | ## Dmenu / Launcher | ||
| 70 | 70 | ||||
| 71 | + | These settings control the `dumber dmenu` CLI command for rofi/fuzzel integration. | |||
| 72 | + | ||||
| 71 | | Key | Type | Default | Description | | 73 | | Key | Type | Default | Description | | ||
| 72 | |-----|------|---------|-------------| | 74 | |-----|------|---------|-------------| | ||
| 73 | | `dmenu.max_history_items` | int | `20` | Max items shown in launcher | | 75 | | `dmenu.max_history_items` | int | `20` | Max items shown in launcher | | ||
| 74 | - | | `dmenu.show_visit_count` | bool | `true` | Show visit counts | | 76 | + | | `dmenu.show_visit_count` | bool | `true` | Show visit counts in output | |
| 75 | - | | `dmenu.show_last_visited` | bool | `true` | Show last visited dates | | 77 | + | | `dmenu.show_last_visited` | bool | `true` | Show last visited dates in output | |
| 76 | | `dmenu.history_prefix` | string | `"🕒"` | Prefix for history items | | 78 | | `dmenu.history_prefix` | string | `"🕒"` | Prefix for history items | | ||
| 77 | | `dmenu.shortcut_prefix` | string | `"🔍"` | Prefix for shortcuts | | 79 | | `dmenu.shortcut_prefix` | string | `"🔍"` | Prefix for shortcuts | | ||
| 78 | | `dmenu.url_prefix` | string | `"🌐"` | Prefix for URLs | | 80 | | `dmenu.url_prefix` | string | `"🌐"` | Prefix for URLs | | ||
| 79 | | `dmenu.date_format` | string | `"2006-01-02 15:04"` | Go time format string | | 81 | | `dmenu.date_format` | string | `"2006-01-02 15:04"` | Go time format string | | ||
| 80 | | `dmenu.sort_by_visit_count` | bool | `true` | Sort by popularity | | 82 | | `dmenu.sort_by_visit_count` | bool | `true` | Sort by popularity | | ||
| 81 | 83 | ||||
| 84 | + | **CLI Usage:** | |||
| 85 | + | ```bash | |||
| 86 | + | # Pipe mode (default) - outputs history for rofi/fuzzel | |||
| 87 | + | dumber dmenu | rofi -dmenu -p "Browse: " | dumber dmenu --select | |||
| 88 | + | ||||
| 89 | + | # Interactive TUI mode | |||
| 90 | + | dumber dmenu --interactive | |||
| 91 | + | ||||
| 92 | + | # Override max items via CLI flag | |||
| 93 | + | dumber dmenu --max 50 | |||
| 94 | + | ``` | |||
| 95 | + | ||||
| 82 | ## Omnibox | 96 | ## Omnibox | ||
| 83 | 97 | ||||
| 84 | | Key | Type | Default | Valid Values | Description | | 98 | | Key | Type | Default | Valid Values | Description | | ||
| @@ -101,19 +115,10 @@ initial_behavior = "recent" # Show recent history when omnibox opens | |||||
| 101 | |-----|------|---------|--------------|-------------| | 115 | |-----|------|---------|--------------|-------------| | ||
| 102 | | `logging.level` | string | `"info"` | `debug`, `info`, `warn`, `error` | Log level | | 116 | | `logging.level` | string | `"info"` | `debug`, `info`, `warn`, `error` | Log level | | ||
| 103 | | `logging.format` | string | `"text"` | `text`, `json` | Log format | | 117 | | `logging.format` | string | `"text"` | `text`, `json` | Log format | | ||
| 104 | - | | `logging.filename` | string | `""` | any | Empty = stdout | | |||
| 105 | - | | `logging.max_size` | int | `100` | > 0 | Max log size in MB | | |||
| 106 | - | | `logging.max_backups` | int | `3` | >= 0 | Number of log backups | | |||
| 107 | | `logging.max_age` | int | `7` | >= 0 | Days to keep logs | | 118 | | `logging.max_age` | int | `7` | >= 0 | Days to keep logs | | ||
| 108 | - | | `logging.compress` | bool | `true` | - | Compress old logs | | |||
| 109 | | `logging.log_dir` | string | `~/.local/state/dumber/logs/` | any | Log directory | | 119 | | `logging.log_dir` | string | `~/.local/state/dumber/logs/` | any | Log directory | | ||
| 110 | | `logging.enable_file_log` | bool | `true` | - | Enable file logging | | 120 | | `logging.enable_file_log` | bool | `true` | - | Enable file logging | | ||
| 111 | - | | `logging.capture_stdout` | bool | `false` | - | Capture stdout to log | | 121 | + | | `logging.capture_console` | bool | `false` | - | Capture browser console to logs | |
| 112 | - | | `logging.capture_stderr` | bool | `false` | - | Capture stderr to log | | |||
| 113 | - | | `logging.capture_c_output` | bool | `false` | - | Capture C/CGO output | | |||
| 114 | - | | `logging.capture_console` | bool | `false` | - | Capture browser console | | |||
| 115 | - | | `logging.debug_file` | string | `"debug.log"` | any | Debug log filename | | |||
| 116 | - | | `logging.verbose_webkit` | bool | `false` | - | Verbose WebKit logs | | |||
| 117 | 122 | ||||
| 118 | ## Appearance | 123 | ## Appearance | ||
| 119 | 124 | ||||
| @@ -151,48 +156,11 @@ accent = "#a8a8a8" | |||||
| 151 | border = "#363636" | 156 | border = "#363636" | ||
| 152 | ``` | 157 | ``` | ||
| 153 | 158 | ||||
| 154 | - | ## Video Acceleration | |||
| 155 | - | ||||
| 156 | - | | Key | Type | Default | Description | | |||
| 157 | - | |-----|------|---------|-------------| | |||
| 158 | - | | `video_acceleration.enable_vaapi` | bool | `true` | Enable VA-API hardware accel | | |||
| 159 | - | | `video_acceleration.auto_detect_gpu` | bool | `true` | Auto-detect GPU driver | | |||
| 160 | - | | `video_acceleration.vaapi_driver_name` | string | `""` | Driver name (auto-detected) | | |||
| 161 | - | | `video_acceleration.enable_all_drivers` | bool | `true` | Enable all VA-API drivers | | |||
| 162 | - | | `video_acceleration.legacy_vaapi` | bool | `false` | Legacy VA-API mode | | |||
| 163 | - | ||||
| 164 | - | ## Codec Preferences | |||
| 165 | - | ||||
| 166 | - | | Key | Type | Default | Valid Values | Description | | |||
| 167 | - | |-----|------|---------|--------------|-------------| | |||
| 168 | - | | `codec_preferences.preferred_codecs` | string | `"av1,h264"` | Comma-separated | Codec priority order | | |||
| 169 | - | | `codec_preferences.force_av1` | bool | `false` | - | Force AV1 codec | | |||
| 170 | - | | `codec_preferences.block_vp9` | bool | `false` | - | Block VP9 codec | | |||
| 171 | - | | `codec_preferences.block_vp8` | bool | `false` | - | Block VP8 codec | | |||
| 172 | - | | `codec_preferences.av1_hardware_only` | bool | `false` | - | Disable AV1 software fallback | | |||
| 173 | - | | `codec_preferences.disable_vp9_hardware` | bool | `false` | - | Disable VP9 hardware accel | | |||
| 174 | - | | `codec_preferences.video_buffer_size_mb` | int | `64` | > 0 | Video buffer size in MB | | |||
| 175 | - | | `codec_preferences.queue_buffer_time_sec` | int | `20` | > 0 | Queue buffer time in seconds | | |||
| 176 | - | | `codec_preferences.custom_user_agent` | string | Chrome UA | any | Custom user agent string | | |||
| 177 | - | | `codec_preferences.av1_max_resolution` | string | `"1080p"` | `720p`, `1080p`, `1440p`, `4k`, `unlimited` | Max AV1 resolution | | |||
| 178 | - | | `codec_preferences.disable_twitch_codec_control` | bool | `true` | - | Disable codec control on Twitch | | |||
| 179 | - | ||||
| 180 | ## Debug Options | 159 | ## Debug Options | ||
| 181 | 160 | ||||
| 182 | | Key | Type | Default | Description | | 161 | | Key | Type | Default | Description | | ||
| 183 | |-----|------|---------|-------------| | 162 | |-----|------|---------|-------------| | ||
| 184 | - | | `debug.enable_webkit_debug` | bool | `false` | Enable WebKit debug logs | | 163 | + | | `debug.enable_devtools` | bool | `true` | Enable browser developer tools (F12, Inspect Element) | |
| 185 | - | | `debug.webkit_debug_categories` | string | `"Network:preconnectTo,ContentFilters"` | Debug categories | | |||
| 186 | - | | `debug.enable_filtering_debug` | bool | `false` | Content filter debug | | |||
| 187 | - | | `debug.enable_webview_debug` | bool | `false` | WebView state debug | | |||
| 188 | - | | `debug.log_webkit_crashes` | bool | `true` | Log WebKit crashes | | |||
| 189 | - | | `debug.enable_script_debug` | bool | `false` | Script injection debug | | |||
| 190 | - | | `debug.enable_general_debug` | bool | `false` | General debug mode | | |||
| 191 | - | | `debug.enable_workspace_debug` | bool | `false` | Workspace navigation debug | | |||
| 192 | - | | `debug.enable_focus_debug` | bool | `false` | Focus state debug | | |||
| 193 | - | | `debug.enable_css_debug` | bool | `false` | CSS reconciler debug | | |||
| 194 | - | | `debug.enable_focus_metrics` | bool | `false` | Focus metrics tracking | | |||
| 195 | - | | `debug.enable_pane_close_debug` | bool | `false` | Pane close debug | | |||
| 196 | 164 | ||||
| 197 | ## Rendering & Zoom | 165 | ## Rendering & Zoom | ||
| 198 | 166 | ||||
| @@ -287,19 +255,9 @@ cancel = ["escape"] | |||||
| 287 | | Key | Type | Default | Description | | 255 | | Key | Type | Default | Description | | ||
| 288 | |-----|------|---------|-------------| | 256 | |-----|------|---------|-------------| | ||
| 289 | | `content_filtering.enabled` | bool | `true` | Enable ad blocking | | 257 | | `content_filtering.enabled` | bool | `true` | Enable ad blocking | | ||
| 290 | - | | `content_filtering.whitelist` | array | See below | Domains to skip ad blocking | | |||
| 291 | | `content_filtering.filter_lists` | array | See below | Filter list URLs to use | | 258 | | `content_filtering.filter_lists` | array | See below | Filter list URLs to use | | ||
| 292 | 259 | ||||
| 293 | - | **Default whitelist:** | 260 | + | > **Note:** Domain whitelist is managed via the database (`content_whitelist` table), not the config file. |
| 294 | - | ```toml | |||
| 295 | - | [content_filtering] | |||
| 296 | - | enabled = true | |||
| 297 | - | whitelist = [ | |||
| 298 | - | "twitch.tv", | |||
| 299 | - | "passport.twitch.tv", | |||
| 300 | - | "gql.twitch.tv" | |||
| 301 | - | ] | |||
| 302 | - | ``` | |||
| 303 | 261 | ||||
| 304 | **Default filter lists:** | 262 | **Default filter lists:** | ||
| 305 | ```toml | 263 | ```toml | ||
| @@ -329,20 +287,17 @@ filter_lists = [ | |||||
| 329 | 287 | ||||
| 330 | ## Environment Variables | 288 | ## Environment Variables | ||
| 331 | 289 | ||||
| 332 | - | All config values can be overridden via environment variables with the prefix `DUMB_BROWSER_`: | 290 | + | All config values can be overridden via environment variables with the prefix `DUMBER_`: |
| 333 | 291 | ||||
| 334 | ```bash | 292 | ```bash | ||
| 335 | # Database | 293 | # Database | ||
| 336 | - | DUMB_BROWSER_DATABASE_PATH=/custom/path/db.sqlite | 294 | + | DUMBER_DATABASE_PATH=/custom/path/db.sqlite |
| 337 | 295 | ||||
| 338 | # Rendering | 296 | # Rendering | ||
| 339 | DUMBER_RENDERING_MODE=cpu | 297 | DUMBER_RENDERING_MODE=cpu | ||
| 340 | - | DUMBER_DEFAULT_ZOOM=1.5 | 298 | + | DUMBER_DEFAULT_WEBPAGE_ZOOM=1.5 |
| 341 | 299 | ||||
| 342 | - | # Video/Codec | 300 | + | # Logging |
| 343 | - | DUMBER_VIDEO_ACCELERATION_ENABLE=true | 301 | + | DUMBER_LOG_LEVEL=debug |
| 344 | - | LIBVA_DRIVER_NAME=iHD | 302 | + | DUMBER_LOG_FORMAT=json |
| 345 | - | DUMBER_PREFERRED_CODECS=av1,vp9,h264 | |||
| 346 | ``` | 303 | ``` | ||
| 347 | - | ||||
| 348 | - | **Note:** Some video/codec env vars use `DUMBER_*` prefix and match GStreamer/VA-API conventions. | |||
M internal/cli/cmd/dmenu.go +32 -5
| @@ -12,6 +12,7 @@ import ( | |||
| 12 | 12 | "github.com/spf13/cobra" | |
| 13 | 13 | ||
| 14 | 14 | "github.com/bnema/dumber/internal/cli/model" | |
| 15 | + | "github.com/bnema/dumber/internal/infrastructure/config" | |
| 15 | 16 | ) | |
| 16 | 17 | ||
| 17 | 18 | var ( | |
| @@ -38,7 +39,7 @@ func init() { | |||
| 38 | 39 | ||
| 39 | 40 | dmenuCmd.Flags().BoolVarP(&dmenuInteractive, "interactive", "i", false, "use interactive TUI mode") | |
| 40 | 41 | dmenuCmd.Flags().BoolVar(&dmenuSelect, "select", false, "process selection from stdin") | |
| 41 | - | dmenuCmd.Flags().IntVar(&dmenuMax, "max", 100, "maximum entries to output") | |
| 42 | + | dmenuCmd.Flags().IntVar(&dmenuMax, "max", 0, "maximum entries to output (default from config)") | |
| 42 | 43 | } | |
| 43 | 44 | ||
| 44 | 45 | func runDmenu(cmd *cobra.Command, args []string) error { | |
| @@ -61,18 +62,31 @@ func runDmenu(cmd *cobra.Command, args []string) error { | |||
| 61 | 62 | return runDmenuPipe() | |
| 62 | 63 | } | |
| 63 | 64 | ||
| 65 | + | // getDmenuConfig returns the dmenu configuration, with CLI flag overrides. | |
| 66 | + | func getDmenuConfig() config.DmenuConfig { | |
| 67 | + | app := GetApp() | |
| 68 | + | cfg := app.Config.Dmenu | |
| 69 | + | ||
| 70 | + | // Override max if explicitly set via CLI flag | |
| 71 | + | if dmenuMax > 0 { | |
| 72 | + | cfg.MaxHistoryItems = dmenuMax | |
| 73 | + | } | |
| 74 | + | ||
| 75 | + | return cfg | |
| 76 | + | } | |
| 77 | + | ||
| 64 | 78 | // runDmenuPipe outputs history entries for launcher consumption. | |
| 65 | 79 | func runDmenuPipe() error { | |
| 66 | 80 | app := GetApp() | |
| 67 | 81 | ctx := context.Background() | |
| 82 | + | cfg := getDmenuConfig() | |
| 68 | 83 | ||
| 69 | - | entries, err := app.SearchHistoryUC.GetRecent(ctx, dmenuMax, 0) | |
| 84 | + | entries, err := app.SearchHistoryUC.GetRecent(ctx, cfg.MaxHistoryItems, 0) | |
| 70 | 85 | if err != nil { | |
| 71 | 86 | return fmt.Errorf("get history: %w", err) | |
| 72 | 87 | } | |
| 73 | 88 | ||
| 74 | - | // Output in rofi-compatible format with icon hints | |
| 75 | - | // Format: text\0icon\x1ficonpath | |
| 89 | + | // Output in rofi-compatible format | |
| 76 | 90 | for _, entry := range entries { | |
| 77 | 91 | title := entry.Title | |
| 78 | 92 | if title == "" { | |
| @@ -84,9 +98,22 @@ func runDmenuPipe() error { | |||
| 84 | 98 | title = title[:77] + "..." | |
| 85 | 99 | } | |
| 86 | 100 | ||
| 101 | + | // Build output line based on config | |
| 102 | + | var parts []string | |
| 103 | + | parts = append(parts, cfg.HistoryPrefix+" "+title) | |
| 104 | + | ||
| 105 | + | if cfg.ShowVisitCount && entry.VisitCount > 0 { | |
| 106 | + | parts[0] = fmt.Sprintf("%s (%d)", parts[0], entry.VisitCount) | |
| 107 | + | } | |
| 108 | + | ||
| 109 | + | if cfg.ShowLastVisited && !entry.LastVisited.IsZero() { | |
| 110 | + | dateStr := entry.LastVisited.Format(cfg.DateFormat) | |
| 111 | + | parts[0] = fmt.Sprintf("%s [%s]", parts[0], dateStr) | |
| 112 | + | } | |
| 113 | + | ||
| 87 | 114 | // Output with URL as the actual value (for selection) | |
| 88 | 115 | // Using tab separator so rofi can use -d '\t' | |
| 89 | - | fmt.Printf("%s\t%s\n", title, entry.URL) | |
| 116 | + | fmt.Printf("%s\t%s\n", parts[0], entry.URL) | |
| 90 | 117 | } | |
| 91 | 118 | ||
| 92 | 119 | return nil | |
| @@ -12,6 +12,7 @@ import ( | |||||
| 12 | "github.com/spf13/cobra" | 12 | "github.com/spf13/cobra" | ||
| 13 | 13 | ||||
| 14 | "github.com/bnema/dumber/internal/cli/model" | 14 | "github.com/bnema/dumber/internal/cli/model" | ||
| 15 | + | "github.com/bnema/dumber/internal/infrastructure/config" | |||
| 15 | ) | 16 | ) | ||
| 16 | 17 | ||||
| 17 | var ( | 18 | var ( | ||
| @@ -38,7 +39,7 @@ func init() { | |||||
| 38 | 39 | ||||
| 39 | dmenuCmd.Flags().BoolVarP(&dmenuInteractive, "interactive", "i", false, "use interactive TUI mode") | 40 | dmenuCmd.Flags().BoolVarP(&dmenuInteractive, "interactive", "i", false, "use interactive TUI mode") | ||
| 40 | dmenuCmd.Flags().BoolVar(&dmenuSelect, "select", false, "process selection from stdin") | 41 | dmenuCmd.Flags().BoolVar(&dmenuSelect, "select", false, "process selection from stdin") | ||
| 41 | - | dmenuCmd.Flags().IntVar(&dmenuMax, "max", 100, "maximum entries to output") | 42 | + | dmenuCmd.Flags().IntVar(&dmenuMax, "max", 0, "maximum entries to output (default from config)") |
| 42 | } | 43 | } | ||
| 43 | 44 | ||||
| 44 | func runDmenu(cmd *cobra.Command, args []string) error { | 45 | func runDmenu(cmd *cobra.Command, args []string) error { | ||
| @@ -61,18 +62,31 @@ func runDmenu(cmd *cobra.Command, args []string) error { | |||||
| 61 | return runDmenuPipe() | 62 | return runDmenuPipe() | ||
| 62 | } | 63 | } | ||
| 63 | 64 | ||||
| 65 | + | // getDmenuConfig returns the dmenu configuration, with CLI flag overrides. | |||
| 66 | + | func getDmenuConfig() config.DmenuConfig { | |||
| 67 | + | app := GetApp() | |||
| 68 | + | cfg := app.Config.Dmenu | |||
| 69 | + | ||||
| 70 | + | // Override max if explicitly set via CLI flag | |||
| 71 | + | if dmenuMax > 0 { | |||
| 72 | + | cfg.MaxHistoryItems = dmenuMax | |||
| 73 | + | } | |||
| 74 | + | ||||
| 75 | + | return cfg | |||
| 76 | + | } | |||
| 77 | + | ||||
| 64 | // runDmenuPipe outputs history entries for launcher consumption. | 78 | // runDmenuPipe outputs history entries for launcher consumption. | ||
| 65 | func runDmenuPipe() error { | 79 | func runDmenuPipe() error { | ||
| 66 | app := GetApp() | 80 | app := GetApp() | ||
| 67 | ctx := context.Background() | 81 | ctx := context.Background() | ||
| 82 | + | cfg := getDmenuConfig() | |||
| 68 | 83 | ||||
| 69 | - | entries, err := app.SearchHistoryUC.GetRecent(ctx, dmenuMax, 0) | 84 | + | entries, err := app.SearchHistoryUC.GetRecent(ctx, cfg.MaxHistoryItems, 0) |
| 70 | if err != nil { | 85 | if err != nil { | ||
| 71 | return fmt.Errorf("get history: %w", err) | 86 | return fmt.Errorf("get history: %w", err) | ||
| 72 | } | 87 | } | ||
| 73 | 88 | ||||
| 74 | - | // Output in rofi-compatible format with icon hints | 89 | + | // Output in rofi-compatible format |
| 75 | - | // Format: text\0icon\x1ficonpath | |||
| 76 | for _, entry := range entries { | 90 | for _, entry := range entries { | ||
| 77 | title := entry.Title | 91 | title := entry.Title | ||
| 78 | if title == "" { | 92 | if title == "" { | ||
| @@ -84,9 +98,22 @@ func runDmenuPipe() error { | |||||
| 84 | title = title[:77] + "..." | 98 | title = title[:77] + "..." | ||
| 85 | } | 99 | } | ||
| 86 | 100 | ||||
| 101 | + | // Build output line based on config | |||
| 102 | + | var parts []string | |||
| 103 | + | parts = append(parts, cfg.HistoryPrefix+" "+title) | |||
| 104 | + | ||||
| 105 | + | if cfg.ShowVisitCount && entry.VisitCount > 0 { | |||
| 106 | + | parts[0] = fmt.Sprintf("%s (%d)", parts[0], entry.VisitCount) | |||
| 107 | + | } | |||
| 108 | + | ||||
| 109 | + | if cfg.ShowLastVisited && !entry.LastVisited.IsZero() { | |||
| 110 | + | dateStr := entry.LastVisited.Format(cfg.DateFormat) | |||
| 111 | + | parts[0] = fmt.Sprintf("%s [%s]", parts[0], dateStr) | |||
| 112 | + | } | |||
| 113 | + | ||||
| 87 | // Output with URL as the actual value (for selection) | 114 | // Output with URL as the actual value (for selection) | ||
| 88 | // Using tab separator so rofi can use -d '\t' | 115 | // Using tab separator so rofi can use -d '\t' | ||
| 89 | - | fmt.Printf("%s\t%s\n", title, entry.URL) | 116 | + | fmt.Printf("%s\t%s\n", parts[0], entry.URL) |
| 90 | } | 117 | } | ||
| 91 | 118 | ||||
| 92 | return nil | 119 | return nil | ||