Skip to content

Commit 5a887fb

Browse files
omusnicoleepp
andauthored
Implement indent function (#6)
* Implement indent function * Update README.md Co-authored-by: Nicole Epp <nicole.epp@invenia.ca>
1 parent b9b2b62 commit 5a887fb

File tree

5 files changed

+82
-8
lines changed

5 files changed

+82
-8
lines changed

README.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,14 @@ Tooling for manipulating multiline strings.
1010

1111
## Features
1212

13-
The package features a multiline string literal (`@m_str`), inspired from [YAML's block scalars](https://yaml-multiline.info/), which provide options for manipulating multiline string literals via a style and chomp indicator:
13+
The package features support for:
14+
15+
- Multiline string literals (`@m_str`, `multiline`)
16+
- An indent function which only indents non-blank lines (`indent`)
17+
18+
### Multiline String Literal
19+
20+
The multiline string literal (`@m_str`), inspired from [YAML's block scalars](https://yaml-multiline.info/), which provide options for manipulating multiline string literals via a style and chomp indicator:
1421

1522
- Style indicator:
1623
- `f` replace newlines with spaces (folded)
@@ -23,7 +30,7 @@ The package features a multiline string literal (`@m_str`), inspired from [YAML'
2330
The indicators are provided after the ending quote of the string (e.g. `m"hello\nworld!"fc`).
2431
If no indicators are provided the default behaviour is folded/strip.
2532

26-
## Example
33+
#### Example
2734

2835
When writing a long string literal you may want to break the string up over multiple lines in the code, to make it easier to read, but have the string be printed as a single line.
2936
Specifically, when writing an long error message you may want to break up the string over multiple lines:
@@ -54,3 +61,19 @@ with the non-magical computation occurring on this device.
5461
```
5562

5663
Take note that a Julia [triple-quoted string literal](https://docs.julialang.org/en/v1/manual/strings/#Triple-Quoted-String-Literals) will leave most newlines in place.
64+
65+
### Indent
66+
67+
The `indent` function will indent non-empty lines of a string by a number of spaces.
68+
69+
```julia
70+
julia> str = """
71+
A blank line:
72+
73+
plus another line at the end.
74+
"""
75+
"A blank line:\n\nplus another line at the end.\n"
76+
77+
julia> indent(str, 4)
78+
" A blank line:\n\n plus another line at the end.\n"
79+
```

src/MultilineStrings.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module MultilineStrings
22

3-
export @m_str, multiline
3+
export @m_str, indent, multiline
44

55
const DEFAULT_STYLE = :folded
66
const DEFAULT_CHOMP = :strip
@@ -198,4 +198,6 @@ function _process_indicators(indicators::AbstractString)
198198
return style, chomp
199199
end
200200

201+
include("indent.jl")
202+
201203
end

src/indent.jl

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
indent(str::AbstractString, n::Int)
3+
4+
Indent each non-blank line by `n` spaces.
5+
6+
# Examples
7+
```jldoctest; setup = :(using MultilineStrings)
8+
julia> indent("a\\nb", 4)
9+
" a\\n b"
10+
11+
julia> indent(" a\\n \\n b", 2)
12+
" a\\n \\n b"
13+
```
14+
15+
See also `Base.unintent` and `Base.indentation`.
16+
"""
17+
function indent(str::AbstractString, n::Int)
18+
n == 0 && return str
19+
# Note: this loses the type of the original string
20+
buf = IOBuffer(sizehint=sizeof(str))
21+
indent_str = ' ' ^ n
22+
23+
line_start = firstindex(str)
24+
blank_line = true
25+
for (i, ch) in enumerate(str)
26+
if ch == '\n'
27+
!blank_line && print(buf, indent_str)
28+
print(buf, SubString(str, line_start, i))
29+
line_start = nextind(str, i)
30+
blank_line = true
31+
elseif blank_line && !isspace(ch)
32+
blank_line = false
33+
end
34+
end
35+
36+
# Last line of string that doesn't contain a newline
37+
!blank_line && print(buf, indent_str)
38+
print(buf, SubString(str, line_start, lastindex(str)))
39+
40+
String(take!(buf))
41+
end

test/indent.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@testset "indent" begin
2+
@test indent("", 4) == ""
3+
@test indent("\n", 4) == "\n"
4+
@test indent(" \n ", 2) == " \n "
5+
6+
@test indent("a", 4) == " a"
7+
@test indent("a\n\nb", 4) == " a\n\n b"
8+
end

test/runtests.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
using Documenter: doctest
22
using MultilineStrings
3-
using MultilineStrings: MultilineStrings, @m_str, multiline, interpolate
3+
using MultilineStrings: MultilineStrings, @m_str, indent, interpolate, multiline
44
using Test
55
using YAML: YAML
66

7-
indent(str, n) = join(map(line -> (" " ^ n) * line, split(str, '\n')), '\n')
8-
97
function yaml_block(str, block_scalar)
108
yaml = "example: $block_scalar\n$(indent(str, 2))"
119
YAML.load(yaml)["example"]
@@ -28,8 +26,6 @@ const TEST_STRINGS = [
2826
"starting newline" => "\nbar",
2927
]
3028

31-
doctest(MultilineStrings)
32-
3329
# Validate `yaml_block` function
3430
for (test, str) in TEST_STRINGS
3531
@assert yaml_block(str, "|+") == str
@@ -147,4 +143,8 @@ end
147143
@test m"""$(join(("a", "b") .* "\n", ""))"""fc == "a b\n"
148144
end
149145
end
146+
147+
include("indent.jl")
148+
149+
doctest(MultilineStrings)
150150
end

0 commit comments

Comments
 (0)