Skip to content

Make chat content selectable and add Copy context menu#1

Merged
buggerman merged 1 commit intomainfrom
selectable-chat-text
Apr 24, 2026
Merged

Make chat content selectable and add Copy context menu#1
buggerman merged 1 commit intomainfrom
selectable-chat-text

Conversation

@buggerman
Copy link
Copy Markdown
Owner

Summary

  • Make every message kind selectable, not just privmsg/notice bodies — timestamps, sender nicks, actions, joins/parts/quits/nicks/kicks, topics, mode changes, and server numerics now all respond to drag-select and ⌘C.
  • Add a right-click context menu on each message row with Copy Message, Copy Text, and Copy Nickname.

Changes

  • Sources/BryggaCore/IRC/IRCFormatting.swift — new public stripControlCodes(_:) helper. Strips bold / italic / underline / strikethrough / reverse / reset / monospace / color (^K<fg>[,<bg>]) control bytes, preserving the surrounding text. Additive; no existing API changed.
  • Sources/Brygga/Views/ContentView.swift
    • import AppKit for NSPasteboard.
    • .textSelection(.enabled) hoisted to the LazyVStack inside MessageList and ServerMessageList so selection works across every row kind in every list (main chat, server console, detached window).
    • Redundant per-Text .textSelection modifiers in MessageRow removed.
    • MessageRow.rowBody gains a .contextMenu with the three Copy items and a private copy(_:) pasteboard helper plus a plainLogLine computed property. Copy Message emits [HH:mm] <nick> body for privmsg, [HH:mm] -nick- body for notice, and [HH:mm] * nick body for action / presence kinds.
  • Tests/IRCFormattingTests.swift — 5 new tests covering bold/italic/underline, color sequences with fg+bg, literal comma after ^K<digit> (ambiguous-separator case), reset + reverse + strikethrough, and plain-text identity.

Test plan

  • `swift build` — passes
  • `swift test` — 88 tests pass (was 83, +5 new)
  • `swiftformat --lint .` — clean
  • Manual (macOS 15 / Liquid Glass on 26):
    • Drag across a run of messages of mixed kinds; ⌘C; paste into TextEdit; confirm rows render as plain-text log lines.
    • Right-click any privmsg / notice / action / join row → verify Copy Message, Copy Text, Copy Nickname each place the expected string on the clipboard.
    • Click a URL in a message — link still opens (no regression from the selection modifier).
    • Repeat in the server console tab and in a detached channel window (⌘⇧D).

Risk / rollback

Low. Purely additive on the selection side; no protocol, persistence, or threading changes. Revert the commit if the context menu conflicts with link-tap behaviour on any macOS version we care about.

Known limitation addressed in a follow-up: SwiftUI's `.textSelection` only supports per-`Text` selection — drag-selection does not cross row boundaries. Proper mIRC-style multi-line copy lands in a follow-up PR that backs `MessageList` with an `NSViewRepresentable` wrapping `NSScrollView` + `NSTextView`.

Lift .textSelection(.enabled) to the LazyVStack containers in
MessageList and ServerMessageList so every message kind — privmsg,
notice, action, join/part/quit/nick/kick, topic, mode, and server
numerics — is selectable, not just privmsg/notice content.

Attach a .contextMenu to MessageRow with Copy Message, Copy Text, and
Copy Nickname items. Copy Message emits a plain-text log-style line
using the row's current timestamp format; Copy Text emits just the
message body with mIRC control codes stripped; Copy Nickname emits the
sender.

SwiftUI's .textSelection only supports per-Text selection, not
cross-row drag-selection. Proper mIRC-style multi-line copy requires an
NSTextView-backed buffer and lands in a follow-up.
@buggerman buggerman merged commit ec0a9d5 into main Apr 24, 2026
1 check passed
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.

1 participant