fix replace in normal and visual modes
This commit is contained in:
parent
14eec66e38
commit
216b1aec08
3 changed files with 100 additions and 24 deletions
|
@ -352,6 +352,29 @@ pub fn surrounding_word(map: &DisplaySnapshot, position: DisplayPoint) -> Range<
|
||||||
start..end
|
start..end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn split_display_range_by_lines(
|
||||||
|
map: &DisplaySnapshot,
|
||||||
|
range: Range<DisplayPoint>,
|
||||||
|
) -> Vec<Range<DisplayPoint>> {
|
||||||
|
let mut result = Vec::new();
|
||||||
|
|
||||||
|
let mut start = range.start;
|
||||||
|
// Loop over all the covered rows until the one containing the range end
|
||||||
|
for row in range.start.row()..range.end.row() {
|
||||||
|
let row_end_column = map.line_len(row);
|
||||||
|
let end = map.clip_point(DisplayPoint::new(row, row_end_column), Bias::Left);
|
||||||
|
if start != end {
|
||||||
|
result.push(start..end);
|
||||||
|
}
|
||||||
|
start = map.clip_point(DisplayPoint::new(row + 1, 0), Bias::Left);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the final range from the start of the last end to the original range end.
|
||||||
|
result.push(start..range.end);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -429,14 +429,42 @@ pub(crate) fn normal_replace(text: &str, cx: &mut MutableAppContext) {
|
||||||
vim.update_active_editor(cx, |editor, cx| {
|
vim.update_active_editor(cx, |editor, cx| {
|
||||||
editor.transact(cx, |editor, cx| {
|
editor.transact(cx, |editor, cx| {
|
||||||
editor.set_clip_at_line_ends(false, cx);
|
editor.set_clip_at_line_ends(false, cx);
|
||||||
editor.change_selections(None, cx, |s| {
|
let (map, display_selections) = editor.selections.all_display(cx);
|
||||||
s.move_with(|map, selection| {
|
// Selections are biased right at the start. So we need to store
|
||||||
*selection.end.column_mut() += 1;
|
// anchors that are biased left so that we can restore the selections
|
||||||
selection.end = map.clip_point(selection.end, Bias::Right);
|
// after the change
|
||||||
});
|
let stable_anchors = editor
|
||||||
|
.selections
|
||||||
|
.disjoint_anchors()
|
||||||
|
.into_iter()
|
||||||
|
.map(|selection| {
|
||||||
|
let start = selection.start.bias_left(&map.buffer_snapshot);
|
||||||
|
start..start
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let edits = display_selections
|
||||||
|
.into_iter()
|
||||||
|
.map(|selection| {
|
||||||
|
let mut range = selection.range();
|
||||||
|
*range.end.column_mut() += 1;
|
||||||
|
range.end = map.clip_point(range.end, Bias::Right);
|
||||||
|
|
||||||
|
(
|
||||||
|
range.start.to_offset(&map, Bias::Left)
|
||||||
|
..range.end.to_offset(&map, Bias::Left),
|
||||||
|
text,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
editor.buffer().update(cx, |buffer, cx| {
|
||||||
|
buffer.edit(edits, None, cx);
|
||||||
});
|
});
|
||||||
editor.insert(text, cx);
|
|
||||||
editor.set_clip_at_line_ends(true, cx);
|
editor.set_clip_at_line_ends(true, cx);
|
||||||
|
editor.change_selections(None, cx, |s| {
|
||||||
|
s.select_anchor_ranges(stable_anchors);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
vim.pop_operator(cx)
|
vim.pop_operator(cx)
|
||||||
|
@ -487,6 +515,16 @@ mod test {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #[gpui::test]
|
||||||
|
// async fn test_enter(cx: &mut gpui::TestAppContext) {
|
||||||
|
// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["enter"]);
|
||||||
|
// cx.assert_all(indoc! {"
|
||||||
|
// ˇThe qˇuick broˇwn
|
||||||
|
// ˇfox jumps"
|
||||||
|
// })
|
||||||
|
// .await;
|
||||||
|
// }
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_k(cx: &mut gpui::TestAppContext) {
|
async fn test_k(cx: &mut gpui::TestAppContext) {
|
||||||
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["k"]);
|
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["k"]);
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use editor::{
|
use editor::{
|
||||||
display_map::ToDisplayPoint, scroll::autoscroll::Autoscroll, Bias, ClipboardSelection,
|
display_map::ToDisplayPoint, movement, scroll::autoscroll::Autoscroll, Bias, ClipboardSelection,
|
||||||
};
|
};
|
||||||
use gpui::{actions, MutableAppContext, ViewContext};
|
use gpui::{actions, MutableAppContext, ViewContext};
|
||||||
use language::{AutoindentMode, SelectionGoal};
|
use language::{AutoindentMode, SelectionGoal};
|
||||||
|
@ -318,32 +318,47 @@ pub(crate) fn visual_replace(text: &str, line: bool, cx: &mut MutableAppContext)
|
||||||
vim.update_active_editor(cx, |editor, cx| {
|
vim.update_active_editor(cx, |editor, cx| {
|
||||||
editor.transact(cx, |editor, cx| {
|
editor.transact(cx, |editor, cx| {
|
||||||
let (display_map, selections) = editor.selections.all_adjusted_display(cx);
|
let (display_map, selections) = editor.selections.all_adjusted_display(cx);
|
||||||
let mut new_selections = Vec::new();
|
|
||||||
editor.buffer().update(cx, |buffer, cx| {
|
|
||||||
let mut edits = Vec::new();
|
|
||||||
for selection in selections.iter() {
|
|
||||||
let mut selection = selection.clone();
|
|
||||||
if !line && !selection.reversed {
|
|
||||||
// Head is at the end of the selection. Adjust the end position to
|
|
||||||
// to include the character under the cursor.
|
|
||||||
*selection.end.column_mut() = selection.end.column() + 1;
|
|
||||||
selection.end = display_map.clip_point(selection.end, Bias::Right);
|
|
||||||
}
|
|
||||||
|
|
||||||
let range = selection
|
// Selections are biased right at the start. So we need to store
|
||||||
.map(|p| p.to_offset(&display_map, Bias::Right))
|
// anchors that are biased left so that we can restore the selections
|
||||||
.range();
|
// after the change
|
||||||
new_selections.push(range.start..range.start);
|
let stable_anchors = editor
|
||||||
|
.selections
|
||||||
|
.disjoint_anchors()
|
||||||
|
.into_iter()
|
||||||
|
.map(|selection| {
|
||||||
|
let start = selection.start.bias_left(&display_map.buffer_snapshot);
|
||||||
|
start..start
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let mut edits = Vec::new();
|
||||||
|
for selection in selections.iter() {
|
||||||
|
let mut selection = selection.clone();
|
||||||
|
if !line && !selection.reversed {
|
||||||
|
// Head is at the end of the selection. Adjust the end position to
|
||||||
|
// to include the character under the cursor.
|
||||||
|
*selection.end.column_mut() = selection.end.column() + 1;
|
||||||
|
selection.end = display_map.clip_point(selection.end, Bias::Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
for row_range in
|
||||||
|
movement::split_display_range_by_lines(&display_map, selection.range())
|
||||||
|
{
|
||||||
|
let range = row_range.start.to_offset(&display_map, Bias::Right)
|
||||||
|
..row_range.end.to_offset(&display_map, Bias::Right);
|
||||||
let text = text.repeat(range.len());
|
let text = text.repeat(range.len());
|
||||||
edits.push((range, text));
|
edits.push((range, text));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.buffer().update(cx, |buffer, cx| {
|
||||||
buffer.edit(edits, None, cx);
|
buffer.edit(edits, None, cx);
|
||||||
});
|
});
|
||||||
editor.change_selections(None, cx, |s| s.select_ranges(new_selections));
|
editor.change_selections(None, cx, |s| s.select_ranges(stable_anchors));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
vim.pop_operator(cx)
|
vim.switch_mode(Mode::Normal, false, cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue