on master help sign in
add reflow command (#2128)
f9bacedVince Mutolo
Cargo.lock+27
@@ -374,6 +374,7 @@ dependencies = [
374 "slotmap",
374 "slotmap",
375 "smallvec",
375 "smallvec",
376 "smartstring",
376 "smartstring",
377+ "textwrap",
377 "toml",
378 "toml",
378 "tree-sitter",
379 "tree-sitter",
379 "unicode-general-category",
380 "unicode-general-category",
@@ -1005,6 +1006,12 @@ dependencies = [
1005 "version_check",
1006 "version_check",
1006]
1007]
1007
1008
1009+[[package]]
1010+name = "smawk"
1011+version = "0.3.1"
1012+source = "registry+https://github.com/rust-lang/crates.io-index"
1013+checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043"
1014+
1008[[package]]
1015[[package]]
1009name = "socket2"
1016name = "socket2"
1010version = "0.4.4"
1017version = "0.4.4"
@@ -1044,6 +1051,17 @@ dependencies = [
1044 "unicode-xid",
1051 "unicode-xid",
1045]
1052]
1046
1053
1054+[[package]]
1055+name = "textwrap"
1056+version = "0.15.0"
1057+source = "registry+https://github.com/rust-lang/crates.io-index"
1058+checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
1059+dependencies = [
1060+ "smawk",
1061+ "unicode-linebreak",
1062+ "unicode-width",
1063+]
1064+
1047[[package]]
1065[[package]]
1048name = "thiserror"
1066name = "thiserror"
1049version = "1.0.30"
1067version = "1.0.30"
@@ -1179,6 +1197,15 @@ version = "0.5.1"
1179source = "registry+https://github.com/rust-lang/crates.io-index"
1197source = "registry+https://github.com/rust-lang/crates.io-index"
1180checksum = "1218098468b8085b19a2824104c70d976491d247ce194bbd9dc77181150cdfd6"
1198checksum = "1218098468b8085b19a2824104c70d976491d247ce194bbd9dc77181150cdfd6"
1181
1199
1200+[[package]]
1201+name = "unicode-linebreak"
1202+version = "0.1.2"
1203+source = "registry+https://github.com/rust-lang/crates.io-index"
1204+checksum = "3a52dcaab0c48d931f7cc8ef826fa51690a08e1ea55117ef26f89864f532383f"
1205+dependencies = [
1206+ "regex",
1207+]
1208+
1182[[package]]
1209[[package]]
1183name = "unicode-normalization"
1210name = "unicode-normalization"
1184version = "0.1.19"
1211version = "0.1.19"
book/src/generated/typable-cmd.md+1
@@ -59,6 +59,7 @@
59| `:get-option`, `:get` | Get the current value of a config option. |
59| `:get-option`, `:get` | Get the current value of a config option. |
60| `:sort` | Sort ranges in selection. |
60| `:sort` | Sort ranges in selection. |
61| `:rsort` | Sort ranges in selection in reverse order. |
61| `:rsort` | Sort ranges in selection in reverse order. |
62+| `:reflow` | Hard-wrap the current selection of lines to a given width. |
62| `:tree-sitter-subtree`, `:ts-subtree` | Display tree sitter subtree under cursor, primarily for debugging queries. |
63| `:tree-sitter-subtree`, `:ts-subtree` | Display tree sitter subtree under cursor, primarily for debugging queries. |
63| `:config-reload` | Refreshes helix's config. |
64| `:config-reload` | Refreshes helix's config. |
64| `:config-open` | Open the helix config.toml file. |
65| `:config-open` | Open the helix config.toml file. |
helix-core/Cargo.toml+1
@@ -41,6 +41,7 @@ encoding_rs = "0.8"
41chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] }
41chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] }
42
42
43etcetera = "0.3"
43etcetera = "0.3"
44+textwrap = "0.15.0"
44
45
45[dev-dependencies]
46[dev-dependencies]
46quickcheck = { version = "1", default-features = false }
47quickcheck = { version = "1", default-features = false }
helix-core/src/lib.rs+1
@@ -27,6 +27,7 @@ pub mod syntax;
27pub mod test;
27pub mod test;
28pub mod textobject;
28pub mod textobject;
29mod transaction;
29mod transaction;
30+pub mod wrap;
30
31
31pub mod unicode {
32pub mod unicode {
32 pub use unicode_general_category as category;
33 pub use unicode_general_category as category;
helix-core/src/syntax.rs+1
@@ -67,6 +67,7 @@ pub struct LanguageConfiguration {
67 pub shebangs: Vec<String>, // interpreter(s) associated with language
67 pub shebangs: Vec<String>, // interpreter(s) associated with language
68 pub roots: Vec<String>, // these indicate project roots <.git, Cargo.toml>
68 pub roots: Vec<String>, // these indicate project roots <.git, Cargo.toml>
69 pub comment_token: Option<String>,
69 pub comment_token: Option<String>,
70+ pub max_line_length: Option<usize>,
70
71
71 #[serde(default, skip_serializing, deserialize_with = "deserialize_lsp_config")]
72 #[serde(default, skip_serializing, deserialize_with = "deserialize_lsp_config")]
72 pub config: Option<serde_json::Value>,
73 pub config: Option<serde_json::Value>,
helix-core/src/wrap.rsnew file+7
@@ -0,0 +1,7 @@
1+use smartstring::{LazyCompact, SmartString};
2+
3+/// Given a slice of text, return the text re-wrapped to fit it
4+/// within the given width.
5+pub fn reflow_hard_wrap(text: &str, max_line_len: usize) -> SmartString<LazyCompact> {
6+ textwrap::refill(text, max_line_len).into()
7+}
helix-term/src/commands/typed.rs+46
@@ -1051,6 +1051,45 @@ fn sort_impl(
1051 Ok(())
1051 Ok(())
1052}
1052}
1053
1053
1054+fn reflow(
1055+ cx: &mut compositor::Context,
1056+ args: &[Cow<str>],
1057+ _event: PromptEvent,
1058+) -> anyhow::Result<()> {
1059+ let (view, doc) = current!(cx.editor);
1060+
1061+ const DEFAULT_MAX_LEN: usize = 79;
1062+
1063+ // Find the max line length by checking the following sources in order:
1064+ // - The passed argument in `args`
1065+ // - The configured max_line_len for this language in languages.toml
1066+ // - The const default we set above
1067+ let max_line_len: usize = args
1068+ .get(0)
1069+ .map(|num| num.parse::<usize>())
1070+ .transpose()?
1071+ .or_else(|| {
1072+ doc.language_config()
1073+ .and_then(|config| config.max_line_length)
1074+ })
1075+ .unwrap_or(DEFAULT_MAX_LEN);
1076+
1077+ let rope = doc.text();
1078+
1079+ let selection = doc.selection(view.id);
1080+ let transaction = Transaction::change_by_selection(rope, selection, |range| {
1081+ let fragment = range.fragment(rope.slice(..));
1082+ let reflowed_text = helix_core::wrap::reflow_hard_wrap(&fragment, max_line_len);
1083+
1084+ (range.from(), range.to(), Some(reflowed_text))
1085+ });
1086+
1087+ doc.apply(&transaction, view.id);
1088+ doc.append_changes_to_history(view.id);
1089+
1090+ Ok(())
1091+}
1092+
1054fn tree_sitter_subtree(
1093fn tree_sitter_subtree(
1055 cx: &mut compositor::Context,
1094 cx: &mut compositor::Context,
1056 _args: &[Cow<str>],
1095 _args: &[Cow<str>],
@@ -1570,6 +1609,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
1570 fun: sort_reverse,
1609 fun: sort_reverse,
1571 completer: None,
1610 completer: None,
1572 },
1611 },
1612+ TypableCommand {
1613+ name: "reflow",
1614+ aliases: &[],
1615+ doc: "Hard-wrap the current selection of lines to a given width.",
1616+ fun: reflow,
1617+ completer: None,
1618+ },
1573 TypableCommand {
1619 TypableCommand {
1574 name: "tree-sitter-subtree",
1620 name: "tree-sitter-subtree",
1575 aliases: &["ts-subtree"],
1621 aliases: &["ts-subtree"],