@@ -108,7 +108,25 @@ local x = 2
108108 assert .matches (' Missing end marker' , warnings [1 ])
109109 end )
110110
111- it (' warns on empty SEARCH section' , function ()
111+ it (' parses empty SEARCH section as insert operation' , function ()
112+ -- Empty search means "insert at cursor position"
113+ local input = [[
114+ <<<<<<< SEARCH
115+
116+ =======
117+ local x = 2
118+ >>>>>>> REPLACE
119+ ]]
120+ local replacements , warnings = search_replace .parse_blocks (input )
121+
122+ assert .equals (1 , # replacements )
123+ assert .equals (0 , # warnings )
124+ assert .equals (' ' , replacements [1 ].search )
125+ assert .equals (' local x = 2' , replacements [1 ].replace )
126+ assert .is_true (replacements [1 ].is_insert )
127+ end )
128+
129+ it (' parses whitespace-only SEARCH section as insert operation' , function ()
112130 -- Note: Empty search with content on same line as separator
113131 -- The parser requires \n======= so whitespace-only search still needs proper structure
114132 local input = [[
@@ -120,9 +138,10 @@ local x = 2
120138]]
121139 local replacements , warnings = search_replace .parse_blocks (input )
122140
123- assert .equals (0 , # replacements )
124- assert .equals (1 , # warnings )
125- assert .matches (' Empty SEARCH section' , warnings [1 ])
141+ assert .equals (1 , # replacements )
142+ assert .equals (0 , # warnings )
143+ assert .equals (' ' , replacements [1 ].search )
144+ assert .is_true (replacements [1 ].is_insert )
126145 end )
127146
128147 it (' handles empty REPLACE section (deletion)' , function ()
@@ -277,4 +296,86 @@ describe('search_replace.apply', function()
277296
278297 vim .api .nvim_buf_delete (buf , { force = true })
279298 end )
299+
300+ it (' inserts at cursor row when is_insert is true' , function ()
301+ local buf = vim .api .nvim_create_buf (false , true )
302+ vim .api .nvim_buf_set_lines (buf , 0 , - 1 , false , { ' line 1' , ' line 2' , ' line 3' })
303+
304+ local replacements = {
305+ { search = ' ' , replace = ' inserted text' , block_number = 1 , is_insert = true },
306+ }
307+
308+ -- Insert before row 1 (0-indexed), so inserts before "line 2"
309+ local success , errors , count = search_replace .apply (buf , replacements , 1 )
310+
311+ assert .is_true (success )
312+ assert .equals (0 , # errors )
313+ assert .equals (1 , count )
314+
315+ local lines = vim .api .nvim_buf_get_lines (buf , 0 , - 1 , false )
316+ assert .are .same ({ ' line 1' , ' inserted text' , ' line 2' , ' line 3' }, lines )
317+
318+ vim .api .nvim_buf_delete (buf , { force = true })
319+ end )
320+
321+ it (' inserts at empty line cursor position' , function ()
322+ local buf = vim .api .nvim_create_buf (false , true )
323+ vim .api .nvim_buf_set_lines (buf , 0 , - 1 , false , { ' line 1' , ' ' , ' line 3' })
324+
325+ local replacements = {
326+ { search = ' ' , replace = ' new content' , block_number = 1 , is_insert = true },
327+ }
328+
329+ -- Insert before row 1 (0-indexed), the empty line
330+ local success , errors , count = search_replace .apply (buf , replacements , 1 )
331+
332+ assert .is_true (success )
333+ assert .equals (0 , # errors )
334+ assert .equals (1 , count )
335+
336+ local lines = vim .api .nvim_buf_get_lines (buf , 0 , - 1 , false )
337+ assert .are .same ({ ' line 1' , ' new content' , ' ' , ' line 3' }, lines )
338+
339+ vim .api .nvim_buf_delete (buf , { force = true })
340+ end )
341+
342+ it (' inserts multiline content at cursor row' , function ()
343+ local buf = vim .api .nvim_create_buf (false , true )
344+ vim .api .nvim_buf_set_lines (buf , 0 , - 1 , false , { ' line 1' , ' ' , ' line 3' })
345+
346+ local replacements = {
347+ { search = ' ' , replace = ' first\n second\n third' , block_number = 1 , is_insert = true },
348+ }
349+
350+ -- Insert before row 1 (0-indexed)
351+ local success , errors , count = search_replace .apply (buf , replacements , 1 )
352+
353+ assert .is_true (success )
354+ assert .equals (0 , # errors )
355+ assert .equals (1 , count )
356+
357+ local lines = vim .api .nvim_buf_get_lines (buf , 0 , - 1 , false )
358+ assert .are .same ({ ' line 1' , ' first' , ' second' , ' third' , ' ' , ' line 3' }, lines )
359+
360+ vim .api .nvim_buf_delete (buf , { force = true })
361+ end )
362+
363+ it (' returns error for insert without cursor_row' , function ()
364+ local buf = vim .api .nvim_create_buf (false , true )
365+ vim .api .nvim_buf_set_lines (buf , 0 , - 1 , false , { ' line 1' })
366+
367+ local replacements = {
368+ { search = ' ' , replace = ' inserted text' , block_number = 1 , is_insert = true },
369+ }
370+
371+ -- No cursor_row provided
372+ local success , errors , count = search_replace .apply (buf , replacements )
373+
374+ assert .is_false (success )
375+ assert .equals (1 , # errors )
376+ assert .matches (' Insert operation requires cursor position' , errors [1 ])
377+ assert .equals (0 , count )
378+
379+ vim .api .nvim_buf_delete (buf , { force = true })
380+ end )
280381end )
0 commit comments