From 83204b8fcc9c322c489b277532a7f7607e3b6d8e Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Tue, 3 Dec 2024 09:53:07 +0100 Subject: [PATCH] Correctly indent multiline variable blocks in let This patch fixes a bug where multiline variable blocks in let would not intent correctly, fixes #97. --- CHANGELOG.md | 14 ++++++++++++++ src/runestone.jl | 40 +++++++++++++++++++++++++++++++++++++++- test/runtests.jl | 6 ++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52d5801..53e50c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Fix a bug that caused "single space after keyword" to not apply after the `function` keyword in non-standard function definitions. ([#113]) + - Fix a bug that caused multiline variable blocks in `let` to not indent correctly ([#97], + [#116]). This bug is classified as a [spec-bug] and the fix will result in diffs like the + following: + ```diff + let a = 1, + - b = 2 + + b = 2 + a + b + end + ``` ## [v1.0.1] - 2024-11-28 ### Fixed @@ -17,11 +27,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [v1.0.0] - 2024-11-06 First stable release of Runic.jl. See [README.md](README.md) for details and documentation. +[spec-bug]: https://github.com/fredrikekre/Runic.jl?tab=readme-ov-file#version-policy + [v1.0.0]: https://github.com/fredrikekre/Runic.jl/releases/tag/v1.0.0 [v1.0.1]: https://github.com/fredrikekre/Runic.jl/releases/tag/v1.0.1 +[#97]: https://github.com/fredrikekre/Runic.jl/issues/97 [#109]: https://github.com/fredrikekre/Runic.jl/issues/109 [#110]: https://github.com/fredrikekre/Runic.jl/issues/110 [#113]: https://github.com/fredrikekre/Runic.jl/issues/113 +[#116]: https://github.com/fredrikekre/Runic.jl/issues/116 diff --git a/src/runestone.jl b/src/runestone.jl index cfb2541..5b492e1 100644 --- a/src/runestone.jl +++ b/src/runestone.jl @@ -1640,6 +1640,33 @@ function indent_function_or_macro(ctx::Context, node::Node) return any_kid_changed ? make_node(node, kids) : nothing end +# Soft-indentation between the variables +function indent_let_varblock(ctx::Context, node::Node) + @assert kind(node) === K"block" && !is_leaf(node) + kids = verified_kids(node) + changed = false + if length(kids) == 0 + @assert span(node) == 0 + # Empty block, but where are spaces and comments? + return nothing + end + # First node *must* be a space (?) + i = 1 + kid = kids[i] + @assert kind(kid) === K"Whitespace" + i = findnext(x -> !JuliaSyntax.is_whitespace(x), kids, i + 1) + i === nothing && return nothing + @assert kind(kids[i]) in KSet"Identifier = $ macrocall" # This is a bit unnecessary + while (i = findnext(x -> kind(x) === K"NewlineWs", kids, i + 1); i !== nothing) + @assert kind(kids[i]) === K"NewlineWs" + if !has_tag(kids[i], TAG_LINE_CONT) + kids[i] = add_tag(kids[i], TAG_LINE_CONT) + changed = true + end + end + return changed ? make_node(node, kids) : nothing +end + function indent_let(ctx::Context, node::Node) kids = verified_kids(node) any_kid_changed = false @@ -1651,13 +1678,24 @@ function indent_let(ctx::Context, node::Node) kids[let_idx] = add_tag(let_node, TAG_INDENT) any_kid_changed = true end - # Second node is the variables block (will be soft-indented by the assignments pass) + # Second node is the variables block vars_idx = 2 vars_node = kids[vars_idx] @assert !is_leaf(vars_node) && kind(vars_node) === K"block" if span(vars_node) > 0 && length(verified_kids(vars_node)) > 0 @assert kind(last_leaf(vars_node)) !== "NewlineWs" end + let p = position(ctx.fmt_io) + for i in 1:(vars_idx - 1) + accept_node!(ctx, kids[i]) + end + vars_node′ = indent_let_varblock(ctx, vars_node) + if vars_node′ !== nothing + kids[vars_idx] = vars_node′ + any_kid_changed = true + end + seek(ctx.fmt_io, p) + end # # Third node is the NewlineWs before the block # ln_idx = 3 # ln_node = kids[ln_idx] diff --git a/test/runtests.jl b/test/runtests.jl index 0445b39..b491339 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -912,6 +912,12 @@ end # K"cartesian_iterator" @test format_string("for i in I,\n$(sp)j in J\n# body\nend") == "for i in I,\n j in J\n # body\nend" + # K"let" + for a in ("x = 1", "x", "@inline foo() = 1", "\$x"), + b in ("y = 1", "y", "@inline bar() = 1", "\$y") + @test format_string("let $(a),\n$(sp)$(b)\n nothing\nend") == + "let $(a),\n $(b)\n nothing\nend" + end end end