Align selections via & (#1101)
* align lines * remove log statement * use selections to align * fix a clippy issue * only accept 1,2,3 as user count * Update helix-term/src/commands.rs Co-authored-by: Ivan Tham <pickfire@riseup.net> * return if user count is not correct * add doc Co-authored-by: Ivan Tham <pickfire@riseup.net>
This commit is contained in:
parent
f24e5a3c41
commit
21143e8d22
3 changed files with 73 additions and 1 deletions
|
@ -92,6 +92,7 @@
|
|||
| `s` | Select all regex matches inside selections | `select_regex` |
|
||||
| `S` | Split selection into subselections on regex matches | `split_selection` |
|
||||
| `Alt-s` | Split selection on newlines | `split_selection_on_newline` |
|
||||
| `&` | Align selection in columns | `align_selections` |
|
||||
| `_` | Trim whitespace from the selection | `trim_selections` |
|
||||
| `;` | Collapse selection onto a single cursor | `collapse_selection` |
|
||||
| `Alt-;` | Flip selection cursor and anchor | `flip_selections` |
|
||||
|
|
|
@ -314,6 +314,7 @@ impl Command {
|
|||
join_selections, "Join lines inside selection",
|
||||
keep_selections, "Keep selections matching regex",
|
||||
remove_selections, "Remove selections matching regex",
|
||||
align_selections, "Align selections in column",
|
||||
keep_primary_selection, "Keep primary selection",
|
||||
remove_primary_selection, "Remove primary selection",
|
||||
completion, "Invoke completion popup",
|
||||
|
@ -657,6 +658,76 @@ 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".to_string(),
|
||||
);
|
||||
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 = 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 {
|
||||
let (l1, l2) = sel.line_range(text);
|
||||
if l1 != l2 {
|
||||
cx.editor
|
||||
.set_error("align cannot work with multi line selections".to_string());
|
||||
return;
|
||||
}
|
||||
// if the selection is not in the same line with last selection, we set the column to 0
|
||||
column = if l1 != last_line { 0 } else { column + 1 };
|
||||
last_line = l1;
|
||||
|
||||
if column < column_widths.len() {
|
||||
if sel.to() - sel.from() > column_widths[column] {
|
||||
column_widths[column] = sel.to() - sel.from();
|
||||
}
|
||||
} else {
|
||||
// a new column, current selection width is the temp width of the column
|
||||
column_widths.push(sel.to() - sel.from());
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
(
|
||||
range.from(),
|
||||
range.to(),
|
||||
Some(
|
||||
align_fragment_to_width(&range.fragment(text), column_widths[column], align_style)
|
||||
.into(),
|
||||
),
|
||||
)
|
||||
});
|
||||
|
||||
doc.apply(&transaction, view.id);
|
||||
doc.append_changes_to_history(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 (view, doc) = current!(cx.editor);
|
||||
|
||||
|
|
|
@ -604,7 +604,7 @@ impl Default for Keymaps {
|
|||
// "q" => record_macro,
|
||||
// "Q" => replay_macro,
|
||||
|
||||
// & align selections
|
||||
"&" => align_selections,
|
||||
"_" => trim_selections,
|
||||
|
||||
"(" => rotate_selections_backward,
|
||||
|
|
Loading…
Reference in a new issue