@@ -135,4 +135,78 @@ describe("Testing utils module", function()
135135 eq (utils .strsplit (" ,foo,bar," , " ," ), { " " , " foo" , " bar" , " " })
136136 eq (utils .strsplit (" foobar" , " ," ), { " foobar" })
137137 end )
138+
139+ it (" regex_strip_anchors" , function ()
140+ -- nil input
141+ eq ({ utils .regex_strip_anchors (nil ) }, { [2 ] = 0 , [3 ] = 0 })
142+ -- empty string
143+ eq ({ utils .regex_strip_anchors (" " ) }, { " " , 0 , 0 })
144+ -- no anchors
145+ eq ({ utils .regex_strip_anchors (" foobar" ) }, { " foobar" , 0 , 0 })
146+ -- only start anchor
147+ eq ({ utils .regex_strip_anchors (" ^foobar" ) }, { " foobar" , 1 , 0 })
148+ -- only end anchor
149+ eq ({ utils .regex_strip_anchors (" foobar$" ) }, { " foobar" , 0 , 1 })
150+ -- both anchors
151+ eq ({ utils .regex_strip_anchors (" ^foobar$" ) }, { " foobar" , 1 , 1 })
152+ -- anchors in middle (should not be stripped)
153+ eq ({ utils .regex_strip_anchors (" foo^bar$baz" ) }, { " foo^bar$baz" , 0 , 0 })
154+ -- only anchors
155+ eq ({ utils .regex_strip_anchors (" ^" ) }, { " " , 1 , 0 })
156+ eq ({ utils .regex_strip_anchors (" $" ) }, { " " , 0 , 1 })
157+ eq ({ utils .regex_strip_anchors (" ^$" ) }, { " " , 1 , 1 })
158+ -- single character with anchors
159+ eq ({ utils .regex_strip_anchors (" ^x$" ) }, { " x" , 1 , 1 })
160+ end )
161+
162+ it (" ctag_match" , function ()
163+ -- no slashes
164+ eq (utils .ctag_match (" foobar" ), nil )
165+ -- single slash (needs at least 2 slashes)
166+ eq (utils .ctag_match (" foo/bar" ), nil )
167+ -- anchored slahes
168+ eq ({ utils .ctag_match (" /foo/" ) }, { 1 , 5 })
169+ -- two slashes (finds the two rightmost unescaped slashes)
170+ eq ({ utils .ctag_match (" /foo/bar/baz" ) }, { 5 , 9 })
171+ -- escaped slash only (should ignore escaped ones)
172+ eq (utils .ctag_match ([[ /foo\/bar]] ), nil )
173+ eq (utils .ctag_match ([[ /foo\\\/bar]] ), nil )
174+ -- escaped slash backslash before slash
175+ eq ({ utils .ctag_match ([[ /foo\\/bar]] ) }, { 1 , 7 })
176+ eq ({ utils .ctag_match ([[ /foo\\\\/bar]] ) }, { 1 , 9 })
177+ -- mixed escaped and unescaped
178+ eq ({ utils .ctag_match ([[ foo/bar\/baz/qux]] ) }, { 4 , 13 })
179+ -- reverse search from end
180+ eq ({ utils .ctag_match (" /a/b/c/d" ) }, { 5 , 7 })
181+ end )
182+
183+ it (" ctag_escape" , function ()
184+ -- empty string
185+ eq (utils .ctag_escape (" " ), " " )
186+ -- no special characters
187+ eq (utils .ctag_escape (" foobar" ), " foobar" )
188+ -- escaped backslash (\\ becomes \, then rg_escape doubles it back)
189+ eq (utils .ctag_escape (" foo\\ bar" ), " foo\\\\ bar" )
190+ -- unescape escaped slash (\/ becomes /)
191+ eq (utils .ctag_escape (" foo\\ /bar" ), " foo/bar" )
192+ -- regex escape (rg_escape behavior)
193+ eq (utils .ctag_escape (" foo.bar" ), " foo\\ .bar" )
194+ eq (utils .ctag_escape (" foo*bar" ), " foo\\ *bar" )
195+ -- ^ at start gets unescaped (was escaped by rg_escape)
196+ eq (utils .ctag_escape (" ^foobar" ), " ^foobar" )
197+ -- $ at end gets unescaped (was escaped by rg_escape)
198+ eq (utils .ctag_escape (" foobar$" ), " foobar$" )
199+ -- already escaped ^ at start stays escaped (rg_escape adds another backslash)
200+ eq (utils .ctag_escape (" \\ ^foobar" ), " \\\\\\ ^foobar" )
201+ -- already escaped $ at end stays escaped
202+ eq (utils .ctag_escape (" foobar\\ $" ), " foobar\\\\ $" )
203+ -- ^ in middle stays escaped
204+ eq (utils .ctag_escape (" foo^bar" ), " foo\\ ^bar" )
205+ -- $ in middle stays escaped
206+ eq (utils .ctag_escape (" foo$bar" ), " foo\\ $bar" )
207+ -- combination of patterns
208+ eq (utils .ctag_escape (" ^foo.bar$" ), " ^foo\\ .bar$" )
209+ -- escaped backslash before dot (\. becomes ., then rg_escape escapes both)
210+ eq (utils .ctag_escape (" foo\\ .bar" ), " foo\\\\\\ .bar" )
211+ end )
138212end )
0 commit comments