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

add reflow command #2128

Merged
merged 5 commits into from
May 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
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
27 changes: 27 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions book/src/generated/typable-cmd.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
| `:set-option`, `:set` | Set a config option at runtime |
| `:sort` | Sort ranges in selection. |
| `:rsort` | Sort ranges in selection in reverse order. |
| `:reflow` | Hard-wrap the current selection of lines to a given width. |
| `:tree-sitter-subtree`, `:ts-subtree` | Display tree sitter subtree under cursor, primarily for debugging queries. |
| `:config-reload` | Refreshes helix's config. |
| `:config-open` | Open the helix config.toml file. |
1 change: 1 addition & 0 deletions helix-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ encoding_rs = "0.8"
chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] }

etcetera = "0.3"
textwrap = "0.15.0"

[dev-dependencies]
quickcheck = { version = "1", default-features = false }
1 change: 1 addition & 0 deletions helix-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub mod syntax;
pub mod test;
pub mod textobject;
mod transaction;
pub mod wrap;

pub mod unicode {
pub use unicode_general_category as category;
Expand Down
1 change: 1 addition & 0 deletions helix-core/src/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ pub struct LanguageConfiguration {
pub shebangs: Vec<String>, // interpreter(s) associated with language
pub roots: Vec<String>, // these indicate project roots <.git, Cargo.toml>
pub comment_token: Option<String>,
pub max_line_length: Option<usize>,

#[serde(default, skip_serializing, deserialize_with = "deserialize_lsp_config")]
pub config: Option<serde_json::Value>,
Expand Down
7 changes: 7 additions & 0 deletions helix-core/src/wrap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use smartstring::{LazyCompact, SmartString};

/// Given a slice of text, return the text re-wrapped to fit it
/// within the given width.
pub fn reflow_hard_wrap(text: &str, max_line_len: usize) -> SmartString<LazyCompact> {
textwrap::refill(text, max_line_len).into()
}
46 changes: 46 additions & 0 deletions helix-term/src/commands/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,45 @@ fn sort_impl(
Ok(())
}

fn reflow(
cx: &mut compositor::Context,
args: &[Cow<str>],
_event: PromptEvent,
) -> anyhow::Result<()> {
let (view, doc) = current!(cx.editor);

const DEFAULT_MAX_LEN: usize = 79;

// Find the max line length by checking the following sources in order:
// - The passed argument in `args`
// - The configured max_line_len for this language in languages.toml
// - The const default we set above
let max_line_len: usize = args
.get(0)
.map(|num| num.parse::<usize>())
.transpose()?
.or_else(|| {
doc.language_config()
.and_then(|config| config.max_line_length)
})
.unwrap_or(DEFAULT_MAX_LEN);

let rope = doc.text();

let selection = doc.selection(view.id);
let transaction = Transaction::change_by_selection(rope, selection, |range| {
let fragment = range.fragment(rope.slice(..));
let reflowed_text = helix_core::wrap::reflow_hard_wrap(&fragment, max_line_len);

(range.from(), range.to(), Some(reflowed_text))
});

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

Ok(())
}

fn tree_sitter_subtree(
cx: &mut compositor::Context,
_args: &[Cow<str>],
Expand Down Expand Up @@ -1474,6 +1513,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[
fun: sort_reverse,
completer: None,
},
TypableCommand {
name: "reflow",
aliases: &[],
doc: "Hard-wrap the current selection of lines to a given width.",
fun: reflow,
completer: None,
},
Comment on lines +1516 to +1522
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we should just bind it to gq.

Copy link
Member

Choose a reason for hiding this comment

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

gq could be awkward given the goto menu g. We might be able to use = although I think that is currently saving a spot for LSP-driven format.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know any other good bindings for it beside gq which is similar to vim, we might have to tweak goto menu to goto/misc menu

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Seems like this decision shouldn't block the PR. I imagine it's pretty easy to add an alias later.

TypableCommand {
name: "tree-sitter-subtree",
aliases: &["ts-subtree"],
Expand Down