- Add blockId field to ChatBlock (12-char MD5 hash of counter+name)
- Bookmarks now use blockId instead of volatile list index
- Plumb URLs use blockId: ollie://session/agent#abc123def456
- Add indexForBlockId() to look up current index from stable ID
- Action buttons always visible (no hover flicker)
- All ToolButtons now use theme.fontSize-based sizing
- Height, width, margins, and spacing scale with font
- Removed all hardcoded pixel values from bookmark UI
- Add bookmark button (📌) on chat block hover
- Bookmarks section in left panel (SessionTree) with grouped view
- Non-persistent GUI-only state using ListModel
- Click bookmark to scroll to that block in chat
- Bookmark format: sessionName/agentName with block content preview
- Add activeSessionName/activeAgentName C++ getters for display
B3 (right-click) on a word now plumbs it directly without visually
selecting it first. Double-click word selection includes underscores,
so snake_case selects the whole identifier.
MouseArea's onDoubleClicked doesn't fire when placed on a TextEdit with
selectByMouse:true — the TextEdit's internal mouse handling consumes the
events. TapHandler coexists with TextEdit's mouse handling and reliably
receives double-tap events.
Double-click on a bracket or quote delimiter now selects the content
between the matching pair. Quotes use parity to decide opener/closer
direction. Falls back to word selection when no delimiter is adjacent.
Works in chat blocks (mainTextEdit, textComponent) and prompt textarea.
Extract selectBracketPair, selectWordAt, and helpers into TextSelection.js
and import it in both ChatBlockDelegate.qml and ChatPane.qml. Prompt
textarea now has the same double-click behavior as chat blocks:
delimiter adjacent to cursor -> select pair content, else -> word select.
Quotes use parity to decide direction and scan document-wide, so
multi-line content between the pair is selected in full.
Quote matching now scans the whole block text and computes opener/closer
parity document-wide, so content between a '' "" `` pair that spans
multiple lines is selected in full. The adjacent quote (left or right of
the cursor) sets the direction; the matching end quote is found by
scanning that way.
The overlay MouseArea swallows the B1 double-click, so returning
mouse.accepted=false did not make the TextEdit perform its native
word select — a non-delimiter double-click selected nothing. Now the
handler selects the word directly via selectWordAt when no bracket or
quote pair is under the cursor, so double-click is deterministic:
delimiter -> pair select, otherwise -> word select.
The Item wrapper added in 1cfa424 set height: mainTextEdit.height while
the TextEdit used anchors.fill: parent, so the TextEdit height depended
on the Item height and vice versa. The resulting binding loop collapsed
the block layout into visual garbage. Size the TextEdit from
width: parent.width and let its content height drive the Item.
selectBracketPair now also handles '' "" `` quote pairs. Since a
quote char opens and closes with the same glyph, a quote to the right
of the cursor scans forward for its match, and a quote to the left
scans backward.
Double-clicking next to a bracket (()[]{}) selects the text between
the matching pair, including nested pairs. Falls through to the
default word-select when no bracket is adjacent.
Also: B3-click on word now highlights it before plumbing.
Handle events in onPressed instead of onClicked so they work
with editable text. Remove propagateComposedEvents since we
want to intercept middle/right clicks completely.
RMB on text without selection now expands to the word at cursor using
acme's isfilec character set: alphanumeric + . - + / : @
This matches acme behavior for clicking on file paths like foo.go:42
Plumb messages now include the current session's cwd as wdir.
Added sessionCwd() helper to ChatPane and ChatBlockDelegate.
Updated plumber.plumb() to accept optional wdir parameter.
B3 (right-click) now only plumbs selection when available — no fallback
context menu. Mouse chording (B1+B2 cut, B1+B3 paste) still works.
Removed contextMenuComponent and promptContextMenu entirely.
- Remove chatPane property from delegate (was shadowing id, causing binding loop)
- Remove contentArea MouseArea from inside Column (invalid anchor)
- Simplify hovered property to use only headerArea
- Edit button now copies to clipboard instead of trying to access chatPane