44
44
if ! exists (' g:bullets_pad_right' )
45
45
let g: bullets_pad_right = 1
46
46
end
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
47
58
" ------------------------------------------------------ }}}
48
59
49
60
" Bullet type detection ---------------------------------------- {{{
@@ -110,6 +121,37 @@ fun! s:match_roman_list_item(input_text)
110
121
\ }
111
122
endfun
112
123
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
+
113
155
fun ! s: match_checkbox_bullet_item (input_text)
114
156
let l: checkbox_bullet_regex = ' \v(^(\s*)- \[[x ]?\](\s+))(.*)'
115
157
let l: matches = matchlist (a: input_text , l: checkbox_bullet_regex )
@@ -159,6 +201,7 @@ fun! s:parse_bullet(line_text)
159
201
let l: chk_bullet_matches = s: match_checkbox_bullet_item (a: line_text )
160
202
let l: num_bullet_matches = s: match_numeric_list_item (a: line_text )
161
203
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 )
162
205
163
206
if ! empty (l: chk_bullet_matches )
164
207
return l: chk_bullet_matches
@@ -168,6 +211,8 @@ fun! s:parse_bullet(line_text)
168
211
return l: num_bullet_matches
169
212
elseif ! empty (l: rom_bullet_matches )
170
213
return l: rom_bullet_matches
214
+ elseif ! empty (l: abc_bullet_matches )
215
+ return l: abc_bullet_matches
171
216
else
172
217
return {}
173
218
endif
@@ -209,6 +254,10 @@ fun! s:next_bullet_str(bullet)
209
254
let l: islower = a: bullet .bullet == # tolower (a: bullet .bullet)
210
255
let l: next_num = s: arabic2roman (s: roman2arabic (a: bullet .bullet) + 1 , l: islower )
211
256
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 . ' '
212
261
elseif a: bullet .bullet_type == # ' num'
213
262
let l: next_num = a: bullet .bullet + 1
214
263
return a: bullet .leading_space . l: next_num . a: bullet .closure . ' '
@@ -247,6 +296,14 @@ fun! s:insert_new_bullet()
247
296
let l: curr_line_num = line (' .' )
248
297
let l: next_line_num = l: curr_line_num + g: bullets_line_spacing
249
298
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
250
307
let l: send_return = 1
251
308
let l: normal_mode = mode () == # ' n'
252
309
@@ -258,7 +315,7 @@ fun! s:insert_new_bullet()
258
315
" We don't want to create a new bullet if the previous one was not used,
259
316
" instead we want to delete the empty bullet - like word processors do
260
317
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 )
262
319
263
320
let l: next_bullet_list = [s: pad_to_length (s: next_bullet_str (l: bullet ), l: bullet .bullet_length)]
264
321
@@ -392,6 +449,33 @@ endfunction
392
449
393
450
" Roman numerals ---------------------------------------------- }}}
394
451
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
+
395
479
" Renumbering --------------------------------------------- {{{
396
480
fun ! s: renumber_selection ()
397
481
let l: selection_lines = s: get_visual_selection_lines ()
0 commit comments