-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
add reflow command #2128
Changes from 4 commits
78b18f9
a3127d4
e8c84a5
363113e
d6c2996
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1012,6 +1012,37 @@ fn sort_impl( | |
Ok(()) | ||
} | ||
|
||
fn reflow( | ||
cx: &mut compositor::Context, | ||
args: &[Cow<str>], | ||
_event: PromptEvent, | ||
) -> anyhow::Result<()> { | ||
// TODO: Can we instead take an Option<Cow<str>>, and then if the user | ||
// doesn't pass in a selection, default to 79 characters per line? | ||
|
||
const DEFAULT_MAX_LEN: Cow<'static, str> = Cow::Borrowed("79"); | ||
let max_line_len: usize = args.get(0).unwrap_or(&DEFAULT_MAX_LEN).parse()?; | ||
|
||
let (view, doc) = current!(cx.editor); | ||
let rope = doc.text(); | ||
|
||
// TODO: If only a single character is selected, we should expand the | ||
// selection to whatever "object" (can we use treesitter for this? text query?) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would be tricky because of inconsistencies between grammars. For example, in Rust, each line in a comment is a separate node, so it would just end up reflowing a single line, instead of all the consecutive lines of comments together. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, that's interesting. We can scrap this TODO, then. Plus, if we have a way of "expanding" the selection to a comment block or something, then we basically achieve the same effect because this operates on selections. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think we probably also want to ignore comment in the reflow, at least it should be as convenient as vim, also note that rust supports quite a few form of comments and that should be handled as well here, like My experience with kakoune using external There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The library we're using ( // A B
// C D E F and it reflowed to: // A B C D E F We fall down a bit in trying to reflow from one line to many, since the library we're using can't detect the comment prefix when it's not repeated. We also still have an issue where the library will eat blank lines and reflow across them. I'd file both of those points under "future work" on this feature. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, that's future work. It could be defined in a language.toml as something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey folks! Textwrap author here :-) It's super cool to see I wrote There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mgeisler textwrap is an awesome library! I started to implement this feature myself before I was aware textwrap existed, so I have a bit of an idea of the work that went into a more comprehensive solution. And the optimal line breaking is just really cool. Re: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! I think we should do exactly that: change the API of |
||
// that single selection is part of. | ||
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>], | ||
|
@@ -1474,6 +1505,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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we should just bind it to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know any other good bindings for it beside There was a problem hiding this comment. Choose a reason for hiding this commentThe 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"], | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe not necessarily in this PR, but it might also be cool to add a config option to set the default max line width if you prefer a wider width, but don't want to give it explicitly every time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. I can add that real quick to this PR, and clean up some of the comments and TODOs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this should be set on a global config especially when different languages very likely have different width, notably
I think this should be within
languages.toml
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes to me, and I included it in the version I just pushed.
Any opinions on the name of the config value? I made it a top-level key called
max_line_length
and it currently gets parsed to ausize
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
line_wrapping_width
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can add some sensible defaults for the languages.toml like rust 100.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I'll have to look into that. Any tips on where those defaults might go? I was a bit confused by the code that processes the
languages.toml
file.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Go to
That is just an example, I think the variable name may not the that.