|
|
@@ -45,35 +45,32 @@ This is the persistent context file for Claude Code. Keep it concise and useful.
|
|
|
- Config defaults embedded via `//go:embed config.toml`
|
|
|
|
|
|
## Our Changes (vs upstream)
|
|
|
-- **Image viewer**: `image_viewer` config (default: `mpv`) — opens image attachments in configured viewer with TUI suspend/resume instead of browser
|
|
|
-- **mpv geometry**: `viewerArgs()` auto-detects terminal geometry via `xdotool` on X11, passes `--geometry`, `--force-window`, `--loop-file=inf` to mpv
|
|
|
-- **Save image**: `save_image` keybind (`S`) — saves image attachment to `image_save_dir`
|
|
|
-- **Attachment URL fix**: split `builder.Write(filename+"\n"+url)` into proper `NewLine()` + `.Url()` style
|
|
|
-- **Supported image types**: jpeg, png, webp, gif (via `supportedImageTypes` map)
|
|
|
-- **ShortHelp**: `o` (open) now shows in bottom tooltip bar when message has attachments/URLs
|
|
|
-- **Help keybind**: changed from `ctrl+.` to `?` — `ctrl+.` not reliably handled by terminals
|
|
|
-- **Edit config**: `E` keybind (only active in help overlay) opens config in `$EDITOR`/vim via `app.Suspend()`
|
|
|
-- **Editor default**: falls back to `vim` when `editor = "default"` and `$EDITOR` is unset
|
|
|
-- **Guild state persistence**: expanded/collapsed guild state saved to `~/.cache/discordo/state.json`, restored on launch via `guildstate.go`
|
|
|
-- **Focus on channel select**: AutoFocus now targets messages list instead of message input when selecting a channel
|
|
|
-- **Security hardening**: path traversal prevention (`filepath.Base`), HTTPS-only downloads, bounded downloads (100MB), `exec.LookPath` viewer validation, atomic guild state writes, restrictive file permissions (0700/0600), env token warning
|
|
|
-- **Editor security**: replaced `sh -c` with direct `exec.Command` + `strings.Fields` (merged editor files into single `editor.go`, no build tags)
|
|
|
-- **God file split**: extracted `url_extractor.go`, `embed_renderer.go`, `attachment_handler.go` from `messages_list.go`
|
|
|
-- **Image viewer args**: `image_viewer_args` config field — explicit viewer args, bypasses xdotool auto-detection (Wayland-friendly)
|
|
|
-- **Brotli body leak fix**: transport.go properly closes underlying HTTP body
|
|
|
-- **Cache panic fix**: `cache.Get()` uses comma-ok assertion instead of bare type assert
|
|
|
-- **Reactions display**: renders message reactions below content (`drawReactions`), bold for own reactions, real-time updates via gateway events
|
|
|
-- **Search picker**: `/` keybind opens fuzzy search over current channel messages (`search_picker.go`)
|
|
|
-- **Thread indicators**: shows "Thread: name" on messages with threads, `t` keybind navigates to thread
|
|
|
-- **User info popup**: `w` keybind shows author info (username, join date, roles, color) in overlay (`user_info.go`)
|
|
|
-- **Command mode**: `:` keybind opens vim-style command input, supports `:q`/`:quit`/`:logout` (`command_input.go`)
|
|
|
-- **LRU cache cap**: `itemByID` map evicts stale entries when exceeding 500 items (COMP #17)
|
|
|
-- **Replace open-golang**: replaced `skratchdot/open-golang` with stdlib `os/exec` + `runtime.GOOS` (TECH #1)
|
|
|
-- **ESC focus cycling**: ESC cycles focus: input → messages → guilds → input (full loop); left/right arrows navigate between guilds and messages
|
|
|
-- **Channel state persistence**: category/forum expand/collapse state saved to `state.json` alongside guild state (`ExpandedChannels` map)
|
|
|
-- **MarkRead fix**: uses newest fetched message ID instead of potentially stale `channel.LastMessageID`
|
|
|
-- **Reply quote italic**: reply lines rendered with dim + italic style
|
|
|
-- **Picker browse mode**: ESC in overlay pickers (channels, search, attachments) enters browse mode (j/k/g/G navigate, `i` returns to input, second ESC closes) via shared `pickerBrowseHandleKey` helper
|
|
|
+- **Image viewer**: `image_viewer` / `image_viewer_args` config, `save_image` keybind (`S`), mpv geometry auto-detection via `xdotool`, supported types: jpeg/png/webp/gif
|
|
|
+- **Attachments**: URL fix (proper `NewLine()` + `.Url()` style), `o` in ShortHelp when attachments/URLs present
|
|
|
+- **Help/Config**: `?` keybind (was `ctrl+.`), `E` edits config in `$EDITOR`/vim from help overlay
|
|
|
+- **State persistence**: guild + channel expand/collapse state in `~/.cache/discordo/state.json` (`guildstate.go`)
|
|
|
+- **Focus/Navigation**: AutoFocus targets messages list on channel select; ESC cycles input→messages→guilds→input; left/right arrows between panels
|
|
|
+- **Security hardening**: path traversal prevention, HTTPS-only downloads, bounded downloads (100MB), `exec.LookPath` validation, atomic writes, restrictive perms, direct `exec.Command` (no `sh -c`)
|
|
|
+- **Bug fixes**: Brotli body leak, cache type assertion panic, MarkRead uses newest fetched message ID
|
|
|
+- **Code structure**: extracted `url_extractor.go`, `embed_renderer.go`, `attachment_handler.go` from `messages_list.go`; replaced `open-golang` with stdlib
|
|
|
+- **Reactions display**: renders below content (`drawReactions`), bold for own, real-time gateway updates
|
|
|
+- **Search picker**: `/` opens fuzzy search over current channel messages (`search_picker.go`)
|
|
|
+- **Thread indicators**: "Thread: name" display, `t` navigates to thread
|
|
|
+- **User info popup**: `w` shows author info overlay (`user_info.go`)
|
|
|
+- **Command mode**: `:` opens vim-style input, supports `:q`/`:quit`/`:logout` (`command_input.go`)
|
|
|
+- **LRU cache cap**: `itemByID` evicts stale entries past 500 items
|
|
|
+- **Reply quote italic**: dim + italic style for reply lines
|
|
|
+- **Picker browse mode**: ESC in overlay pickers enters browse mode (j/k/g/G/i) via `pickerBrowseHandleKey`
|
|
|
+- **Link display compression**: `ui.LinkDisplayText()` shows human-friendly labels instead of raw URLs in chat and embeds (e.g., CDN filename, "Tenor GIF", "Substack - author")
|
|
|
+
|
|
|
+## Adding Link Display Rules
|
|
|
+To add a new site-specific URL label, edit `ui.LinkDisplayText()` in `internal/ui/util.go`:
|
|
|
+1. Add a host match (`host == "example.com"` or `strings.HasSuffix(host, ".example.com")`) after the existing site blocks
|
|
|
+2. Use `segments` (pre-split path segments) to extract meaningful parts (e.g., `segments[1]` for subreddit in `/r/{sub}`)
|
|
|
+3. Return a short label string (e.g., `"SiteName - " + segments[1]`)
|
|
|
+4. The raw URL is preserved as OSC 8 hyperlink metadata — only the visible text changes
|
|
|
+- Currently handled: Discord CDN (filename), Tenor (GIF), Substack (author), YouTube, X/Twitter, Reddit (subreddit), GitHub (owner/repo)
|
|
|
+- Fallback: `host + truncated path` (max 48 chars)
|
|
|
|
|
|
## Config Fields We Added
|
|
|
- `image_viewer` — external image viewer command (default: `"mpv"`, `"default"` = system opener)
|