Skip to content

Commit

Permalink
Implement indent function (#6)
Browse files Browse the repository at this point in the history
* Implement indent function
* Update README.md

Co-authored-by: Nicole Epp <[email protected]>
  • Loading branch information
omus and nicoleepp authored Dec 10, 2020
1 parent b9b2b62 commit 5a887fb
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 8 deletions.
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ Tooling for manipulating multiline strings.

## Features

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:
The package features support for:

- Multiline string literals (`@m_str`, `multiline`)
- An indent function which only indents non-blank lines (`indent`)

### Multiline String Literal

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:

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

## Example
#### Example

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.
Specifically, when writing an long error message you may want to break up the string over multiple lines:
Expand Down Expand Up @@ -54,3 +61,19 @@ with the non-magical computation occurring on this device.
```

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.

### Indent

The `indent` function will indent non-empty lines of a string by a number of spaces.

```julia
julia> str = """
A blank line:
plus another line at the end.
"""
"A blank line:\n\nplus another line at the end.\n"

julia> indent(str, 4)
" A blank line:\n\n plus another line at the end.\n"
```
4 changes: 3 additions & 1 deletion src/MultilineStrings.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module MultilineStrings

export @m_str, multiline
export @m_str, indent, multiline

const DEFAULT_STYLE = :folded
const DEFAULT_CHOMP = :strip
Expand Down Expand Up @@ -198,4 +198,6 @@ function _process_indicators(indicators::AbstractString)
return style, chomp
end

include("indent.jl")

end
41 changes: 41 additions & 0 deletions src/indent.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
indent(str::AbstractString, n::Int)
Indent each non-blank line by `n` spaces.
# Examples
```jldoctest; setup = :(using MultilineStrings)
julia> indent("a\\nb", 4)
" a\\n b"
julia> indent(" a\\n \\n b", 2)
" a\\n \\n b"
```
See also `Base.unintent` and `Base.indentation`.
"""
function indent(str::AbstractString, n::Int)
n == 0 && return str
# Note: this loses the type of the original string
buf = IOBuffer(sizehint=sizeof(str))
indent_str = ' ' ^ n

line_start = firstindex(str)
blank_line = true
for (i, ch) in enumerate(str)
if ch == '\n'
!blank_line && print(buf, indent_str)
print(buf, SubString(str, line_start, i))
line_start = nextind(str, i)
blank_line = true
elseif blank_line && !isspace(ch)
blank_line = false
end
end

# Last line of string that doesn't contain a newline
!blank_line && print(buf, indent_str)
print(buf, SubString(str, line_start, lastindex(str)))

String(take!(buf))
end
8 changes: 8 additions & 0 deletions test/indent.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@testset "indent" begin
@test indent("", 4) == ""
@test indent("\n", 4) == "\n"
@test indent(" \n ", 2) == " \n "

@test indent("a", 4) == " a"
@test indent("a\n\nb", 4) == " a\n\n b"
end
10 changes: 5 additions & 5 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using Documenter: doctest
using MultilineStrings
using MultilineStrings: MultilineStrings, @m_str, multiline, interpolate
using MultilineStrings: MultilineStrings, @m_str, indent, interpolate, multiline
using Test
using YAML: YAML

indent(str, n) = join(map(line -> (" " ^ n) * line, split(str, '\n')), '\n')

function yaml_block(str, block_scalar)
yaml = "example: $block_scalar\n$(indent(str, 2))"
YAML.load(yaml)["example"]
Expand All @@ -28,8 +26,6 @@ const TEST_STRINGS = [
"starting newline" => "\nbar",
]

doctest(MultilineStrings)

# Validate `yaml_block` function
for (test, str) in TEST_STRINGS
@assert yaml_block(str, "|+") == str
Expand Down Expand Up @@ -147,4 +143,8 @@ end
@test m"""$(join(("a", "b") .* "\n", ""))"""fc == "a b\n"
end
end

include("indent.jl")

doctest(MultilineStrings)
end

0 comments on commit 5a887fb

Please sign in to comment.