From 8b512adbbcf62f49b3e92410e643c86f2e70908a Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 15 Sep 2024 17:50:43 -0400 Subject: Move each example to its own folder --- examples/wrap/wrap.tm | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 examples/wrap/wrap.tm (limited to 'examples/wrap/wrap.tm') diff --git a/examples/wrap/wrap.tm b/examples/wrap/wrap.tm new file mode 100644 index 00000000..54198193 --- /dev/null +++ b/examples/wrap/wrap.tm @@ -0,0 +1,102 @@ +HELP := " + wrap: A tool for wrapping lines of text + + usage: wrap [--help] [files...] [--width=80] [--inplace=no] [--min_split=3] [--no-rewrap] [--hyphen='-'] + --help: Print this message and exit + [files...]: The files to wrap (stdin is used if no files are provided) + --width=N: The width to wrap the text + --inplace: Whether or not to perform the modification in-place or print the output + --min-split=N: The minimum amount of text on either end of a hyphenation split + --rewrap|--no-rewrap: Whether to rewrap text that is already wrapped or only split long lines + --hyphen='-': The text to use for hyphenation +" + +UNICODE_HYPHEN := \{hyphen} + +func unwrap(text:Text, preserve_paragraphs=yes, hyphen=UNICODE_HYPHEN)->Text: + if preserve_paragraphs: + paragraphs := text:split($/{2+ nl}/) + if paragraphs.length > 1: + return \n\n:join([unwrap(p, hyphen=hyphen, preserve_paragraphs=no) for p in paragraphs]) + + return text:replace($/$(hyphen)$(\n)/, "") + +func wrap(text:Text, width:Int, min_split=3, hyphen="-")->Text: + if width <= 0: + fail("Width must be a positive integer, not $width") + + if 2*min_split - hyphen.length > width: + fail(" + Minimum word split length ($min_split) is too small for the given wrap width ($width)! + + I can't fit a $(2*min_split - hyphen.length)-wide word on a line without splitting it, + ... and I can't split it without splitting into chunks smaller than $min_split. + ") + + lines := [:Text] + line := "" + for word in text:split($/{whitespace}/): + letters := word:split() + skip if letters.length == 0 + + while not _can_fit_word(line, letters, width): + line_space := width - line.length + if line != "": line_space -= 1 + + if min_split > 0 and line_space >= min_split + hyphen.length and letters.length >= 2*min_split: + # Split word with a hyphen: + split := line_space - hyphen.length + split = split _max_ min_split + split = split _min_ (letters.length - min_split) + if line != "": line ++= " " + line ++= ((++) letters:to(split)) ++ hyphen + letters = letters:from(split + 1) + else if line == "": + # Force split word without hyphenation: + if line != "": line ++= " " + line ++= ((++) letters:to(line_space)) + letters = letters:from(line_space + 1) + else: + pass # Move to next line + + lines:insert(line) + line = "" + + if letters.length > 0: + if line != "": line ++= " " + line ++= (++) letters + + if line != "": + lines:insert(line) + + return \n:join(lines) + +func _can_fit_word(line:Text, letters:[Text], width:Int; inline)->Bool: + if line == "": + return letters.length <= width + else: + return line.length + 1 + letters.length <= width + +func main(files:[Path], width=80, inplace=no, min_split=3, rewrap=yes, hyphen=UNICODE_HYPHEN): + if files.length == 0: + files = [(/dev/stdin)] + + for file in files: + text := file:read():or_exit("Could not read file: $(file.text_content)") + + if rewrap: + text = unwrap(text) + + out := if file:is_file() and inplace: + file + else: + (/dev/stdout) + + first := yes + wrapped_paragraphs := [:Text] + for paragraph in text:split($/{2+ nl}/): + wrapped_paragraphs:insert( + wrap(paragraph, width=width, min_split=min_split, hyphen=hyphen) + ) + + out:write(\n\n:join(wrapped_paragraphs) ++ \n) -- cgit v1.2.3