Neovim sign gutter, designed to be mostly VCS agnostic
1local M = {}
2
3local bit = require "bit"
4local sign = require "vcsigns.sign"
5local testing = require "vclib.testing"
6
7---@param s1 integer
8---@param c1 integer
9---@param s2 integer
10---@param c2 integer
11---@return Hunk
12local function _make_hunk(s1, c1, s2, c2)
13 return {
14 minus_start = s1,
15 minus_count = c1,
16 plus_start = s2,
17 plus_count = c2,
18 }
19end
20
21local ADD = { type = sign.SignType.ADD, count = 0 }
22local CHANGE = { type = sign.SignType.CHANGE, count = 0 }
23local function DELETE_BELOW(count)
24 return { type = sign.SignType.DELETE_BELOW, count = count }
25end
26local function DELETE_ABOVE(count)
27 return { type = sign.SignType.DELETE_ABOVE, count = count }
28end
29
30local function _union(a, b)
31 local res = {}
32 res.type = bit.bor(a.type, b.type)
33 res.count = a.count + b.count
34 return res
35end
36
37M.signs = {
38 test_cases = {
39 change = {
40 hunks = {
41 _make_hunk(3, 2, 3, 2),
42 },
43 expected = { nil, nil, CHANGE, CHANGE, nil },
44 line_count = 5,
45 },
46 addition = {
47 hunks = {
48 _make_hunk(2, 0, 3, 2),
49 },
50 expected = { nil, nil, ADD, ADD, nil },
51 line_count = 5,
52 },
53 deletion = {
54 hunks = {
55 _make_hunk(3, 2, 4, 0),
56 },
57 expected = { nil, nil, nil, DELETE_BELOW(2), nil },
58 line_count = 5,
59 },
60 deletion_at_start = {
61 hunks = {
62 _make_hunk(1, 3, 0, 0),
63 },
64 expected = { DELETE_ABOVE(3), nil, nil, nil },
65 line_count = 4,
66 },
67 change_delete_at_start = {
68 hunks = {
69 _make_hunk(1, 3, 1, 1),
70 },
71 expected = { _union(DELETE_ABOVE(3), CHANGE), nil, nil, nil },
72 line_count = 4,
73 },
74 split_complicated_cases = {
75 hunks = {
76 _make_hunk(1, 3, 0, 0),
77 _make_hunk(4, 1, 1, 1),
78 _make_hunk(7, 1, 4, 1),
79 _make_hunk(8, 3, 4, 0),
80 _make_hunk(14, 3, 7, 0),
81 _make_hunk(17, 1, 8, 1),
82 _make_hunk(20, 1, 11, 1),
83 _make_hunk(21, 10, 11, 0),
84 },
85 expected = {
86 _union(DELETE_ABOVE(3), CHANGE),
87 nil,
88 nil,
89 CHANGE,
90 DELETE_ABOVE(3),
91 nil,
92 DELETE_BELOW(3),
93 CHANGE,
94 nil,
95 nil,
96 _union(DELETE_BELOW(10), CHANGE),
97 },
98 line_count = 11,
99 },
100 decongestion_at_top = {
101 hunks = {
102 _make_hunk(1, 1, 0, 0),
103 _make_hunk(3, 1, 1, 0),
104 _make_hunk(5, 3, 2, 0),
105 },
106 expected = {
107 _union(DELETE_ABOVE(1), DELETE_BELOW(1)), -- Combined count 2.
108 DELETE_BELOW(3),
109 nil,
110 nil,
111 nil,
112 },
113 line_count = 5,
114 },
115 -- https://github.com/algmyr/vcsigns.nvim/issues/23
116 issue_23 = {
117 hunks = {
118 _make_hunk(1, 2, 0, 0),
119 _make_hunk(2, 0, 1, 1),
120 _make_hunk(3, 1, 1, 0),
121 _make_hunk(4, 1, 2, 1),
122 },
123 expected = {
124 _union(_union(DELETE_ABOVE(2), ADD), DELETE_BELOW(1)), -- Combined count 3.
125 CHANGE,
126 nil,
127 nil,
128 nil,
129 },
130 line_count = 5,
131 },
132 },
133 test = function(case)
134 local result = sign.compute_signs(case.hunks, case.line_count)
135 for i = 1, case.line_count do
136 local actual = result.signs[i]
137 local expected = case.expected[i]
138 if actual and expected then
139 assert(
140 expected.type == actual.type,
141 "Sign type mismatch at line "
142 .. i
143 .. ": expected "
144 .. sign.sign_type_to_string(expected.type)
145 .. ", got "
146 .. sign.sign_type_to_string(actual.type)
147 )
148 assert(
149 expected.count == actual.count,
150 "Sign count mismatch at line "
151 .. i
152 .. ": expected "
153 .. expected.count
154 .. ", got "
155 .. actual.count
156 )
157 elseif actual or expected then
158 error(
159 "Sign mismatch at line "
160 .. i
161 .. ": expected "
162 .. (expected and sign.sign_type_to_string(expected.type) or "nil")
163 .. ", got "
164 .. (actual and sign.sign_type_to_string(actual.type) or "nil")
165 )
166 end
167 end
168 end,
169}
170
171return M