How to Use Visual Mode (v/V) to Create Range Comments in tuicr
Press v or V in tuicr's diff view to enter visual mode, navigate to select the desired lines, then press c to attach a single comment to the entire highlighted range.
tuicr is a terminal-based code review tool that enables attaching comments to specific line ranges using a Vim-inspired visual selection workflow. The repository agavra/tuicr implements this through a dedicated Visual Select mode, allowing reviewers to highlight contiguous diff blocks before commenting. Mastering how to create range comments in tuicr streamlines the review process by letting you address multi-line logic or context-dependent issues in a single annotation.
Entering Visual Mode
To begin creating a range comment, you must first activate visual mode using either character-wise or line-wise selection.
Character-wise Selection with v
Press v to enter character-wise visual mode. This key maps to Action::EnterVisualMode in src/input/keybindings.rs【🔗 src/input/keybindings.rs#L220-L222】, initializing a selection at the current cursor position.
Line-wise Selection with V
Press V (shift+v) for line-wise visual mode. While this triggers the same EnterVisualMode action, it treats the entire current line as the initial selection unit, making it ideal for selecting complete code blocks.
Expanding the Selection
Once in visual mode, navigation keys move the cursor while simultaneously updating the active VisualSelection. The selection state is stored in App.visual_selection: Option<VisualSelection> as defined in src/app/mod.rs【🔗 src/app/mod.rs#L206-L218】.
Valid navigation keys include:
h,j,k,lor arrow keys for single-step movementCtrl-dandCtrl-ufor half-page jumps- Page up/down for larger movements
As you navigate, the head of the VisualSelection follows the cursor while the anchor remains fixed, effectively growing or shrinking the selected range. This update logic resides in src/app/visual.rs::move_cursor, which is invoked from the main event loop.
Creating the Range Comment
With your target range highlighted:
- Press
cto triggerAction::AddLineComment. When a visual selection exists, tuicr creates a line-range comment covering every line between the anchor and head of the selection. - Type your comment text. The application automatically enters comment input mode (handled by
map_comment_modeinsrc/input/keybindings.rs). - Press Enter to submit the comment.
The comment construction logic executes in src/app/visual.rs【🔗 src/app/visual.rs#L54-L63】, specifically within the add_range_comment method invoked via App::save_comment. The resulting comment attaches to every line in the selected span.
Canceling the Selection
To abort a visual selection without creating a comment, press Esc. This clears InputMode::VisualSelect in src/handler.rs, removing the active selection and returning the application to normal mode.
Visual Rendering and State Management
The selected range renders in the diff view via render_visual_selection in src/ui/diff_view.rs, providing immediate visual feedback through highlighting. Because the selection persists as part of the core App state in src/app/mod.rs, this functionality works consistently across all supported VCS backends including Git, Mercurial, and Jujutsu.
Programmatic Workflow Example
The following Rust pseudocode demonstrates the complete visual selection workflow using tuicr's internal key handling:
// Enter visual mode (v for character-wise, V for line-wise)
app.handle_key(KeyEvent::new(KeyCode::Char('v'), KeyModifiers::NONE));
// Expand selection downward three lines
app.handle_key(KeyEvent::new(KeyCode::Char('j'), KeyModifiers::NONE));
app.handle_key(KeyEvent::new(KeyCode::Char('j'), KeyModifiers::NONE));
app.handle_key(KeyEvent::new(KeyCode::Char('j'), KeyModifiers::NONE));
// Initiate range comment creation
app.handle_key(KeyEvent::new(KeyCode::Char('c'), KeyModifiers::NONE));
// Type comment text
for ch in "Fix is bad".chars() {
app.handle_key(KeyEvent::new(KeyCode::Char(ch), KeyModifiers::NONE));
}
// Submit the comment
app.handle_key(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE));
To cancel the selection programmatically:
app.handle_key(KeyEvent::new(KeyCode::Esc, KeyModifiers::NONE));
Summary
- Press
vorVto enter visual mode and initialize a selection at the current cursor position. - Use navigation keys (
h/j/k/l, arrows, or page keys) to expand the selection range stored inApp.visual_selection. - Press
cto create a line-range comment covering the selected anchor-to-head span. - Submit with Enter or abort with Esc to clear
InputMode::VisualSelect. - The implementation spans
src/input/keybindings.rs,src/app/visual.rs, andsrc/handler.rs, with rendering handled bysrc/ui/diff_view.rs.
Frequently Asked Questions
What is the difference between v and V in tuicr?
Both keys activate visual mode, but v initiates character-wise selection while V initiates line-wise selection. For creating range comments, V is typically more efficient because it selects entire lines of code immediately, whereas v allows finer-grained character positioning.
Can I create a file-wide comment using visual mode?
Yes. Press C (uppercase) instead of c to create a file-wide comment. This action bypasses the visual selection mechanism and attaches the comment to the entire file rather than a specific line range.
Where does tuicr store the visual selection state?
The visual selection is stored in the App struct as visual_selection: Option<VisualSelection>, defined in src/app/mod.rs. The VisualSelection struct maintains both the anchor (starting point) and head (current cursor position) coordinates to define the exact range for commenting.
How do I know which lines are selected?
The selected range is highlighted in the terminal UI by render_visual_selection in src/ui/diff_view.rs. This visual feedback clearly indicates exactly which lines will receive the comment when you press c, ensuring you comment on the intended code block.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →