Skip to content

Add Visual mode with yank and paste functionality#29

Draft
ih8js-git wants to merge 7 commits into
YetAnotherMechanicusEnjoyer:devfrom
ih8js-git:dev
Draft

Add Visual mode with yank and paste functionality#29
ih8js-git wants to merge 7 commits into
YetAnotherMechanicusEnjoyer:devfrom
ih8js-git:dev

Conversation

@ih8js-git
Copy link
Copy Markdown
Contributor

This pull request adds comprehensive Vim-style visual selection and yank/paste support to the text input area, significantly enhancing keyboard-based text manipulation. It introduces Visual and Visual Line modes, enables yanking (copying) and pasting text or lines, and updates the UI to visually highlight selections. The changes also clean up and refactor selection logic and improve key event handling for maintainability.

Vim Visual Mode and Yank/Paste Functionality:

  • Added Visual and VisualLine modes to InputMode, supporting character-wise and line-wise visual selections (src/main.rs, src/ui/vim.rs). [1] [2] [3]
  • Implemented visual selection logic, including tracking the start of a selection, updating the UI to highlight selected text, and handling Esc to exit visual mode and clear selection (src/ui/draw.rs, src/ui/events.rs, src/ui/vim.rs). [1] [2] [3] [4] [5]
  • Added yank buffer to VimState and logic for yanking (copying) and pasting selected text or lines, including support for y, yy, p, and P keybinds (src/ui/vim.rs). [1] [2] [3] [4] [5] [6]

Keybindings and User Documentation:

  • Updated Vim keybindings documentation to include visual selection, yanking, and pasting commands (readme/keybinds.md).

Selection and Key Event Refactors:

  • Refactored selection logic for DMs, guilds, channels, and emojis to use pattern matching for clarity and maintainability (src/ui/events.rs). [1] [2] [3] [4] [5] [6]
  • Improved key event handling by simplifying match arms and removing redundant code (src/ui/events.rs). [1] [2]

Other:

  • Added a new file with two lines of text (file).

Copilot AI review requested due to automatic review settings May 5, 2026 16:59
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds Vim-style visual selection and yank/paste behavior to the text input, including new Visual/VisualLine modes, highlighted selections, and updated key handling/documentation.

Changes:

  • Added visual-mode state and key handling for v/V, y/yy, p/P, and visual delete operations.
  • Updated event routing and drawing so visual selections can be entered, exited, and highlighted in the input UI.
  • Documented the new keybindings and added an unrelated root-level text file.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/ui/vim.rs Adds visual-mode state, yank buffer storage, and most of the new Vim command behavior.
src/ui/events.rs Routes visual modes through Vim handling, updates Esc handling, and refactors selection movement branches.
src/ui/draw.rs Renders highlighted visual selections in the input paragraph.
src/main.rs Extends InputMode and maps visual modes to block cursor styling.
readme/keybinds.md Documents the new visual/yank/paste keybindings.
file Adds an unrelated two-line text file at the repository root.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/ui/vim.rs
Comment on lines +882 to +887
pos = state.input[pos..]
.find('\n')
.map(|i| pos + i)
.unwrap_or(state.input.len());
state.input.insert_str(pos, &yanked);
state.cursor_position = pos + 1;
Comment thread src/ui/vim.rs
let mut pos = state.cursor_position;
if let Some(stripped) = yanked.strip_prefix('\n') {
pos = state.input[..pos].rfind('\n').map(|i| i + 1).unwrap_or(0);
let to_insert = format!("{}\n", stripped);
Comment thread src/ui/vim.rs
let is_linewise = state.mode == InputMode::VisualLine;
if let Some(vim_state) = &mut state.vim_state {
if is_linewise {
vim_state.yank_buffer = format!("\n{}", deleted.trim_matches('\n'));
Comment thread src/ui/vim.rs
Comment on lines +725 to +745
'v' => {
if state.mode == InputMode::Normal {
state.mode = InputMode::Visual;
let cp = state.cursor_position;
if let Some(vim_state) = &mut state.vim_state {
vim_state.visual_start = Some(cp);
}
} else if state.mode == InputMode::Visual {
state.mode = InputMode::Normal;
if let Some(vim_state) = &mut state.vim_state {
vim_state.visual_start = None;
}
}
}
'V' => {
if state.mode == InputMode::Normal {
state.mode = InputMode::VisualLine;
let cp = state.cursor_position;
if let Some(vim_state) = &mut state.vim_state {
vim_state.visual_start = Some(cp);
}
Comment thread src/ui/events.rs
Comment on lines 810 to +817
// In vim mode, Esc switches from Insert to Normal mode and returns early.
// In non-vim mode (or vim Normal mode), Esc triggers navigation (handled below).
if state.vim_mode && state.mode == InputMode::Insert
|| state.mode == InputMode::Command
|| state.mode == InputMode::Search
if state.vim_mode
&& (state.mode == InputMode::Insert
|| state.mode == InputMode::Command
|| state.mode == InputMode::Search
|| state.mode == InputMode::Visual
|| state.mode == InputMode::VisualLine)
Comment thread src/ui/vim.rs
Comment on lines +603 to +620
if state.mode == InputMode::Visual || state.mode == InputMode::VisualLine {
let visual_start = state.vim_state.as_ref().and_then(|vs| vs.visual_start);
if let Some(vs) = visual_start {
let mut start = vs.min(state.cursor_position);
let mut end = vs.max(state.cursor_position);
let end_len = state.input[end..]
.chars()
.next()
.map(|c| c.len_utf8())
.unwrap_or(0);
end = (end + end_len).min(state.input.len());
if state.mode == InputMode::VisualLine {
start = state.input[..start].rfind('\n').map(|i| i + 1).unwrap_or(0);
end = state.input[end..]
.find('\n')
.map(|i| end + i + 1)
.unwrap_or(state.input.len());
}
Comment thread file
@@ -0,0 +1,2 @@
line one
line two
@ih8js-git ih8js-git marked this pull request as draft May 5, 2026 18:04
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is file doing here ? Did you put it by accident ?

@YetAnotherMechanicusEnjoyer YetAnotherMechanicusEnjoyer added the enhancement New feature or request label May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants