Conversation
There was a problem hiding this comment.
Pull request overview
This PR bumps Bor Mail to v0.5.0 and introduces several UX/features around message viewing, threading, compose ergonomics, and mu parsing—along with corresponding documentation and test updates.
Changes:
- Add “view in browser” (V), richer full headers (Ctrl+R), and safer/clickable URL rendering in message view.
- Improve mu parsing & behaviors (Reply-To/List-Post handling, thread expansion, msgid normalization, MIME part counting) and add search query history navigation/persistence.
- Enhance compose editor/file workflow (insert-file prompt, Ctrl+T transpose, Ctrl+Backspace/Ctrl+W word delete) plus new tests and docs; bump version to 0.5.0.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_mu.py | Updates address examples and adds coverage for Reply-To/List-Post parsing via mu JSON + raw email view(). |
| tests/test_compose.py | Adds tests for reply destination precedence and compose editor helper behaviors (insert-file reading, word delete, transpose). |
| tests/test_app_integration.py | Extends mock message shape for new reply/list fields. |
| pyproject.toml | Version bump to 0.5.0. |
| documentation/keyboard_shortcuts.md | Documents new V shortcut. |
| documentation/configuration.md | Documents html.browser_tmp_dir and updates example config. |
| bor/tabs/message_index.py | Implements persisted search history with Up/Down navigation; resets search input via helper. |
| bor/tabs/message.py | Rich full headers, clickable URL markup, msgid normalization for navigation, and “view in browser” action. |
| bor/tabs/compose.py | Adds editor shortcuts (Ctrl+T/Ctrl+Backspace), file insert flow, and reply-to-list logic (List-Post precedence). |
| bor/tabs/attachments.py | Refines kitty image sizing to prefer natural pixel size and scale-to-fit with TIOCGWINSZ fallback. |
| bor/mu.py | Adds List-Post support, improves Reply-To parsing, fixes threading depth and thread discovery, normalizes msgid in view(), adjusts multipart part counting, captures extra headers. |
| bor/config.py | Adds HtmlConfig.browser_tmp_dir. |
| bor/init.py | Version bump to 0.5.0. |
| CHANGELOG.md | Documents v0.5.0 features and fixes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # From | ||
| lines.append(f"[bold]From:[/bold] {self.message.from_addr}") | ||
|
|
||
| # Show effective reply address when it differs from From | ||
| if self.message.list_post_addr and self.message.list_post_addr.email: | ||
| # Mailing list: show the list address (this is where 'r' will send) | ||
| if self.message.list_post_addr.email != self.message.from_addr.email: | ||
| lines.append(f"[bold]List:[/bold] {self.message.list_post_addr.email}") | ||
| elif (self.message.reply_to_addr and | ||
| self.message.reply_to_addr.email != self.message.from_addr.email): | ||
| lines.append(f"[bold]Reply-To:[/bold] {self.message.reply_to_addr}") | ||
|
|
||
| # To | ||
| to_list = ", ".join(str(addr) for addr in self.message.to_addrs) | ||
| lines.append(f"[bold]To:[/bold] {to_list}") |
There was a problem hiding this comment.
MessageHeader renders with Rich markup (it embeds [bold]...[/bold] tags). User-controlled values like From/To names should be escaped (e.g., via rich_escape(str(...))) to avoid markup injection or MarkupError when display names contain [/] or similar markup characters.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
| if self.message.msgid: | ||
| lines.append(f"[bold]Msg-ID:[/bold] {self.message.msgid}") | ||
| lines.append(f"[bold]Message-ID:[/bold] {rich_escape(self.message.msgid)}") | ||
| if self.message.in_reply_to: | ||
| lines.append(f"[bold]Reply-To:[/bold] {self.message.in_reply_to}") | ||
| lines.append(f"[bold]In-Reply-To:[/bold] {rich_escape(self.message.in_reply_to)}") | ||
| if self.message.references: | ||
| n = len(self.message.references) | ||
| sample = " ".join(self.message.references[-2:]) | ||
| suffix = f" (… {n} total)" if n > 2 else "" | ||
| lines.append(f"[bold]References:[/bold] {rich_escape(sample)}{suffix}") |
There was a problem hiding this comment.
In the full-header block you correctly rich_escape several fields, but the earlier basic header fields (From/To/CC/Subject) are still interpolated unescaped into Rich markup strings. To avoid markup injection / MarkupError for subjects or display names containing [ etc., consider escaping all user-controlled header values consistently.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
| try: | ||
| config = get_config() | ||
| tmp_dir_str = config.html.browser_tmp_dir | ||
| tmp_dir = Path(tmp_dir_str).expanduser() if tmp_dir_str else None | ||
| if tmp_dir is not None: | ||
| tmp_dir.mkdir(parents=True, exist_ok=True) | ||
| tmp = tempfile.NamedTemporaryFile( | ||
| suffix=".html", prefix="bor_msg_", delete=False, | ||
| mode="w", encoding="utf-8", dir=tmp_dir, | ||
| ) | ||
| tmp.write(full_html) | ||
| tmp.close() | ||
| webbrowser.open(Path(tmp.name).as_uri()) |
There was a problem hiding this comment.
action_view_in_browser creates a delete=False temp HTML file and never cleans it up, so repeated use will leave many bor_msg_*.html files behind (especially if html.browser_tmp_dir is set to a persistent directory). Consider a cleanup strategy (e.g., reuse a deterministic filename per message/session, or delete older files on startup).
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…markup injection Co-authored-by: slosar <1197186+slosar@users.noreply.github.com>
Co-authored-by: slosar <1197186+slosar@users.noreply.github.com>
Escape all user-controlled header values in message view to prevent Rich markup injection
…umulation Co-authored-by: slosar <1197186+slosar@users.noreply.github.com>
Escape Rich markup in MessageHeader user-controlled values
Fix temp HTML file accumulation in action_view_in_browser
A slew of bug fixes and features.