mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 11:52:19 +00:00
Merge pull request #3432 from rtfeldman/fmt-multiline-when
Format multiline `when` branches
This commit is contained in:
commit
f5f137982c
34 changed files with 495 additions and 365 deletions
|
@ -734,6 +734,7 @@ min = \list ->
|
|||
when List.first list is
|
||||
Ok initial ->
|
||||
Ok (minHelp list initial)
|
||||
|
||||
Err ListWasEmpty ->
|
||||
Err ListWasEmpty
|
||||
|
||||
|
@ -750,6 +751,7 @@ max = \list ->
|
|||
when List.first list is
|
||||
Ok initial ->
|
||||
Ok (maxHelp list initial)
|
||||
|
||||
Err ListWasEmpty ->
|
||||
Err ListWasEmpty
|
||||
|
||||
|
@ -782,6 +784,7 @@ find = \array, pred ->
|
|||
when List.iterate array {} callback is
|
||||
Continue {} ->
|
||||
Err NotFound
|
||||
|
||||
Break found ->
|
||||
Ok found
|
||||
|
||||
|
@ -863,6 +866,7 @@ iterHelp = \list, state, f, index, length ->
|
|||
when f state (List.getUnsafe list index) is
|
||||
Continue nextState ->
|
||||
iterHelp list nextState f (index + 1) length
|
||||
|
||||
Break b ->
|
||||
Break b
|
||||
else
|
||||
|
|
|
@ -12,10 +12,8 @@ Result ok err : [Ok ok, Err err]
|
|||
isOk : Result ok err -> Bool
|
||||
isOk = \result ->
|
||||
when result is
|
||||
Ok _ ->
|
||||
True
|
||||
Err _ ->
|
||||
False
|
||||
Ok _ -> True
|
||||
Err _ -> False
|
||||
|
||||
## Return True if the result indicates a failure, else return False
|
||||
##
|
||||
|
@ -23,10 +21,8 @@ isOk = \result ->
|
|||
isErr : Result ok err -> Bool
|
||||
isErr = \result ->
|
||||
when result is
|
||||
Ok _ ->
|
||||
False
|
||||
Err _ ->
|
||||
True
|
||||
Ok _ -> False
|
||||
Err _ -> True
|
||||
|
||||
## If the result is `Ok`, return the value it holds. Otherwise, return
|
||||
## the given default value.
|
||||
|
@ -37,10 +33,8 @@ isErr = \result ->
|
|||
withDefault : Result ok err, ok -> ok
|
||||
withDefault = \result, default ->
|
||||
when result is
|
||||
Ok value ->
|
||||
value
|
||||
Err _ ->
|
||||
default
|
||||
Ok value -> value
|
||||
Err _ -> default
|
||||
|
||||
## If the result is `Ok`, transform the value it holds by running a conversion
|
||||
## function on it. Then return a new `Ok` holding the transformed value.
|
||||
|
@ -56,10 +50,8 @@ withDefault = \result, default ->
|
|||
map : Result a err, (a -> b) -> Result b err
|
||||
map = \result, transform ->
|
||||
when result is
|
||||
Ok v ->
|
||||
Ok (transform v)
|
||||
Err e ->
|
||||
Err e
|
||||
Ok v -> Ok (transform v)
|
||||
Err e -> Err e
|
||||
|
||||
## If the result is `Err`, transform the value it holds by running a conversion
|
||||
## function on it. Then return a new `Err` holding the transformed value.
|
||||
|
@ -72,10 +64,8 @@ map = \result, transform ->
|
|||
mapErr : Result ok a, (a -> b) -> Result ok b
|
||||
mapErr = \result, transform ->
|
||||
when result is
|
||||
Ok v ->
|
||||
Ok v
|
||||
Err e ->
|
||||
Err (transform e)
|
||||
Ok v -> Ok v
|
||||
Err e -> Err (transform e)
|
||||
|
||||
## If the result is `Ok`, transform the entire result by running a conversion
|
||||
## function on the value the `Ok` holds. Then return that new result.
|
||||
|
@ -88,10 +78,8 @@ mapErr = \result, transform ->
|
|||
after : Result a err, (a -> Result b err) -> Result b err
|
||||
after = \result, transform ->
|
||||
when result is
|
||||
Ok v ->
|
||||
transform v
|
||||
Err e ->
|
||||
Err e
|
||||
Ok v -> transform v
|
||||
Err e -> Err e
|
||||
|
||||
## If the result is `Err`, transform the entire result by running a conversion
|
||||
## function on the value the `Err` holds. Then return that new result.
|
||||
|
@ -104,7 +92,5 @@ after = \result, transform ->
|
|||
afterErr : Result a err, (err -> Result a otherErr) -> Result a otherErr
|
||||
afterErr = \result, transform ->
|
||||
when result is
|
||||
Ok v ->
|
||||
Ok v
|
||||
Err e ->
|
||||
transform e
|
||||
Ok v -> Ok v
|
||||
Err e -> transform e
|
||||
|
|
|
@ -290,6 +290,7 @@ splitFirst = \haystack, needle ->
|
|||
after = Str.substringUnsafe haystack (index + Str.countUtf8Bytes needle) remaining
|
||||
|
||||
Ok { before, after }
|
||||
|
||||
None ->
|
||||
Err NotFound
|
||||
|
||||
|
@ -325,6 +326,7 @@ splitLast = \haystack, needle ->
|
|||
after = Str.substringUnsafe haystack (index + Str.countUtf8Bytes needle) remaining
|
||||
|
||||
Ok { before, after }
|
||||
|
||||
None ->
|
||||
Err NotFound
|
||||
|
||||
|
@ -344,6 +346,7 @@ lastMatchHelp = \haystack, needle, index ->
|
|||
when Num.subChecked index 1 is
|
||||
Ok nextIndex ->
|
||||
lastMatchHelp haystack needle nextIndex
|
||||
|
||||
Err _ ->
|
||||
None
|
||||
|
||||
|
@ -428,6 +431,7 @@ walkScalarsUntilHelp = \string, state, step, index, length ->
|
|||
when step state scalar is
|
||||
Continue newState ->
|
||||
walkScalarsUntilHelp string newState step (index + bytesParsed) length
|
||||
|
||||
Break newState ->
|
||||
newState
|
||||
else
|
||||
|
|
|
@ -46,16 +46,16 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable>(
|
|||
let is_only_newlines = item.before.iter().all(|s| s.is_newline());
|
||||
|
||||
if item.before.is_empty() || is_only_newlines {
|
||||
buf.ensure_ends_in_newline();
|
||||
buf.ensure_ends_with_newline();
|
||||
} else {
|
||||
if is_first_item {
|
||||
// The first item in a multiline collection always begins with exactly
|
||||
// one newline (so the delimiter is at the end of its own line),
|
||||
// and that newline appears before the first comment (if there is one).
|
||||
buf.ensure_ends_in_newline();
|
||||
buf.ensure_ends_with_newline();
|
||||
} else {
|
||||
if item.before.starts_with(&[CommentOrNewline::Newline]) {
|
||||
buf.ensure_ends_in_newline();
|
||||
buf.ensure_ends_with_newline();
|
||||
}
|
||||
|
||||
if item
|
||||
|
@ -113,7 +113,7 @@ pub fn fmt_collection<'a, 'buf, T: ExtractSpaces<'a> + Formattable>(
|
|||
item_indent,
|
||||
);
|
||||
|
||||
buf.ensure_ends_in_newline();
|
||||
buf.ensure_ends_with_newline();
|
||||
buf.indent(braces_indent);
|
||||
} else {
|
||||
// is_multiline == false
|
||||
|
|
|
@ -540,7 +540,7 @@ fn fmt_binops<'a, 'buf>(
|
|||
loc_left_side.format_with_options(buf, apply_needs_parens, Newlines::No, curr_indent);
|
||||
|
||||
if is_multiline {
|
||||
buf.ensure_ends_in_newline();
|
||||
buf.ensure_ends_with_newline();
|
||||
curr_indent = indent + INDENT;
|
||||
buf.indent(curr_indent);
|
||||
} else {
|
||||
|
@ -699,6 +699,8 @@ fn fmt_when<'a, 'buf>(
|
|||
buf.push_str("is");
|
||||
buf.newline();
|
||||
|
||||
let mut prev_branch_was_multiline = false;
|
||||
|
||||
for (branch_index, branch) in branches.iter().enumerate() {
|
||||
let expr = &branch.value;
|
||||
let patterns = &branch.patterns;
|
||||
|
@ -709,10 +711,21 @@ fn fmt_when<'a, 'buf>(
|
|||
if pattern_index == 0 {
|
||||
match &pattern.value {
|
||||
Pattern::SpaceBefore(sub_pattern, spaces) => {
|
||||
let added_blank_line;
|
||||
|
||||
if branch_index > 0 // Never render newlines before the first branch.
|
||||
&& matches!(spaces.first(), Some(CommentOrNewline::Newline))
|
||||
{
|
||||
buf.ensure_ends_in_newline();
|
||||
if prev_branch_was_multiline {
|
||||
// Multiline branches always get a full blank line after them.
|
||||
buf.ensure_ends_with_blank_line();
|
||||
added_blank_line = true;
|
||||
} else {
|
||||
buf.ensure_ends_with_newline();
|
||||
added_blank_line = false;
|
||||
}
|
||||
} else {
|
||||
added_blank_line = false;
|
||||
}
|
||||
|
||||
// Write comments (which may have been attached to the previous
|
||||
|
@ -720,20 +733,33 @@ fn fmt_when<'a, 'buf>(
|
|||
fmt_comments_only(buf, spaces.iter(), NewlineAt::Bottom, indent + INDENT);
|
||||
|
||||
if branch_index > 0 {
|
||||
buf.ensure_ends_in_newline();
|
||||
if prev_branch_was_multiline && !added_blank_line {
|
||||
// Multiline branches always get a full blank line after them
|
||||
// (which we may already have added before a comment).
|
||||
buf.ensure_ends_with_blank_line();
|
||||
} else {
|
||||
buf.ensure_ends_with_newline();
|
||||
}
|
||||
}
|
||||
|
||||
fmt_pattern(buf, sub_pattern, indent + INDENT, Parens::NotNeeded);
|
||||
}
|
||||
other => {
|
||||
buf.ensure_ends_in_newline();
|
||||
if branch_index > 0 {
|
||||
if prev_branch_was_multiline {
|
||||
// Multiline branches always get a full blank line after them.
|
||||
buf.ensure_ends_with_blank_line();
|
||||
} else {
|
||||
buf.ensure_ends_with_newline();
|
||||
}
|
||||
}
|
||||
|
||||
fmt_pattern(buf, other, indent + INDENT, Parens::NotNeeded);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if is_multiline_patterns {
|
||||
buf.ensure_ends_in_newline();
|
||||
buf.ensure_ends_with_newline();
|
||||
// Indent an extra level for the `|`;
|
||||
// otherwise it'll be at the start of the line,
|
||||
// and will be incorrectly parsed as a pattern
|
||||
|
@ -762,7 +788,7 @@ fn fmt_when<'a, 'buf>(
|
|||
fmt_spaces_no_blank_lines(buf, spaces.iter(), indent + (INDENT * 2));
|
||||
|
||||
if is_multiline_expr {
|
||||
buf.ensure_ends_in_newline();
|
||||
buf.ensure_ends_with_newline();
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
@ -776,7 +802,7 @@ fn fmt_when<'a, 'buf>(
|
|||
}
|
||||
_ => {
|
||||
if is_multiline_expr {
|
||||
buf.ensure_ends_in_newline();
|
||||
buf.ensure_ends_with_newline();
|
||||
} else {
|
||||
buf.spaces(1);
|
||||
}
|
||||
|
@ -789,6 +815,8 @@ fn fmt_when<'a, 'buf>(
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
prev_branch_was_multiline = is_multiline_expr || is_multiline_patterns;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ impl<'a> Buf<'a> {
|
|||
|
||||
/// Ensures the current buffer ends in a newline, if it didn't already.
|
||||
/// Doesn't add a newline if the buffer already ends in one.
|
||||
pub fn ensure_ends_in_newline(&mut self) {
|
||||
pub fn ensure_ends_with_newline(&mut self) {
|
||||
if self.spaces_to_flush > 0 {
|
||||
self.flush_spaces();
|
||||
self.newline();
|
||||
|
@ -107,6 +107,19 @@ impl<'a> Buf<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn ensure_ends_with_blank_line(&mut self) {
|
||||
if self.spaces_to_flush > 0 {
|
||||
self.flush_spaces();
|
||||
self.newline();
|
||||
self.newline();
|
||||
} else if !self.text.ends_with('\n') {
|
||||
self.newline();
|
||||
self.newline();
|
||||
} else if !self.text.ends_with("\n\n") {
|
||||
self.newline();
|
||||
}
|
||||
}
|
||||
|
||||
fn flush_spaces(&mut self) {
|
||||
if self.spaces_to_flush > 0 {
|
||||
for _ in 0..self.spaces_to_flush {
|
||||
|
|
|
@ -3341,6 +3341,7 @@ mod test_fmt {
|
|||
when b is
|
||||
1 ->
|
||||
1
|
||||
|
||||
_ ->
|
||||
2
|
||||
"#
|
||||
|
@ -3370,6 +3371,7 @@ mod test_fmt {
|
|||
when year is
|
||||
1999 ->
|
||||
1
|
||||
|
||||
_ ->
|
||||
0
|
||||
"#
|
||||
|
@ -3386,6 +3388,7 @@ mod test_fmt {
|
|||
1 ->
|
||||
# when 1
|
||||
1
|
||||
|
||||
# important
|
||||
# fall through
|
||||
_ ->
|
||||
|
@ -3404,6 +3407,7 @@ mod test_fmt {
|
|||
when 0 is
|
||||
1 # comment
|
||||
| 2 -> "a"
|
||||
|
||||
_ -> "b"
|
||||
"#
|
||||
));
|
||||
|
@ -3431,6 +3435,7 @@ mod test_fmt {
|
|||
when c is
|
||||
6 | 7 ->
|
||||
8
|
||||
|
||||
3 | 4 ->
|
||||
5
|
||||
"#
|
||||
|
@ -3504,15 +3509,19 @@ mod test_fmt {
|
|||
| 2
|
||||
| 3 ->
|
||||
4
|
||||
|
||||
5 | 6 | 7 ->
|
||||
8
|
||||
|
||||
9
|
||||
| 10 -> 11
|
||||
|
||||
12 | 13 ->
|
||||
when c is
|
||||
14 | 15 -> 16
|
||||
17
|
||||
| 18 -> 19
|
||||
|
||||
20 -> 21
|
||||
"#
|
||||
),
|
||||
|
@ -3549,6 +3558,7 @@ mod test_fmt {
|
|||
is
|
||||
1 ->
|
||||
Nothing
|
||||
|
||||
_ ->
|
||||
Just True
|
||||
"#
|
||||
|
@ -3566,6 +3576,7 @@ mod test_fmt {
|
|||
is
|
||||
Complex x y ->
|
||||
simplify x y
|
||||
|
||||
Simple z ->
|
||||
z
|
||||
"#
|
||||
|
@ -3600,6 +3611,7 @@ mod test_fmt {
|
|||
is
|
||||
2 ->
|
||||
x
|
||||
|
||||
_ ->
|
||||
y
|
||||
"#
|
||||
|
@ -3636,6 +3648,7 @@ mod test_fmt {
|
|||
is
|
||||
4 ->
|
||||
x
|
||||
|
||||
_ ->
|
||||
y
|
||||
"#
|
||||
|
@ -3783,6 +3796,7 @@ mod test_fmt {
|
|||
when maybeScore is
|
||||
Just score if score > 21 ->
|
||||
win
|
||||
|
||||
_ ->
|
||||
nextRound
|
||||
"#
|
||||
|
@ -3796,8 +3810,10 @@ mod test_fmt {
|
|||
when authenticationResponse is
|
||||
Ok user if hasPermission user ->
|
||||
loadPage route user
|
||||
|
||||
Ok user ->
|
||||
PageNotFound
|
||||
|
||||
Err _ ->
|
||||
ErrorPage
|
||||
"#
|
||||
|
@ -3903,6 +3919,7 @@ mod test_fmt {
|
|||
when f x == g y == h z is
|
||||
True ->
|
||||
Ok 1
|
||||
|
||||
False ->
|
||||
Err 2
|
||||
"#
|
||||
|
@ -4039,17 +4056,20 @@ mod test_fmt {
|
|||
3
|
||||
* 2 # comment 3
|
||||
< 1 # comment 4
|
||||
|
||||
z ->
|
||||
4
|
||||
/ 5 # comment 5
|
||||
< 1 # comment 6
|
||||
|
||||
46 # first pattern comment
|
||||
| 95 # alternative comment 1
|
||||
| 126 # alternative comment 2
|
||||
| 150 -> # This comment goes after the ->
|
||||
# This comment is for the expr
|
||||
Str.appendScalar output (Num.toU32 byte)
|
||||
|> Result.withDefault "" # this will never fail
|
||||
foo bar
|
||||
|> Result.withDefault "" # one last comment
|
||||
|
||||
_ ->
|
||||
42
|
||||
"#
|
||||
|
@ -4301,6 +4321,7 @@ mod test_fmt {
|
|||
when result is
|
||||
Err _ ->
|
||||
Err {}
|
||||
|
||||
Ok val ->
|
||||
Ok {}
|
||||
)
|
||||
|
@ -4319,6 +4340,7 @@ mod test_fmt {
|
|||
when result is
|
||||
Err _ ->
|
||||
Err {}
|
||||
|
||||
Ok val ->
|
||||
Ok {}
|
||||
)
|
||||
|
@ -4335,6 +4357,7 @@ mod test_fmt {
|
|||
when result is
|
||||
Err _ ->
|
||||
Err {}
|
||||
|
||||
Ok val ->
|
||||
Ok {}
|
||||
)
|
||||
|
@ -4746,6 +4769,7 @@ mod test_fmt {
|
|||
when list is
|
||||
Nil ->
|
||||
Nothing
|
||||
|
||||
Cons first _ ->
|
||||
Just first
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue