reovim_module_vim/operators/
yank.rs1use reovim_kernel::api::v1::RegisterContent;
6
7use super::{Operator, OperatorContext, OperatorError, Range, char_col_to_byte, registers};
8
9#[derive(Debug, Clone, Copy)]
23pub struct YankOperator;
24
25impl Operator for YankOperator {
26 fn id(&self) -> &'static str {
27 "yank"
28 }
29
30 #[cfg_attr(coverage_nightly, coverage(off))]
31 fn execute(&self, ctx: &mut OperatorContext<'_>, range: Range) -> Result<(), OperatorError> {
32 let buffer_arc = ctx
34 .kernel
35 .buffers
36 .get(ctx.buffer_id)
37 .ok_or(OperatorError::BufferNotFound(ctx.buffer_id))?;
38
39 let buffer = buffer_arc.read();
40
41 let start = range.start;
43 let end = range.end;
44 let mut yanked_text = String::new();
45
46 if range.is_linewise {
47 let line_count = buffer.line_count();
51 let clamped_end = end.line.min(line_count.saturating_sub(1));
52
53 for line_idx in start.line..=clamped_end {
54 if let Some(line) = buffer.line(line_idx) {
55 yanked_text.push_str(line);
56 yanked_text.push('\n');
57 }
58 }
59 } else if start.line == end.line {
60 if let Some(line) = buffer.line(start.line) {
62 let char_len = line.chars().count();
63 let start_col = start.column.min(char_len);
64 let end_col = end.column.min(char_len);
65 if start_col < end_col {
66 let start_byte = char_col_to_byte(line, start_col);
67 let end_byte = char_col_to_byte(line, end_col);
68 yanked_text.push_str(&line[start_byte..end_byte]);
69 }
70 }
71 } else {
72 for line_idx in start.line..=end.line {
74 if let Some(line) = buffer.line(line_idx) {
75 if line_idx == start.line {
76 let char_len = line.chars().count();
77 let start_col = start.column.min(char_len);
78 let start_byte = char_col_to_byte(line, start_col);
79 yanked_text.push_str(&line[start_byte..]);
80 yanked_text.push('\n');
81 } else if line_idx == end.line {
82 let char_len = line.chars().count();
83 let end_col = end.column.min(char_len);
84 let end_byte = char_col_to_byte(line, end_col);
85 yanked_text.push_str(&line[..end_byte]);
86 } else {
87 yanked_text.push_str(line);
88 yanked_text.push('\n');
89 }
90 }
91 }
92 }
93
94 drop(buffer);
96
97 let content = if range.is_linewise {
99 RegisterContent::linewise(yanked_text)
100 } else {
101 RegisterContent::characterwise(yanked_text)
102 };
103
104 registers::store_and_sync(ctx.kernel, ctx.registers, ctx.register, &content);
107
108 registers::push_to_history(ctx.clipboard_history, &content);
111
112 Ok(())
113 }
114
115 fn is_linewise(&self) -> bool {
116 false }
118
119 fn is_text_modifying(&self) -> bool {
120 false }
122}