@@ -775,64 +775,62 @@ fn align_selections(cx: &mut Context) {
775775 let (view, doc) = current!(cx.editor);
776776 let text = doc.text().slice(..);
777777 let selection = doc.selection(view.id);
778− let mut column_widths: Vec<Vec<_>> = vec![];
778+
779+ let mut column_widths: Vec<Vec<_>> = Vec::new();
779780 let mut last_line = text.len_lines() + 1;
780− let mut column = 0;
781− // first of all, we need compute all column's width, let use max width of the selections in a column
782− for sel in selection {
783− let (l1, l2) = sel.line_range(text);
784− if l1 != l2 {
781+ let mut col = 0;
782+
783+ for range in selection {
784+ let coords = coords_at_pos(text, range.head);
785+ let anchor_coords = coords_at_pos(text, range.anchor);
786+
787+ if coords.row != anchor_coords.row {
785788 cx.editor
786789 .set_error("align cannot work with multi line selections");
787790 return;
788791 }
789− // if the selection is not in the same line with last selection, we set the column to 0
790− column = if l1 != last_line { 0 } else { column + 1 };
791− last_line = l1;
792−
793− // save all max line cursor of selections
794− let cursor = sel.to() - text.line_to_char(l1);
795− if column < column_widths.len() {
796− column_widths[column].push((l1, cursor));
797− } else {
798− column_widths.push(vec![(l1, cursor)]);
792+
793+ col = if coords.row == last_line { col + 1 } else { 0 };
794+
795+ if col >= column_widths.len() {
796+ column_widths.push(Vec::new());
799797 }
798+ column_widths[col].push((range.from(), coords.col));
799+
800+ last_line = coords.row;
800801 }
801− let mut max_curs = vec![];
802− for i in 0..column_widths.len() {
803− // compute max cursor of current column
804− let max_cur = column_widths[i]
802+
803+ let mut changes = Vec::with_capacity(selection.len());
804+
805+ // Account for changes on each row
806+ let len = column_widths.first().map(|cols| cols.len()).unwrap_or(0);
807+ let mut offs = vec![0; len];
808+
809+ for col in column_widths {
810+ let max_col = col
805811 .iter()
806− .fold(0, |max, &(_, cur)| max.max(cur));
807− max_curs.push(max_cur);
812+ .enumerate()
813+ .map(|(row, (_, cursor))| *cursor + offs[row])
814+ .max()
815+ .unwrap_or(0);
808816
809− let mut pads = std::collections::HashMap::new();
810− for item in column_widths[i].iter_mut() {
811− pads.insert(item.0, max_cur - item.1);
812− }
813− // add pad to right columns
814− for col in column_widths[i + 1..].iter_mut() {
815− for item in col.iter_mut() {
816− item.1 += pads.get(&item.0).unwrap_or(&0);
817+ for (row, (insert_pos, last_col)) in col.into_iter().enumerate() {
818+ let ins_count = max_col - (last_col + offs[row]);
819+
820+ if ins_count == 0 {
821+ continue;
817822 }
823+
824+ offs[row] += ins_count;
825+
826+ changes.push((insert_pos, insert_pos, Some(" ".repeat(ins_count).into())));
818827 }
819828 }
820829
821− last_line = text.len_lines();
822− let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
823− let line = range.cursor_line(text);
824− column = if line != last_line { 0 } else { column + 1 };
825− last_line = line;
826− let max_cur = max_curs[column];
827− let new_cur = column_widths[column]
828− .iter()
829− .fold(max_cur, |c, (l, cur)| if *l == line { *cur } else { c });
830− let mut new_str = " ".repeat(max_cur - new_cur);
831− new_str.push_str(&range.fragment(text));
832−
833− (range.from(), range.to(), Some(new_str.into()))
834− });
830+ // The changeset has to be sorted
831+ changes.sort_unstable_by_key(|(from, _, _)| *from);
835832
833+ let transaction = Transaction::change(doc.text(), changes.into_iter());
836834 doc.apply(&transaction, view.id);
837835}
838836