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, l or arrow keys for single-step movement
  • Ctrl-d and Ctrl-u for 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:

  1. Press c to trigger Action::AddLineComment. When a visual selection exists, tuicr creates a line-range comment covering every line between the anchor and head of the selection.
  2. Type your comment text. The application automatically enters comment input mode (handled by map_comment_mode in src/input/keybindings.rs).
  3. 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 v or V to 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 in App.visual_selection.
  • Press c to 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, and src/handler.rs, with rendering handled by src/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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →