rewrap.rs

  1use crate::{motion::Motion, object::Object, state::Mode, Vim};
  2use collections::HashMap;
  3use editor::{display_map::ToDisplayPoint, scroll::Autoscroll, Bias, Editor, IsVimMode};
  4use gpui::actions;
  5use language::SelectionGoal;
  6use ui::ViewContext;
  7
  8actions!(vim, [Rewrap]);
  9
 10pub(crate) fn register(editor: &mut Editor, cx: &mut ViewContext<Vim>) {
 11    Vim::action(editor, cx, |vim, _: &Rewrap, cx| {
 12        vim.record_current_action(cx);
 13        Vim::take_count(cx);
 14        vim.store_visual_marks(cx);
 15        vim.update_editor(cx, |vim, editor, cx| {
 16            editor.transact(cx, |editor, cx| {
 17                let mut positions = vim.save_selection_starts(editor, cx);
 18                editor.rewrap_impl(IsVimMode::Yes, cx);
 19                editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
 20                    s.move_with(|map, selection| {
 21                        if let Some(anchor) = positions.remove(&selection.id) {
 22                            let mut point = anchor.to_display_point(map);
 23                            *point.column_mut() = 0;
 24                            selection.collapse_to(point, SelectionGoal::None);
 25                        }
 26                    });
 27                });
 28            });
 29        });
 30        if vim.mode.is_visual() {
 31            vim.switch_mode(Mode::Normal, true, cx)
 32        }
 33    });
 34}
 35
 36impl Vim {
 37    pub(crate) fn rewrap_motion(
 38        &mut self,
 39        motion: Motion,
 40        times: Option<usize>,
 41        cx: &mut ViewContext<Self>,
 42    ) {
 43        self.stop_recording(cx);
 44        self.update_editor(cx, |_, editor, cx| {
 45            let text_layout_details = editor.text_layout_details(cx);
 46            editor.transact(cx, |editor, cx| {
 47                let mut selection_starts: HashMap<_, _> = Default::default();
 48                editor.change_selections(None, cx, |s| {
 49                    s.move_with(|map, selection| {
 50                        let anchor = map.display_point_to_anchor(selection.head(), Bias::Right);
 51                        selection_starts.insert(selection.id, anchor);
 52                        motion.expand_selection(map, selection, times, false, &text_layout_details);
 53                    });
 54                });
 55                editor.rewrap_impl(IsVimMode::Yes, cx);
 56                editor.change_selections(None, cx, |s| {
 57                    s.move_with(|map, selection| {
 58                        let anchor = selection_starts.remove(&selection.id).unwrap();
 59                        let mut point = anchor.to_display_point(map);
 60                        *point.column_mut() = 0;
 61                        selection.collapse_to(point, SelectionGoal::None);
 62                    });
 63                });
 64            });
 65        });
 66    }
 67
 68    pub(crate) fn rewrap_object(
 69        &mut self,
 70        object: Object,
 71        around: bool,
 72        cx: &mut ViewContext<Self>,
 73    ) {
 74        self.stop_recording(cx);
 75        self.update_editor(cx, |_, editor, cx| {
 76            editor.transact(cx, |editor, cx| {
 77                let mut original_positions: HashMap<_, _> = Default::default();
 78                editor.change_selections(None, cx, |s| {
 79                    s.move_with(|map, selection| {
 80                        let anchor = map.display_point_to_anchor(selection.head(), Bias::Right);
 81                        original_positions.insert(selection.id, anchor);
 82                        object.expand_selection(map, selection, around);
 83                    });
 84                });
 85                editor.rewrap_impl(IsVimMode::Yes, cx);
 86                editor.change_selections(None, cx, |s| {
 87                    s.move_with(|map, selection| {
 88                        let anchor = original_positions.remove(&selection.id).unwrap();
 89                        let mut point = anchor.to_display_point(map);
 90                        *point.column_mut() = 0;
 91                        selection.collapse_to(point, SelectionGoal::None);
 92                    });
 93                });
 94            });
 95        });
 96    }
 97}
 98
 99#[cfg(test)]
100mod test {
101    use crate::test::NeovimBackedTestContext;
102
103    #[gpui::test]
104    async fn test_indent_gv(cx: &mut gpui::TestAppContext) {
105        let mut cx = NeovimBackedTestContext::new(cx).await;
106        cx.set_neovim_option("shiftwidth=4").await;
107
108        cx.set_shared_state("ˇhello\nworld\n").await;
109        cx.simulate_shared_keystrokes("v j > g v").await;
110        cx.shared_state()
111            .await
112            .assert_eq("«    hello\n ˇ»   world\n");
113    }
114}