4444if ! exists (' g:bullets_pad_right' )
4545 let g: bullets_pad_right = 1
4646end
47+
48+ if ! exists (' g:bullets_max_alpha_characters' )
49+ let g: bullets_max_alpha_characters = 2
50+ end
51+ " calculate the decimal equivalent to the last alphabetical list item
52+ let s: power = g: bullets_max_alpha_characters
53+ let s: abc_max = -1
54+ while s: power >= 0
55+ let s: abc_max += pow (26 ,s: power )
56+ let s: power -= 1
57+ endwhile
4758" ------------------------------------------------------ }}}
4859
4960" Bullet type detection ---------------------------------------- {{{
@@ -110,6 +121,37 @@ fun! s:match_roman_list_item(input_text)
110121 \ }
111122endfun
112123
124+ fun ! s: match_alphabetical_list_item (input_text)
125+ let l: abc_bullet_regex = join ([
126+ \ ' \v^((\s*)(\u{1,' ,
127+ \ string (g: bullets_max_alpha_characters ),
128+ \ ' }|\l{1,' ,
129+ \ string (g: bullets_max_alpha_characters ),
130+ \ ' })(\.|\))(\s+))(.*)' ], ' ' )
131+ let l: matches = matchlist (a: input_text , l: abc_bullet_regex )
132+
133+ if empty (l: matches )
134+ return {}
135+ endif
136+
137+ let l: bullet_length = strlen (l: matches [1 ])
138+ let l: leading_space = l: matches [2 ]
139+ let l: abc = l: matches [3 ]
140+ let l: closure = l: matches [4 ]
141+ let l: trailing_space = l: matches [5 ]
142+ let l: text_after_bullet = l: matches [6 ]
143+
144+ return {
145+ \ ' bullet_type' : ' abc' ,
146+ \ ' bullet_length' : l: bullet_length ,
147+ \ ' leading_space' : l: leading_space ,
148+ \ ' trailing_space' : l: trailing_space ,
149+ \ ' bullet' : l: abc ,
150+ \ ' closure' : l: closure ,
151+ \ ' text_after_bullet' : l: text_after_bullet
152+ \ }
153+ endfun
154+
113155fun ! s: match_checkbox_bullet_item (input_text)
114156 let l: checkbox_bullet_regex = ' \v(^(\s*)- \[[x ]?\](\s+))(.*)'
115157 let l: matches = matchlist (a: input_text , l: checkbox_bullet_regex )
@@ -159,6 +201,7 @@ fun! s:parse_bullet(line_text)
159201 let l: chk_bullet_matches = s: match_checkbox_bullet_item (a: line_text )
160202 let l: num_bullet_matches = s: match_numeric_list_item (a: line_text )
161203 let l: rom_bullet_matches = s: match_roman_list_item (a: line_text )
204+ let l: abc_bullet_matches = s: match_alphabetical_list_item (a: line_text )
162205
163206 if ! empty (l: chk_bullet_matches )
164207 return l: chk_bullet_matches
@@ -168,6 +211,8 @@ fun! s:parse_bullet(line_text)
168211 return l: num_bullet_matches
169212 elseif ! empty (l: rom_bullet_matches )
170213 return l: rom_bullet_matches
214+ elseif ! empty (l: abc_bullet_matches )
215+ return l: abc_bullet_matches
171216 else
172217 return {}
173218 endif
@@ -209,6 +254,10 @@ fun! s:next_bullet_str(bullet)
209254 let l: islower = a: bullet .bullet == # tolower (a: bullet .bullet)
210255 let l: next_num = s: arabic2roman (s: roman2arabic (a: bullet .bullet) + 1 , l: islower )
211256 return a: bullet .leading_space . l: next_num . a: bullet .closure . ' '
257+ elseif a: bullet .bullet_type == # ' abc'
258+ let l: islower = a: bullet .bullet == # tolower (a: bullet .bullet)
259+ let l: next_num = s: dec2abc (s: abc2dec (a: bullet .bullet) + 1 , l: islower )
260+ return a: bullet .leading_space . l: next_num . a: bullet .closure . ' '
212261 elseif a: bullet .bullet_type == # ' num'
213262 let l: next_num = a: bullet .bullet + 1
214263 return a: bullet .leading_space . l: next_num . a: bullet .closure . ' '
@@ -247,6 +296,14 @@ fun! s:insert_new_bullet()
247296 let l: curr_line_num = line (' .' )
248297 let l: next_line_num = l: curr_line_num + g: bullets_line_spacing
249298 let l: bullet = s: detect_bullet_line (l: curr_line_num )
299+ if l: bullet != {} && l: curr_line_num > 1 &&
300+ \ (l: bullet .bullet_type == # ' rom' || l: bullet .bullet_type == # ' abc' )
301+ let l: bullet_prev = s: detect_bullet_line (l: curr_line_num - 1 )
302+ if l: bullet_prev != {} && l: bullet .bullet_type == # ' rom' &&
303+ \ (s: roman2arabic (l: bullet .bullet) != (s: roman2arabic (l: bullet_prev .bullet) + 1 ))
304+ let l: bullet .bullet_type = ' abc'
305+ endif
306+ endif
250307 let l: send_return = 1
251308 let l: normal_mode = mode () == # ' n'
252309
@@ -258,7 +315,7 @@ fun! s:insert_new_bullet()
258315 " We don't want to create a new bullet if the previous one was not used,
259316 " instead we want to delete the empty bullet - like word processors do
260317 call s: delete_empty_bullet (l: curr_line_num )
261- else
318+ elseif ! ( l: bullet .bullet_type == # ' abc ' && s: abc2dec ( l: bullet .bullet) + 1 > s: abc_max )
262319
263320 let l: next_bullet_list = [s: pad_to_length (s: next_bullet_str (l: bullet ), l: bullet .bullet_length)]
264321
@@ -392,6 +449,33 @@ endfunction
392449
393450" Roman numerals ---------------------------------------------- }}}
394451
452+ " Alphabetic ordinals ----------------------------------------- {{{
453+
454+ " Alphabetic ordinal functions
455+ " Treat alphabetic ordinals as base-26 numbers to make things easy
456+ "
457+ fun ! s: abc2dec (abc )
458+ let l: abc = tolower (a: abc )
459+ let l: dec = char2nr (l: abc [0 ]) - char2nr (' a' ) + 1
460+ if len (l: abc ) == 1
461+ return l: dec
462+ else
463+ return float2nr (pow (26 , len (l: abc ) - 1 )) * l: dec + s: abc2dec (l: abc [1 : len (l: abc ) - 1 ])
464+ endif
465+ endfun
466+
467+ fun ! s: dec2abc (dec, islower)
468+ let l: a = a: islower ? ' a' : ' A'
469+ let l: rem = (a: dec - 1 ) % 26
470+ let l: abc = nr2char (l: rem + char2nr (l: a ))
471+ if a: dec <= 26
472+ return l: abc
473+ else
474+ return s: dec2abc ((a: dec - 1 )/ 26 , a: islower ) . l: abc
475+ endif
476+ endfun
477+ " Alphabetic ordinals ----------------------------------------- }}}
478+
395479" Renumbering --------------------------------------------- {{{
396480fun ! s: renumber_selection ()
397481 let l: selection_lines = s: get_visual_selection_lines ()
0 commit comments