summaryrefslogtreecommitdiff
path: root/lib/String/Fold.pm6
blob: 127b913535e2104a46886a29f33bdd8bb7735c60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#! /usr/bin/env false

use v6.c;

unit module String::Fold;

#| Fold a string to contain no lines longer than the given width.
sub fold (
	#| The string to fold.
	Str:D $string,

	#| The maximum width of lines in the text.
	Int:D :$width where 0 < * = 80,

	#| The number of spaces used to indent the text.
	Int:D :$indent where -1 < * = 0,

	--> Str
) is export {
	my Str @folded-lines = [];
	my Str @current-words = [];

	for $string.trim.lines -> $line {
		# Nothing to do if the line is less than the maximum width.
		if ($line.chars <= $width) {
			@folded-lines.append($line);
			next;
		}

		# Work through each word on the line and fold them to the maximum width.
		for $line.words -> $word {
			if (new-line-length(@current-words, $word, $indent) <= $width) {
				@current-words.append($word);
				next;
			}

			@folded-lines.append(@current-words.join(" "));
			@current-words = [$word];
		}

		# Clean up the current list of words.
		@folded-lines.append(@current-words.join(" "));
		@current-words = [];
	}

	# Add the last line if we have any leftover current words.
	@folded-lines.push(@current-words.join(" ")) if @current-words;

	return @folded-lines>>.indent($indent).join("\n");
}

#| Calculate the total line length of a would-be line.
sub new-line-length (
	Str:D @words,
	Str:D $new-word,
	Int:D $indent-width,
	--> Int
) {
	my Int $chars = 0;

	# Get the number of characters in each word.
	$chars += [+] @words>>.chars;

	$chars += @words.elems; # Spaces inbetween the words.
	$chars += $new-word.chars;
	$chars += $indent-width;

	$chars;
}

=begin pod

=NAME    String::Fold
=AUTHOR  Patrick Spek <p.spek@tyil.work>
=VERSION 0.1.2

=head1 SYNOPSIS

fold(Str:D $, Int:D :$width, Int:D :$indent);

=head1 DESCRIPTION

Fold a C<Str> to a given width. Accepts a C<:$width>N<Defaults to C<80>> and a
C<:$indent>N<Defaults to C<0>>.

=head1 EXAMPLES

=head2 Basic usage

=begin input
use String::Fold;

my Str $folded = fold(slurp("some-text-file"));
=end input

This will yield a folded string in C<$folded>. The input file will have all its
lines folded to a maximum width of 80 characters.

=head2 Folding at a custom width

=begin input
use String::Fold;

my Str $folded = slurp("some-text-file").&fold(:width(40));
=end input

This will yield a string folded at 40 characters, instead of the default of 80
characters. Any number higher that C<0> is accepted.

=head2 Indented block

=begin input
use String::Fold;

my Str $indented = slurp("some-text-file").&fold(:indent(8));
=end input

This will yield a string folded at 80 characters (the default), and indented by
8 spaces.

=end pod

# vim: ft=perl6 noet