5.8 KiB
id, title, type, created_date, updated_date
| id | title | type | created_date | updated_date |
|---|---|---|---|---|
| doc-5 | Log Line Copy in Prod-Logs Extension | other | 2026-05-03 21:06 | 2026-05-04 06:55 |
Implementation Analysis: Log Line Copy in Prod-Logs Extension
Problem Summary
The /prod-logs extension (.pi/extensions/prod-logs/index.ts) displays log lines in a scrollable viewer but offers no way to copy lines. The user wants:
- Copy a single line (cursor line) and exit
- Select and copy multiple lines and exit
- Copied lines in ascending (chronological) order
Architecture Context
- Current component:
LogViewerclass — manages scroll offset, renders lines, handles keyboard input - Current UI return type:
ctx.ui.custom<void>— no value returned on close - Current key bindings: Escape/q (close), r (refresh), Up/k Down/j (scroll), PgUp/PgDn (page), Home/End (jump)
- Line ordering:
logLines.reverse()is called before display, so newest-first visually. Copied lines should be oldest-first (ascending). - No cursor concept exists — only a scroll offset
Route A: Cursor + Toggle Selection + setEditorText
Concept
Add a visual cursor line. Enter to copy single line. Space to toggle line selection (multi-select mode). y to copy all selected lines and exit. After exit, call ctx.ui.setEditorText() with the copied text.
Changes to LogViewer
- Add
cursorIndex: number(absolute line index intothis.lines) - Add
selectedIndices: Set<number>(absolute indices) - New key bindings:
Enter→ copy cursor line,done(line)Space→ toggle selection of cursor liney→ copy selected lines (or cursor line if none selected),done(text)
- Render changes:
>prefix on cursor line (styled accent color)●prefix on selected lines (styled success color)- Non-selected, non-cursor lines keep existing
prefix
- Help text update: add "y copy · Space select · Enter copy line"
Return value handling
const copiedText = await ctx.ui.custom<string | null>(...);
if (copiedText !== null) {
ctx.ui.setEditorText(copiedText);
}
Pros
- No external dependencies
setEditorTextis already available in pi's ExtensionAPI- Aligns with the "paste" use case (text in editor = ready to send or copy)
- Simple, contained change to one file
Cons
- Modifies editor content (replaces whatever the user had typed)
- Not a true "system clipboard" copy — the user can't paste outside pi without an extra step
- Toggle-based selection for multi-line is somewhat unusual UX (vs. range selection)
Route B: Visual Mode (Vim-style) + setEditorText
Concept
Vim-inspired visual mode: v enters linewise visual selection, j/k extend the range, y copies and exits. Enter still copies single line. Selection is always a contiguous range.
Changes to LogViewer
- Add
cursorIndex: number(absolute) - Add
visualMode: boolean+visualAnchor: number(start of visual selection) - New key bindings:
Enter→ copy cursor line,done(line)v→ enter visual mode (set anchor to cursor)- In visual mode:
j/kextend selection range y(in visual mode) → copy range [min(anchor,cursor)..max(anchor,cursor)],done(text)Escape→ exit visual mode
- Render changes:
- Selected range lines get
●prefix (styled) - Cursor line gets
>prefix
- Selected range lines get
- Help text: show visual mode help when active
Pros
- Familiar UX for vim users
- Contiguous range selection is intuitive
- Same
setEditorTextapproach — no external deps
Cons
- Slightly more complex state machine (normal mode vs. visual mode)
- Doesn't allow non-contiguous selection (but the user said "contiguous")
- Still modifies editor content
Route C: System Clipboard + Either Selection Model
Concept
Either selection model (A or B), but instead of setEditorText, write to the system clipboard. Requires a package like clipboardy.
Additional Changes
- Add
clipboardydependency (or usenode:child_processwithpbcopy/xclip) - On copy:
clipboardy.writeSync(text)or similar - No need to change return type — can stay
voidsince we don't pass text back
Pros
- True "copy" behavior — paste anywhere
- Doesn't touch editor content
- Works across applications
Cons
- External dependency (
clipboardy— native module, may have install issues) - Platform-specific behavior (macOS
pbcopy, Linuxxclip/wl-copy, Windows) - pi extensions run in the pi process; clipboard access may have security implications
- May not work in headless/server environments where pi runs
Recommendation: Route B (Visual Mode + setEditorText)
Rationale:
- No external dependencies —
setEditorTextis already available - Familiar UX — vim-style visual mode is intuitive for developers
- Contiguous selection — matches the user's "contiguous lines" description
- Simple implementation — contained change to one file, ~100 lines of code
- Immediate value — text in editor can be sent as a prompt or manually copied
Why not clipboard (Route C): The use case for /prod-logs is typically "I found an error line, I want to paste it into my next prompt to ask pi about it." setEditorText serves this perfectly. System clipboard adds complexity and platform fragility without proportional benefit for this specific use case.
Why not toggle selection (Route A): The user said "contiguous lines." Toggle-based selection allows non-contiguous selection, which they don't need. Visual mode is simpler to implement and more conventional.
Outstanding Question for User
How should the copied text be placed in the editor?
- Append to current editor content (preserves what's there)
- Replace current editor content (clean slate)
My leaning: Replace, because the user's intent is to paste a log line as a new prompt.