feat(formatter): implement outdent formatting for multiline lists and records

This commit is contained in:
Sean Hagstrom 2022-04-24 16:35:09 +01:00
parent 3d9daed836
commit b147890b08
9 changed files with 647 additions and 87 deletions

View File

@ -191,12 +191,26 @@ pub fn fmt_body<'a, 'buf>(
buf.push_str(" =");
if body.is_multiline() {
match body {
Expr::SpaceBefore(_, _) => {
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT);
}
Expr::Record { .. } | Expr::List { .. } => {
buf.newline();
body.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent + INDENT);
Expr::SpaceBefore(sub_def, spaces) => {
let should_outdent = match sub_def {
Expr::Record { .. } | Expr::List { .. } => {
let is_only_newlines = spaces.iter().all(|s| s.is_newline());
is_only_newlines && sub_def.is_multiline()
}
_ => false,
};
if should_outdent {
buf.spaces(1);
sub_def.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
} else {
body.format_with_options(
buf,
Parens::NotNeeded,
Newlines::Yes,
indent + INDENT,
);
}
}
_ => {
buf.spaces(1);

View File

@ -186,14 +186,75 @@ impl<'a> Formattable for Expr<'a> {
loc_expr.format_with_options(buf, Parens::InApply, Newlines::Yes, indent);
let multiline_args = loc_args.iter().any(|loc_arg| loc_arg.is_multiline());
let last_arg_index = loc_args.len() - 1;
if multiline_args {
let should_outdent_last_arg =
loc_args
.iter()
.enumerate()
.fold(false, |found_multiline_expr, val| {
let (index, loc_arg) = val;
if index == last_arg_index {
match loc_arg.value {
SpaceBefore(sub_expr, spaces) => match sub_expr {
Record { .. } | List { .. } => {
let is_only_newlines =
spaces.iter().all(|s| s.is_newline());
is_only_newlines
&& !found_multiline_expr
&& sub_expr.is_multiline()
}
_ => false,
},
Record { .. } | List { .. } => {
!found_multiline_expr && loc_arg.is_multiline()
}
_ => false,
}
} else {
loc_arg.is_multiline()
}
});
if multiline_args && !should_outdent_last_arg {
let arg_indent = indent + INDENT;
for loc_arg in loc_args.iter() {
buf.newline();
loc_arg.format_with_options(buf, Parens::InApply, Newlines::No, arg_indent);
}
} else if multiline_args && should_outdent_last_arg {
for (index, loc_arg) in loc_args.iter().enumerate() {
buf.spaces(1);
if index == last_arg_index {
match loc_arg.value {
SpaceBefore(sub_expr, _) => {
sub_expr.format_with_options(
buf,
Parens::InApply,
Newlines::Yes,
indent,
);
}
_ => {
loc_arg.format_with_options(
buf,
Parens::InApply,
Newlines::Yes,
indent,
);
}
}
} else {
loc_arg.format_with_options(
buf,
Parens::InApply,
Newlines::Yes,
indent,
);
}
}
} else {
for loc_arg in loc_args.iter() {
buf.spaces(1);
@ -846,7 +907,34 @@ fn fmt_closure<'a, 'buf>(
}
};
loc_ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, body_indent);
if is_multiline {
match &loc_ret.value {
SpaceBefore(sub_expr, spaces) => {
let should_outdent = match sub_expr {
Record { .. } | List { .. } => {
let is_only_newlines = spaces.iter().all(|s| s.is_newline());
is_only_newlines && sub_expr.is_multiline()
}
_ => false,
};
if should_outdent {
buf.spaces(1);
sub_expr.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
} else {
loc_ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, body_indent);
}
}
Record { .. } | List { .. } => {
loc_ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, indent);
}
_ => {
loc_ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, body_indent);
}
}
} else {
loc_ret.format_with_options(buf, Parens::NotNeeded, Newlines::Yes, body_indent);
}
}
fn fmt_backpassing<'a, 'buf>(

View File

@ -626,6 +626,392 @@ mod test_fmt {
));
}
#[test]
fn lambda_returns_record() {
expr_formats_same(indoc!(
r#"
toRecord = \_ -> {
x: 1,
y: 2,
z: 3,
}
toRecord
"#
));
expr_formats_same(indoc!(
r#"
func = \_ ->
{ x: 1, y: 2, z: 3 }
func
"#
));
expr_formats_same(indoc!(
r#"
toRecord = \_ ->
val = 0
{
x: 1,
y: 2,
z: 3,
}
toRecord
"#
));
expr_formats_to(
indoc!(
r#"
toRecord = \_ ->
{
x: 1,
y: 2,
z: 3,
}
toRecord
"#
),
indoc!(
r#"
toRecord = \_ -> {
x: 1,
y: 2,
z: 3,
}
toRecord
"#
),
);
}
#[test]
fn lambda_returns_list() {
expr_formats_same(indoc!(
r#"
toList = \_ -> [
1,
2,
3,
]
toList
"#
));
expr_formats_same(indoc!(
r#"
func = \_ ->
[ 1, 2, 3 ]
func
"#
));
expr_formats_same(indoc!(
r#"
toList = \_ ->
val = 0
[
1,
2,
3,
]
toList
"#
));
expr_formats_to(
indoc!(
r#"
toList = \_ ->
[
1,
2,
3,
]
toList
"#
),
indoc!(
r#"
toList = \_ -> [
1,
2,
3,
]
toList
"#
),
);
}
#[test]
fn multiline_list_func_arg() {
expr_formats_same(indoc!(
r#"
result = func arg [
1,
2,
3,
]
result
"#
));
expr_formats_to(
indoc!(
r#"
result = func arg
[ 1, 2, 3 ]
result
"#
),
indoc!(
r#"
result = func
arg
[ 1, 2, 3 ]
result
"#
),
);
expr_formats_to(
indoc!(
r#"
result = func arg [
1,
2,
3,
]
result
"#
),
indoc!(
r#"
result = func arg [
1,
2,
3,
]
result
"#
),
);
expr_formats_to(
indoc!(
r#"
result = func [
1,
2,
3,
]
arg
result
"#
),
indoc!(
r#"
result = func
[
1,
2,
3,
]
arg
result
"#
),
);
expr_formats_to(
indoc!(
r#"
result = func arg
[
1,
2,
3,
]
result
"#
),
indoc!(
r#"
result = func arg [
1,
2,
3,
]
result
"#
),
);
expr_formats_same(indoc!(
r#"
result = func
arg
[
1,
2,
3,
]
result
"#
));
}
#[test]
fn multiline_record_func_arg() {
expr_formats_same(indoc!(
r#"
result = func arg {
x: 1,
y: 2,
z: 3,
}
result
"#
));
expr_formats_to(
indoc!(
r#"
result = func arg
{ x: 1, y: 2, z: 3 }
result
"#
),
indoc!(
r#"
result = func
arg
{ x: 1, y: 2, z: 3 }
result
"#
),
);
expr_formats_to(
indoc!(
r#"
result = func arg {
x: 1,
y: 2,
z: 3,
}
result
"#
),
indoc!(
r#"
result = func arg {
x: 1,
y: 2,
z: 3,
}
result
"#
),
);
expr_formats_to(
indoc!(
r#"
result = func {
x: 1,
y: 2,
z: 3,
}
arg
result
"#
),
indoc!(
r#"
result = func
{
x: 1,
y: 2,
z: 3,
}
arg
result
"#
),
);
expr_formats_to(
indoc!(
r#"
result = func arg
{
x: 1,
y: 2,
z: 3,
}
result
"#
),
indoc!(
r#"
result = func arg {
x: 1,
y: 2,
z: 3,
}
result
"#
),
);
expr_formats_same(indoc!(
r#"
result = func
arg
{
x: 1,
y: 2,
z: 3,
}
result
"#
));
}
#[test]
fn record_updating() {
expr_formats_same(indoc!(
@ -1301,6 +1687,27 @@ mod test_fmt {
fn multi_line_list_def() {
expr_formats_same(indoc!(
r#"
l = [
1,
2,
]
l
"#
));
expr_formats_same(indoc!(
r#"
l =
[ 1, 2 ]
l
"#
));
expr_formats_to(
indoc!(
r#"
l =
[
1,
@ -1308,8 +1715,19 @@ mod test_fmt {
]
l
"#
));
"#
),
indoc!(
r#"
l = [
1,
2,
]
l
"#
),
);
expr_formats_to(
indoc!(
@ -1324,11 +1742,10 @@ mod test_fmt {
),
indoc!(
r#"
results =
[
Ok 4,
Ok 5,
]
results = [
Ok 4,
Ok 5,
]
allOks results
"#
@ -1417,18 +1834,69 @@ mod test_fmt {
#[test]
fn multi_line_record_def() {
expr_formats_same(indoc!(
r#"
pos = {
x: 4,
y: 11,
z: 16,
}
pos
"#
));
expr_formats_same(indoc!(
r#"
pos =
{ x: 4, y: 11, z: 16 }
pos
"#
));
expr_formats_same(indoc!(
r#"
myDef =
list = [
a,
b,
]
{
c,
d,
}
myDef
"#
));
expr_formats_to(
indoc!(
r#"
pos =
{
x: 4,
y: 11,
z: 16,
}
pos
"#
),
indoc!(
r#"
pos = {
x: 4,
y: 11,
z: 16,
}
pos
"#
));
pos
"#
),
);
expr_formats_to(
indoc!(
@ -1443,11 +1911,10 @@ mod test_fmt {
),
indoc!(
r#"
pos =
{
x: 5,
y: 10,
}
pos = {
x: 5,
y: 10,
}
pos
"#

View File

@ -12,13 +12,12 @@ Model position :
}
initialModel : position -> Model position
initialModel = \start ->
{
evaluated: Set.empty,
openSet: Set.single start,
costs: Dict.single start 0,
cameFrom: Dict.empty,
}
initialModel = \start -> {
evaluated: Set.empty,
openSet: Set.single start,
costs: Dict.single start 0,
cameFrom: Dict.empty,
}
cheapestOpen : (position -> F64), Model position -> Result position {}
cheapestOpen = \costFn, model ->

View File

@ -20,11 +20,10 @@ loopHelp = \{ remaining, string } ->
c = Num.intCast z
combined = Num.bitwiseOr (Num.bitwiseOr (Num.shiftLeftBy 16 a) (Num.shiftLeftBy 8 b)) c
Loop
{
remaining: remaining - 3,
string: Str.concat string (bitsToChars combined 0),
}
Loop {
remaining: remaining - 3,
string: Str.concat string (bitsToChars combined 0),
}
else if remaining == 0 then
Bytes.Decode.succeed (Done string)
else if remaining == 2 then

View File

@ -132,11 +132,10 @@ encodeHelp = \encoder, offset, output ->
List.walk
bs
{ output, offset }
\accum, byte ->
{
offset: accum.offset + 1,
output: List.set accum.output offset byte,
}
\accum, byte -> {
offset: accum.offset + 1,
output: List.set accum.output offset byte,
}
Sequence _ encoders ->
List.walk

View File

@ -29,20 +29,19 @@ Model : {
}
init : Bounds -> Model
init = \{ width, height } ->
{
# Screen height and width
width,
height,
# Paddle X-coordinate
paddleX: (width * 0.5) - (paddleWidth * width * 0.5),
# Ball coordinates
ballX: width * 0.5,
ballY: height * 0.4,
# Delta - how much ball moves in each tick
dBallX: 4,
dBallY: 4,
}
init = \{ width, height } -> {
# Screen height and width
width,
height,
# Paddle X-coordinate
paddleX: (width * 0.5) - (paddleWidth * width * 0.5),
# Ball coordinates
ballX: width * 0.5,
ballY: height * 0.4,
# Delta - how much ball moves in each tick
dBallX: 4,
dBallY: 4,
}
update : Model, Event -> Model
update = \model, event ->
@ -125,23 +124,21 @@ render = \model ->
top = Num.toF32 (row * blockHeight)
border = blockBorder * blockWidth
outer = Rect
{
left,
top,
width: blockWidth,
height: blockHeight,
color: { r: color.r * 0.8, g: color.g * 0.8, b: color.b * 0.8, a: 1 },
}
outer = Rect {
left,
top,
width: blockWidth,
height: blockHeight,
color: { r: color.r * 0.8, g: color.g * 0.8, b: color.b * 0.8, a: 1 },
}
inner = Rect
{
left: left + border,
top: top + border,
width: blockWidth - (border * 2),
height: blockHeight - (border * 2),
color,
}
inner = Rect {
left: left + border,
top: top + border,
width: blockWidth - (border * 2),
height: blockHeight - (border * 2),
color,
}
[ outer, inner ]

View File

@ -8,14 +8,12 @@ render =
styles = { bgColor: rgba 100 50 50 1, borderColor: rgba 10 20 30 1, borderWidth: 10, textColor: rgba 220 220 250 1 }
Col
[
Row
[
Button (Text "Corner ") styles,
Button (Text "Top Mid ") { styles & bgColor: rgba 100 100 50 1 },
Button (Text "Top Right ") { styles & bgColor: rgba 50 50 150 1 },
],
Button (Text "Mid Left ") { styles & bgColor: rgba 150 100 100 1 },
Button (Text "Bottom Left") { styles & bgColor: rgba 150 50 50 1 },
]
Col [
Row [
Button (Text "Corner ") styles,
Button (Text "Top Mid ") { styles & bgColor: rgba 100 100 50 1 },
Button (Text "Top Right ") { styles & bgColor: rgba 50 50 150 1 },
],
Button (Text "Mid Left ") { styles & bgColor: rgba 150 100 100 1 },
Button (Text "Bottom Left") { styles & bgColor: rgba 150 50 50 1 },
]

View File

@ -6,9 +6,8 @@ app "tui"
Model : Str
main : Program Model
main =
{
init: \{ } -> "Hello World",
update: \model, new -> Str.concat model new,
view: \model -> Str.concat model "!",
}
main = {
init: \{ } -> "Hello World",
update: \model, new -> Str.concat model new,
view: \model -> Str.concat model "!",
}