Skip to content

V0.5 - #2

Merged
slosar merged 20 commits into
mainfrom
v0.5
Mar 4, 2026
Merged

V0.5#2
slosar merged 20 commits into
mainfrom
v0.5

Conversation

@slosar

@slosar slosar commented Mar 4, 2026

Copy link
Copy Markdown
Owner

A slew of bug fixes and features.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread bor/tabs/message.py
Comment on lines 141 to 155
# 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}")

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

Comment thread bor/tabs/message.py
Comment on lines 185 to +193
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}")

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

Comment thread bor/tabs/compose.py
Comment thread bor/tabs/message.py Outdated
Comment on lines +907 to +919
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())

Copilot AI Mar 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

Comment thread bor/tabs/message.py Outdated

Copilot AI commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

@slosar I've opened a new pull request, #3, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

@slosar I've opened a new pull request, #4, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

@slosar I've opened a new pull request, #5, to work on those changes. Once the pull request is ready, I'll request review from you.

slosar and others added 8 commits March 4, 2026 14:57
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
@slosar
slosar merged commit 88bc9c0 into main Mar 4, 2026
2 checks passed
@slosar
slosar deleted the v0.5 branch March 4, 2026 20:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants