rewrap.rs

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