• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bombsimon / wsl / 24284976958

11 Apr 2026 02:54PM UTC coverage: 94.19% (-0.08%) from 94.274%
24284976958

push

github

web-flow
feat: add cuddle-max-statements config (#245)

* feat: add cuddle-max-statements config

Allow configuring how many statements can be cuddled above block
statements (if, for, range, switch, select, send, go, defer), provided
each cuddled statement has at least one identifier used in the block.
Default is 1 (backward compatible), 0 means unlimited.

This has been requested multiple times over the years. The new
`cuddle-max-statements` config replaces the hardcoded limit of 1
while preserving all existing behavior at the default setting.

Also refactors: extract isAssignDeclOrIncDec, add Cursor.NthPrevious,
replace identIntersection with short-circuiting identsIntersect, build
target ident set once via cuddleTargetIdents, and clean up the
enforceLimit parameter to use bool instead of int sentinel.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update docs for flag and README

* Fix panic, drop `groupedDecls`, add more tests

With the old `groupedDecls` we got overlapping reports resulting in
panic in some code bases (e.g. the `assignVarAssign` test case).

Never create overlapping diagnostics.

* Add more tests

* Add better error message

* Add non-block tests

* Add tests for first-in-block

* Use early return pattern

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

104 of 107 new or added lines in 4 files covered. (97.2%)

2 existing lines in 1 file now uncovered.

1378 of 1463 relevant lines covered (94.19%)

321.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.67
/cursor.go
1
package wsl
2

3
import (
4
        "go/ast"
5
)
6

7
// Cursor holds a list of statements and a pointer to where in the list we are.
8
// Each block gets a new cursor and can be used to check previous or coming
9
// statements.
10
type Cursor struct {
11
        currentIdx int
12
        statements []ast.Stmt
13
        checkType  CheckType
14
}
15

16
// NewCursor creates a new cursor with a given list of statements.
17
func NewCursor(statements []ast.Stmt) *Cursor {
1,282✔
18
        return &Cursor{
1,282✔
19
                currentIdx: -1,
1,282✔
20
                statements: statements,
1,282✔
21
        }
1,282✔
22
}
1,282✔
23

24
func (c *Cursor) SetChecker(ct CheckType) {
1,110✔
25
        c.checkType = ct
1,110✔
26
}
1,110✔
27

28
func (c *Cursor) NextNode() ast.Node {
27✔
29
        defer c.Save()()
27✔
30

27✔
31
        var nextNode ast.Node
27✔
32
        if c.Next() {
54✔
33
                nextNode = c.Stmt()
27✔
34
        }
27✔
35

36
        return nextNode
27✔
37
}
38

39
func (c *Cursor) Next() bool {
3,034✔
40
        if c.currentIdx >= len(c.statements)-1 {
4,036✔
41
                return false
1,002✔
42
        }
1,002✔
43

44
        c.currentIdx++
2,032✔
45

2,032✔
46
        return true
2,032✔
47
}
48

49
func (c *Cursor) Previous() bool {
3,614✔
50
        if c.currentIdx <= 0 {
5,055✔
51
                return false
1,441✔
52
        }
1,441✔
53

54
        c.currentIdx--
2,173✔
55

2,173✔
56
        return true
2,173✔
57
}
58

59
func (c *Cursor) PreviousNode() ast.Node {
1,043✔
60
        defer c.Save()()
1,043✔
61

1,043✔
62
        var previousNode ast.Node
1,043✔
63
        if c.Previous() {
1,764✔
64
                previousNode = c.Stmt()
721✔
65
        }
721✔
66

67
        return previousNode
1,043✔
68
}
69

70
func (c *Cursor) Stmt() ast.Stmt {
7,800✔
71
        return c.statements[c.currentIdx]
7,800✔
72
}
7,800✔
73

74
func (c *Cursor) Save() func() {
3,127✔
75
        idx := c.currentIdx
3,127✔
76

3,127✔
77
        return func() {
6,254✔
78
                c.currentIdx = idx
3,127✔
79
        }
3,127✔
80
}
81

82
func (c *Cursor) Len() int {
303✔
83
        return len(c.statements)
303✔
84
}
303✔
85

86
func (c *Cursor) Nth(n int) ast.Stmt {
23✔
87
        return c.statements[n]
23✔
88
}
23✔
89

90
func (c *Cursor) NthPrevious(n int) ast.Node {
32✔
91
        idx := c.currentIdx - n
32✔
92
        if idx < 0 {
32✔
NEW
93
                return nil
×
NEW
94
        }
×
95

96
        return c.statements[idx]
32✔
97
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc