profile
viewpoint

mgeisler/cram 4

Go port of Cram

mgeisler/easymr 1

Easy map-reduce framework for ZeroCloud

mgeisler/agouti 0

A WebDriver client and acceptance testing library for Go

mgeisler/aho-corasick 0

A fast implementation of Aho-Corasick in Rust.

mgeisler/amazon-ecs-plugin 0

Amazon EC2 Container Service Plugin for Jenkins

mgeisler/ammonia 0

An HTML sanitizer

mgeisler/angular.js 0

HTML enhanced for web apps

mgeisler/api-guidelines 0

https://rust-lang-nursery.github.io/api-guidelines/

mgeisler/arsert 0

Fancy (received pronunciation) assertions with automatic debug information for failures

mgeisler/askama 0

Type-safe, compiled Jinja-like templates for Rust

pull request commentmgeisler/textwrap

Blanket impl for types that deref to WordSplitter

Hey @Benjamin-L,

Okay, no worries! Perhaps we can add some more pointers to the hyphenation feature so it's easier to find?

Benjamin-L

comment created time in 2 days

issue commentmgeisler/textwrap

Support for columns

That's perfectly fine, no promises needed! I'll simply let the issue be open in case you find time :smile:

wucke13

comment created time in 3 days

issue commentmgeisler/textwrap

Forbid unsafe code

Hi @ralpha okay, thanks for the link to the Rust Safety Dance, looks like a very useful resource!

I've added the attribute and will definitely be careful if I ever add some unsafe code.

ralpha

comment created time in 4 days

push eventmgeisler/textwrap

Martin Geisler

commit sha fc86550d969a7ca574a12687b78855715df4e239

Forbid the use of unsafe code We currently don't have any unsafe code in `textwrap` -- adding this attribute ensure that we'll think careful about it before adding any. Fixes #210.

view details

Martin Geisler

commit sha c708b787d5da0920c804e9cc532775f7ceb43419

Merge pull request #216 from mgeisler/forbid-unsafe-code Forbid the use of unsafe code

view details

push time in 4 days

PR merged mgeisler/textwrap

Forbid the use of unsafe code

We currently don't have any unsafe code in textwrap -- adding this attribute ensure that we'll think careful about it before adding any. The Rust Safety Dance project promises to be a great resource in ensuring that any unsafe code added is, infact, safe.

Fixes #210.

+1 -0

0 comment

1 changed file

mgeisler

pr closed time in 4 days

issue closedmgeisler/textwrap

Forbid unsafe code

textwrap does not seem to use unsafe code, which is very good :)

To prevent this from ever happening, add following line to the top:

#![forbid(unsafe_code)]

of https://github.com/mgeisler/textwrap/blob/master/src/lib.rs

This will make the package green in https://github.com/rust-secure-code/cargo-geiger

closed time in 4 days

ralpha

PR opened mgeisler/textwrap

Forbid the use of unsafe code

We currently don't have any unsafe code in textwrap -- adding this attribute ensure that we'll think careful about it before adding any.

Fixes #210.

+1 -0

0 comment

1 changed file

pr created time in 4 days

create barnchmgeisler/textwrap

branch : forbid-unsafe-code

created branch time in 4 days

issue commentmgeisler/textwrap

Support for columns

Hi @wucke13 — I'm sorry, I forgot to reply back to you!

Yes, I think it's pretty clear what you mean and I think your function signature is great! I like the general &str arguments for the gaps. I would call it wrap_columns to clearly relate it to the existing wrap function.

The way I generated the example above was to wrap the text at 12 columns and then simply copy-paste the wrapped lines from the second half after the first half.

So I think it should be possible to implement this by first wrapping the text using the column with given (so total_width: usize should actually be options: WrapOptions now, just like wrap). Then collect the wrapped lines into a Vec<Cow<'_, str>>, count the number of lines finally rearrange the lines. I don't know if your HashMap<String, String> code above does something similar?

Here is a sketch of what I have in mind:

let wrapped_lines = wrap(text, options).collect::<Vec<_>>();
let lines_per_column = wrapped_lines.len() / columns; // Need to round this up 
let columns = Vec::new();
for line_no in 0..lines_per_column {
    let mut line = String::from(left_gap);
    for column_no in 0..columns {
        line.push_str(lines[line_no + column_no * lines_per_column]);
        if column_no < columns - 1 {
            line.push_str(mid_gap);
        }
    }
    line.push_str(right_gap);
    columns.push(line);
}

There are certainly rounding errors in this :smile: Also, it just occured to me that the lines would need padding, just like you do above with format!...

Would you be up for implementing this? It would need some documentation, tests, etc...

wucke13

comment created time in 4 days

pull request commentmgeisler/textwrap

Make indent preserve the of \n in the input string (stop adding a trailing \n)

I just noticed that a stabilization PR has been put up for the split_inclusive feature: https://github.com/rust-lang/rust/pull/77858 — I'm not sure how long it will take to be reviewed, though.

jRimbault

comment created time in 4 days

issue commentrust-lang/rust

Tracking Issue for split_inclusive

A stabilization PR has been put up for the split_inclusive feature: https://github.com/rust-lang/rust/pull/77858 — I'm not sure how long it will take to be reviewed, though.

golddranks

comment created time in 4 days

pull request commentmgeisler/textwrap

Reintroducing the type parameter on `Options` (previously known as `Wrapper`).

Thanks for writing a great commit message in your first commit — if you could squash the formatting commit into the first, then I'll be happy to merge this.

No big hurry, though, since I also want to redo the internal wrapping algorithm before I make a new release. I hope to have this out in a week or so.

Cryptjar

comment created time in 4 days

Pull request review commentmgeisler/textwrap

Reintroducing the type parameter on `Options` (previously known as `Wrapper`).

 pub trait WordSplitter: std::fmt::Debug {     fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)>; } +impl WordSplitter for Box<dyn WordSplitter> {+    fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)> {+        use std::ops::Deref;+        self.deref().split(word)+    }+}+/* Alternative, also adds impls for specific Box<S> i.e. Box<HyphenSplitter>

I'll be happy to simply leave this out for now and then merge the rest — then we can make forward progress.

Cryptjar

comment created time in 4 days

PullRequestReviewEvent

Pull request review commentmgeisler/textwrap

Reintroducing the type parameter on `Options` (previously known as `Wrapper`).

 pub trait WordSplitter: std::fmt::Debug {     fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)>; } +impl WordSplitter for Box<dyn WordSplitter> {+    fn split<'w>(&self, word: &'w str) -> Vec<(&'w str, &'w str, &'w str)> {+        use std::ops::Deref;+        self.deref().split(word)+    }+}+/* Alternative, also adds impls for specific Box<S> i.e. Box<HyphenSplitter>

Ah, this was the example you mentioned in your PR description. I'm not sure exactly what the pros/cons are of these two options.

Cryptjar

comment created time in 4 days

PullRequestReviewEvent

Pull request review commentmgeisler/textwrap

Reintroducing the type parameter on `Options` (previously known as `Wrapper`).

 impl<'a> Options<'a> {     /// **Note:** Only available when the `terminal_size` feature is     /// enabled.     #[cfg(feature = "terminal_size")]-    pub fn with_termwidth() -> Options<'static> {-        Options::new(termwidth())+    pub fn with_termwidth() -> Self {+        Self::new(termwidth())+    }+}+impl<'a, S> Options<'a, S> {+    /// Creates a new `Options` with the specified width and splitter. Equivalent

Could you expand the docstring a little to explain why this constructor is necessary or better than using new() followed by splitter()?

Cryptjar

comment created time in 4 days

PullRequestReviewEvent

pull request commentmgeisler/textwrap

Reintroducing the type parameter on `Options` (previously known as `Wrapper`).

Hi @Cryptjar,

Thanks for catching this! I had not thought about how changing to Box<dyn WordSplitter> would take away functionality, so thanks for restoring it!

As for your questions,

  • The name of Options::new_const could be changed (maybe to new_static). [...] Yet another alternative, would be to just remove Options::new_const, since the fundamental use-case (const fn) is also covered by Options::with_splitter.

The situation that I to avoid is code like this

enum Wrapper {
    H(textwrap::Wrapper<'static, Standard>),
    N(textwrap::Wrapper<'static, textwrap::NoHyphenation>),
}

from gst-plugins-rs, discussed in #178.

I think I would lean towards let Options::new return a Options<Box<dyn WordSplitter>> by default so that all options can be changed in a uniform way afterwards. The Options::with_splitter constructor would then be the way to go if you want a hard-coded type.

  • Whether to implement WordSplitter only for Box<dyn WordSplitter> or for all Box<S>

Are you suggesting adding an implementation for Box<S> where S: WordSplitter? I'm not quite sure what the implication of thi is, but if it makes it easier for people to use the library, then I'm all for it :-)

  • Whether to implement splitter setter method only on the dynamic dispatch variant (aka Options<Box<dyn WordSplitter>>). Then, it might also take an arbitrary impl WordSplitter by value and put it into a Box.

Yeah, good question... I've so far though of the setter method as a builder method — something to use when contructing the Options. I was then thinking people would simply assign to the struct fields afterwards if something should be changed. I figured this would be the simplest API overall.

However, I'm very much curious to hear of better ways to design this.

  • Now, it is also possible to make Options Clone again. Well, at least where the type parameter is Clone, which it isn't for the default Box<dyn WordSplitter>.

That would be nice :+1:

Cryptjar

comment created time in 4 days

issue commentmgeisler/textwrap

Allow the use of the library outside of the context of the terminal

I’m not quite sure about the parametrization. If you don’t want to have the length type as a type parameter, does that mean you’d perform all internal calculations with a f64? This could be problematic because generally speaking, you can’t convert a usize to a f64.

Right, that would be troublesome. I think it's fine to have Options<T>. The minor problem I was talking about is that you wouldn't be able to do something like this:

// Simple ASCII-only width provider, returns u16:
let options = Options::new(80).set_width_provider(|word| word.len() as u16);
...
// Fancy width provider, returns f64:
options.set_width_provider(|word| some_font_lib::measure_text(word).width());

since options would be "locked" to Options<u16> after the first line. A similar thing happened (happens) with the Wrapper<T: WordSplitter> API — which I got rid of in #213. However, I don't think this is a real problem since I expect people to stick to one type for their width measurements.

So let's say it's fine to parameterize WrapOptions. I think it could be an associated type which we can use in a method called, say, measure:

pub trait WrapOptions {
    type Width;

    fn measure<'w>(&self, word: &'w str) -> Self::Width;
}

When dealing with rich text, the string width also depends on the formatting (font family, font style, font size, ...). There might be different styles within a paragraph. So there should be an option to wrap arbitrary types that implement a Wrappable (?) trait (or, more precisely, a vector/slice/iterator of such elements).

Yes, that's a great point! My experimental code is exactly trying to abstract away such things by only manipulating words and lines. Putting it behind a trait sounds like just right thing to do.

So far I'm structuring the code so that a first pass finds the words and a second pass creates lines as necessary. So the "words" could also come from somewhere external. I'll try to put it up as soon as possible.

Moxinilian

comment created time in 11 days

issue commentmgeisler/textwrap

Allow the use of the library outside of the context of the terminal

I'm also currently working on completely rewriting the internals so that the code is much less tied to characters/graphemes. Instead, I'm trying to let the code operate in terms of Line and Word structs:

pub struct Word {
    idx: usize,   // Index into current line
    len: usize,   // Lenght in bytes
    width: usize, // Width in columns, including trailing whitespace
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Line {
    idx: usize,   // Index into text
    len: usize,   // Length in bytes
    width: usize, // Width in columns
}

The two width fields could then be T instead.

Moxinilian

comment created time in 11 days

issue commentmgeisler/textwrap

Allow the use of the library outside of the context of the terminal

Hi @Moxinilian and @robinkrahl, as mentioned in #128, I would still like to see textwrap used outside the context of the terminal. So some way of measuring the displayed width of non-console text seems like a great first step.

As mentioned in https://github.com/mgeisler/textwrap/pull/128#issuecomment-711286080, I could imagine expanding the WrapOptions trait with a width(&str) -> T method, which would measure a single word, or rather a grapheme, since I want to start using graphemes as the unit when breaking apart long words.

The implementation of WrapOptions for usize would then change to something along the lines of

impl WrapOptions<usize> for usize {
    fn width(&self, word: &str) -> usize {
        word.width()
    }
}

Writing this makes me realize that there is already a width() -> usize method on the WrapOptions trait :smile: That's a bit silly, so we would need a better word for one of the two...

The Options struct could be parameterized by T and it could gain a width_provider method which takes a closure which measures the width. This would move us back towards the old API where Wrapper<T> was parameterized on the type of "word splitter" used.

An annoying consequence of that was that it was hard to create a program which would dynamically change concrete type of WordSplitter used — you locked yourself into one kind of WordSplitter when you first created your Wrapper struct. The new Options avoids this by instead holding a Box<dyn WordSplitter>. That works because all word splitters have the same API, so I don't know if the same technique will work smoothly when the closures differ in return type?

Moxinilian

comment created time in 11 days

PR closed mgeisler/textwrap

Added support for custom width providers

This is part of the ongoing effort to support #126 This PR offers a way to set custom (integer) widths for characters. It does not add support for floating point numbers yet. This allows the user to pass to most functions a closure taking a char and returning its width as a usize. I tried to limit API changes for simple tasks by leaving the fill and wrap functions intact in signature, and added wrap_dynamic and fill_dynamic that take the closure. I was not really inspired with those names, if you want me to change them to something else I would be glad to do it. I also chose to re-export unicode_width::UnicodeWidthChar as it will probably come in handy for people writing custom closures, avoiding them to depend on unicode_width.

Example:

let wrap = Wrapper::new(15);
let res = wrap.wrap_dynamic("Concurrency without data races.", |c| {
    if c == 'h' {
        c.width().unwrap_or(0) + 4
    } else {
        c.width().unwrap_or(0)
    }
});
assert_eq!(res, vec!["Concurrency", "without", "data races."]);

This example illustrates an hypothetical case where an h would actually take 5 columns instead of 1. I included it as a test, with its equivalent for Wrapper::fill_dynamic.

Benchmark:

before
test fill_100 ... bench:         539 ns/iter (+/- 115)
test fill_200 ... bench:       1,188 ns/iter (+/- 141)
test fill_400 ... bench:       2,416 ns/iter (+/- 329)
test fill_800 ... bench:       5,349 ns/iter (+/- 974)
test wrap_100 ... bench:         639 ns/iter (+/- 111)
test wrap_200 ... bench:       1,397 ns/iter (+/- 206)
test wrap_400 ... bench:       2,729 ns/iter (+/- 405)
test wrap_800 ... bench:       5,575 ns/iter (+/- 664)

after
test fill_100 ... bench:         554 ns/iter (+/- 139)
test fill_200 ... bench:       1,199 ns/iter (+/- 145)
test fill_400 ... bench:       2,409 ns/iter (+/- 1,570)
test fill_800 ... bench:       5,142 ns/iter (+/- 658)
test wrap_100 ... bench:         632 ns/iter (+/- 113)
test wrap_200 ... bench:       1,430 ns/iter (+/- 221)
test wrap_400 ... bench:       2,732 ns/iter (+/- 323)
test wrap_800 ... bench:       5,417 ns/iter (+/- 456)

Zero-cost abstraction really is awesome.

+165 -41

10 comments

1 changed file

Moxinilian

pr closed time in 11 days

pull request commentmgeisler/textwrap

Added support for custom width providers

Hi @robinkrahl, I think this PR has stalled, but I would still like to see this kind of feature implemented. @Moxinilian, if you're still interested in this, then please let us know!

I recently rewrote some of the inner parts of textwrap (#213), so I think this PR should be closed and then a new one could be opened to fit with the new API. Ideally, this change should be invisible at the surface-level of the API, so that one can continue to write

let lines = wrap("some text", 80);

Perhaps the WrapOptions trait could gain a width(&str) -> T method, where T can be usize, float, or even u16 as needed (I mention u16 since the terminal_size crate measures the width in u16, which makes me think that it's completely overkill to use usize all over).

Let me close this PR for now and then we can perhaps discuss more in #126.

Moxinilian

comment created time in 11 days

issue commentmgeisler/textwrap

Support for tabs and hanging indent

Thanks, that's good feedback! I think I need a Features section somewhere on the first page you see in the documentation. Like this:

Features

  • Supports Unicode characters and emojis.
  • Support for hanging indentation via the initial_indent and subsequent_indent.
  • Automatic handling of ANSI color codes.
  • more stuff as I think of it :-)

I'll keep the issue open so I remember to update the documentation like this before the next release.

cmcqueen

comment created time in 14 days

push eventmgeisler/textwrap

Martin Geisler

commit sha 5820ce3cf1faa66136b1cbcd2d9d14859b5ed64f

Fix documentation for wrap The first part of the documentation was lost by accident in #213.

view details

Martin Geisler

commit sha e49a2a3366ff776877d4454e5637f60b7ff6d6bb

Merge pull request #214 from mgeisler/doc-fixes Fix documentation for wrap

view details

push time in 14 days

PR merged mgeisler/textwrap

Fix documentation for wrap

The first part of the documentation was lost by accident in #213.

+13 -0

0 comment

1 changed file

mgeisler

pr closed time in 14 days

PR opened mgeisler/textwrap

Fix documentation for wrap

The first part of the documentation was lost by accident in #213.

+13 -0

0 comment

1 changed file

pr created time in 16 days

create barnchmgeisler/textwrap

branch : doc-fixes

created branch time in 16 days

Pull request review commentmgeisler/textwrap

Make indent preserve the of \n in the input string (stop adding a trailing \n)

 mod tests {     #[test]     #[rustfmt::skip]     fn indent_nonempty() {-        let x = vec!["  foo",-                     "bar",-                     "  baz"];-        let y = vec!["//  foo",-                     "//bar",-                     "//  baz"];-        assert_eq!(indent(&add_nl(&x), "//"), add_nl(&y));+        let text = r##"  foo

Thanks, the explicit lists look good!

Can I get you to squash all your commits into a single commit with a commit message such as

Make indent preserve the lack of a trailing \n

Before, indent("foo", " ") would give " foo\n". It now preserves any trailing \n present in the input string. This makes indent behave consistently with dedent. New tests were added to ensure this on a number of corner cases.

You could also mention that we now require Rust version N.NN (when we know this at some point).

jRimbault

comment created time in a month

PullRequestReviewEvent

push eventmgeisler/textwrap

Martin Geisler

commit sha dcd322cf6681bfac5d2ea6cef9ce003c0a0e567a

Replace the wrap function with wrap_iter The wrap and wrap_iter functions both return lines of wrapped text. The difference is that wrap_iter return an iterator, whereas wrap collects the lines into a vector.

view details

Martin Geisler

commit sha 9274f255a301b83f38b7b5048ed3426e9468c9a8

Remove Wrapper::into_wrap_iter method It was only used from textwrap::wrap and removing it makes our API leaner without losing expressive power.

view details

Martin Geisler

commit sha 835d1904960bc2d62eefbd5ce37dceede525ce08

Replace Wrapper struct with Options This is a breaking change which simplifies and streamlines the API in several ways: * Instead of having both Wrapper::wrap and a top-level wrap function, we now only have the wrap function. This should simplify things a little since there is now just one way to use the API. * The Wrapper struct has been turned into an Options struct, which carries all the configuration settings. * The API of the wrap and fill functions have changed in a backwards compatible fashion. They still take a string and a width: textwrap::fill("some string", 10); * In addition to an usize width, you can now also pass Options as the second argument: textwrap::fill("some string", Options::new(10).break_words(false));

view details

Martin Geisler

commit sha d81f434a25845a1219f847d7dafb2ecb72634d2b

Merge pull request #213 from mgeisler/simplify-api Simplify API with only top-level functions

view details

push time in a month

PR merged mgeisler/textwrap

Simplify API with only top-level functions

This is a breaking change which simplifies and stream-lines the API in several ways:

  • Instead of having both Wrapper::wrap and a top-level textwrap::wrap function, we now only have the textwrap::wrap function. This should simplify things a little since there is now just one way to use the API.

  • The Wrapper struct has been turned into an Options struct.

  • The API of textwrap::wrap and textwrap::fill functions have changed in a backwards compatible fashion. They still take a string and a width:

    textwrap::fill("some string", 10);
    
  • In addition to a usize width, you can now also pass Options as the second argument:

    textwrap::fill("some string", Options::new(10).break_words(false));
    

Migration from using Wrapper is simple: change a call to Wrapper::fill to fill:

use textwrap::Wrapper;
let wrapper = Wrapper::new(10).initial_indent("  ");
wrapper.fill("some string")

into

use textwrap::{Options, fill};
let options = Options::new(10).initial_indent("  ");
fill("some string", &options)
+400 -445

0 comment

7 changed files

mgeisler

pr closed time in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha dcd322cf6681bfac5d2ea6cef9ce003c0a0e567a

Replace the wrap function with wrap_iter The wrap and wrap_iter functions both return lines of wrapped text. The difference is that wrap_iter return an iterator, whereas wrap collects the lines into a vector.

view details

Martin Geisler

commit sha 9274f255a301b83f38b7b5048ed3426e9468c9a8

Remove Wrapper::into_wrap_iter method It was only used from textwrap::wrap and removing it makes our API leaner without losing expressive power.

view details

Martin Geisler

commit sha 835d1904960bc2d62eefbd5ce37dceede525ce08

Replace Wrapper struct with Options This is a breaking change which simplifies and streamlines the API in several ways: * Instead of having both Wrapper::wrap and a top-level wrap function, we now only have the wrap function. This should simplify things a little since there is now just one way to use the API. * The Wrapper struct has been turned into an Options struct, which carries all the configuration settings. * The API of the wrap and fill functions have changed in a backwards compatible fashion. They still take a string and a width: textwrap::fill("some string", 10); * In addition to an usize width, you can now also pass Options as the second argument: textwrap::fill("some string", Options::new(10).break_words(false));

view details

push time in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha e8456919b58b11ac8ff40b3cbae7fbc6c55fbfcf

Replace Wrapper struct with Options This is a breaking change which simplifies and streamlines the API in several ways: * Instead of having both Wrapper::wrap and a top-level wrap function, we now only have the wrap function. This should simplify things a little since there is now just one way to use the API. * The Wrapper struct has been turned into an Options struct, which carries all the configuration settings. * The API of the wrap and fill functions have changed in a backwards compatible fashion. They still take a string and a width: textwrap::fill("some string", 10); * In addition to an usize width, you can now also pass Options as the second argument: textwrap::fill("some string", Options::new(10).break_words(false));

view details

push time in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha 13a1dc18a91946e58069d0eafc375f85cc4b5630

Replace the wrap function with wrap_iter The wrap and wrap_iter functions both return lines of wrapped text. The difference is that wrap_iter return an iterator, whereas wrap collects the lines into a vector.

view details

Martin Geisler

commit sha b6d689a82487c6340a6563eb6e0accc35273aa62

Remove Wrapper::into_wrap_iter method It was only used from textwrap::wrap and removing it makes our API leaner without losing expressive power.

view details

Martin Geisler

commit sha dfb7b462ad4e24683316f9d30f6888722518bda9

Remove Wrapper struct from API, replace with Options This is a breaking change which simplifies and stream-lines the API in several ways: * Instead of having both `Wrapper::wrap` and a top-level `textwrap::wrap` function, we now only have the `textwrap::wrap` function. This should simplify things a little since there is now just one way to use the API. * The `Wrapper` struct has been turned into an `Options` struct. * The API of `textwrap::wrap` and `textwrap::fill` functions have changed in a backwards compatible fashion. They still take a string and a width: textwrap::fill("some string", 10); * In addition to a `usize` width, you can now also pass `Options` as the second argument: textwrap::fill("some string", Options::new(10).break_words(false));

view details

push time in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha 4b7a6647db8dcd9a29352bbdbc0301ba06c40481

Remove Wrapper struct from API, replace with Options This is a breaking change which simplifies and stream-lines the API in several ways: * Instead of having both `Wrapper::wrap` and a top-level `textwrap::wrap` function, we now only have the `textwrap::wrap` function. This should simplify things a little since there is now just one way to use the API. * The `Wrapper` struct has been turned into an `Options` struct. * The API of `textwrap::wrap` and `textwrap::fill` functions have changed in a backwards compatible fashion. They still take a string and a width: textwrap::fill("some string", 10); * In addition to a `usize` width, you can now also pass `Options` as the second argument: textwrap::fill("some string", Options::new(10).break_words(false));

view details

push time in a month

Pull request review commentmgeisler/textwrap

Make indent preserve the of \n in the input string (stop adding a trailing \n)

 mod tests {     #[test]     #[rustfmt::skip]     fn indent_nonempty() {-        let x = vec!["  foo",-                     "bar",-                     "  baz"];-        let y = vec!["//  foo",-                     "//bar",-                     "//  baz"];-        assert_eq!(indent(&add_nl(&x), "//"), add_nl(&y));+        let text = r##"  foo

Hmm... yeah, good question. I guess the most direct way would be to include things like \n in the strings, and then join them without adding a separator. So perhaps we can throw out the add_nl function and let the tests be explicit:

        let lines = &[
            "foo\n", //
            "bar\n",
        ];
        let expected = &[
            "  foo\n", //
            "  bar\n",
        ];
        assert_eq!(&indent(&lines.join(""), "  "), &expected.join("")); 
``

the `//` makes `rustfmt` align things consistently so that it is easy to compare the two lists visually. I like that each line is shown in full, with escape characters and everything. Trailing whitespace would then be

```rust
        let lines = &[
            "foo  \n", //
            "bar    ",
        ];
        let expected = &[
            "  foo  \n", //
            "  bar    ",
        ];
        assert_eq!(&indent(&lines.join(""), "  "), &expected.join("")); 
``

If you want, you could try updating the existing tests to use this scheme. It would be a good preparation for this PR.
jRimbault

comment created time in a month

PullRequestReviewEvent

Pull request review commentmgeisler/textwrap

Make indent preserve the of \n in the input string (stop adding a trailing \n)

 /// ``` /// use textwrap::indent; ///-/// assert_eq!(indent(" \t  Foo   ", "->"), "-> \t  Foo   \n");+/// assert_eq!(indent(" \t  Foo   ", "->"), "-> \t  Foo   "); /// ``` pub fn indent(s: &str, prefix: &str) -> String {-    let mut result = String::new();-    for line in s.lines() {-        if line.chars().any(|c| !c.is_whitespace()) {-            result.push_str(prefix);-            result.push_str(line);+    let mut output = String::new();++    for line in s.split_inclusive('\n') {+        if line.trim_start().len() == 0 {+            output.push_str(line);+        } else {+            output.push_str(prefix);+            output.push_str(line);

Well, it's almost the same in both cases :smile:

jRimbault

comment created time in a month

PullRequestReviewEvent

push eventmgeisler/textwrap

Martin Geisler

commit sha 819a426cf7f0d1197cf344ee250d5878090341e1

Remove Wrapper struct from API, replace with Options This is a breaking change which simplifies and stream-lines the API in several ways: * Instead of having both `Wrapper::wrap` and a top-level `textwrap::wrap` function, we now only have the `textwrap::wrap` function. This should simplify things a little since there is now just one way to use the API. * The `Wrapper` struct has been turned into an `Options` struct. * The API of `textwrap::wrap` and `textwrap::fill` functions have changed in a backwards compatible fashion. They still take a string and a width: textwrap::fill("some string", 10); * In addition to a `usize` width, you can now also pass `Options` as the second argument: textwrap::fill("some string", Options::new(10).break_words(false));

view details

push time in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha 6c768f9f6aab0ad5706356a88fe9d7f45759e346

Remove Wrapper struct from API, replace with Options This is a breaking change which simplifies and stream-lines the API in several ways: * Instead of having both `Wrapper::wrap` and a top-level `textwrap::wrap` function, we now only have the `textwrap::wrap` function. This should simplify things a little since there is now just one way to use the API. * The `Wrapper` struct has been turned into an `Options` struct. * The API of `textwrap::wrap` and `textwrap::fill` functions have changed in a backwards compatible fashion. They still take a string and a width: textwrap::fill("some string", 10); * In addition to a `usize` width, you can now also pass `Options` as the second argument: textwrap::fill("some string", Options::new(10).break_words(false));

view details

push time in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha bde7d5a26c5337a19f9010c757fce205eb63f1d2

Remove Wrapper struct from API, replace with Options This is a breaking change which simplifies and stream-lines the API in several ways: * Instead of having both `Wrapper::wrap` and a top-level `textwrap::wrap` function, we now only have the `textwrap::wrap` function. This should simplify things a little since there is now just one way to use the API. * The `Wrapper` struct has been turned into an `Options` struct. * The API of `textwrap::wrap` and `textwrap::fill` functions have changed in a backwards compatible fashion. They still take a string and a width: textwrap::fill("some string", 10); * In addition to a `usize` width, you can now also pass `Options` as the second argument: textwrap::fill("some string", Options::new(10).break_words(false));

view details

push time in a month

issue commentmgeisler/textwrap

Forbid unsafe code

Hey @ralpha, I'm actually considering introducing a function that will use a bit of unsafe code to cheaply wrap a string inplace (as discussed in #166. Such a line would then need to go.

If a dependency has both safe and unsafe functions, can cargo geiger then tell me if I only call code in the safe subset of my dependencies? Or is a dependency flagged as "safe" or "unsafe" as a whole?

ralpha

comment created time in a month

Pull request review commentmgeisler/textwrap

Make indent preserve the of \n in the input string (stop adding a trailing \n)

 mod tests {     #[test]     #[rustfmt::skip]     fn indent_nonempty() {-        let x = vec!["  foo",-                     "bar",-                     "  baz"];-        let y = vec!["//  foo",-                     "//bar",-                     "//  baz"];-        assert_eq!(indent(&add_nl(&x), "//"), add_nl(&y));+        let text = r##"  foo

I tried to use the add_nl helper function together with a vector to align the lines in the source code and to make it crystal clear if a string has trailing whitespace. I would prefer to keep this somehow, but I'm open for better ways of doing it :-)

jRimbault

comment created time in a month

PullRequestReviewEvent

Pull request review commentmgeisler/textwrap

Make indent preserve the of \n in the input string (stop adding a trailing \n)

 mod tests {     /// Add newlines. Ensures that the final line in the vector also     /// has a newline.

The comment is outdated now.

jRimbault

comment created time in a month

PullRequestReviewEvent

Pull request review commentmgeisler/textwrap

Make indent preserve the of \n in the input string (stop adding a trailing \n)

 /// ``` /// use textwrap::indent; ///-/// assert_eq!(indent(" \t  Foo   ", "->"), "-> \t  Foo   \n");+/// assert_eq!(indent(" \t  Foo   ", "->"), "-> \t  Foo   "); /// ``` pub fn indent(s: &str, prefix: &str) -> String {-    let mut result = String::new();-    for line in s.lines() {-        if line.chars().any(|c| !c.is_whitespace()) {-            result.push_str(prefix);-            result.push_str(line);+    let mut output = String::new();++    for line in s.split_inclusive('\n') {+        if line.trim_start().len() == 0 {+            output.push_str(line);+        } else {+            output.push_str(prefix);+            output.push_str(line);

Perhaps it would be a tiny bit simpler to do

if (!line.trim().is_empty()) {
  output.push_str(prefix);
}
output.push_str(line);

I think that should do the same: conditionally add the prefix, unconditionally add the line including any trailing whitespace in the line.

jRimbault

comment created time in a month

PullRequestReviewEvent

Pull request review commentmgeisler/textwrap

Make indent preserve the of \n in the input string (stop adding a trailing \n)

 /// ->Foo /// /// ->Bar-///+///   \t

The comment above is now incorrect:

... the whitespace is replaced by a single newline (\n)

jRimbault

comment created time in a month

PullRequestReviewEvent

PR closed mgeisler/textwrap

Add the indent tests from the python std tests suite

cf issue #207

The tests don't pass currently, #209 makes them pass.

+80 -0

1 comment

1 changed file

jRimbault

pr closed time in a month

pull request commentmgeisler/textwrap

Add the indent tests from the python std tests suite

Closing in preference for #209 as discussed in #207.

jRimbault

comment created time in a month

issue commentmgeisler/textwrap

The indent function always adds a final \n, even if the input string has no \n

Thanks for the tip about fixing the GitHub workflow!

I don't have a working branch as such, so I'll just close #208 for now.

jRimbault

comment created time in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha b4c9a19ea85a7a8ccd1f6f4af382ff4302cca4d5

wip: turn wrap into wrap_iter, remove the latter

view details

Martin Geisler

commit sha 117352f6b3ad2a50a2246d2afc10067d99833504

Rename Wrapper to Options

view details

Martin Geisler

commit sha 5af49e6dc53a033ac3a888e89c9f5b3b4ce7f8a6

simplify docstrings

view details

Martin Geisler

commit sha 0fb324f2718b6f5f346c347367fd74de7523163f

magic from into stuff

view details

push time in a month

PR opened mgeisler/textwrap

Simplify API

This is still work in progress.

+368 -426

0 comment

7 changed files

pr created time in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha 7b7e64e214458b5b05fb63d7d8a17e222b22173a

Trigger build GitHub workflow on new pull requests Thanks to @jRimbault for explaining how to fix this in #207. To avoid running no less than eight checks whenever I push something to a new branch, we now only run the build workflow on pushes to the master branch.

view details

Martin Geisler

commit sha e2e0ff32d1696b641dad0eed942b8a33e7f9a6c0

Merge pull request #212 from mgeisler/trigger-build-workflow-on-pull-request Trigger build GitHub workflow on new pull requests

view details

Martin Geisler

commit sha 8b7fc6b69bf34f973ed610d99adf692f880e5a3b

wip: turn wrap into wrap_iter, remove the latter

view details

Martin Geisler

commit sha ed6d0ba33328f34cae0112a66fb08b578f4b4c25

wip: remove Wrapper:fill

view details

Martin Geisler

commit sha 42b221bdc355801e82593f02874c1f452cea0e4a

wip: remove Wrapper::wrap

view details

Martin Geisler

commit sha 700695b22e910f5642656ff92881f6ea0ac085d4

rename wrap_with to wrap_with_options

view details

Martin Geisler

commit sha 46337ec89b8d56bbd1e24e17684ad71004b377c1

Remove IntoWrapIter

view details

Martin Geisler

commit sha 0ddfdf4890055744049d0a7a2008b604698a0d0a

Remove WrapIterImpl, move the code into WrapIter

view details

Martin Geisler

commit sha d517bb3ce29ca05f75d381deca35ab8921198873

Be explicit about 'static lifetime for Wrapper::new

view details

Martin Geisler

commit sha 02dfa7ebd1be6aefa998c56810cfbd985eb3c1e2

Rename Wrapper to Options

view details

Martin Geisler

commit sha d5b384eef90d0dbef545a02b872253dc6987ce97

simplify docstrings

view details

Martin Geisler

commit sha c806234ded10d1a00e4a7d95c72fcf9f43b4e5a7

magic from into stuff

view details

Martin Geisler

commit sha 5abeb29080b93c80449ad32ac839e774d174402d

impl WrapOptions for usize

view details

Martin Geisler

commit sha a52bd4470b6d0cf84e971ff9c4a8fa8fc49b37f2

bench with Options and usize, inline trait impls

view details

Martin Geisler

commit sha 41418a736f94cc18d358d2bb19446f63b5dc772a

remove phantom!

view details

Martin Geisler

commit sha ec59da9e09f1c16685a37cbaa5e222dfd25e8439

simplify lifetimes

view details

push time in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha 7b7e64e214458b5b05fb63d7d8a17e222b22173a

Trigger build GitHub workflow on new pull requests Thanks to @jRimbault for explaining how to fix this in #207. To avoid running no less than eight checks whenever I push something to a new branch, we now only run the build workflow on pushes to the master branch.

view details

Martin Geisler

commit sha e2e0ff32d1696b641dad0eed942b8a33e7f9a6c0

Merge pull request #212 from mgeisler/trigger-build-workflow-on-pull-request Trigger build GitHub workflow on new pull requests

view details

push time in a month

PR merged mgeisler/textwrap

Trigger build GitHub workflow on new pull requests

Thanks to @jRimbault for explaining how to fix this in #207.

+5 -1

0 comment

1 changed file

mgeisler

pr closed time in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha 7b7e64e214458b5b05fb63d7d8a17e222b22173a

Trigger build GitHub workflow on new pull requests Thanks to @jRimbault for explaining how to fix this in #207. To avoid running no less than eight checks whenever I push something to a new branch, we now only run the build workflow on pushes to the master branch.

view details

push time in a month

PR opened mgeisler/textwrap

Trigger build GitHub workflow on new pull requests

Thanks to @jRimbault for explaining how to fix this in #207.

+1 -1

0 comment

1 changed file

pr created time in a month

create barnchmgeisler/textwrap

branch : trigger-build-workflow-on-pull-request

created branch time in a month

create barnchmgeisler/textwrap

branch : simplify-api

created branch time in a month

issue commentdalance/procs

Do we need the note about config file is not found?

Hey @dalance Awesome, I think that is much better! Thanks :smile:

shinokada

comment created time in a month

issue commentdalance/procs

Do we need the note about config file is not found?

The note was the first thing I noticed when trying out procs — and I would remove it. To me, it makes the program "annoying by default", which is a bad default :smile:

I would make procs work like other Unix system tools, which don't mention a potential config file on every invocation. Let people read about the config file in the man page (or the homepage if there is no man page).

shinokada

comment created time in a month

issue commentmgeisler/textwrap

Support for tabs and hanging indent

Having written the code above, I realize that it could be useful to ship a utility function that does this kind of thing.

cmcqueen

comment created time in a month

issue commentmgeisler/textwrap

Support for tabs and hanging indent

Hi @cmcqueen That's a great use case! We do have some support for this already via the initial_indent and subsequent_indent fields on Wrapper.

That is, you can do this kind of indentation by first constructing the "-i <filename> " part, set that as initial_indent and then construct a string with spaces of the same length for the subsequent_indent, Something like this:

pub fn main() {
    let options = vec![
        (
            'i',
            "filename",
            "Input file. ELF, PE (portable executable) object file formats are accepted.",
        ),
        (
            'o',
            "filename",
            "Output file. Binary, Intel hex or Motorola hex file formats are accepted.",
        ),
        (
            'v',
            "int",
            "Verbosity level. Set to 42 to receive more output than you ever wanted.",
        ),
    ];

    for (short, param, help) in &options {
        let left_column = format!("-{} <{}>", short, param);
        // Adjust 20 as needed, perhaps compute it from the longest parameter name
        let initial_indent = format!("{:1$}", left_column, 20); 
        let subsequent_indent = " ".repeat(20);
        let wrapper = textwrap::Wrapper::new(65)  // 65 is your line width
            .initial_indent(&initial_indent)
            .subsequent_indent(&subsequent_indent);
        println!("{}", wrapper.fill(help));
    }
}

Playground link.

If you want to be more careful, you should measure the length of the strings using the unicode-width crate, just like textwrap does internally.

Does this help? By the way, crates like clap already do this kind of formatting for you.

cmcqueen

comment created time in a month

Pull request review commentrust-lang/rfcs

Destructuring assignment

+- Feature Name: `destructuring_assignment`+- Start Date: 2020-04-17+- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)+- Rust Issue: [rust-lang/rust#71126](https://github.com/rust-lang/rust/issues/71126)+- Proof-of-concept: [rust-lang/rust#71156](https://github.com/rust-lang/rust/pull/71156)++# Summary+[summary]: #summary++We allow destructuring on assignment, as in `let` declarations. For instance, the following are now+accepted:++```rust+(a, b) = (0, 1);+(x, y, .., z) = (1.0, 2.0, 3.0, 4.0, 5.0);+[_, f] = foo();+[g, _, h, ..] = ['a', 'w', 'e', 's', 'o', 'm', 'e', '!'];+Struct { x: a, y: b } = bar();+```++This brings assignment in line with `let` declaration, in which destructuring is permitted. This+will simplify and improve idiomatic code involving mutability.++# Motivation+[motivation]: #motivation++Destructuring assignment increases the consistency of the language, in which assignment is typically+expected to behave similarly to variable declations. The aim is that this feature will increase the+clarity and concision of idiomatic Rust, primarily in code that makes use of mutability. This+feature is+[highly desired among Rust developers](https://github.com/rust-lang/rfcs/issues/372).++# Guide-level explanation+[guide-level-explanation]: #guide-level-explanation++You may destructure a value when making an assignment, just as when you declare variables. See the+[Summary](#Summary) for examples. The following structures may be destructured:++- Tuples.+- Slices.+- (Tuple) structs.++You may use `_` and `..` as in a normal declaration pattern to ignore certain values.++# Reference-level explanation+[reference-level-explanation]: #reference-level-explanation++The feature as described here has been implemented as a proof-of-concept (https://github.com/rust-lang/rust/pull/71156). It follows essentially the+[suggestions of @Kimundi](https://github.com/rust-lang/rfcs/issues/372#issuecomment-214022963) and+[of @drunwald](https://github.com/rust-lang/rfcs/issues/372#issuecomment-262519146).++The Rust compiler already parses complex expressions on the left-hand side of an assignment, but+does not handle them other than emitting an error later in compilation. We propose to add+special-casing for several classes of expressions on the left-hand side of an assignment, which act+in accordance with destructuring assignment: i.e. as if the left-hand side were actually a pattern.+Actually supporting patterns directly on the left-hand side of an assignment significantly+complicates Rust's grammar and it is not clear that it is even technically feasible. Conversely,+handling some classes of expressions is much simpler, and is indistinguishable to users, who will+receive pattern-oriented diagnostics due to the desugaring of expressions into patterns.++The general idea is that we will desugar the following complex assignments as demonstrated.++```rust+(a, b) = (3, 4);++[a, b] = [3, 4];++Struct { x: a, y: b } = Struct { x: 3, y: 4};++// desugars to:++{+    let (_a, _b) = (3, 4);+    a = _a;+    b = _b;+}++{+    let [_a, _b] = [3, 4];+    a = _a;+    b = _b;+}++{+    let Struct { x: _a, y: _b } = Struct { x: 3, y: 4};+    a = _a;+    b = _b;+}+```++We support the following classes of expressions:++- Tuples.+- Slices.+- (Tuple) structs.++In the desugaring, we convert the expression `(a, b)` into an analogous pattern `(_a, _b)` (whose+identifiers are fresh and thus do not conflict with existing variables). A nice side-effect is that+we inherit the diagnostics for normal pattern-matching, so users benefit from existing diagnostics for destructuring declarations.++## Diagnostics++It is worth being explicit that, in the implementation, the diagnostics that are reported are+pattern diagnostics: that is, because the desugaring occurs regardless, the messages will imply that+the left-hand side of an assignment is a true pattern (the one the expression has been converted+to). For example:++```rust+[*a] = [1, 2]; // error: pattern requires 1 element but array has 2+```++Whilst `[*a]` is not strictly speaking a pattern, it behaves similarly to one in this context. We+think that this results in a better user experience, as intuitively the left-hand side of a+destructuring assignment acts like a pattern "in spirit", but this is technically false: we should+be careful that this does not result in misleading diagnostics.++## Underscores and ellipses++In patterns, we may use `_` and `..` to ignore certain values, without binding them. While range+patterns already have analogues in terms of range expressions, the underscore wildcard pattern+currently has no analogous expression. We thus add one, which is only permitted in the left-hand side+of an assignment: any other use results in the same "reserved identifier" error that currently+occurs for invalid uses of `_` as an expression. A consequence is that the following becomes valid:++```rust+_ = 5;+```++Functional record update syntax (i.e. `..x`) is forbidden in destructuring assignment, as we believe+there is no sensible and clear semantics for it in this setting. This restriction could be relaxed+in the future if a use-case is found.++The desugaring treats the `_` expression as an `_` pattern and the fully empty range `..` as a `..` pattern. No corresponding assignments are generated. For example:++```rust+let mut a;+(a, _) = (3, 4);+(.., a) = (1, 2, 3, 4);++// desugars to:++{+    let (_a, _) = (3, 4);+    a = _a;+}++{+    let (.., _a) = (1, 2, 3, 4);+    a = _a;+}+```++and similarly for slices and structs.++## Unsupported patterns++We do not support the following "patterns" in destructuring assignment:++- `&x = foo();`.+- `&mut x = foo();`.+- `ref x = foo();`.++This is primarily for learnability: the behaviour of `&` can already be slightly confusing to+newcomers, as it has different meanings depending on whether it is used in an expression or pattern.+In destructuring assignment, the left-hand side of an assignment consists of sub*expressions*, but+which act intuitively like patterns, so it is not clear what `&` and friends should mean. We feel it is more+confusing than helpful to allow these cases. Conversely, destructuring tuples, slices or structs is+very natural and we do not foresee confusion with allowing these.++Our implementation is forwards-compatible with allowing these patterns in destructuring assigmnent, in any case, so we lose nothing by not allowing them from the start.++## Compound destructuring assignment++We forbid destructuring compound assignment, i.e. destructuring for operators like `+=`, `*=` and so+on. This is both for the sake of simplicity and since there are relevant design questions that do not have obvious answers,+e.g. how this could interact with custom implementations of the operators.++## Order-of-assignment++The right-hand side of the assignment is always evaluated first. Then, assignments are performed+left-to-right. Note that component expressions in the left-hand side may be complex, and not simply+identifiers.++In a declaration, each identifier may be bound at most once. That is, the following is invalid:++```rust+let (a, a) = (1, 2);+```++For destructuring assignments, we currently permit assignments containing identical identifiers. However, these trigger an "unused assignment"+warning.++```rust+(a, a) = (1, 2); // warning: value assigned to `a` is never read+assert_eq!(a, 2);+```++We could try to explicitly forbid this. However, the chosen behaviour is justified in two ways:+- A destructuring+assignment can always be written as a series of assignments, so this behaviour matches its+expansion.+- In general, we are not able to tell when overlapping+assignments are made, so the error would be fallible. This is illustrated by the following example:++```rust+fn foo<'a>(x: &'a mut u32) -> &'a mut u32 {+    x+}++fn main() {+    let mut x: u32 = 10;+    // We cannot tell that the same variable is being assigned to+    // in this instance.+    (*foo(&mut x), *foo(&mut x)) = (5, 6);+    assert_eq!(x, 6);+}+```++We thus feel that a lint is more appropriate.++# Drawbacks+[drawbacks]: #drawbacks++- It could be argued that this feature increases the surface area of the language and thus complexity. However, we feel that by decreasing surprise, it actually makes the language less complex for users.+- It is possible that these changes could result in some confusing diagnostics. However, we have not found any during testing, and these could in any case be ironed out before stabilisation.++# Rationale and alternatives+[rationale-and-alternatives]: #rationale-and-alternatives++As we argue above, we believe this change increases the perceived consistency of Rust and improves+idiomatic code in the presence of mutability, and that the+implementation is simple and intuitive.++One potential alternative that has been put forth in the past is to allow arbitrary patterns on the left-hand side of an assignment,+but as discussed above and [extensively in this+thread](https://github.com/rust-lang/rfcs/issues/372), it is difficult to see how this could work in+practice (especially with complex left-hand sides that do not simply involve identifiers) and it is not clear that this would have any advantages.++# Prior art+[prior-art]: #prior-art++The most persuasive prior art is Rust itself, which already permits destructuring+declarations. Intuitively, a declaration is an assignment that also introduces a new binding.+Therefore, it seems clear that assignments should act similarly to declarations where possible.+However, it is also the case that destructuring assignments are present in many languages that permit destructuring+declarations.++- JavaScript+[supports destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment).+- Python [supports destructuring assignment](https://blog.tecladocode.com/destructuring-in-python/).+- Perl+[supports destructuring assignment](https://perl6advent.wordpress.com/2017/12/05/day-5-destructure-your-arguments-with-perl-6-signatures/).+- And so on...++It is a general pattern that languages support destructuring assignment when they support+destructuring declarations.++# Unresolved questions+[unresolved-questions]: #unresolved-questions++None.++# Future possibilities+[future-possibilities]: #future-possibilities++- The implementation already supports destructuring of every class of expressions that currently make+sense in Rust. This feature naturally should be extended to any new class of expressions for which+it makes sense.+- It could make sense to permit+[destructuring compound assignments](#Compound-destructuring-assignment) in the future, though we+defer this question for later discussions.+- It could make sense to permit [`ref` and `&`](#Unsupported-patterns) in the future.+- It [has been suggested](https://github.com/rust-lang/rfcs/issues/372#issuecomment-365606878) that+mixed declarations and assignments could be permitted, as in the following:

In addition to what @varkor wrote above, I would suggest that people could simply pre-declare the variables they would like to declare in a mixed assignment. So instead of

// old_ident is already in scope, and is written to here:
let (<magic keyword> old_ident, new_ident) = some_tuple;

one would use

// old_ident is already in scope
let new_indent;  // new_indent is now also in scope
(old_ident, new_ident) = some_tuple;  // write to both
varkor

comment created time in a month

PullRequestReviewEvent

issue commentmgeisler/textwrap

indent is adding a last newline

Hi @jRimbault Thank you very much for the excellent bug report and the accompanying fixes!

Since it uses a nightly API, I guess we'll just let is sit and wait for a bit...?

In the mean time, I'll have to look at why the tests didn't actually break as expected! I recently switched to GitHub actions, but I must have misconfigured it somehow :-)

If I read #208 and #209 correctly, then I think #208 is a subset of #209? If so, I would prefer to close #208 and simply merge the tests together with the implementation.

jRimbault

comment created time in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha 6810a97d9e5bbd55588b8ce87cc4f4c9d8b84bd2

Change Wrapper.splitter from T: WordSplitter to Box<dyn WordSplitter> Before, the Wrapper would be generic in the type of WordSplitter used. This meant that Wrapper<NoHyphenation> would be a different type than Wrapper<HyphenSplitter>. The result is that you need to fix the type of WordSplitter at compile time. This makes it hard to make interactive programs, something which was raised in #178. Making splitter a Box<dyn WordSplitter> makes the field less special. We can therefore simplify the API by removing the with_splitter constructor. The performance is unchanged by this, even when testing with the hyphenation feature enabled.

view details

Martin Geisler

commit sha 276103dd05159c5fe3b5f4f528e03cec81ba8263

Merge pull request #206 from mgeisler/dynamic-dispatch Change Wrapper.splitter from T: WordSplitter to Box<dyn WordSplitter>

view details

push time in a month

PR merged mgeisler/textwrap

Change Wrapper.splitter from T: WordSplitter to Box<dyn WordSplitter>

Before, the Wrapper would be generic in the type of WordSplitter used. This meant that Wrapper<NoHyphenation> would be a different type than Wrapper<HyphenSplitter>.

The result is that you need to fix the type of WordSplitter at compile time. This makes it hard to make interactive programs, something which was raised in #178.

Making splitter a Box<dyn WordSplitter> makes the field less special. We can therefore simplify the API by removing the with_splitter constructor.

The performance is unchanged by this, even when testing with the hyphenation feature enabled.

+91 -85

0 comment

7 changed files

mgeisler

pr closed time in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha 6810a97d9e5bbd55588b8ce87cc4f4c9d8b84bd2

Change Wrapper.splitter from T: WordSplitter to Box<dyn WordSplitter> Before, the Wrapper would be generic in the type of WordSplitter used. This meant that Wrapper<NoHyphenation> would be a different type than Wrapper<HyphenSplitter>. The result is that you need to fix the type of WordSplitter at compile time. This makes it hard to make interactive programs, something which was raised in #178. Making splitter a Box<dyn WordSplitter> makes the field less special. We can therefore simplify the API by removing the with_splitter constructor. The performance is unchanged by this, even when testing with the hyphenation feature enabled.

view details

push time in a month

issue commentmgeisler/textwrap

Support for columns

Hi @wucke13! Oh, that's a cool idea!

I guess the function should return a String? A string with the text already formatted into the columns? So if your text above is wrapped into 12 columns, it should return a string looking like this:

  Hi, I would   │  Something
  love to be    │  like this
  able to wrap  │  quick draft
  a text into   │  could be the
  mutiple       │  API for it.
  columns.      │
wucke13

comment created time in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha 62c643c591a9762f66c83ff73cdd3b1ecde4784b

Change Wrapper.splitter from T: WordSplitter to Box<dyn WordSplitter> Before, the Wrapper would be generic in the type of WordSplitter used. This meant that Wrapper<NoHyphenation> would be a different type than Wrapper<HyphenSplitter>. The result is that you need to fix the type of WordSplitter at compile time. This makes it hard to make interactive programs, something which was raised in #178. Making splitter a Box<dyn WordSplitter> makes the field less special. We can therefore simplify the API by removing the with_splitter constructor. The performance is unchanged by this, even when testing with the hyphenation feature enabled.

view details

push time in a month

PR opened mgeisler/textwrap

Change Wrapper.splitter from T: WordSplitter to Box<dyn WordSplitter>

Before, the Wrapper would be generic in the type of WordSplitter used. This meant that Wrapper<NoHyphenation> would be a different type than Wrapper<HyphenSplitter>.

The result is that you need to fix the type of WordSplitter at compile time. This makes it hard to make interactive programs, something which was raised in #178.

Making splitter a Box<dyn WordSplitter> makes the field less special. We can therefore simplify the API by removing the with_splitter constructor.

The performance is unchanged by this, even when testing with the hyphenation feature enabled.

+91 -86

0 comment

7 changed files

pr created time in a month

create barnchmgeisler/textwrap

branch : dynamic-dispatch

created branch time in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha 259357fc6291057b53a7b4c6ff4ad55fec8ae412

Use larger benchmark sizes to improve benchmark stability Even with 1600 character long strings (roughly 20 lines of text in a terminal), the timings for the three benchmarks are tiny: fill/1600: 9.885 us wrap/1600: 10.277 us hyphenation/1600: 40.196 us

view details

Martin Geisler

commit sha 089594dd5e02d2ad2787a1edfacf1ed11b887000

Merge pull request #204 from mgeisler/benchmark-sizes Use larger benchmark sizes to improve benchmark stability

view details

push time in a month

PR merged mgeisler/textwrap

Use larger benchmark sizes to improve benchmark stability

Even with 1600 character long strings (roughly 20 lines of text in a terminal), the timings for the three benchmarks are tiny:

fill/1600:         9.885 us
wrap/1600:        10.277 us
hyphenation/1600: 40.196 us
+1 -1

0 comment

1 changed file

mgeisler

pr closed time in a month

PR opened mgeisler/textwrap

Use larger benchmark sizes to improve benchmark stability

Even with 1600 character long strings (roughly 20 lines of text in a terminal), the timings for the three benchmarks are tiny:

fill/1600:         9.885 us
wrap/1600:        10.277 us
hyphenation/1600: 40.196 us
+1 -1

0 comment

1 changed file

pr created time in a month

create barnchmgeisler/textwrap

branch : benchmark-sizes

created branch time in a month

PR opened redox-os/termion

Allow resetting cursor style to terminal default

This adds cursor::DefaultStyle, which will reset the cursor style back to the terminal default. The default is normally a block cursor, which is why this might seem to give the same results as cursor::BlinkingBlock. However, if you change the cursor style in the terminal settings (I tested with Gnome Terminal), then you will see an effect of this escape sequence.

This Super User answer links to more documentation and discussion around this feature.

+1 -0

0 comment

1 changed file

pr created time in a month

push eventmgeisler/termion

Martin Geisler

commit sha 20a2579a055a280a78d872170c94714f221a8ed1

Allow resetting cursor style to terminal default This adds `cursor::DefaultStyle`, which will reset the cursor style back to the terminal default. The default is normally a block cursor, which is why this might seem to give the same results as `cursor::BlinkingBlock`. However, if you change the cursor style in the terminal settings (I tested with Gnome Terminal), then you will see an effect of this escape sequence. This [Super User answer](https://superuser.com/a/1302503/22077) links to more documentation and discussion around this feature.

view details

push time in a month

fork mgeisler/termion

Mirror of https://gitlab.redox-os.org/redox-os/termion

fork in a month

push eventmgeisler/textwrap

Martin Geisler

commit sha f005b9a6960990aa9d02ccdcc23f10f714d428c0

Drop old and unused CI configuration The Codecov configuration file isn't necessary any longer since we only track coverage on the master branch.

view details

Martin Geisler

commit sha 895f65ead6af8ea34c089590692fbf409105abc1

Merge pull request #203 from mgeisler/only-use-github-actions Drop old and unused CI configuration

view details

push time in 2 months

PR merged mgeisler/textwrap

Drop old and unused CI configuration

The Codecov configuration file isn't necessary any longer since we only track coverage on the master branch.

+0 -61

0 comment

4 changed files

mgeisler

pr closed time in 2 months

PR opened mgeisler/textwrap

Drop old and unused CI configuration

The Codecov configuration file isn't necessary any longer since we only track coverage on the master branch.

+0 -61

0 comment

4 changed files

pr created time in 2 months

create barnchmgeisler/textwrap

branch : only-use-github-actions

created branch time in 2 months

push eventmgeisler/textwrap

Martin Geisler

commit sha d49e82a74fa3685dcbca593d8bc4a4e751b65db9

benches: switch to the Criterion library This benchmark harness gives us nice graphs where it's easier to see how the performance varies with the input size.

view details

Martin Geisler

commit sha daf7b5e9ae563a9d7ff99e49cc5d2185e322718d

Merge pull request #202 from mgeisler/criterion-benchmarks Switch to the Criterion library for our benchmarks

view details

push time in 2 months

PR merged mgeisler/textwrap

Switch to the Criterion library for our benchmarks

This benchmark harness gives us nice graphs where it's easier to see how the performance varies with the input size.

+37 -89

1 comment

3 changed files

mgeisler

pr closed time in 2 months

push eventmgeisler/textwrap

Martin Geisler

commit sha da454e42c181946325bb20718a1d655864fc8498

Let functions return "impl Iterator" to hide iterator structs This slims down our public API a little by hiding the concrete type of iterator returned. This will hopefully make the API easier to understand.

view details

Martin Geisler

commit sha 53253940589a18078fb392a197833fd5834d153b

Merge pull request #201 from mgeisler/hide-iterators Let functions return "impl Iterator" to hide iterator structs

view details

push time in 2 months

PR merged mgeisler/textwrap

Let functions return "impl Iterator" to hide iterator structs

This slims down our public API a little by hiding the concrete type of iterator returned. This will hopefully make the API easier to understand.

+23 -46

1 comment

1 changed file

mgeisler

pr closed time in 2 months

PR opened mgeisler/textwrap

Switch to the Criterion library for our benchmarks

This benchmark harness gives us nice graphs where it's easier to see how the performance varies with the input size.

+37 -89

0 comment

3 changed files

pr created time in 2 months

PR opened mgeisler/textwrap

Let functions return "impl Iterator" to hide iterator structs

This slims down our public API a little by hiding the concrete type of iterator returned. This will hopefully make the API easier to understand.

+23 -46

0 comment

1 changed file

pr created time in 2 months

create barnchmgeisler/textwrap

branch : hide-iterators

created branch time in 2 months

issue commentrust-lang/rust-mode

markdown mode in docs

I was looking for similar functionality and found that I can use poporg together with markdown-mode to edit the Markdown comments in their own buffer.

I load and configure the packages with use-package:

(use-package markdown-mode)

(use-package poporg
  :config
  (setq poporg-edit-hook '(gfm-mode))
  (setq poporg-comment-skip-regexp "[[:space:]!/]*")
  (setq markdown-fontify-code-block-default-mode 'rust-mode)
  :bind (:map rust-mode-map ("C-c \"" . poporg-dwim)))

;; From https://doc.rust-lang.org/rustdoc/documentation-tests.html#attributes
(setq rustdoc-attributes '("ignore" "should_panic" "no_run" "compile_fail" "edition2018"))

(defun mg-markdown-get-lang-mode (lang)
  (if (member lang rustdoc-attributes) 'rust-mode))
(advice-add 'markdown-get-lang-mode :before-until #'mg-markdown-get-lang-mode)

This binds C-c " to poporg-dwim, which will open a new buffer with the comment. The /// or //! prefix is stripped automatically and later reinserted. The buffer is in gfm-mode and will syntax highlight code blocks as rust-mode by default — including blocks marked with atributes like no_run. Such blocks would normally be unhighlighted since the attribute isn't recognized as a language.

The variables I set should probably be made buffer-local, but for now having them set globally seems okay.

Hope this is useful to someone!

droundy

comment created time in 2 months

create barnchmgeisler/smawk

branch : exclude-git-files

created branch time in 2 months

create barnchmgeisler/textwrap

branch : criterion-benchmarks

created branch time in 2 months

more