Merge pull request #3432 from rtfeldman/fmt-multiline-when

Format multiline `when` branches
This commit is contained in:
Richard Feldman 2022-07-12 12:54:11 -04:00 committed by GitHub
commit f5f137982c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 495 additions and 365 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;
}
}

View file

@ -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 {

View file

@ -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