tlc: fix F5/F6/F8 to MC parity — no-op on no selection
Reverts F5/F6/F8 from operating on current line (TLC extension) to MC behavior: do nothing when no selection is active. MC's eval_marks returns false when mark1==mark2, so F5/F6/F8 in MC are no-ops without a selection. Removes the now-dead copy_line/cut_line/delete_line_no_sel helpers and their tests. Replaces with MC-parity no-op tests. Extracts current_line_range() helper from select_current_line and duplicate_line_or_selection (also covers unindent_selection pattern). Removes ~50 lines of duplicated line-range computation.
This commit is contained in:
@@ -396,44 +396,34 @@ impl Editor {
|
||||
}
|
||||
return EditorResult::Running;
|
||||
}
|
||||
// F5 — Copy block (or current line if no selection).
|
||||
// F5 — Copy block. MC parity: no-op when no selection.
|
||||
if key == Key::f(5) {
|
||||
if self.cursor.has_selection() {
|
||||
if let Some(text) = self.cursor.selected_text(&self.buffer) {
|
||||
self.clipboard = Some(text.to_string());
|
||||
let _ = crate::editor::clipboard_osc52::osc52_copy(&text);
|
||||
self.message = Some("Block copied".to_string());
|
||||
}
|
||||
} else {
|
||||
let _ = self.copy_line();
|
||||
if let Some(text) = self.cursor.selected_text(&self.buffer) {
|
||||
self.clipboard = Some(text.to_string());
|
||||
let _ = crate::editor::clipboard_osc52::osc52_copy(&text);
|
||||
self.message = Some("Block copied".to_string());
|
||||
}
|
||||
return EditorResult::Running;
|
||||
}
|
||||
// F6 — Move (cut) block (or current line if no selection).
|
||||
// F6 — Move (cut) block. MC parity: no-op when no selection.
|
||||
if key == Key::f(6) {
|
||||
if self.cursor.has_selection() {
|
||||
if let Some(text) = self.cursor.selected_text(&self.buffer) {
|
||||
self.clipboard = Some(text.to_string());
|
||||
let _ = crate::editor::clipboard_osc52::osc52_copy(&text);
|
||||
self.cursor.delete_selection(&mut self.buffer);
|
||||
self.cursor.set_position(self.buffer.cursor(), &self.buffer);
|
||||
self.modified = true;
|
||||
self.message = Some("Block moved".to_string());
|
||||
}
|
||||
} else {
|
||||
let _ = self.cut_line();
|
||||
if let Some(text) = self.cursor.selected_text(&self.buffer) {
|
||||
self.clipboard = Some(text.to_string());
|
||||
let _ = crate::editor::clipboard_osc52::osc52_copy(&text);
|
||||
self.cursor.delete_selection(&mut self.buffer);
|
||||
self.cursor.set_position(self.buffer.cursor(), &self.buffer);
|
||||
self.modified = true;
|
||||
self.message = Some("Block moved".to_string());
|
||||
}
|
||||
return EditorResult::Running;
|
||||
}
|
||||
// F8 — Delete block (or current line if no selection).
|
||||
// F8 — Delete block. MC parity: no-op when no selection.
|
||||
if key == Key::f(8) {
|
||||
if self.cursor.has_selection() {
|
||||
self.cursor.delete_selection(&mut self.buffer);
|
||||
self.cursor.set_position(self.buffer.cursor(), &self.buffer);
|
||||
self.modified = true;
|
||||
self.message = Some("Block deleted".to_string());
|
||||
} else {
|
||||
let _ = self.delete_line_no_sel();
|
||||
}
|
||||
return EditorResult::Running;
|
||||
}
|
||||
|
||||
@@ -737,105 +737,38 @@ bracket_flash: None,
|
||||
/// any). Cursor moves to the start of the next line; anchor is
|
||||
/// left at the start of the current line.
|
||||
pub fn select_current_line(&mut self) {
|
||||
let total = self.buffer.as_string().len();
|
||||
let bytes = self.buffer.as_string().into_bytes();
|
||||
let mut line_start = self.buffer.cursor();
|
||||
while line_start > 0 && bytes[line_start - 1] != b'\n' {
|
||||
line_start -= 1;
|
||||
}
|
||||
let mut line_end = self.buffer.cursor();
|
||||
while line_end < total && bytes[line_end] != b'\n' {
|
||||
line_end += 1;
|
||||
}
|
||||
if line_end < total {
|
||||
line_end += 1;
|
||||
}
|
||||
let (line_start, line_end) = self.current_line_range();
|
||||
self.buffer.set_cursor(line_start);
|
||||
self.cursor.set_position(line_start, &self.buffer);
|
||||
self.cursor.start_selection();
|
||||
self.cursor.set_position(line_end, &self.buffer);
|
||||
}
|
||||
|
||||
/// Copy the current line (with newline) to the clipboard when no
|
||||
/// selection is active. Returns true if a line was copied.
|
||||
pub fn copy_line(&mut self) -> bool {
|
||||
if self.cursor.has_selection() {
|
||||
return false;
|
||||
}
|
||||
/// Compute the byte range of the current line, starting at the
|
||||
/// beginning of the line and ending just past the trailing
|
||||
/// newline (or at end of buffer if the last line has no newline).
|
||||
fn current_line_range(&self) -> (usize, usize) {
|
||||
let total = self.buffer.as_string().len();
|
||||
let bytes = self.buffer.as_string().into_bytes();
|
||||
let mut line_start = self.buffer.cursor();
|
||||
let cursor = self.buffer.cursor();
|
||||
let mut line_start = cursor;
|
||||
while line_start > 0 && bytes[line_start - 1] != b'\n' {
|
||||
line_start -= 1;
|
||||
}
|
||||
let mut line_end = self.buffer.cursor();
|
||||
let mut line_end = cursor;
|
||||
while line_end < total && bytes[line_end] != b'\n' {
|
||||
line_end += 1;
|
||||
}
|
||||
if line_end < total {
|
||||
line_end += 1;
|
||||
}
|
||||
let text = String::from_utf8_lossy(&bytes[line_start..line_end]).into_owned();
|
||||
self.clipboard = Some(text.clone());
|
||||
let _ = crate::editor::clipboard_osc52::osc52_copy(&text);
|
||||
self.message = Some("Line copied".to_string());
|
||||
true
|
||||
}
|
||||
|
||||
/// Cut the current line (with newline) to the clipboard when no
|
||||
/// selection is active. Returns true if a line was cut.
|
||||
pub fn cut_line(&mut self) -> bool {
|
||||
if self.cursor.has_selection() {
|
||||
return false;
|
||||
}
|
||||
let total = self.buffer.as_string().len();
|
||||
let bytes = self.buffer.as_string().into_bytes();
|
||||
let mut line_start = self.buffer.cursor();
|
||||
while line_start > 0 && bytes[line_start - 1] != b'\n' {
|
||||
line_start -= 1;
|
||||
}
|
||||
let mut line_end = self.buffer.cursor();
|
||||
while line_end < total && bytes[line_end] != b'\n' {
|
||||
line_end += 1;
|
||||
}
|
||||
if line_end < total {
|
||||
line_end += 1;
|
||||
}
|
||||
let text = String::from_utf8_lossy(&bytes[line_start..line_end]).into_owned();
|
||||
self.clipboard = Some(text.clone());
|
||||
let _ = crate::editor::clipboard_osc52::osc52_copy(&text);
|
||||
self.buffer.begin_undo_group();
|
||||
self.buffer.set_cursor(line_start);
|
||||
for _ in line_start..line_end {
|
||||
self.buffer.delete_forward();
|
||||
}
|
||||
self.cursor.set_position(self.buffer.cursor(), &self.buffer);
|
||||
self.cursor.clear_selection();
|
||||
self.buffer.end_undo_group();
|
||||
self.modified = true;
|
||||
self.message = Some("Line cut".to_string());
|
||||
true
|
||||
}
|
||||
|
||||
/// Delete the current line (with newline) when no selection is
|
||||
/// active. Returns true if a line was deleted.
|
||||
pub fn delete_line_no_sel(&mut self) -> bool {
|
||||
if self.cursor.has_selection() {
|
||||
return false;
|
||||
}
|
||||
self.buffer.delete_line();
|
||||
self.cursor.set_position(self.buffer.cursor(), &self.buffer);
|
||||
self.cursor.clear_selection();
|
||||
self.modified = true;
|
||||
self.message = Some("Line deleted".to_string());
|
||||
true
|
||||
(line_start, line_end)
|
||||
}
|
||||
|
||||
/// Duplicate the current line (with newline) when no selection
|
||||
/// is active, or duplicate the selected block otherwise.
|
||||
/// Returns true if anything was duplicated.
|
||||
pub fn duplicate_line_or_selection(&mut self) -> bool {
|
||||
let total = self.buffer.as_string().len();
|
||||
let bytes = self.buffer.as_string().into_bytes();
|
||||
if let Some((s, e)) = self.cursor.selection() {
|
||||
let text = String::from_utf8_lossy(&bytes[s..e]).into_owned();
|
||||
@@ -849,17 +782,7 @@ bracket_flash: None,
|
||||
self.message = Some("Duplicated".to_string());
|
||||
return true;
|
||||
}
|
||||
let mut line_start = self.buffer.cursor();
|
||||
while line_start > 0 && bytes[line_start - 1] != b'\n' {
|
||||
line_start -= 1;
|
||||
}
|
||||
let mut line_end = self.buffer.cursor();
|
||||
while line_end < total && bytes[line_end] != b'\n' {
|
||||
line_end += 1;
|
||||
}
|
||||
if line_end < total {
|
||||
line_end += 1;
|
||||
}
|
||||
let (line_start, line_end) = self.current_line_range();
|
||||
let text = String::from_utf8_lossy(&bytes[line_start..line_end]).into_owned();
|
||||
self.buffer.begin_undo_group();
|
||||
self.buffer.set_cursor(line_end);
|
||||
@@ -2362,37 +2285,41 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f5_without_selection_copies_line() {
|
||||
fn f5_without_selection_is_noop_mc_parity() {
|
||||
let mut e = make_empty();
|
||||
e.insert_str("first\nsecond\nthird\n");
|
||||
e.buffer.set_cursor(8);
|
||||
e.cursor.set_position(8, &e.buffer);
|
||||
e.handle_key(Key::f(5));
|
||||
assert_eq!(e.clipboard.as_deref(), Some("second\n"));
|
||||
assert_eq!(e.clipboard, None);
|
||||
assert_eq!(e.buffer().as_string(), "first\nsecond\nthird\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f6_without_selection_cuts_line() {
|
||||
fn f6_without_selection_is_noop_mc_parity() {
|
||||
let mut e = make_empty();
|
||||
e.insert_str("first\nsecond\nthird\n");
|
||||
e.buffer.mark_saved();
|
||||
e.modified = false;
|
||||
e.buffer.set_cursor(8);
|
||||
e.cursor.set_position(8, &e.buffer);
|
||||
e.handle_key(Key::f(6));
|
||||
assert_eq!(e.clipboard.as_deref(), Some("second\n"));
|
||||
assert_eq!(e.buffer().as_string(), "first\nthird\n");
|
||||
assert!(e.is_modified());
|
||||
assert_eq!(e.clipboard, None);
|
||||
assert_eq!(e.buffer().as_string(), "first\nsecond\nthird\n");
|
||||
assert!(!e.is_modified());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn f8_without_selection_deletes_line() {
|
||||
fn f8_without_selection_is_noop_mc_parity() {
|
||||
let mut e = make_empty();
|
||||
e.insert_str("first\nsecond\nthird\n");
|
||||
e.buffer.mark_saved();
|
||||
e.modified = false;
|
||||
e.buffer.set_cursor(8);
|
||||
e.cursor.set_position(8, &e.buffer);
|
||||
e.handle_key(Key::f(8));
|
||||
assert_eq!(e.buffer().as_string(), "first\nthird\n");
|
||||
assert!(e.is_modified());
|
||||
assert_eq!(e.buffer().as_string(), "first\nsecond\nthird\n");
|
||||
assert!(!e.is_modified());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user