pull/13354/merge
krabodyan 2025-06-14 23:57:52 +03:00 committed by GitHub
commit 62f15e95a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 148 additions and 1 deletions

View File

@ -70,6 +70,7 @@
| `:toggle-option`, `:toggle` | Toggle a config option at runtime.<br>For example to toggle smart case search, use `:toggle search.smart-case`. |
| `:get-option`, `:get` | Get the current value of a config option. |
| `:sort` | Sort ranges in selection. |
| `:index` | Inserts indexes into selections. |
| `:reflow` | Hard-wrap the current selection of lines to a given width. |
| `:tree-sitter-subtree`, `:ts-subtree` | Display the smallest tree-sitter subtree that spans the primary selection, primarily for debugging queries. |
| `:config-reload` | Refresh user config. |

View File

@ -9,7 +9,7 @@ use super::*;
use helix_core::command_line::{Args, Flag, Signature, Token, TokenKind};
use helix_core::fuzzy::fuzzy_match;
use helix_core::indent::MAX_INDENT;
use helix_core::line_ending;
use helix_core::{line_ending, SmartString};
use helix_stdx::path::home_dir;
use helix_view::document::{read_to_string, DEFAULT_LANGUAGE_NAME};
use helix_view::editor::{CloseError, ConfigEvent};
@ -2146,6 +2146,115 @@ fn sort(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> anyhow:
Ok(())
}
fn index(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> anyhow::Result<()> {
if event != PromptEvent::Validate {
return Ok(());
}
let step = if let Some(arg) = args.first() {
arg.parse()
.ok()
.filter(|&step| step != 0)
.context("Step must be a positive integer greater than zero")?
} else {
1
};
let start = if let Some(arg) = args.get_flag("start") {
arg.parse().context("Argument to --start must be an integer")?
} else {
1
};
index_impl(
cx,
args.has_flag("reverse"),
args.has_flag("desc"),
args.has_flag("pad"),
start,
step,
)
}
fn index_impl(
cx: &mut compositor::Context,
reverse: bool,
desc: bool,
pad: bool,
start: isize,
step: usize,
) -> anyhow::Result<()> {
let scrolloff = cx.editor.config().scrolloff;
let (view, doc) = current!(cx.editor);
let text = doc.text().slice(..);
let selection = doc.selection(view.id);
if selection.len() == 1 {
bail!("Sorting requires multiple selections. Hint: split selection first");
}
let mut fragments: Vec<_> = selection
.slices(text)
.map(|fragment| fragment.chunks().collect())
.collect();
let count_selections = fragments.len();
let mut iter: Vec<isize> = if desc {
let start_from = start - ((count_selections - 1) * step) as isize;
(start_from..=start)
.rev()
.step_by(step)
.take(count_selections)
.collect()
} else {
(start..).step_by(step).take(count_selections).collect()
};
if reverse {
iter.reverse();
}
fragments.iter_mut().zip(&iter).for_each(|(frag, index)| {
let index_str = if pad {
let width = iter
.iter()
.map(|&num| {
if num == 0 {
return 1;
}
let width = num.abs().ilog10() as usize + 1;
if num > 0 {
width
} else {
width + 1
}
})
.max()
.unwrap(); // we already checked that we have multiple selections
format!("{:0width$}", index, width = width)
} else {
index.to_string()
};
*frag = SmartString::from(index_str);
});
let transaction = Transaction::change(
doc.text(),
selection
.into_iter()
.zip(fragments)
.map(|(s, fragment)| (s.from(), s.to(), Some(fragment))),
);
doc.apply(&transaction, view.id);
doc.append_changes_to_history(view);
view.ensure_cursor_in_view(doc, scrolloff);
Ok(())
}
fn reflow(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> anyhow::Result<()> {
if event != PromptEvent::Validate {
return Ok(());
@ -3373,6 +3482,43 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
..Signature::DEFAULT
},
},
TypableCommand {
name: "index",
aliases: &["i"],
doc: "Inserts indexes into selections.",
fun: index,
completer: CommandCompleter::none(),
signature: Signature {
positionals: (0, Some(1)),
flags: &[
Flag {
name: "start",
alias: Some('x'),
doc: "Set the starting number to count from",
completions: Some(&[])
},
Flag {
name: "reverse",
alias: Some('r'),
doc: "Index in reverse order",
..Flag::DEFAULT
},
Flag {
name: "desc",
alias: Some('d'),
doc: "Index in descending order",
..Flag::DEFAULT
},
Flag {
name: "pad",
alias: Some('p'),
doc: "Add leading zeros to start",
..Flag::DEFAULT
},
],
..Signature::DEFAULT
},
},
TypableCommand {
name: "reflow",
aliases: &[],