Code Monkey home page Code Monkey logo

textwrap's Introduction

Textwrap

Textwrap is a library for wrapping and indenting text. It is most often used by command-line programs to format dynamic output nicely so it looks good in a terminal. You can also use Textwrap to wrap text set in a proportional font—such as text used to generate PDF files, or drawn on a HTML5 canvas using WebAssembly.

Usage

To use the textwrap crate, add this to your Cargo.toml file:

[dependencies]
textwrap = "0.16"

By default, this enables word wrapping with support for Unicode strings. Extra features can be enabled with Cargo features—and the Unicode support can be disabled if needed. This allows you slim down the library and so you will only pay for the features you actually use.

Please see the Cargo Features in the crate documentation for a full list of the available features as well as their impact on the size of your binary.

Documentation

API documentation

Getting Started

Word wrapping is easy using the wrap and fill functions:

#[cfg(feature = "smawk")] {
let text = "textwrap: an efficient and powerful library for wrapping text.";
assert_eq!(
    textwrap::wrap(text, 28),
    vec![
        "textwrap: an efficient",
        "and powerful library for",
        "wrapping text.",
    ]
);
}

Sharp-eyed readers will notice that the first line is 22 columns wide. So why is the word “and” put in the second line when there is space for it in the first line?

The explanation is that textwrap does not just wrap text one line at a time. Instead, it uses an optimal-fit algorithm which looks ahead and chooses line breaks which minimize the gaps left at ends of lines. This is controlled with the smawk Cargo feature, which is why the example is wrapped in the cfg-block.

Without look-ahead, the first line would be longer and the text would look like this:

#[cfg(not(feature = "smawk"))] {
let text = "textwrap: an efficient and powerful library for wrapping text.";
assert_eq!(
    textwrap::wrap(text, 28),
    vec![
        "textwrap: an efficient and",
        "powerful library for",
        "wrapping text.",
    ]
);
}

The second line is now shorter and the text is more ragged. The kind of wrapping can be configured via Options::wrap_algorithm.

If you enable the hyphenation Cargo feature, you get support for automatic hyphenation for about 70 languages via high-quality TeX hyphenation patterns.

Your program must load the hyphenation pattern and configure Options::word_splitter to use it:

#[cfg(feature = "hyphenation")] {
use hyphenation::{Language, Load, Standard};
use textwrap::{fill, Options, WordSplitter};

let dictionary = Standard::from_embedded(Language::EnglishUS).unwrap();
let options = textwrap::Options::new(28).word_splitter(WordSplitter::Hyphenation(dictionary));
let text = "textwrap: an efficient and powerful library for wrapping text.";

assert_eq!(
    textwrap::wrap(text, &options),
    vec![
        "textwrap: an efficient and",
        "powerful library for wrap-",
        "ping text."
    ]
);
}

The US-English hyphenation patterns are embedded when you enable the hyphenation feature. They are licensed under a permissive license and take up about 88 KB in your binary. If you need hyphenation for other languages, you need to download a precompiled .bincode file and load it yourself. Please see the hyphenation documentation for details.

Wrapping Strings at Compile Time

If your strings are known at compile time, please take a look at the procedural macros from the textwrap-macros crate.

Examples

The library comes with a collection of small example programs that shows various features.

If you want to see Textwrap in action right away, then take a look at examples/wasm/, which shows how to wrap sans-serif, serif, and monospace text. It uses WebAssembly and is automatically deployed to https://mgeisler.github.io/textwrap/.

For the command-line examples, you’re invited to clone the repository and try them out for yourself! Of special note is examples/interactive.rs. This is a demo program which demonstrates most of the available features: you can enter text and adjust the width at which it is wrapped interactively. You can also adjust the Options used to see the effect of different WordSplitters and wrap algorithms.

Run the demo with

$ cargo run --example interactive

The demo needs a Linux terminal to function.

Release History

Please see the CHANGELOG file for details on the changes made in each release.

License

Textwrap can be distributed according to the MIT license. Contributions will be accepted under the same license.

textwrap's People

Contributors

9999years avatar anyakichi avatar axelchalon avatar cryptjar avatar cstyles avatar davidkorczynski avatar dependabot-preview[bot] avatar dependabot[bot] avatar guillaumegomez avatar hcpl avatar jelmer avatar jrimbault avatar justformaven avatar kestrer avatar kianmeng avatar koiuo avatar makotoe avatar mgeisler avatar minoru avatar robinkrahl avatar sdroege avatar sunfishcode avatar tapeinosyne avatar tertsdiepraam avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

textwrap's Issues

Use automatic intra-doc links

When rust-lang/rust#74430 lands in a stable Rust release, we should go through the doc strings and change them from

/// Use the [`wrap`] function...
/// [`wrap`]: fn.wrap.html

to

/// Use the [`wrap`] function...

That is, we can rely on rustdoc to automatically find the right target for internal documentation links.

Word broken even though it would fit on line

This test case fails, even though the "qqqqqqqqq" word is only 9 characters long:

    #[test]
    fn test_very_ragged() {
        // Example of inputs that produce very ragged output with the
        // greedy algorithm.
        assert_eq!(wrap("a b c d e f g h i j k l m n o p qqqqqqqqq", 10),
                   vec!["a b c d e", "f g h i j", "k l m n o", "p", "qqqqqqqqq"]);
    }

It fails with

---- tests::test_very_ragged stdout ----
	thread 'tests::test_very_ragged' panicked at 'assertion failed: `(left == right)`
  left: `["a b c d e", "f g h i j", "k l m n o", "p qqqqqqqq", "q"]`,
 right: `["a b c d e", "f g h i j", "k l m n o", "p", "qqqqqqqqq"]`', src/lib.rs:1080:8

hyphenation is no longer maintained

It appears that hyphenation is no longer being maintained, and as a result, it is blocking ripgrep from being packaged in Debian. I'm opening this issue to see if you're willing to brainstorm ideas on a path forward here.

Unless hyphenation becomes actively maintained, I think the only path forward is to find a way to remove it from textwrap's dependency tree. Here are some ideas:

  • textwrap could vendor hyphenation's functionality and provide it itself. This means the maintenance burden gets shifted to the maintainers of this crate.
  • Someone forks and maintains hyphenation by publishing a different crate that provides the same functionality, and then textwrap switches to that fork. This means the maintenance burden gets shifted to whoever makes the fork.
  • I fork hyphenation and maintain it myself. I'd prefer not to do this, because if I do, I'm going to want to dig into it and solve the problem from first principles. (I don't know whether the existing implementation is the same one that I would arrive at.) However, it might be possible that textwrap only needs a small piece of functionality from hyphenation. If so, perhaps I could just provide that, but I haven't investigated yet.

What are your thoughts?

Support not squeezing whitespace

We currently split the input string by whitespace and process the words one by one. This implies that we squeeze runs of whitespace to a single space.

We could instead have a mode where whitespace is significant and kept in the output. This would make it possible to wrap text like this line by line:

foobar:    Have lots of foos and bars in the output.
baz:       Show a single bar in the output, but only if it is a full moon.

Lines that wrap would still line up somewhat:

foobar:    Have lots of foos and bars in
the output.
baz:       Show a single bar in the output,
but only if it is a full moon.

In Python's textwrap this option is called replace_whitespace, but I think I'll call it squeeze_whitespace instead. The option should come in handy to support the output wanted in clap-rs/clap#617.

Immediatedly add word if it fits

When a word fits on the current line, we don't need to compute all the possible splits. We can simply push it onto the line and continue with next word.

wrap could return an iterator

The wrap method currently returns Vec<String> but it could return an iterator instead. This would make it possible to output a large help text line-by-line and do less allocations.

However, if wrap is mostly called through fill, this might not really improve anything since fill still needs to copy the data into a new string.

Wrap on soft-hyphens

It could be useful if we could wrap text on explicit soft-hyphens, U+00AD. In my limited testing, soft-hyphens are shown as spaces in a terminal (I tested with Gnome Terminal). We should therefore remove all soft-hyphens except for those used to break lines. So

A text with ex\u{ad}pli\u{ad}cit soft-hyp\u{ad}hens

will be wrapped as

A test with expli-
cit soft-hyphens

The soft-hyphens are gone, except for the one that got turned into a normal hyphen.

Respect non-breaking spaces

According to the comment on #28, we treat non-breaking spaces as normal whitespace and break on it. We should probably not do that :-)

Panic on string with em-dash

Here's an example program that causes the panic:

extern crate textwrap;

fn main() {
    let problematic_string = "osts: – https://knowledgetester.org/2016/09/20/generalist-specialist-t-and-pi-shaped-testers/ – http://www.dataminingblog.com/the-5-most-common-data-relationships-shown-through-visualization/";
    textwrap::fill(problematic_string, 86);
}

and here's the panic:

thread 'main' panicked at 'byte index 97 is not a char boundary; it is inside '–' (bytes 96..99) of `osts: – https://knowledgetester.org/2016/09/20/generalist-specialist-t-and-pi-shaped-testers/ – http://www.dataminingblog.com/the-5-most-common-data-relationships-shown-through-visualization/`', libcore/str/mod.rs:2257:5
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
             at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1: std::sys_common::backtrace::print
             at libstd/sys_common/backtrace.rs:71
             at libstd/sys_common/backtrace.rs:59
   2: std::panicking::default_hook::{{closure}}
             at libstd/panicking.rs:207
   3: std::panicking::default_hook
             at libstd/panicking.rs:223
   4: std::panicking::begin_panic
             at libstd/panicking.rs:402
   5: std::panicking::try::do_call
             at libstd/panicking.rs:349
   6: std::panicking::try::do_call
             at libstd/panicking.rs:325
   7: core::ptr::drop_in_place
             at libcore/panicking.rs:72
   8: core::str::run_utf8_validation
             at libcore/str/mod.rs:0
   9: core::str::traits::<impl core::ops::index::Index<core::ops::range::RangeFrom<usize>> for str>::index
             at /Users/travis/build/rust-lang/rust/src/libcore/str/mod.rs:2010
  10: <core::str::CharIndices<'a> as core::iter::iterator::Iterator>::next
             at /Users/travis/build/rust-lang/rust/src/libcore/option.rs:376
  11: core::str::traits::<impl core::slice::SliceIndex<str> for core::ops::range::RangeFrom<usize>>::index
             at /Users/travis/build/rust-lang/rust/src/libcore/str/mod.rs:2010
  12: core::str::traits::<impl core::ops::index::Index<core::ops::range::RangeFrom<usize>> for str>::index
             at /Users/travis/build/rust-lang/rust/src/libcore/str/mod.rs:1765
  13: textwrap_fail::main
             at /Users/rkd/.cargo/registry/src/github.com-1ecc6299db9ec823/textwrap-0.9.0/src/lib.rs:634
  14: textwrap_fail::main
             at /Users/rkd/.cargo/registry/src/github.com-1ecc6299db9ec823/textwrap-0.9.0/src/lib.rs:544
  15: alloc::string::<impl core::convert::From<&'a str> for alloc::borrow::Cow<'a, str>>::from
             at /Users/travis/build/rust-lang/rust/src/libcore/iter/mod.rs:1701
  16: textwrap_fail::main
             at /Users/rkd/.cargo/registry/src/github.com-1ecc6299db9ec823/textwrap-0.9.0/src/lib.rs:370
  17: textwrap::WrapIterImpl::impl_next::{{closure}}
             at /Users/rkd/.cargo/registry/src/github.com-1ecc6299db9ec823/textwrap-0.9.0/src/lib.rs:749
  18: textwrap_fail::main
             at src/main.rs:5
  19: std::rt::lang_start::{{closure}}
             at /Users/travis/build/rust-lang/rust/src/libstd/rt.rs:74
  20: std::panicking::try::do_call
             at libstd/rt.rs:59
             at libstd/panicking.rs:306
  21: panic_unwind::dwarf::eh::read_encoded_pointer
             at libpanic_unwind/lib.rs:102
  22: std::sys_common::at_exit_imp::cleanup
             at libstd/panicking.rs:285
             at libstd/panic.rs:361
             at libstd/rt.rs:58
  23: std::rt::lang_start
             at /Users/travis/build/rust-lang/rust/src/libstd/rt.rs:74
  24: textwrap_fail::main

This is with textwrap 0.9.

Add a "fast_wrap" function that reuses the input string

The current wrap method allocates completely new strings for each line. This is necessary is one wants to support automatic hyphenation since the output can be different from the input in that case.

However, for the simple case with no hyphenation, it should be possible to return Vec<&str> where each &str is a slice of the original input string. This would mean fewer allocations and no copying of data, which ought to be faster.

Unintended wrapping when using external splitter

Consider the code:

use hyphenation;
use hyphenation::Load;
use textwrap;

let us_hyph = hyphenation::Standard::from_embedded(
    hyphenation::Language::EnglishUS).unwrap();
let input = "participation is the key to sucess";
let wrapper = textwrap::Wrapper::new(10);
let output = "participat\nion is the\nkey to\nsucess";
assert_eq!(output, wrapper.fill(input));
let wrapper = textwrap::Wrapper::with_splitter(10, us_hyph);
let output = "participa-\ntion\n \nis the key\nto sucess";
assert_eq!(output, wrapper.fill(input));
// expected output "participa-\ntion is the\nkey to\nsucess";

The first wrapper works okay (though it has to split the word in the middle) but the second wrapper with the hyphenator ends up having a blank third line instead of the expected result (in comments).

This might be a bug in the hyphenator library, but I'm not familiar enough with the code to know.

Update examples to the 2018 edition

2018 edition edition is already out, it would good to update the examples in README to 2018 edition. I checked that the last release was also around 2018.

Separate soft line break finding and wrapping

Currently this library does the soft line break finding and wrapping in one step to go from &str to String. However this is very inefficient for static blocks of text, which will require recalculating the soft line break positions every single time the viewport is resized. My suggestion is to have the wrapping functions take in an impl Iterator<Item = &str> and use that instead. Then instead of having the complex WordSplitter trait, we can have simple functions that take an &str and return an Iterator<Item = &str>.

If you're happy with the idea then I will work on this, I just need to get some feedback first.

Wrapping quotations

Hi. Thanks for developing this, it is really useful!

I have an issue: When wrapping the following content:

> foo bar baz
> baz baz

for example, I end up with

> foo
bar
baz
> baz
baz

But I want the quotes to be fixed, of course:

> foo
> bar
> baz
> baz
> baz

Could you please add support for this? It is useful for wrapping Email quotations for example, but I think it could also be useful for wrapping markdown and other formats.

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

Hello, this is a feature request.

It could be really useful to be able to use this library outside of the context of the CLI.
I'm thinking about Piston text, that provides rendered characters with their widths depending on font-size, TrueType Font, etc... I just browsed the source code, and I believe supporting it would only be a matter of allowing to insert custom sizes for characters, but I am not sure as I obviously do not grasp all of the big picture. It would also require to handle floating point numbers in some way, as maybe the size could not be an integer.
If you believe it's a good idea and is easy enough, I could do it myself.

Thanks in advance!

Make term_size an optional dependency

Currently, term_size is a required dependency of this crate. This means that all consumers of this library must also install the transitive closure of term_size's dependencies, even those who are not willing to use its functionality.

This is an especially important consideration given that term_size makes heavy use of unsafe, so crates with a zero-unsafe policy (such as one I am currently authoring) may not be able to use textwrap even though they don't actually need any of its unsafe-dependent functionality.

Since with_termwidth() is more or less trivial, and the termwidth() function literally just wraps term_size with a hardcoded default value, it seems to me that it is not the right trade-off that has been made in this regard.

Consequently, I suggest one of the following, in decreasing order of preference:

  • Remove the term_size dependency, termwidth(), and with_termwidth() altogether, because the latter two are trivial and the default value of 80 might not be suitable for everyone anyway.
  • Make with_termwidth() and termwidth() a non-default, optional feature and term_size an optional dependency, so they are not included by default, but those who are willing to use the functionality can still continue doing so without breaking code changes.
  • Make with_termwidth() and termwidth() a default, optional feature and term_size an optional dependency, so they are included by default, but those who are not willing to use the functionality can opt out.

This is blocking clap-rs/clap#1055.

Non breaking words

Hello,

When I run:

let text = "textwrap: a small library for wrapping text.";

println!(
    "{}",
    textwrap::Wrapper::new(1).break_words(false).fill(text)
);

I get the non-expected results:

textwrap:
 
a
small
 librar
y
 fo
r
 wrappin
g
 text
.

Yet I expect:

textwrap:
a
small
library
for
wrapping
text.

Same with 2, 3, 4 ...

Thank you!

Perhaps add a refill method

It could be nice if textwrap supported "refilling" a paragraph. It should take an existing string like this

let help = "This is a long help text.
            It continues on this line
            since nicely-wrapped
            lines look better in the
            source code.

            This is a second paragraph
            in the same string.";

This string contains newlines and extra indentation. Refilling it would mean ignoring the extra newlines and indentation, and then otherwise wrapping it at some width.

Multiple paragraphs should probably be supported in order to make it extra convenient.

License issues

This issue might be problematic:
tapeinosyne/hyphenation#17

Although the hyphenation crate is an optional dependency there are quite a number of files licensed as GPL. I am not a licensing expect but this seem troublesome. It also comes up when using https://fossa.com checking crates that depend on clap. Because clap depends on textwrap, although it does not use the hyphenation feature (Apparently fossa is not aware of cargo features).

Take newlines into account when wrapping

println!("{}",fill("1 3 5 7
1 3 5 7",11));

/*
Expected:
1 3 5 7
1 3 5 7

Actual output:
1 3 5 7
1 3
5 7
*/

Currently, it seems that fill considers line breaks like any other whitespace character. It would be nice if the function could take line breaks into account when computing the wrapping!

Support for columns

Hi, I would love to be able to wrap a text into mutiple columns.

Something like this quick draft could be the API for it.

pub fn columns (s: &str, columns: usize, width: usize, outer_gap: usize, inner_gap: usize );

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

Example:

// this test fails currently
#[test]
fn indented_text_should_have_the_same_number_of_lines_as_the_original_text() {
    let texts = ["foo\nbar", "foo\nbar\n", "foo\nbar\nbaz"];
    for original in texts.iter() {
        let indented = indent(original, "");
        assert_eq!(&indented, original);
    }
}

There should be the same number of lines in the input and output (unless the prefix contains a newline).

Python tests reference, python source reference, can't be implemented the same way in rust without the split_inclusive feature. (cf. python's splitlines)

Python script passes the same test
from textwrap import indent

for original in ["foo\nbar", "foo\nbar\n", "foo\nbar\nbaz"]:
    indented = indent(original, "")
    assert original == indented

Support for tabs and hanging indent

The use case I'm thinking of is for a command-line program describing its options. Eg

-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.

Handle ANSI color codes

Textwrap currently doesn't know about ANSI color codes for colored terminal output. It simply treats these escape codes as any other character and this can mess up the output as shown here: clap-rs/clap#1246.

The custom width functionality of #128 could perhaps be used to solve this problem, but I feel it would be nice if this was a builtin feature (perhaps an optional feature depending on how invasive it will be to handle this).

Integer size and overflow when calculating penalty

When testing the optimal-fit algorithm, I encountered a panic during the cost calculations:

thread 'main' panicked at 'attempt to multiply with overflow', .../textwrap-0.13.0/src/core.rs:710:21

I fixed this by multiplying my mm widths with the factor 100 instead of 1000, which should still be a sufficient precision. But looking at the cost calculations, I have two follow-up questions:

  • Why are the costs stored as a i32 instead of a usize? They are generated by adding positive usize values, positive integer constants and other costs, so usize should work too.
  • How should overflows be handled when calculating the penalty? I changed the i32 type to usize, causing an integer overflow at the same location for the max_width test case that sets the line width to usize::MAX. This is currently working, probably because the huge value target_width - line_width is cropped when casting to i32 before updating the cost. Shouldn’t the cost calculation use saturating additions and multiplications if large line widths are supported?

Bad hyphenation in layout example

I just noticed that the layout example looks weird:

$ cargo run --all-features --example layout
.------------------ Width: 46 -------------------.
| Memory safety without garbage collection. Co-  |
| ncurrency without data races. Zero-cost a-     |
| bstractions.                                   |
.-------------------- Width: 49 --------------------.
| Memory safety without garbage collection. Concu-  |
| rrency without data races. Zero-cost a-           |
| bstractions.                                      |
.-------------------- Width: 50 ---------------------.
| Memory safety without garbage collection. Concu-   |
| rrency without data races. Zero-cost abstra-       |
| ctions.                                            |

This is with version 0.9.0. I think there has been a regression since I don't believe it looked like this in the past — notice how all the hyphenated words are broken in weird places.

Wrap multiple strings into a single paragraph (i.e. keep state while wrapping)

Hello,

I'd like to wrap paragraph text from a Markdown document parsed with pulldown_cmark.

This library feeds me a stream of events which intersperses the text of a paragraph with other events about formatting, eg:

  1. Text(Lorem ipsum dolor sit )
  2. Softwrap
  3. Text(amet, )
  4. Start(Bold)
  5. Text(consetetur)
  6. End(Bold)
  7. Text(sadipscing elitr)

To wrap all Text into a single paragraph I'd currently need to wrap each Text individually into a sequence of lines, measure the length of the last line, and then use that length (plus an extra space) as initial_indent for the next Text event, and so on…

This is certainly possible but not exactly convenient and I can't profit from textwrap's work, which already measured the length of the text.

Could textwrap provide a ParagraphWrapper which keeps state of wrapping?

Perhaps iterate over grapheme clusters instead of Unicode scalars

We currently wrap strings by iterating over Unicode code points (char elements) and splitting on whitespace.

The unicode-segmentation crate allows iterating over grapheme clusters instead, which (as far as I understand), means that it will treat things like "e\u{301}" ("e" followed by a combining accent aigu, e.g. é) as a single entity.

When iterating over Unicode strings, it's generally recommended to use grapheme clusters instead of individual code points.

Support initial and subsequent indent

The Python textwrap module has options for controlling the left margin of the wrapped lines. They two settings are called initial_indent and subsequent_indent and if they're set to "* " (asteris, space) and " " (space, space) respectively, your wrapped text becomes a nice little list item.

That sounds useful, so let's add support for that too.

Automatic hyphenation

There is a hyphenation crate available on crates.io which provides hyphenation patterns for many languages. This can be used to automatically hyphenate the text, thus providing better wrapping.

Unexpected behaviour when wrapping ANSI escape codes

Hello!

I understand that ANSI wrapping support was added in #140. However adding ANSI codes to the example string from the README produces unexpected line wrapping:

fn main() {
    let text = "\u{001b}[31mtextwrap\u{001b}[0m: an efficient and powerful library for wrapping text.";
    println!("{}", textwrap::fill(text, 28));
}

produces:

textwrap: an
efficient and powerful
library for wrapping text.

expected:

textwrap: an efficient
and powerful library for
wrapping text.

Embedding the `Wrapper` object in a struct

Hey, thanks for the crate :)

I'm writing a simple GStreamer wrapper around it, my end use case is to format "any" text so that it can be used as input to a CEA 608 closed captioning element, CEA 608 exposes a simple grid system to position characters, that grid is at most 32 columns wide.

The element receives buffers of data, with a timestamp and a duration, and each buffer must be formatted as it arrives and sent out on the spot. I don't want to recreate a wrapper for each buffer, and instead store it in a State structure. In addition, the interface I exposed on the element accepts an optional path to a dictionary, which can be changed at runtime, including setting it to None to not use hyphenation at all.

The implementation I ended up with is https://gitlab.freedesktop.org/meh/gst-plugins-rs/-/blob/textwrap/text/wrap/src/gsttextwrap.rs#L101 , and I'll continue that way for now, but that's not ideal: I'd much rather store a Wrapper<WordSplitter>, with its default set to Wrapper::with_splitter(columns, NoHyphenation). I can't do this however of course, because the size of WordSplitter is not known at compile-time, but I also can't use Box because there is no impl for it either. I would also rather not have to use 'static as the lifetime here.

I'm not very well-versed in terms of designing rust APIs so I don't have a good suggestion, but I hope we can come up with something a bit more elegant for that use case :)

Again, thanks for the crate, the functionality is exactly what I was looking for!

Feature Request: dedent_less_than

Hi, I'm using this lib and I need some special dedent.

Can you add this function that dedent white spaces less than n?

https://stackoverflow.com/questions/60337455/how-to-trim-space-less-than-n-times

pub fn dedent_less_than(input: &str, indent: usize) -> String {
    let mut out : String = String::from(input);
    let mut j: usize = 0;
    let mut is_counting = true;
    let mut ws_cnt = 0;
    unsafe {
        let outb = out.as_bytes_mut();
        for i in 0..outb.len() {
            if is_counting == true && outb[i] == b' '  {
                ws_cnt+=1;
                if ws_cnt == indent {
                    is_counting = false;
                }
            } else {
                is_counting=false;
                if outb[i]== b'\n' {
                    is_counting=true;
                    ws_cnt=0;
                }
                outb[j]=outb[i];
                j+=1;
            }
        }
    }
    out.truncate(j);
    out
}

Release of version with hyphenation 0.7

In Debian, we packaged textwrap 0.10. We usually try to package the latest versions of crates only, and for the packages to migrate from the unstable to the testing repository, all feature dependencies need to be packaged as well. In this specific case, packaging hyphenation 0.6 would require a whole tree of old dependencies, which we try to avoid. I have seen that hyphenation has been updated to 0.7 in textwrap master. Can we expect a release of textwrap any time soon?

Make `fill_inplace` take an &mut str

Since it doesn't change the length of the string, it can take an &mut str instead of an &mut String. This will remove one layer of indirection and make it more flexible.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.