Text

Text wrapping

Text wrapped and filled at a width for plain-text emails and terminals: paragraphs refilled, hanging indents for lists, and > quoting for replies.

Version 1.0.0 · 6 functions · 1 crate

#email#text#terminal#export

Functions

What use text_wrap.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use wrap_lines, wrap_fill from text_wrap (Quillo 0.6).

wrap_lines(text: str, width: int) → listor an error

text as lines of at most width columns, breaking between words (wide characters such as 日本 count 2). Line breaks in the text are kept; a word longer than a line is split.

wrap_fill(text: str, width: int) → stror an error

text refilled at width: each paragraph (blank line apart) joined and wrapped again, for a plain-text email body.

wrap_hanging(text: str, width: int, first: str, rest: str) → stror an error

text refilled at width with first before its first line and rest before the others, per paragraph: a hanging indent ("1. " and " ") or a bullet ("* " and " ").

wrap_quote(text: str, width: int) → stror an error

text quoted for a reply, each line refilled at width and starting with "> ", blank lines as ">".

wrap_indent(text: str, prefix: str) → stror an error

text with prefix before each line that is not blank.

wrap_dedent(text: str) → stror an error

text with the spaces all its lines share taken off the front: for text written indented inside code.

Get it

$ quillo install text_wrap               # text_wrap.qwer into this folder$ quillo install text_wrap --example     # and its example, text_wrap.qwe

Or with curl:

$ curl -O https://quillolang.org/plugins/files/text_wrap.qwer$ curl -O https://quillolang.org/plugins/files/text_wrap.qwe

Then, in your program, all of it or only what you call:

main.qwe
use text_wrap.qweruse wrap_lines, wrap_fill from text_wrap      // Quillo 0.6: only these

It uses this crate, which cargo fetches the first time the plugin is built:

[dependencies]
textwrap = "0.16"

Example

text_wrap.qwe
// A plain-text email: the body filled at 60 columns, a numbered list with hanging indents, and the message replied to quoted.////   quillo run text_wrap.qwe      then open http://localhost:8080/reply.txtuse "text_wrap.qwer"let original = "Could you send the invoice for October again? The one I got has the old address on it, and our accountant needs the new one before the end of the month.\n\nThanks, Ada"let steps = ["Open Settings and choose Billing, then pick the invoice you want to download again.", "Change the address under Company details; the next invoices will carry it."]route GET /reply.txt {    let body = wrap_fill("Hi Ada, here is the October invoice again with the new address. I have also changed it for the invoices to come, so this will not happen again.", 60)?    let list = enumerate(steps) | map((p) => wrap_hanging(p[1], 60, `${p[0] + 1}. `, "   ")?)    let text = `${body}\n\n${join(list, "\n")}\n\nOn 28 October, Ada wrote:\n${wrap_quote(original, 60)?}\n`    respond(200, text, { "content-type": "text/plain; charset=utf-8" })}route GET /lines ? { width: int = 20 } = wrap_lines("The quick brown fox jumps over the lazy dog.", width)?
$ quillo run text_wrap.qwe$ curl 'localhost:8080/reply.txt'$ curl 'localhost:8080/lines'

Source

text_wrap.qwer
//! Text wrapped and filled at a width, for plain-text emails, terminals and fixed-width files: paragraphs kept, words never cut unless longer than a line, indents and "> " quoting.//! version: 1.0.0//!//! [dependencies]//! textwrap = "0.16"use textwrap::Options;const MAX: usize = 5_000_000;fn check(text: &str, width: i64) -> Result<usize, String> {    if text.len() > MAX {        return Err("text up to 5 MB".into());    }    Ok(width.clamp(1, 10_000) as usize)}fn each_paragraph(text: &str, f: impl Fn(&str) -> String) -> String {    text.split("\n\n").map(|p| f(&p.split_whitespace().collect::<Vec<_>>().join(" "))).collect::<Vec<_>>().join("\n\n")}/// `text` as lines of at most `width` columns, breaking between words (wide characters such as 日本 count 2). Line breaks in the text are kept; a word longer than a line is split.pub fn wrap_lines(text: &str, width: i64) -> Result<Vec<String>, String> {    let w = check(text, width)?;    Ok(textwrap::wrap(text, w).into_iter().map(|l| l.into_owned()).collect())}/// `text` refilled at `width`: each paragraph (blank line apart) joined and wrapped again, for a plain-text email body.pub fn wrap_fill(text: &str, width: i64) -> Result<String, String> {    let w = check(text, width)?;    Ok(each_paragraph(text, |p| textwrap::fill(p, w)))}/// `text` refilled at `width` with `first` before its first line and `rest` before the others, per paragraph: a hanging indent ("1. " and "   ") or a bullet ("* " and "  ").pub fn wrap_hanging(text: &str, width: i64, first: &str, rest: &str) -> Result<String, String> {    let w = check(text, width)?;    Ok(each_paragraph(text, |p| textwrap::fill(p, Options::new(w).initial_indent(first).subsequent_indent(rest))))}/// `text` quoted for a reply, each line refilled at `width` and starting with "> ", blank lines as ">".pub fn wrap_quote(text: &str, width: i64) -> Result<String, String> {    let w = check(text, width)?;    let filled = each_paragraph(text, |p| textwrap::fill(p, Options::new(w.saturating_sub(2).max(1)).initial_indent("").subsequent_indent("")));    Ok(filled.lines().map(|l| if l.is_empty() { ">".to_string() } else { format!("> {}", l) }).collect::<Vec<_>>().join("\n"))}/// `text` with `prefix` before each line that is not blank.pub fn wrap_indent(text: &str, prefix: &str) -> Result<String, String> {    check(text, 1)?;    Ok(textwrap::indent(text, prefix))}/// `text` with the spaces all its lines share taken off the front: for text written indented inside code.pub fn wrap_dedent(text: &str) -> Result<String, String> {    check(text, 1)?;    Ok(textwrap::dedent(text))}
HTML to text html_text.qwer · 1.0.0HTML as readable plain text for the text part of an email: headings, lists and tables laid out, links listed at the end, and one-line previews.emailhtmltextexport7 views · 7 downloadsHyphenation hyphenation.qwer · 1.0.0Words hyphenated by the rules of 80 languages and spellings, patterns built in: a word's syllables, soft hyphens put in text and HTML for narrow columns and e-mails, and text wrapped at a width with words broken where they may be.textlanguagesemailwriting6 views · 7 downloadsTemplates templates.qwer · 1.0.0Jinja templates your users can edit for emails, invoices and pages: sandboxed, escaped for HTML, with filters such as money and truncate, and checked before they are saved.templatesemailhtmltext7 views · 8 downloadsText tables text_table.qwer · 1.0.0Rows as aligned plain-text tables for e-mails, logs, terminals and READMEs: box-drawn, ASCII, plain or Markdown, numbers to the right, wide characters measured right, long cells cut; and Markdown tables read back into rows.reportsemailterminalmarkdown7 views · 7 downloadsMailboxes mbox.qwer · 1.0.0Mailboxes in the mbox format read message by message: lists, search, one message in full with its attachments, each saved as .eml, and messages appended.emailimportexportsupportattachments7 views · 9 downloadsRTF rtf.qwer · 1.0.0RTF documents read as plain text with their title and author, and simple RTF written: headings, bold and italic runs and tables, for Word, Pages and TextEdit.documentswordtextimportexport7 views · 8 downloads
Thread
76Useful? Like it, or add to its thread below.

Thread 0 posts

On Text wrapping: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.