@@ -297,6 +297,55 @@ fun! s:match_bullet_list_item(input_text)
297297endfun
298298" ------------------------------------------------------- }}}
299299
300+ " Selection management ----------------------------------- {{{
301+
302+ " These functions help us maintain the cursor or selection across operation
303+ "
304+ " When getting selection we record
305+ " 1. The start and end line of the selection
306+ " 2. Thd the offset of the start and end column the line end
307+ "
308+ " When setting the selection we set the start and end at the same _offset_
309+ " From the new line start and end. As we manipulate line prefixes, the
310+ " offset from the end represents the correct new cursor position
311+ fun ! s: get_selection (is_visual)
312+ let l: sel = {}
313+ let l: mode = a: is_visual ? visualmode () : ' '
314+ if l: mode == # ' v' || l: mode == # ' V' || l: mode == # " \<C-v> "
315+ let [l: start_line , l: start_col ] = getpos (" '<" )[1 :2 ]
316+ let l: sel .start_line = l: start_line
317+ let l: sel .start_offset = strlen (getline (sel .start_line)) - l: start_col
318+ let [l: end_line , l: end_col ] = getpos (" '>" )[1 :2 ]
319+ let l: sel .end_line = l: end_line
320+ let l: sel .end_offset = strlen (getline (sel .end_line)) - l: end_col
321+ let l: sel .visual_mode = l: mode
322+ else
323+ let l: sel .start_line = line (' .' )
324+ let l: sel .start_offset = strlen (getline (sel .start_line)) - col (' .' )
325+ let l: sel .end_line = l: sel .start_line
326+ let l: sel .end_offset = l: sel .start_offset
327+ let l: sel .visual_mode = ' '
328+ endif
329+ return l: sel
330+ endfun
331+
332+ fun ! s: set_selection (sel )
333+ let l: start_col = strlen (getline (a: sel .start_line)) - a: sel .start_offset
334+ let l: end_col = strlen (getline (a: sel .end_line)) - a: sel .end_offset
335+
336+ call cursor (a: sel .start_line, l: start_col )
337+ if a: sel .start_line != a: sel .end_line || l: start_col != l: end_col
338+ if a: sel .visual_mode == " \<C-v> "
339+ execute " normal! \<C-v> "
340+ elseif a: sel .visual_mode == ' V' || a: sel .visual_mode == ' v'
341+ execute " normal! v"
342+ endif
343+ call cursor (a: sel .end_line, l: end_col )
344+ endif
345+ endfun
346+
347+ " ------------------------------------------------------- }}}
348+
300349" Resolve Bullet Type ----------------------------------- {{{
301350fun ! s: closest_bullet_types (from_line_num, max_indent)
302351 let l: lnum = a: from_line_num
@@ -347,7 +396,9 @@ fun! s:find_by_type(bullet_types, type)
347396 return s: find (a: bullet_types , ' v:val.bullet_type ==# "' . a: type . ' "' )
348397endfun
349398
350- " Roman Numeral vs Alphabetic Bullets ---------------------------------- {{{
399+ " --------------------------------------------------------- }}}
400+
401+ " Roman Numeral vs Alphabetic Bullets --------------------- {{{
351402fun ! s: resolve_rom_or_abc (bullet_types)
352403 let l: first_type = a: bullet_types [0 ]
353404 let l: prev_search_starting_line = l: first_type .starting_at_line_num - g: bullets_line_spacing
@@ -396,7 +447,7 @@ fun! s:has_rom_and_abc(bullet_types)
396447endfun
397448" ------------------------------------------------------- }}}
398449
399- " Checkbox vs Standard Bullets ----------------------------------------- {{{
450+ " Checkbox vs Standard Bullets -------------------------- {{{
400451fun ! s: resolve_chk_or_std (bullet_types)
401452 " if it matches both regular and checkbox it is most likely a checkbox
402453 return s: find_by_type (a: bullet_types , ' chk' )
@@ -409,8 +460,6 @@ fun! s:has_chk_and_std(bullet_types)
409460endfun
410461" ------------------------------------------------------- }}}
411462
412- " ------------------------------------------------------- }}}
413-
414463" Build Next Bullet -------------------------------------- {{{
415464fun ! s: next_bullet_str (bullet)
416465 let l: bullet_type = get (a: bullet , ' bullet_type' )
@@ -500,7 +549,7 @@ fun! s:insert_new_bullet()
500549 " indent if previous line ended in a colon
501550 if l: indent_next
502551 " demote the new bullet
503- call s: change_bullet_level_and_renumber (-1 )
552+ call s: change_line_bullet_level (-1 , l: next_line_num )
504553 " reset cursor position after indenting
505554 let l: col = strlen (getline (l: next_line_num )) + 1
506555 call setpos (' .' , [0 , l: next_line_num , l: col ])
@@ -539,8 +588,6 @@ fun! s:line_ends_in_colon(lnum)
539588endfun
540589" --------------------------------------------------------- }}}
541590
542- " --------------------------------------------------------- }}}
543-
544591" Checkboxes ---------------------------------------------- {{{
545592fun ! s: find_checkbox_position (lnum)
546593 let l: line_text = getline (a: lnum )
@@ -749,21 +796,26 @@ endfun
749796
750797" Renumbering --------------------------------------------- {{{
751798fun ! s: renumber_selection ()
752- let l: selection_lines = s: get_visual_selection_lines ()
799+ let l: sel = s: get_selection (1 )
800+ call s: renumber_lines (l: sel .start_line, l: sel .end_line)
801+ call s: set_selection (l: sel )
802+ endfun
803+
804+ fun ! s: renumber_lines (start , end )
753805 let l: prev_indent = -1
754806 let l: levels = {} " stores all the info about the current outline/list
755807
756- for l: line in l: selection_lines
757- let l: indent = indent (l: line . nr)
758- let l: bullet = s: closest_bullet_types (l: line . nr, l: indent )
808+ for l: nr in range ( a: start , a: end )
809+ let l: indent = indent (l: nr )
810+ let l: bullet = s: closest_bullet_types (l: nr , l: indent )
759811 let l: bullet = s: resolve_bullet_type (l: bullet )
760812 let l: curr_level = s: get_level (l: bullet )
761813 if l: curr_level > 1
762814 " then it's an AsciiDoc list and shouldn't be renumbered
763815 break
764816 endif
765817
766- if ! empty (l: bullet ) && l: bullet .starting_at_line_num == l: line . nr
818+ if ! empty (l: bullet ) && l: bullet .starting_at_line_num == l: nr
767819 " skip wrapped lines and lines that aren't bullets
768820 if (l: indent > l: prev_indent || ! has_key (l: levels , l: indent ))
769821 \ && l: bullet .bullet_type !=# ' chk' && l: bullet .bullet_type !=# ' std'
@@ -818,68 +870,54 @@ fun! s:renumber_selection()
818870 let l: renumbered_line = l: bullet .leading_space
819871 \ . l: new_bullet
820872 \ . l: bullet .text_after_bullet
821- call setline (l: line . nr, l: renumbered_line )
873+ call setline (l: nr , l: renumbered_line )
822874 elseif l: bullet .bullet_type == # ' chk'
823875 " Reset the checkbox marker if it already exists, or blank otherwise
824876 let l: marker = has_key (l: bullet , ' checkbox_marker' ) ?
825877 \ l: bullet .checkbox_marker : ' '
826- call s: set_checkbox (l: line . nr, l: marker )
878+ call s: set_checkbox (l: nr , l: marker )
827879 endif
828880 endif
829881 endfor
830882endfun
831883
832- fun ! s: renumber_whole_list (... )
833- " Renumbers the whole list containing the cursor.
834- " Does not renumber across blank lines.
835- " Takes 2 optional arguments containing starting and ending cursor positions
836- " so that we can reset the existing visual selection after renumbering.
884+ " Renumbers the whole list containing the cursor.
885+ fun ! s: renumber_whole_list ()
837886 let l: first_line = s: first_bullet_line (line (' .' ))
838887 let l: last_line = s: last_bullet_line (line (' .' ))
839888 if l: first_line > 0 && l: last_line > 0
840- " Create a visual selection around the current list so that we can call
841- " s:renumber_selection() to do the renumbering.
842- call setpos (" '<" , [0 , l: first_line , 1 , 0 ])
843- call setpos (" '>" , [0 , l: last_line , 1 , 0 ])
844- call s: renumber_selection ()
845- if a: 0 == 2
846- " Reset the starting visual selection
847- call setpos (" '<" , [0 , a: 1 [0 ], a: 1 [1 ], 0 ])
848- call setpos (" '>" , [0 , a: 2 [0 ], a: 2 [1 ], 0 ])
849- execute ' normal! gv'
850- endif
889+ call s: renumber_lines (l: first_line , l: last_line )
851890 endif
852891endfun
853892
854893command ! -range =% RenumberSelection call <SID> renumber_selection ()
855894command ! RenumberList call <SID> renumber_whole_list ()
895+
856896" --------------------------------------------------------- }}}
857897
858898" Changing outline level ---------------------------------- {{{
859- fun ! s: change_bullet_level (direction)
860- let l: lnum = line (' .' )
861- let l: curr_line = s: parse_bullet (l: lnum , getline (l: lnum ))
899+ fun ! s: change_line_bullet_level (direction, lnum)
900+ let l: curr_line = s: parse_bullet (a: lnum , getline (a: lnum ))
862901
863902 if a: direction == 1
864- if l: curr_line != [] && indent (l : lnum ) == 0
903+ if l: curr_line != [] && indent (a : lnum ) == 0
865904 " Promoting a bullet at the highest level will delete the bullet
866- call setline (l: lnum , l: curr_line [0 ].text_after_bullet)
867- execute ' normal! $'
905+ call setline (a: lnum , l: curr_line [0 ].text_after_bullet)
868906 return
869907 else
870- execute ' normal! <<$ '
908+ execute a: lnum . ' normal! <<'
871909 endif
872910 else
873- execute ' normal! >>$ '
911+ execute a: lnum . ' normal! >>'
874912 endif
875913
876914 if l: curr_line == []
877915 " If the current line is not a bullet then don't do anything else.
878916 return
879917 endif
880918
881- let l: curr_indent = indent (l : lnum )
882- let l: curr_bullet= s: closest_bullet_types (l : lnum , l: curr_indent )
919+ let l: curr_indent = indent (a : lnum )
920+ let l: curr_bullet = s: closest_bullet_types (a : lnum , l: curr_indent )
883921 let l: curr_bullet = s: resolve_bullet_type (l: curr_bullet )
884922
885923 let l: curr_line = l: curr_bullet .starting_at_line_num
@@ -963,42 +1001,27 @@ fun! s:change_bullet_level(direction)
9631001 endif
9641002
9651003 " Apply the new bullet
966- call setline (l: lnum , l: next_bullet_str )
967-
968- execute ' normal! $'
969- return
1004+ call setline (a: lnum , l: next_bullet_str )
9701005endfun
9711006
972- fun ! s: change_bullet_level_and_renumber (direction)
973- " Calls change_bullet_level and then renumber_whole_list if required
974- call s: change_bullet_level (a: direction )
975- if g: bullets_renumber_on_change
976- call s: renumber_whole_list ()
977- endif
978- endfun
9791007
980- fun ! s: visual_change_bullet_level (direction)
1008+ fun ! s: change_bullet_level (direction, is_visual )
9811009 " Changes the bullet level for each of the selected lines
982- let l: start = getpos (" '<" )[1 :2 ]
983- let l: end = getpos (" '>" )[1 :2 ]
984- let l: selected_lines = range (l: start [0 ], l: end [0 ])
985- for l: lnum in l: selected_lines
986- " Iterate the cursor position over each line and then call
987- " s:change_bullet_level for that cursor position.
988- call setpos (' .' , [0 , l: lnum , 1 , 0 ])
989- call s: change_bullet_level (a: direction )
1010+ let l: sel = s: get_selection (a: is_visual )
1011+ for l: lnum in range (l: sel .start_line, l: sel .end_line)
1012+ call s: change_line_bullet_level (a: direction , l: lnum )
9901013 endfor
1014+
9911015 if g: bullets_renumber_on_change
992- " Pass the current visual selection so that it gets reset after
993- " renumbering the list.
994- call s: renumber_whole_list (l: start , l: end )
1016+ call s: renumber_whole_list ()
9951017 endif
1018+ call s: set_selection (l: sel )
9961019endfun
9971020
998- command ! BulletDemote call <SID> change_bullet_level_and_renumber (-1 )
999- command ! BulletPromote call <SID> change_bullet_level_and_renumber ( 1 )
1000- command ! -range =% BulletDemoteVisual call <SID> visual_change_bullet_level ( - 1 )
1001- command ! -range =% BulletPromoteVisual call <SID> visual_change_bullet_level ( 1 )
1021+ command ! BulletDemote call <SID> change_bullet_level (-1 , 0 )
1022+ command ! BulletPromote call <SID> change_bullet_level ( 1 , 0 )
1023+ command ! -range =% BulletDemoteVisual call <SID> change_bullet_level ( -1 , 1 )
1024+ command ! -range =% BulletPromoteVisual call <SID> change_bullet_level ( 1 , 1 )
10021025
10031026" --------------------------------------------------------- }}}
10041027
@@ -1089,7 +1112,7 @@ fun! s:get_visual_selection_lines()
10891112 let l: index = l: lnum1
10901113 let l: lines_with_index = []
10911114 for l: line in l: lines
1092- let l: lines_with_index += [ {' text' : l: line , ' nr' : l: index }]
1115+ call add ( l: lines_with_index, {' text' : l: line , ' nr' : l: index })
10931116 let l: index += 1
10941117 endfor
10951118 return l: lines_with_index
0 commit comments