Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor align_selection using kakoune logic #1675

Merged
merged 2 commits into from
Mar 3, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 36 additions & 38 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -774,18 +774,11 @@ fn trim_selections(cx: &mut Context) {

// align text in selection
fn align_selections(cx: &mut Context) {
let align_style = cx.count();
if align_style > 3 {
cx.editor
.set_error("align only accept 1,2,3 as count to set left/center/right align");
return;
}

let (view, doc) = current!(cx.editor);
let text = doc.text().slice(..);
let selection = doc.selection(view.id);
let mut column_widths = vec![];
let mut last_line = text.len_lines();
let mut column_widths: Vec<Vec<_>> = vec![];
let mut last_line = text.len_lines() + 1;
let mut column = 0;
// first of all, we need compute all column's width, let use max width of the selections in a column
for sel in selection {
Expand All @@ -799,47 +792,52 @@ fn align_selections(cx: &mut Context) {
column = if l1 != last_line { 0 } else { column + 1 };
last_line = l1;

// save all max line cursor of selections
let cursor = sel.to() - text.line_to_char(l1);
if column < column_widths.len() {
if sel.to() - sel.from() > column_widths[column] {
column_widths[column] = sel.to() - sel.from();
}
column_widths[column].push((l1, cursor));
} else {
// a new column, current selection width is the temp width of the column
column_widths.push(sel.to() - sel.from());
column_widths.push(vec![(l1, cursor)]);
}
}
let mut max_curs = vec![];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let mut max_curs = vec![];
let mut max_curs = Vec::with_capacity(column_widths.len())

for i in 0..column_widths.len() {
// compute max cursor of current column
let max_cur = column_widths[i]
.iter()
.fold(0, |max, &(_, cur)| max.max(cur));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.iter().map(|(_, cur)| cur).max()?

max_curs.push(max_cur);

let mut pads = std::collections::HashMap::new();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let mut pads = std::collections::HashMap::new();
let mut pads = std::collections::HashMap::with_capacity(column_widths[i].len());

for item in column_widths[i].iter_mut() {
pads.insert(item.0, max_cur - item.1);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for item in column_widths[i].iter_mut() {
pads.insert(item.0, max_cur - item.1);
}
for (line_start, cursor) in &column_widths[i] {
pads.insert(line_start, max_cur - cursor);
}

// add pad to right columns
for col in column_widths[i + 1..].iter_mut() {
for item in col.iter_mut() {
item.1 += pads.get(&item.0).unwrap_or(&0);
}
}
}

last_line = text.len_lines();
// once we get the with of each column, we transform each selection with to it's column width based on the align style
let transaction = Transaction::change_by_selection(doc.text(), selection, |range| {
let l = range.cursor_line(text);
column = if l != last_line { 0 } else { column + 1 };
last_line = l;
let line = range.cursor_line(text);
column = if line != last_line { 0 } else { column + 1 };
last_line = line;
let max_cur = max_curs[column];
let new_cur = column_widths[column]
.iter()
.fold(max_cur, |c, (l, cur)| if *l == line { *cur } else { c });
let mut new_str = " ".repeat(max_cur - new_cur);
new_str.push_str(&range.fragment(text));

(
range.from(),
range.to(),
Some(
align_fragment_to_width(&range.fragment(text), column_widths[column], align_style)
.into(),
),
)
(range.from(), range.to(), Some(new_str.into()))
});

doc.apply(&transaction, view.id);
}

fn align_fragment_to_width(fragment: &str, width: usize, align_style: usize) -> String {
let trimed = fragment.trim_matches(|c| c == ' ');
let mut s = " ".repeat(width - trimed.chars().count());
match align_style {
1 => s.insert_str(0, trimed), // left align
2 => s.insert_str(s.len() / 2, trimed), // center align
3 => s.push_str(trimed), // right align
n => unimplemented!("{}", n),
}
s
}

fn goto_window(cx: &mut Context, align: Align) {
let count = cx.count() - 1;
let (view, doc) = current!(cx.editor);
Expand Down