@@ -222,45 +222,48 @@ M.change_surround = function(args)
222222 buffer .set_curpos (args .curpos )
223223 -- Get the selections to change, as well as the delimiters to replace those selections
224224 local selections = utils .get_nearest_selections (args .del_char , " change" )
225- local delimiters = args .add_delimiters ()
226- if selections and delimiters then
227- -- Avoid adding any, and remove any existing whitespace after the
228- -- opening delimiter if only whitespace exists between it and the end
229- -- of the line. Avoid adding or removing leading whitespace before the
230- -- closing delimiter if only whitespace exists between it and the
231- -- beginning of the line.
232-
233- local space_begin , space_end = buffer .get_line (selections .left .last_pos [1 ]):find (" %s*$" )
234- if space_begin - 1 <= selections .left .last_pos [2 ] then -- Whitespace is adjacent to opening delimiter
235- -- Trim trailing whitespace from opening delimiter
236- delimiters [1 ][# delimiters [1 ]] = delimiters [1 ][# delimiters [1 ]]:gsub (" %s+$" , " " )
237- -- Grow selection end to include trailing whitespace, so it gets removed
238- selections .left .last_pos [2 ] = space_end
239- end
225+ local raw_delimiters = args .add_delimiters ()
226+ if not (selections and raw_delimiters ) then
227+ cache .set_callback (" v:lua.require'nvim-surround'.change_callback" )
228+ return
229+ end
230+ local delimiters = utils .normalize_delimiters (raw_delimiters )
231+ -- Avoid adding any, and remove any existing whitespace after the
232+ -- opening delimiter if only whitespace exists between it and the end
233+ -- of the line. Avoid adding or removing leading whitespace before the
234+ -- closing delimiter if only whitespace exists between it and the
235+ -- beginning of the line.
236+
237+ local space_begin , space_end = buffer .get_line (selections .left .last_pos [1 ]):find (" %s*$" )
238+ if space_begin - 1 <= selections .left .last_pos [2 ] then -- Whitespace is adjacent to opening delimiter
239+ -- Trim trailing whitespace from opening delimiter
240+ delimiters [1 ][# delimiters [1 ]] = delimiters [1 ][# delimiters [1 ]]:gsub (" %s+$" , " " )
241+ -- Grow selection end to include trailing whitespace, so it gets removed
242+ selections .left .last_pos [2 ] = space_end
243+ end
240244
241- space_begin , space_end = buffer .get_line (selections .right .first_pos [1 ]):find (" ^%s*" )
242- if space_end + 1 >= selections .right .first_pos [2 ] then -- Whitespace is adjacent to closing delimiter
243- -- Trim leading whitespace from closing delimiter
244- delimiters [2 ][1 ] = delimiters [2 ][1 ]:gsub (" ^%s+" , " " )
245- -- Shrink selection beginning to exclude leading whitespace, so it remains unchanged
246- selections .right .first_pos [2 ] = space_end + 1
247- end
245+ space_begin , space_end = buffer .get_line (selections .right .first_pos [1 ]):find (" ^%s*" )
246+ if space_end + 1 >= selections .right .first_pos [2 ] then -- Whitespace is adjacent to closing delimiter
247+ -- Trim leading whitespace from closing delimiter
248+ delimiters [2 ][1 ] = delimiters [2 ][1 ]:gsub (" ^%s+" , " " )
249+ -- Shrink selection beginning to exclude leading whitespace, so it remains unchanged
250+ selections .right .first_pos [2 ] = space_end + 1
251+ end
248252
249- local sticky_pos = buffer .with_extmark (args .curpos , function ()
250- buffer .change_selection (selections .right , delimiters [2 ])
251- buffer .change_selection (selections .left , delimiters [1 ])
252- end )
253- buffer .restore_curpos ({
254- first_pos = selections .left .first_pos ,
255- sticky_pos = sticky_pos ,
256- old_pos = args .curpos ,
257- })
253+ local sticky_pos = buffer .with_extmark (args .curpos , function ()
254+ buffer .change_selection (selections .right , delimiters [2 ])
255+ buffer .change_selection (selections .left , delimiters [1 ])
256+ end )
257+ buffer .restore_curpos ({
258+ first_pos = selections .left .first_pos ,
259+ sticky_pos = sticky_pos ,
260+ old_pos = args .curpos ,
261+ })
258262
259- if args .line_mode then
260- local first_line = selections .left .first_pos [1 ]
261- local last_line = selections .right .last_pos [1 ]
262- config .get_opts ().indent_lines (first_line , last_line + # delimiters [1 ] + # delimiters [2 ] - 2 )
263- end
263+ if args .line_mode then
264+ local first_line = selections .left .first_pos [1 ]
265+ local last_line = selections .right .last_pos [1 ]
266+ config .get_opts ().indent_lines (first_line , last_line + # delimiters [1 ] + # delimiters [2 ] - 2 )
264267 end
265268
266269 cache .set_callback (" v:lua.require'nvim-surround'.change_callback" )
@@ -365,7 +368,9 @@ M.change_callback = function()
365368 return
366369 end
367370
371+ -- To handle number prefixing properly, we just run the replacement algorithm multiple times
368372 for _ = 1 , cache .change .count do
373+ -- If at any point we are unable to find a surrounding pair to change, early exit
369374 local selections = utils .get_nearest_selections (del_char , " change" )
370375 if not selections then
371376 return
@@ -382,6 +387,8 @@ M.change_callback = function()
382387 end
383388
384389 -- Get the new surrounding delimiter pair, prioritizing any delimiters in the cache
390+ -- NB: This must occur between drawing the highlights and clearing them, so the selections are properly
391+ -- highlighted if the user is providing (blocking) input
385392 local delimiters = cache .change .add_delimiters and cache .change .add_delimiters ()
386393 if not delimiters then
387394 if change and change .replacement then
@@ -398,20 +405,19 @@ M.change_callback = function()
398405 return
399406 end
400407
408+ local add_delimiters = function ()
409+ return delimiters
410+ end
401411 -- Set the cache
402412 cache .change = {
403413 del_char = del_char ,
404- add_delimiters = function ()
405- return delimiters
406- end ,
414+ add_delimiters = add_delimiters ,
407415 line_mode = cache .change .line_mode ,
408416 count = cache .change .count ,
409417 }
410418 M .change_surround ({
411419 del_char = del_char ,
412- add_delimiters = function ()
413- return delimiters
414- end ,
420+ add_delimiters = add_delimiters ,
415421 line_mode = cache .change .line_mode ,
416422 count = cache .change .count ,
417423 curpos = buffer .get_curpos (),
0 commit comments