Repository navigation
feat: interactive table of contents, clickable links, open in $EDITOR - #24
Merged
Merged
Conversation
Press o (toc_focus, rebindable) to move keyboard focus into the sidebar, opening it if it was closed. j/k/arrows move, g/G first/last, Ctrl+d/Ctrl+u/PageUp/PageDown page, Enter jumps to the heading through the back/forward history, h/l fold and unfold subheadings in the sidebar, / filters headings as you type, Esc/q/o return to the document. With mouse capture on, a click on a sidebar row jumps to that heading and the wheel over the sidebar scrolls it instead of the document. The sidebar now scrolls to keep the current heading in view, and a heading on the viewport's second row (where n/N and jumps put it) counts as current. The interaction state lives in a small TocState model with unit tests.
With mouse capture on, a press and release on the same cell, with no drag and not part of a double click, on a link follows it through the same open_link path as link-hint mode: web and mail links open in the browser, .md files and #anchors open in ink and are recorded in back/forward history. The link is found from the link_url of the span under the pointer, measured in display columns. Dragging still selects and copies, double and triple clicks still select a word or line, and with --no-mouse the terminal keeps handling clicks itself.
e (edit, rebindable) suspends the TUI through the same restore and setup functions used at exit and startup, runs $VISUAL, then $EDITOR, then vi (notepad on Windows) on the current file, and reloads it afterwards, keeping the reader on the same heading. The editor command is split shell-style and never run through a shell. The line comes from the heading the viewport is in (layout records source positions for headings only), mapped past stripped frontmatter, and is only passed when the file still has the loaded text at that line: +N for vi/vim/nvim/nano/emacs/emacsclient/kak/micro, --goto file:N for code/codium/cursor, file:N for subl/zed/hx, nothing for unknown editors. A path starting with - or + gets ./ so no editor reads it as an option or command. Ctrl-C belongs to the editor while it runs. stdin and URL documents, an editor that cannot start or that exits non-zero, all end with the TUI restored and a message in the status bar.
Enter was documented as following the first visible link but only looked at the top six lines of the viewport, and only for .md and #anchor links. It now takes the first followable link in the whole viewport, web and mail links included (through the same open_link path as f), and says so when there is none.
…wser The file browser read events straight from crossterm, so a background colour reply that missed the startup query could arrive as key presses there. It now enters the TUI through the reader's enter_tui, runs the same discard_late_reply filter, and reads events through the reader's queue (input::next_event).
When the terminal goes away (a closed SSH session, a killed tmux), crossterm's event reader loops forever on the dead tty and never returns to the event loop, so the SIGHUP that came with the hangup was never acted on: ink kept running and burned a core. A watchdog thread now restores what it can and exits with 128+signal if a termination signal stays pending for a second. It stands down while an external editor owns the terminal, so ink never exits underneath it.
Merged
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
omoves focus into the sidebar (opening it if needed). Move withj/k, jump with Enter, fold subtrees withh/l, filter headings with/. Clicking a row jumps to it, and the wheel over the sidebar scrolls the sidebar. Jumps are recorded in history.$EDITOR.esuspends the reader, opens the file in$VISUALor$EDITORat the line of the current section, then reloads. Editor commands with arguments are split without a shell, and a path starting with-is prefixed with./.Known limits
Testing
Unit tests for the TOC model and the editor argv mapping, and pty tests for TOC focus/filter/jump, link click vs drag, and the editor round trip. fmt, clippy and the full suite pass locally. Windows is compile-checked by this PR's CI only.
🤖 Generated with Claude Code
https://claude.ai/code/session_01UVcvmQrSXd2eyt32g4ko19