Repository: fredrikekre/Runic.jl
Pull request #117 (2024-12-03 09:29:03)

Fix multiple spaces after `let`
This patch ensures that a single space is used also after `let` like other keywords.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/fredrikekre/Runic.jl/pull/117?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Fredrik+Ekre) Report
Attention: Patch coverage is `70.96774%` with `9 lines` in your changes missing coverage. Please review.
> Project coverage is 57.62%. Comparing base [(`f9212e7`)](https://app.codecov.io/gh/fredrikekre/Runic.jl/commit/f9212e781f38bdd976b5bdad0cd25d90a4e74531?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Fredrik+Ekre) to head [(`e23a650`)](https://app.codecov.io/gh/fredrikekre/Runic.jl/commit/e23a65022009ae1f7ebd4cdc9204095ebfac459f?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Fredrik+Ekre).

| [Files with missing lines](https://app.codecov.io/gh/fredrikekre/Runic.jl/pull/117?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Fredrik+Ekre) | Patch % | Lines |
|---|---|---|
| [src/runestone.jl](https://app.codecov.io/gh/fredrikekre/Runic.jl/pull/117?src=pr&el=tree&filepath=src%2Frunestone.jl&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Fredrik+Ekre#diff-c3JjL3J1bmVzdG9uZS5qbA==) | 70.96% | [9 Missing :warning: ](https://app.codecov.io/gh/fredrikekre/Runic.jl/pull/117?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Fredrik+Ekre) |

> :exclamation:  There is a different number of reports uploaded between BASE (f9212e7) and HEAD (e23a650). Click for more details.
> 
> <details><summary>HEAD has 7 uploads less than BASE</summary>
>
>| Flag | BASE (f9212e7) | HEAD (e23a650) |
>|------|------|------|
>||8|1|
></details>

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff             @@
##           master     #117       +/-   ##
===========================================
- Coverage   93.69%   57.62%   -36.07%     
===========================================
  Files           8        7        -1     
  Lines        3566     3585       +19     
===========================================
- Hits         3341     2066     -1275     
- Misses        225     1519     +1294     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/fredrikekre/Runic.jl/pull/117?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Fredrik+Ekre).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Fredrik+Ekre).


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 53e50c0..faa955e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,10 +8,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 ## Unreleased changes
 ### Changed
  - Fix a bug that caused "single space after keyword" to not apply after the `function`
-   keyword in non-standard function definitions. ([#113])
+   keyword in non-standard function definitions ([#113]). This bug is classified as a
+   [spec-bug] and the fix will result in diffs like the following:
+   ```diff
+   -function()
+   +function ()
+        # ...
+    end
+   ```
+ - Fix a bug that caused "single space after keyword" to not apply after `let` ([#117]).
+   This bug is classified as a [spec-bug] and the fix will result in diffs like the
+   following when `let` is followed by multiple spaces in the source:
+   ```diff
+   -let  a = 1
+   +let a = 1
+        a
+    end
+   ```
  - 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:
+   following whenever multiline variable blocks exist in the source:
    ```diff
     let a = 1,
    -    b = 2
diff --git a/src/runestone.jl b/src/runestone.jl
index 5b492e1..8d0c95d 100644
--- a/src/runestone.jl
+++ b/src/runestone.jl
@@ -1107,6 +1107,42 @@ function no_spaces_around_colon_etc(ctx::Context, node::Node)
     return no_spaces_around_x(ctx, node, is_x)
 end
 
+function space_after_let(ctx, node)
+    @assert kind(node) === K"let" && !is_leaf(node)
+    p = position(ctx.fmt_io)
+    kids = verified_kids(node)
+    let_node = kids[1]
+    @assert kind(let_node) === K"let"
+    accept_node!(ctx, let_node)
+    vars_idx = 2
+    vars_node = kids[vars_idx]
+    @assert kind(vars_node) === K"block"
+    vars_kids = verified_kids(vars_node)
+    if length(vars_kids) == 0
+        @assert span(vars_node) == 0
+        seek(ctx.fmt_io, p)
+        # Empty block, but where are spaces and comments?
+        return nothing
+    end
+    # First node *must* be a space (?)
+    vars_kid = vars_kids[1]
+    @assert kind(vars_kid) === K"Whitespace"
+    if span(vars_kid) == 1
+        seek(ctx.fmt_io, p)
+        return nothing
+    else
+        replace_bytes!(ctx, " ", span(vars_kid))
+        ws = Node(JuliaSyntax.SyntaxHead(K"Whitespace", JuliaSyntax.TRIVIA_FLAG), 1)
+        vars_kids′ = copy(vars_kids)
+        vars_kids′[1] = ws
+        vars_node′ = make_node(vars_node, vars_kids′)
+        kids′ = copy(kids)
+        kids′[vars_idx] = vars_node′
+        seek(ctx.fmt_io, p)
+        return make_node(node, kids′)
+    end
+end
+
 # Single space around keywords:
 # Both sides of: `where`, `do` (if followed by arguments)
 # Right hand side of: `mutable`, `struct`, `abstract`, `primitive`, `type`, `function` (if
@@ -1114,6 +1150,9 @@ end
 # global, const
 function spaces_around_keywords(ctx::Context, node::Node)
     is_leaf(node) && return nothing
+    if kind(node) === K"let"
+        return space_after_let(ctx, node)
+    end
     keyword_set = KSet"""
     where do mutable struct abstract primitive type function if elseif catch while return
     local global const module baremodule


Test patch:
diff --git a/test/runtests.jl b/test/runtests.jl
index b491339..bee4b60 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -552,6 +552,8 @@ end
         @test format_string("function f()\n    return$(sp)\nend") == "function f()\n    return\nend"
         @test format_string("module$(sp)A\nend") == "module A\nend"
         @test format_string("module$(sp)(A)\nend") == "module (A)\nend"
+        @test format_string("let$(sp)x = 1\nend") == "let x = 1\nend"
+        @test format_string("let$(sp)\nend") == "let\nend"
         for word in ("local", "global"), rhs in ("a", "a, b", "a = 1", "a, b = 1, 2")
             word == "const" && rhs in ("a", "a, b") && continue
             @test format_string("$(word)$(sp)$(rhs)") == "$(word) $(rhs)"