rewrap.rs

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