detached 2e8f954

docs: update keyboard shortcuts and config documentation

Updates README with Ctrl+ only shortcuts (removes Cmd/Ctrl variants), simplifies config reference to point to docs/CONFIG.md, adds JSON Schema feature to CHANGELOG, and notes BREAKING change for keyboard shortcuts migration.
commit
2e8f954aa38e2830980fe922a5cb5d3ac3fad2dd
author
bnema · · 2025-10-23 20:48 UTC
committer
bnema · · 2025-10-24 17:33 UTC
parent
a5becb3
signature
GPG Unverified2B82207D370127A0 The key is unknown
3 files · +330 -129
M CHANGELOG.md +3 -1
@@ -9,14 +9,16 @@ All notable changes to this project will be documented in this file.
99 - **DNS prefetch**: Added capability to prefetch DNS for links to speed up future requests
1010 - **Page cache (bfcache)**: Enabled WebKit back/forward cache for instant navigation
1111 - **Smooth scrolling**: Enabled WebKit smooth scrolling for better UX
12+- **JSON Schema**: Auto-generated config schema for IDE autocompletion and validation
1213
1314 ### Changed
1415 - **Database performance**: Enabled WAL mode with optimized PRAGMAs (64MB cache, memory-mapped I/O, 5s busy timeout) for 70k reads/sec, 3.6k writes/sec
1516 - **Zoom performance**: In-memory cache eliminates database reads during page transitions
1617 - **History writes**: Batched writes with background processor (flush every 5s or 50 items) to reduce I/O overhead
18+- **BREAKING: Keyboard shortcuts**: All shortcuts now use `ctrl+` instead of `cmdorctrl+`. Existing configs with `cmdorctrl` still work via backward compatibility. Delete `~/.config/dumber/config.json` to regenerate with new defaults.
1719
1820 ### Fixed
19-- **Graceful shutdown deadlock**: Resolved GTK main loop deadlock on Cmd+Q by removing mutex locks and GTK calls after main loop exit
21+- **Graceful shutdown deadlock**: Resolved GTK main loop deadlock on Ctrl+Q by removing mutex locks and GTK calls after main loop exit
2022 - Command typos now show proper error instead of opening in browser
2123 - History queue now uses buffered channel to prevent blocking on shutdown
2224
@@ -9,14 +9,16 @@ All notable changes to this project will be documented in this file.
9 - **DNS prefetch**: Added capability to prefetch DNS for links to speed up future requests9 - **DNS prefetch**: Added capability to prefetch DNS for links to speed up future requests
10 - **Page cache (bfcache)**: Enabled WebKit back/forward cache for instant navigation10 - **Page cache (bfcache)**: Enabled WebKit back/forward cache for instant navigation
11 - **Smooth scrolling**: Enabled WebKit smooth scrolling for better UX11 - **Smooth scrolling**: Enabled WebKit smooth scrolling for better UX
12+- **JSON Schema**: Auto-generated config schema for IDE autocompletion and validation
12 13
13 ### Changed14 ### Changed
14 - **Database performance**: Enabled WAL mode with optimized PRAGMAs (64MB cache, memory-mapped I/O, 5s busy timeout) for 70k reads/sec, 3.6k writes/sec15 - **Database performance**: Enabled WAL mode with optimized PRAGMAs (64MB cache, memory-mapped I/O, 5s busy timeout) for 70k reads/sec, 3.6k writes/sec
15 - **Zoom performance**: In-memory cache eliminates database reads during page transitions16 - **Zoom performance**: In-memory cache eliminates database reads during page transitions
16 - **History writes**: Batched writes with background processor (flush every 5s or 50 items) to reduce I/O overhead17 - **History writes**: Batched writes with background processor (flush every 5s or 50 items) to reduce I/O overhead
18+- **BREAKING: Keyboard shortcuts**: All shortcuts now use `ctrl+` instead of `cmdorctrl+`. Existing configs with `cmdorctrl` still work via backward compatibility. Delete `~/.config/dumber/config.json` to regenerate with new defaults.
17 19
18 ### Fixed20 ### Fixed
19-- **Graceful shutdown deadlock**: Resolved GTK main loop deadlock on Cmd+Q by removing mutex locks and GTK calls after main loop exit21+- **Graceful shutdown deadlock**: Resolved GTK main loop deadlock on Ctrl+Q by removing mutex locks and GTK calls after main loop exit
20 - Command typos now show proper error instead of opening in browser22 - Command typos now show proper error instead of opening in browser
21 - History queue now uses buffered channel to prevent blocking on shutdown23 - History queue now uses buffered channel to prevent blocking on shutdown
22 24
M README.md +32 -128
@@ -41,22 +41,22 @@ Dumber is a minimalist browser and launcher companion focused on speed and simpl
4141 | Shortcut | Action | Notes |
4242 |----------|--------|-------|
4343 | **F12** | Open Developer Tools | WebKit inspector |
44-| **Ctrl/Cmd+L** | Open Omnibox | URL/search input with history |
45-| **Ctrl/Cmd+F** | Find in Page | Search text within current page |
46-| **Ctrl/Cmd+=** | Zoom In | Firefox-compatible zoom levels |
47-| **Ctrl/Cmd++** | Zoom In | Alternative plus key |
48-| **Ctrl/Cmd+-** | Zoom Out | Works across keyboard layouts |
49-| **Ctrl/Cmd+0** | Reset Zoom | Return to 100% zoom |
50-| **Ctrl/Cmd+Shift+C** | Copy URL | Copy current URL to clipboard with toast |
51-| **Ctrl/Cmd+Shift+P** | Print Page | Open native print dialog |
52-| **Ctrl/Cmd+R** / **F5** | Reload Page | Refresh current page |
53-| **Ctrl/Cmd+Shift+R** | Hard Reload | Refresh ignoring cache |
44+| **Ctrl+L** | Open Omnibox | URL/search input with history |
45+| **Ctrl+F** | Find in Page | Search text within current page |
46+| **Ctrl+=** | Zoom In | Firefox-compatible zoom levels |
47+| **Ctrl++** | Zoom In | Alternative plus key |
48+| **Ctrl+-** | Zoom Out | Works across keyboard layouts |
49+| **Ctrl+0** | Reset Zoom | Return to 100% zoom |
50+| **Ctrl+Shift+C** | Copy URL | Copy current URL to clipboard with toast |
51+| **Ctrl+Shift+P** | Print Page | Open native print dialog |
52+| **Ctrl+R** / **F5** | Reload Page | Refresh current page |
53+| **Ctrl+Shift+R** | Hard Reload | Refresh ignoring cache |
5454 | **Ctrl+←** / **Ctrl+→** | Navigate Back/Forward | Browser history navigation |
5555
5656 #### Zellij-Inspired Pane Management
5757 | Shortcut | Action | Notes |
5858 |----------|--------|-------|
59-| **Ctrl/Cmd+P** | Enter Pane Mode | Modal mode for pane operations |
59+| **Ctrl+P** | Enter Pane Mode | Modal mode for pane operations |
6060 | **→** / **R** (in pane mode) | Split Right | Create new pane to the right |
6161 | **←** / **L** (in pane mode) | Split Left | Create new pane to the left |
6262 | **↑** / **U** (in pane mode) | Split Up | Create new pane above |
@@ -178,7 +178,7 @@ The pane system is fully configurable via `config.json`:
178178 "workspace": {
179179 "enable_zellij_controls": true,
180180 "pane_mode": {
181- "activation_shortcut": "cmdorctrl+p",
181+ "activation_shortcut": "ctrl+p",
182182 "timeout_ms": 3000,
183183 "action_bindings": {
184184 "arrowright": "split-right",
@@ -208,134 +208,38 @@ Dumber follows the XDG Base Directory spec:
208208
209209 A default `config.json` is created on first run. Config changes are watched and applied at runtime when possible.
210210
211-### Complete Configuration Reference
211+### How Configuration Works
212212
213-#### Database Configuration
214-```json
215-"database": {
216- "path": "~/.local/state/dumber/history.db",
217- "max_connections": 1,
218- "max_idle_time": "5m0s",
219- "query_timeout": "30s"
220-}
221-```
213+- **Config file**: `~/.config/dumber/config.json` (supports `.yaml` and `.toml` too)
214+- **Format**: JSON/YAML/TOML - auto-detected
215+- **JSON Schema**: Auto-generated for IDE autocompletion and validation
216+- **Live reload**: Changes are automatically applied without restarting
217+- **Environment variables**: Override any setting with `DUMB_BROWSER_*` or `DUMBER_*` prefix
218+- **Default values**: Sensible defaults for all settings
222219
223-#### History Management
224-```json
225-"history": {
226- "max_entries": 10000,
227- "retention_period_days": 365,
228- "cleanup_interval_days": 1
229-}
230-```
220+### Quick Examples
231221
232-#### Search Shortcuts
233222 ```json
234-"search_shortcuts": {
235- "g": { "url": "https://www.google.com/search?q=%s", "description": "Google search" },
236- "gh": { "url": "https://github.com/search?q=%s", "description": "GitHub search" },
237- "yt": { "url": "https://www.youtube.com/results?search_query=%s", "description": "YouTube search" },
238- "w": { "url": "https://en.wikipedia.org/wiki/%s", "description": "Wikipedia search" },
239- "ddg": { "url": "https://duckduckgo.com/?q=%s", "description": "DuckDuckGo search" },
240- "so": { "url": "https://stackoverflow.com/search?q=%s", "description": "Stack Overflow search" },
241- "r": { "url": "https://www.reddit.com/search?q=%s", "description": "Reddit search" },
242- "npm": { "url": "https://www.npmjs.com/search?q=%s", "description": "npm package search" },
243- "go": { "url": "https://pkg.go.dev/search?q=%s", "description": "Go package search" },
244- "mdn": { "url": "https://developer.mozilla.org/en-US/search?q=%s", "description": "MDN Web Docs search" }
245-}
246-```
247-
248-#### Dmenu Integration
249-```json
250-"dmenu": {
251- "max_history_items": 20,
252- "show_visit_count": true,
253- "show_last_visited": true,
254- "history_prefix": "🕒",
255- "shortcut_prefix": "🔍",
256- "url_prefix": "🌐",
257- "date_format": "2006-01-02 15:04",
258- "sort_by_visit_count": true
259-}
260-```
261-
262-#### Logging Configuration
263-```json
264-"logging": {
265- "level": "info",
266- "format": "text",
267- "filename": "",
268- "max_size": 100,
269- "max_backups": 3,
270- "max_age": 7,
271- "compress": true
272-}
273-```
274-
275-#### Appearance Settings
276-```json
277-"appearance": {
278- "color_scheme": "default",
279- "sans_font": "Fira Sans",
280- "serif_font": "Fira Sans",
281- "monospace_font": "Fira Code",
282- "default_font_size": 16,
223+{
283224 "default_zoom": 1.2,
284- "color_palette": {
285- "light": {
286- "background": "#ffffff",
287- "surface": "#f5f5f5",
288- "text": "#1a1a1a",
289- "text_muted": "#6b7280",
290- "accent": "#3b82f6",
291- "border": "#e5e7eb"
292- },
293- "dark": {
294- "background": "#0a0a0a",
295- "surface": "#1a1a1a",
296- "text": "#e5e7eb",
297- "text_muted": "#9ca3af",
298- "accent": "#60a5fa",
299- "border": "#374151"
300- }
225+ "rendering_mode": "gpu",
226+ "search_shortcuts": {
227+ "g": { "url": "https://google.com/search?q=%s", "description": "Google" }
228+ },
229+ "workspace": {
230+ "enable_zellij_controls": true,
231+ "popups": { "behavior": "split" }
301232 }
302233 }
303234 ```
304-- `color_scheme`: `"prefer-dark"`, `"prefer-light"`, or `"default"` (follows system theme)
305-
306-#### Rendering Mode (GPU/CPU)
307-```json
308-"rendering_mode": "auto"
309-```
310-- `auto`: Detect GPU availability and use GPU when available (default)
311-- `gpu`: Force GPU acceleration (Vulkan/OpenGL via GTK4)
312-- `cpu`: Force software rendering
313-
314-### Environment Variables
315-All config values can be overridden with environment variables using the `DUMB_BROWSER_` prefix:
316235
236+Environment variable override:
317237 ```bash
318-# Database
319-DUMB_BROWSER_DATABASE_PATH="./browser.db"
320-DUMB_BROWSER_DATABASE_MAX_CONNECTIONS=5
321-
322-# Rendering mode (special variable name)
323-DUMBER_RENDERING_MODE="gpu"
324-
325-# Dmenu settings
326-DUMB_BROWSER_DMENU_MAX_HISTORY_ITEMS=50
327-DUMB_BROWSER_DMENU_SHOW_VISIT_COUNT=false
328-
329-# Logging
330-DUMB_BROWSER_LOGGING_LEVEL="debug"
331-DUMB_BROWSER_LOGGING_FORMAT="json"
238+DUMBER_RENDERING_MODE=cpu dumber
239+DUMB_BROWSER_LOGGING_LEVEL=debug dumber
332240 ```
333241
334-### CLI Flags
335-The browse command supports additional runtime flags:
336-```bash
337-dumber browse --rendering-mode=gpu https://example.com
338-```
242+**📖 Complete documentation**: See [docs/CONFIG.md](docs/CONFIG.md) for all available settings, defaults, and valid values.
339243
340244
341245 ## Building With WebKitGTK 6 (GTK4)
@@ -41,22 +41,22 @@ Dumber is a minimalist browser and launcher companion focused on speed and simpl
41 | Shortcut | Action | Notes |41 | Shortcut | Action | Notes |
42 |----------|--------|-------|42 |----------|--------|-------|
43 | **F12** | Open Developer Tools | WebKit inspector |43 | **F12** | Open Developer Tools | WebKit inspector |
44-| **Ctrl/Cmd+L** | Open Omnibox | URL/search input with history |44+| **Ctrl+L** | Open Omnibox | URL/search input with history |
45-| **Ctrl/Cmd+F** | Find in Page | Search text within current page |45+| **Ctrl+F** | Find in Page | Search text within current page |
46-| **Ctrl/Cmd+=** | Zoom In | Firefox-compatible zoom levels |46+| **Ctrl+=** | Zoom In | Firefox-compatible zoom levels |
47-| **Ctrl/Cmd++** | Zoom In | Alternative plus key |47+| **Ctrl++** | Zoom In | Alternative plus key |
48-| **Ctrl/Cmd+-** | Zoom Out | Works across keyboard layouts |48+| **Ctrl+-** | Zoom Out | Works across keyboard layouts |
49-| **Ctrl/Cmd+0** | Reset Zoom | Return to 100% zoom |49+| **Ctrl+0** | Reset Zoom | Return to 100% zoom |
50-| **Ctrl/Cmd+Shift+C** | Copy URL | Copy current URL to clipboard with toast |50+| **Ctrl+Shift+C** | Copy URL | Copy current URL to clipboard with toast |
51-| **Ctrl/Cmd+Shift+P** | Print Page | Open native print dialog |51+| **Ctrl+Shift+P** | Print Page | Open native print dialog |
52-| **Ctrl/Cmd+R** / **F5** | Reload Page | Refresh current page |52+| **Ctrl+R** / **F5** | Reload Page | Refresh current page |
53-| **Ctrl/Cmd+Shift+R** | Hard Reload | Refresh ignoring cache |53+| **Ctrl+Shift+R** | Hard Reload | Refresh ignoring cache |
54 | **Ctrl+←** / **Ctrl+→** | Navigate Back/Forward | Browser history navigation |54 | **Ctrl+←** / **Ctrl+→** | Navigate Back/Forward | Browser history navigation |
55 55
56 #### Zellij-Inspired Pane Management56 #### Zellij-Inspired Pane Management
57 | Shortcut | Action | Notes |57 | Shortcut | Action | Notes |
58 |----------|--------|-------|58 |----------|--------|-------|
59-| **Ctrl/Cmd+P** | Enter Pane Mode | Modal mode for pane operations |59+| **Ctrl+P** | Enter Pane Mode | Modal mode for pane operations |
60 | **→** / **R** (in pane mode) | Split Right | Create new pane to the right |60 | **→** / **R** (in pane mode) | Split Right | Create new pane to the right |
61 | **←** / **L** (in pane mode) | Split Left | Create new pane to the left |61 | **←** / **L** (in pane mode) | Split Left | Create new pane to the left |
62 | **↑** / **U** (in pane mode) | Split Up | Create new pane above |62 | **↑** / **U** (in pane mode) | Split Up | Create new pane above |
@@ -178,7 +178,7 @@ The pane system is fully configurable via `config.json`:
178 "workspace": {178 "workspace": {
179 "enable_zellij_controls": true,179 "enable_zellij_controls": true,
180 "pane_mode": {180 "pane_mode": {
181- "activation_shortcut": "cmdorctrl+p",181+ "activation_shortcut": "ctrl+p",
182 "timeout_ms": 3000,182 "timeout_ms": 3000,
183 "action_bindings": {183 "action_bindings": {
184 "arrowright": "split-right",184 "arrowright": "split-right",
@@ -208,134 +208,38 @@ Dumber follows the XDG Base Directory spec:
208 208
209 A default `config.json` is created on first run. Config changes are watched and applied at runtime when possible.209 A default `config.json` is created on first run. Config changes are watched and applied at runtime when possible.
210 210
211-### Complete Configuration Reference211+### How Configuration Works
212 212
213-#### Database Configuration213+- **Config file**: `~/.config/dumber/config.json` (supports `.yaml` and `.toml` too)
214-```json214+- **Format**: JSON/YAML/TOML - auto-detected
215-"database": {215+- **JSON Schema**: Auto-generated for IDE autocompletion and validation
216- "path": "~/.local/state/dumber/history.db",216+- **Live reload**: Changes are automatically applied without restarting
217- "max_connections": 1,217+- **Environment variables**: Override any setting with `DUMB_BROWSER_*` or `DUMBER_*` prefix
218- "max_idle_time": "5m0s",218+- **Default values**: Sensible defaults for all settings
219- "query_timeout": "30s"
220-}
221-```
222 219
223-#### History Management220+### Quick Examples
224-```json
225-"history": {
226- "max_entries": 10000,
227- "retention_period_days": 365,
228- "cleanup_interval_days": 1
229-}
230-```
231 221
232-#### Search Shortcuts
233 ```json222 ```json
234-"search_shortcuts": {223+{
235- "g": { "url": "https://www.google.com/search?q=%s", "description": "Google search" },
236- "gh": { "url": "https://github.com/search?q=%s", "description": "GitHub search" },
237- "yt": { "url": "https://www.youtube.com/results?search_query=%s", "description": "YouTube search" },
238- "w": { "url": "https://en.wikipedia.org/wiki/%s", "description": "Wikipedia search" },
239- "ddg": { "url": "https://duckduckgo.com/?q=%s", "description": "DuckDuckGo search" },
240- "so": { "url": "https://stackoverflow.com/search?q=%s", "description": "Stack Overflow search" },
241- "r": { "url": "https://www.reddit.com/search?q=%s", "description": "Reddit search" },
242- "npm": { "url": "https://www.npmjs.com/search?q=%s", "description": "npm package search" },
243- "go": { "url": "https://pkg.go.dev/search?q=%s", "description": "Go package search" },
244- "mdn": { "url": "https://developer.mozilla.org/en-US/search?q=%s", "description": "MDN Web Docs search" }
245-}
246-```
247-
248-#### Dmenu Integration
249-```json
250-"dmenu": {
251- "max_history_items": 20,
252- "show_visit_count": true,
253- "show_last_visited": true,
254- "history_prefix": "🕒",
255- "shortcut_prefix": "🔍",
256- "url_prefix": "🌐",
257- "date_format": "2006-01-02 15:04",
258- "sort_by_visit_count": true
259-}
260-```
261-
262-#### Logging Configuration
263-```json
264-"logging": {
265- "level": "info",
266- "format": "text",
267- "filename": "",
268- "max_size": 100,
269- "max_backups": 3,
270- "max_age": 7,
271- "compress": true
272-}
273-```
274-
275-#### Appearance Settings
276-```json
277-"appearance": {
278- "color_scheme": "default",
279- "sans_font": "Fira Sans",
280- "serif_font": "Fira Sans",
281- "monospace_font": "Fira Code",
282- "default_font_size": 16,
283 "default_zoom": 1.2,224 "default_zoom": 1.2,
284- "color_palette": {225+ "rendering_mode": "gpu",
285- "light": {226+ "search_shortcuts": {
286- "background": "#ffffff",227+ "g": { "url": "https://google.com/search?q=%s", "description": "Google" }
287- "surface": "#f5f5f5",228+ },
288- "text": "#1a1a1a",229+ "workspace": {
289- "text_muted": "#6b7280",230+ "enable_zellij_controls": true,
290- "accent": "#3b82f6",231+ "popups": { "behavior": "split" }
291- "border": "#e5e7eb"
292- },
293- "dark": {
294- "background": "#0a0a0a",
295- "surface": "#1a1a1a",
296- "text": "#e5e7eb",
297- "text_muted": "#9ca3af",
298- "accent": "#60a5fa",
299- "border": "#374151"
300- }
301 }232 }
302 }233 }
303 ```234 ```
304-- `color_scheme`: `"prefer-dark"`, `"prefer-light"`, or `"default"` (follows system theme)
305-
306-#### Rendering Mode (GPU/CPU)
307-```json
308-"rendering_mode": "auto"
309-```
310-- `auto`: Detect GPU availability and use GPU when available (default)
311-- `gpu`: Force GPU acceleration (Vulkan/OpenGL via GTK4)
312-- `cpu`: Force software rendering
313-
314-### Environment Variables
315-All config values can be overridden with environment variables using the `DUMB_BROWSER_` prefix:
316 235
236+Environment variable override:
317 ```bash237 ```bash
318-# Database238+DUMBER_RENDERING_MODE=cpu dumber
319-DUMB_BROWSER_DATABASE_PATH="./browser.db"239+DUMB_BROWSER_LOGGING_LEVEL=debug dumber
320-DUMB_BROWSER_DATABASE_MAX_CONNECTIONS=5
321-
322-# Rendering mode (special variable name)
323-DUMBER_RENDERING_MODE="gpu"
324-
325-# Dmenu settings
326-DUMB_BROWSER_DMENU_MAX_HISTORY_ITEMS=50
327-DUMB_BROWSER_DMENU_SHOW_VISIT_COUNT=false
328-
329-# Logging
330-DUMB_BROWSER_LOGGING_LEVEL="debug"
331-DUMB_BROWSER_LOGGING_FORMAT="json"
332 ```240 ```
333 241
334-### CLI Flags242+**📖 Complete documentation**: See [docs/CONFIG.md](docs/CONFIG.md) for all available settings, defaults, and valid values.
335-The browse command supports additional runtime flags:
336-```bash
337-dumber browse --rendering-mode=gpu https://example.com
338-```
339 243
340 244
341 ## Building With WebKitGTK 6 (GTK4)245 ## Building With WebKitGTK 6 (GTK4)
A docs/CONFIG.md +295 -0
@@ -0,0 +1,295 @@
1+# Configuration Reference
2+
3+**Primary format**: JSON
4+**Location**: `~/.config/dumber/config.json`
5+**Also supports**: YAML (`.yaml`) and TOML (`.toml`)
6+**JSON Schema**: `~/.config/dumber/config.schema.json` (auto-generated)
7+
8+## IDE Integration
9+
10+For autocompletion and validation in VS Code or other editors, add this to the top of your `config.json`:
11+
12+```json
13+{
14+ "$schema": "./config.schema.json",
15+ "default_zoom": 1.2,
16+ ...
17+}
18+```
19+
20+The schema is automatically generated when you first create a config file.
21+
22+## Database
23+
24+| Key | Type | Default | Description |
25+|-----|------|---------|-------------|
26+| `database.path` | string | `~/.local/state/dumber/dumber.sqlite` | Database file path |
27+
28+## History
29+
30+| Key | Type | Default | Valid Values | Description |
31+|-----|------|---------|--------------|-------------|
32+| `history.max_entries` | int | `10000` | > 0 | Maximum number of history entries |
33+| `history.retention_period_days` | int | `365` | > 0 | Days to keep history (1 year) |
34+| `history.cleanup_interval_days` | int | `1` | > 0 | How often to run cleanup |
35+
36+## Search Shortcuts
37+
38+| Key | Type | Default | Description |
39+|-----|------|---------|-------------|
40+| `search_shortcuts` | map | See defaults | Map of shortcut aliases to URLs |
41+
42+**Default shortcuts:**
43+```json
44+{
45+ "search_shortcuts": {
46+ "g": {
47+ "url": "https://google.com/search?q=%s",
48+ "description": "Google Search"
49+ },
50+ "gh": {
51+ "url": "https://github.com/search?q=%s",
52+ "description": "GitHub"
53+ },
54+ "yt": {
55+ "url": "https://youtube.com/results?search_query=%s",
56+ "description": "YouTube"
57+ }
58+ }
59+}
60+```
61+
62+## Dmenu / Launcher
63+
64+| Key | Type | Default | Description |
65+|-----|------|---------|-------------|
66+| `dmenu.max_history_items` | int | `20` | Max items shown in launcher |
67+| `dmenu.show_visit_count` | bool | `true` | Show visit counts |
68+| `dmenu.show_last_visited` | bool | `true` | Show last visited dates |
69+| `dmenu.history_prefix` | string | `"🕒"` | Prefix for history items |
70+| `dmenu.shortcut_prefix` | string | `"🔍"` | Prefix for shortcuts |
71+| `dmenu.url_prefix` | string | `"🌐"` | Prefix for URLs |
72+| `dmenu.date_format` | string | `"2006-01-02 15:04"` | Go time format string |
73+| `dmenu.sort_by_visit_count` | bool | `true` | Sort by popularity |
74+
75+## Logging
76+
77+| Key | Type | Default | Valid Values | Description |
78+|-----|------|---------|--------------|-------------|
79+| `logging.level` | string | `"info"` | `debug`, `info`, `warn`, `error` | Log level |
80+| `logging.format` | string | `"text"` | `text`, `json` | Log format |
81+| `logging.filename` | string | `""` | any | Empty = stdout |
82+| `logging.max_size` | int | `100` | > 0 | Max log size in MB |
83+| `logging.max_backups` | int | `3` | >= 0 | Number of log backups |
84+| `logging.max_age` | int | `7` | >= 0 | Days to keep logs |
85+| `logging.compress` | bool | `true` | - | Compress old logs |
86+| `logging.log_dir` | string | `~/.local/state/dumber/logs/` | any | Log directory |
87+| `logging.enable_file_log` | bool | `true` | - | Enable file logging |
88+| `logging.capture_stdout` | bool | `false` | - | Capture stdout to log |
89+| `logging.capture_stderr` | bool | `false` | - | Capture stderr to log |
90+| `logging.capture_c_output` | bool | `false` | - | Capture C/CGO output |
91+| `logging.capture_console` | bool | `false` | - | Capture browser console |
92+| `logging.debug_file` | string | `"debug.log"` | any | Debug log filename |
93+| `logging.verbose_webkit` | bool | `false` | - | Verbose WebKit logs |
94+
95+## Appearance
96+
97+| Key | Type | Default | Description |
98+|-----|------|---------|-------------|
99+| `appearance.sans_font` | string | `"Fira Sans"` | Sans-serif font |
100+| `appearance.serif_font` | string | `"Fira Sans"` | Serif font |
101+| `appearance.monospace_font` | string | `"Fira Code"` | Monospace font |
102+| `appearance.default_font_size` | int | `16` | Font size in points |
103+| `appearance.color_scheme` | string | `"default"` | `prefer-dark`, `prefer-light`, `default` |
104+
105+### Color Palettes
106+
107+**Light palette:**
108+```json
109+{
110+ "appearance": {
111+ "light_palette": {
112+ "background": "#f8f8f8",
113+ "surface": "#f2f2f2",
114+ "surface_variant": "#ececec",
115+ "text": "#1a1a1a",
116+ "muted": "#6e6e6e",
117+ "accent": "#404040",
118+ "border": "#d2d2d2"
119+ }
120+ }
121+}
122+```
123+
124+**Dark palette:**
125+```json
126+{
127+ "appearance": {
128+ "dark_palette": {
129+ "background": "#0e0e0e",
130+ "surface": "#1a1a1a",
131+ "surface_variant": "#141414",
132+ "text": "#e4e4e4",
133+ "muted": "#848484",
134+ "accent": "#a8a8a8",
135+ "border": "#363636"
136+ }
137+ }
138+}
139+```
140+
141+## Video Acceleration
142+
143+| Key | Type | Default | Description |
144+|-----|------|---------|-------------|
145+| `video_acceleration.enable_vaapi` | bool | `true` | Enable VA-API hardware accel |
146+| `video_acceleration.auto_detect_gpu` | bool | `true` | Auto-detect GPU driver |
147+| `video_acceleration.vaapi_driver_name` | string | `""` | Driver name (auto-detected) |
148+| `video_acceleration.enable_all_drivers` | bool | `true` | Enable all VA-API drivers |
149+| `video_acceleration.legacy_vaapi` | bool | `false` | Legacy VA-API mode |
150+
151+## Codec Preferences
152+
153+| Key | Type | Default | Valid Values | Description |
154+|-----|------|---------|--------------|-------------|
155+| `codec_preferences.preferred_codecs` | string | `"av1,h264"` | Comma-separated | Codec priority order |
156+| `codec_preferences.force_av1` | bool | `false` | - | Force AV1 codec |
157+| `codec_preferences.block_vp9` | bool | `false` | - | Block VP9 codec |
158+| `codec_preferences.block_vp8` | bool | `true` | - | Block VP8 codec |
159+| `codec_preferences.av1_hardware_only` | bool | `false` | - | Disable AV1 software fallback |
160+| `codec_preferences.disable_vp9_hardware` | bool | `false` | - | Disable VP9 hardware accel |
161+| `codec_preferences.video_buffer_size_mb` | int | `16` | > 0 | Video buffer size in MB |
162+| `codec_preferences.queue_buffer_time_sec` | int | `10` | > 0 | Queue buffer time in seconds |
163+| `codec_preferences.custom_user_agent` | string | Chrome UA | any | Custom user agent string |
164+| `codec_preferences.av1_max_resolution` | string | `"1080p"` | `720p`, `1080p`, `1440p`, `4k`, `unlimited` | Max AV1 resolution |
165+| `codec_preferences.disable_twitch_codec_control` | bool | `true` | - | Disable codec control on Twitch |
166+
167+## Debug Options
168+
169+| Key | Type | Default | Description |
170+|-----|------|---------|-------------|
171+| `debug.enable_webkit_debug` | bool | `false` | Enable WebKit debug logs |
172+| `debug.webkit_debug_categories` | string | `"Network:preconnectTo,ContentFilters"` | Debug categories |
173+| `debug.enable_filtering_debug` | bool | `false` | Content filter debug |
174+| `debug.enable_webview_debug` | bool | `false` | WebView state debug |
175+| `debug.log_webkit_crashes` | bool | `true` | Log WebKit crashes |
176+| `debug.enable_script_debug` | bool | `false` | Script injection debug |
177+| `debug.enable_general_debug` | bool | `false` | General debug mode |
178+| `debug.enable_workspace_debug` | bool | `false` | Workspace navigation debug |
179+| `debug.enable_focus_debug` | bool | `false` | Focus state debug |
180+| `debug.enable_css_debug` | bool | `false` | CSS reconciler debug |
181+| `debug.enable_focus_metrics` | bool | `false` | Focus metrics tracking |
182+| `debug.enable_pane_close_debug` | bool | `false` | Pane close debug |
183+
184+## Rendering & Zoom
185+
186+| Key | Type | Default | Valid Values | Description |
187+|-----|------|---------|--------------|-------------|
188+| `rendering_mode` | string | `"gpu"` | `auto`, `gpu`, `cpu` | Rendering mode |
189+| `use_dom_zoom` | bool | `false` | - | Use DOM-based zoom |
190+| `default_zoom` | float | `1.2` | > 0 | Default zoom level (120%) |
191+
192+## Workspace Configuration
193+
194+| Key | Type | Default | Description |
195+|-----|------|---------|-------------|
196+| `workspace.enable_zellij_controls` | bool | `true` | Enable Zellij-style keybindings |
197+
198+### Pane Mode
199+
200+| Key | Type | Default | Description |
201+|-----|------|---------|-------------|
202+| `workspace.pane_mode.activation_shortcut` | string | `"ctrl+p"` | Pane mode activation key |
203+| `workspace.pane_mode.timeout_ms` | int | `3000` | Pane mode timeout (ms) |
204+| `workspace.pane_mode.action_bindings` | map | See below | Pane mode key bindings |
205+
206+**Default pane mode bindings:**
207+```json
208+{
209+ "workspace": {
210+ "pane_mode": {
211+ "action_bindings": {
212+ "arrowright": "split-right",
213+ "arrowleft": "split-left",
214+ "arrowup": "split-up",
215+ "arrowdown": "split-down",
216+ "r": "split-right",
217+ "l": "split-left",
218+ "u": "split-up",
219+ "d": "split-down",
220+ "x": "close-pane",
221+ "enter": "confirm",
222+ "escape": "cancel"
223+ }
224+ }
225+ }
226+}
227+```
228+
229+### Tab Shortcuts
230+
231+| Key | Type | Default | Description |
232+|-----|------|---------|-------------|
233+| `workspace.tabs.new_tab` | string | `"ctrl+t"` | New tab shortcut |
234+| `workspace.tabs.close_tab` | string | `"ctrl+w"` | Close tab shortcut |
235+| `workspace.tabs.next_tab` | string | `"ctrl+tab"` | Next tab shortcut |
236+| `workspace.tabs.previous_tab` | string | `"ctrl+shift+tab"` | Previous tab shortcut |
237+
238+### Popup Behavior
239+
240+| Key | Type | Default | Valid Values | Description |
241+|-----|------|---------|--------------|-------------|
242+| `workspace.popups.behavior` | string | `"split"` | `split`, `stacked`, `tabbed`, `windowed` | Popup opening mode |
243+| `workspace.popups.placement` | string | `"right"` | `right`, `left`, `top`, `bottom` | Split direction |
244+| `workspace.popups.open_in_new_pane` | bool | `true` | - | Open popups in workspace |
245+| `workspace.popups.follow_pane_context` | bool | `true` | - | Follow parent pane context |
246+| `workspace.popups.blank_target_behavior` | string | `"pane"` | `pane`, `tab` | `_blank` target handling |
247+| `workspace.popups.enable_smart_detection` | bool | `true` | - | Use WindowProperties for detection |
248+| `workspace.popups.oauth_auto_close` | bool | `true` | - | Auto-close OAuth popups |
249+
250+### Workspace Styling
251+
252+| Key | Type | Default | Description |
253+|-----|------|---------|-------------|
254+| `workspace.styling.border_width` | int | `2` | Border width in pixels |
255+| `workspace.styling.border_color` | string | `"@theme_selected_bg_color"` | Border color (CSS or theme var) |
256+| `workspace.styling.pane_mode_border_color` | string | `"#FFA500"` | Pane mode border color (orange) |
257+| `workspace.styling.transition_duration` | int | `120` | Transition duration (ms) |
258+| `workspace.styling.border_radius` | int | `0` | Border radius in pixels |
259+
260+## Content Filtering
261+
262+| Key | Type | Default | Description |
263+|-----|------|---------|-------------|
264+| `content_filtering_whitelist` | array | See below | Domains to skip ad blocking |
265+
266+**Default whitelist:**
267+```json
268+{
269+ "content_filtering_whitelist": [
270+ "twitch.tv",
271+ "passport.twitch.tv",
272+ "gql.twitch.tv"
273+ ]
274+}
275+```
276+
277+## Environment Variables
278+
279+All config values can be overridden via environment variables with the prefix `DUMB_BROWSER_`:
280+
281+```bash
282+# Database
283+DUMB_BROWSER_DATABASE_PATH=/custom/path/db.sqlite
284+
285+# Rendering
286+DUMBER_RENDERING_MODE=cpu
287+DUMBER_DEFAULT_ZOOM=1.5
288+
289+# Video/Codec
290+DUMBER_VIDEO_ACCELERATION_ENABLE=true
291+LIBVA_DRIVER_NAME=iHD
292+DUMBER_PREFERRED_CODECS=av1,vp9,h264
293+```
294+
295+**Note:** Some video/codec env vars use `DUMBER_*` prefix and match GStreamer/VA-API conventions.
@@ -0,0 +1,295 @@
1+# Configuration Reference
2+
3+**Primary format**: JSON
4+**Location**: `~/.config/dumber/config.json`
5+**Also supports**: YAML (`.yaml`) and TOML (`.toml`)
6+**JSON Schema**: `~/.config/dumber/config.schema.json` (auto-generated)
7+
8+## IDE Integration
9+
10+For autocompletion and validation in VS Code or other editors, add this to the top of your `config.json`:
11+
12+```json
13+{
14+ "$schema": "./config.schema.json",
15+ "default_zoom": 1.2,
16+ ...
17+}
18+```
19+
20+The schema is automatically generated when you first create a config file.
21+
22+## Database
23+
24+| Key | Type | Default | Description |
25+|-----|------|---------|-------------|
26+| `database.path` | string | `~/.local/state/dumber/dumber.sqlite` | Database file path |
27+
28+## History
29+
30+| Key | Type | Default | Valid Values | Description |
31+|-----|------|---------|--------------|-------------|
32+| `history.max_entries` | int | `10000` | > 0 | Maximum number of history entries |
33+| `history.retention_period_days` | int | `365` | > 0 | Days to keep history (1 year) |
34+| `history.cleanup_interval_days` | int | `1` | > 0 | How often to run cleanup |
35+
36+## Search Shortcuts
37+
38+| Key | Type | Default | Description |
39+|-----|------|---------|-------------|
40+| `search_shortcuts` | map | See defaults | Map of shortcut aliases to URLs |
41+
42+**Default shortcuts:**
43+```json
44+{
45+ "search_shortcuts": {
46+ "g": {
47+ "url": "https://google.com/search?q=%s",
48+ "description": "Google Search"
49+ },
50+ "gh": {
51+ "url": "https://github.com/search?q=%s",
52+ "description": "GitHub"
53+ },
54+ "yt": {
55+ "url": "https://youtube.com/results?search_query=%s",
56+ "description": "YouTube"
57+ }
58+ }
59+}
60+```
61+
62+## Dmenu / Launcher
63+
64+| Key | Type | Default | Description |
65+|-----|------|---------|-------------|
66+| `dmenu.max_history_items` | int | `20` | Max items shown in launcher |
67+| `dmenu.show_visit_count` | bool | `true` | Show visit counts |
68+| `dmenu.show_last_visited` | bool | `true` | Show last visited dates |
69+| `dmenu.history_prefix` | string | `"🕒"` | Prefix for history items |
70+| `dmenu.shortcut_prefix` | string | `"🔍"` | Prefix for shortcuts |
71+| `dmenu.url_prefix` | string | `"🌐"` | Prefix for URLs |
72+| `dmenu.date_format` | string | `"2006-01-02 15:04"` | Go time format string |
73+| `dmenu.sort_by_visit_count` | bool | `true` | Sort by popularity |
74+
75+## Logging
76+
77+| Key | Type | Default | Valid Values | Description |
78+|-----|------|---------|--------------|-------------|
79+| `logging.level` | string | `"info"` | `debug`, `info`, `warn`, `error` | Log level |
80+| `logging.format` | string | `"text"` | `text`, `json` | Log format |
81+| `logging.filename` | string | `""` | any | Empty = stdout |
82+| `logging.max_size` | int | `100` | > 0 | Max log size in MB |
83+| `logging.max_backups` | int | `3` | >= 0 | Number of log backups |
84+| `logging.max_age` | int | `7` | >= 0 | Days to keep logs |
85+| `logging.compress` | bool | `true` | - | Compress old logs |
86+| `logging.log_dir` | string | `~/.local/state/dumber/logs/` | any | Log directory |
87+| `logging.enable_file_log` | bool | `true` | - | Enable file logging |
88+| `logging.capture_stdout` | bool | `false` | - | Capture stdout to log |
89+| `logging.capture_stderr` | bool | `false` | - | Capture stderr to log |
90+| `logging.capture_c_output` | bool | `false` | - | Capture C/CGO output |
91+| `logging.capture_console` | bool | `false` | - | Capture browser console |
92+| `logging.debug_file` | string | `"debug.log"` | any | Debug log filename |
93+| `logging.verbose_webkit` | bool | `false` | - | Verbose WebKit logs |
94+
95+## Appearance
96+
97+| Key | Type | Default | Description |
98+|-----|------|---------|-------------|
99+| `appearance.sans_font` | string | `"Fira Sans"` | Sans-serif font |
100+| `appearance.serif_font` | string | `"Fira Sans"` | Serif font |
101+| `appearance.monospace_font` | string | `"Fira Code"` | Monospace font |
102+| `appearance.default_font_size` | int | `16` | Font size in points |
103+| `appearance.color_scheme` | string | `"default"` | `prefer-dark`, `prefer-light`, `default` |
104+
105+### Color Palettes
106+
107+**Light palette:**
108+```json
109+{
110+ "appearance": {
111+ "light_palette": {
112+ "background": "#f8f8f8",
113+ "surface": "#f2f2f2",
114+ "surface_variant": "#ececec",
115+ "text": "#1a1a1a",
116+ "muted": "#6e6e6e",
117+ "accent": "#404040",
118+ "border": "#d2d2d2"
119+ }
120+ }
121+}
122+```
123+
124+**Dark palette:**
125+```json
126+{
127+ "appearance": {
128+ "dark_palette": {
129+ "background": "#0e0e0e",
130+ "surface": "#1a1a1a",
131+ "surface_variant": "#141414",
132+ "text": "#e4e4e4",
133+ "muted": "#848484",
134+ "accent": "#a8a8a8",
135+ "border": "#363636"
136+ }
137+ }
138+}
139+```
140+
141+## Video Acceleration
142+
143+| Key | Type | Default | Description |
144+|-----|------|---------|-------------|
145+| `video_acceleration.enable_vaapi` | bool | `true` | Enable VA-API hardware accel |
146+| `video_acceleration.auto_detect_gpu` | bool | `true` | Auto-detect GPU driver |
147+| `video_acceleration.vaapi_driver_name` | string | `""` | Driver name (auto-detected) |
148+| `video_acceleration.enable_all_drivers` | bool | `true` | Enable all VA-API drivers |
149+| `video_acceleration.legacy_vaapi` | bool | `false` | Legacy VA-API mode |
150+
151+## Codec Preferences
152+
153+| Key | Type | Default | Valid Values | Description |
154+|-----|------|---------|--------------|-------------|
155+| `codec_preferences.preferred_codecs` | string | `"av1,h264"` | Comma-separated | Codec priority order |
156+| `codec_preferences.force_av1` | bool | `false` | - | Force AV1 codec |
157+| `codec_preferences.block_vp9` | bool | `false` | - | Block VP9 codec |
158+| `codec_preferences.block_vp8` | bool | `true` | - | Block VP8 codec |
159+| `codec_preferences.av1_hardware_only` | bool | `false` | - | Disable AV1 software fallback |
160+| `codec_preferences.disable_vp9_hardware` | bool | `false` | - | Disable VP9 hardware accel |
161+| `codec_preferences.video_buffer_size_mb` | int | `16` | > 0 | Video buffer size in MB |
162+| `codec_preferences.queue_buffer_time_sec` | int | `10` | > 0 | Queue buffer time in seconds |
163+| `codec_preferences.custom_user_agent` | string | Chrome UA | any | Custom user agent string |
164+| `codec_preferences.av1_max_resolution` | string | `"1080p"` | `720p`, `1080p`, `1440p`, `4k`, `unlimited` | Max AV1 resolution |
165+| `codec_preferences.disable_twitch_codec_control` | bool | `true` | - | Disable codec control on Twitch |
166+
167+## Debug Options
168+
169+| Key | Type | Default | Description |
170+|-----|------|---------|-------------|
171+| `debug.enable_webkit_debug` | bool | `false` | Enable WebKit debug logs |
172+| `debug.webkit_debug_categories` | string | `"Network:preconnectTo,ContentFilters"` | Debug categories |
173+| `debug.enable_filtering_debug` | bool | `false` | Content filter debug |
174+| `debug.enable_webview_debug` | bool | `false` | WebView state debug |
175+| `debug.log_webkit_crashes` | bool | `true` | Log WebKit crashes |
176+| `debug.enable_script_debug` | bool | `false` | Script injection debug |
177+| `debug.enable_general_debug` | bool | `false` | General debug mode |
178+| `debug.enable_workspace_debug` | bool | `false` | Workspace navigation debug |
179+| `debug.enable_focus_debug` | bool | `false` | Focus state debug |
180+| `debug.enable_css_debug` | bool | `false` | CSS reconciler debug |
181+| `debug.enable_focus_metrics` | bool | `false` | Focus metrics tracking |
182+| `debug.enable_pane_close_debug` | bool | `false` | Pane close debug |
183+
184+## Rendering & Zoom
185+
186+| Key | Type | Default | Valid Values | Description |
187+|-----|------|---------|--------------|-------------|
188+| `rendering_mode` | string | `"gpu"` | `auto`, `gpu`, `cpu` | Rendering mode |
189+| `use_dom_zoom` | bool | `false` | - | Use DOM-based zoom |
190+| `default_zoom` | float | `1.2` | > 0 | Default zoom level (120%) |
191+
192+## Workspace Configuration
193+
194+| Key | Type | Default | Description |
195+|-----|------|---------|-------------|
196+| `workspace.enable_zellij_controls` | bool | `true` | Enable Zellij-style keybindings |
197+
198+### Pane Mode
199+
200+| Key | Type | Default | Description |
201+|-----|------|---------|-------------|
202+| `workspace.pane_mode.activation_shortcut` | string | `"ctrl+p"` | Pane mode activation key |
203+| `workspace.pane_mode.timeout_ms` | int | `3000` | Pane mode timeout (ms) |
204+| `workspace.pane_mode.action_bindings` | map | See below | Pane mode key bindings |
205+
206+**Default pane mode bindings:**
207+```json
208+{
209+ "workspace": {
210+ "pane_mode": {
211+ "action_bindings": {
212+ "arrowright": "split-right",
213+ "arrowleft": "split-left",
214+ "arrowup": "split-up",
215+ "arrowdown": "split-down",
216+ "r": "split-right",
217+ "l": "split-left",
218+ "u": "split-up",
219+ "d": "split-down",
220+ "x": "close-pane",
221+ "enter": "confirm",
222+ "escape": "cancel"
223+ }
224+ }
225+ }
226+}
227+```
228+
229+### Tab Shortcuts
230+
231+| Key | Type | Default | Description |
232+|-----|------|---------|-------------|
233+| `workspace.tabs.new_tab` | string | `"ctrl+t"` | New tab shortcut |
234+| `workspace.tabs.close_tab` | string | `"ctrl+w"` | Close tab shortcut |
235+| `workspace.tabs.next_tab` | string | `"ctrl+tab"` | Next tab shortcut |
236+| `workspace.tabs.previous_tab` | string | `"ctrl+shift+tab"` | Previous tab shortcut |
237+
238+### Popup Behavior
239+
240+| Key | Type | Default | Valid Values | Description |
241+|-----|------|---------|--------------|-------------|
242+| `workspace.popups.behavior` | string | `"split"` | `split`, `stacked`, `tabbed`, `windowed` | Popup opening mode |
243+| `workspace.popups.placement` | string | `"right"` | `right`, `left`, `top`, `bottom` | Split direction |
244+| `workspace.popups.open_in_new_pane` | bool | `true` | - | Open popups in workspace |
245+| `workspace.popups.follow_pane_context` | bool | `true` | - | Follow parent pane context |
246+| `workspace.popups.blank_target_behavior` | string | `"pane"` | `pane`, `tab` | `_blank` target handling |
247+| `workspace.popups.enable_smart_detection` | bool | `true` | - | Use WindowProperties for detection |
248+| `workspace.popups.oauth_auto_close` | bool | `true` | - | Auto-close OAuth popups |
249+
250+### Workspace Styling
251+
252+| Key | Type | Default | Description |
253+|-----|------|---------|-------------|
254+| `workspace.styling.border_width` | int | `2` | Border width in pixels |
255+| `workspace.styling.border_color` | string | `"@theme_selected_bg_color"` | Border color (CSS or theme var) |
256+| `workspace.styling.pane_mode_border_color` | string | `"#FFA500"` | Pane mode border color (orange) |
257+| `workspace.styling.transition_duration` | int | `120` | Transition duration (ms) |
258+| `workspace.styling.border_radius` | int | `0` | Border radius in pixels |
259+
260+## Content Filtering
261+
262+| Key | Type | Default | Description |
263+|-----|------|---------|-------------|
264+| `content_filtering_whitelist` | array | See below | Domains to skip ad blocking |
265+
266+**Default whitelist:**
267+```json
268+{
269+ "content_filtering_whitelist": [
270+ "twitch.tv",
271+ "passport.twitch.tv",
272+ "gql.twitch.tv"
273+ ]
274+}
275+```
276+
277+## Environment Variables
278+
279+All config values can be overridden via environment variables with the prefix `DUMB_BROWSER_`:
280+
281+```bash
282+# Database
283+DUMB_BROWSER_DATABASE_PATH=/custom/path/db.sqlite
284+
285+# Rendering
286+DUMBER_RENDERING_MODE=cpu
287+DUMBER_DEFAULT_ZOOM=1.5
288+
289+# Video/Codec
290+DUMBER_VIDEO_ACCELERATION_ENABLE=true
291+LIBVA_DRIVER_NAME=iHD
292+DUMBER_PREFERRED_CODECS=av1,vp9,h264
293+```
294+
295+**Note:** Some video/codec env vars use `DUMBER_*` prefix and match GStreamer/VA-API conventions.

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