From 76429d5e332898e7ce8429fa913137c68756f3d8 Mon Sep 17 00:00:00 2001 From: Harshad Vedartham Date: Fri, 2 Feb 2024 17:23:57 -0800 Subject: [PATCH 1/3] Caching with a reference count --- README.md | 2 +- plugin/bullets.vim | 73 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index a1501c1..6645ad5 100644 --- a/README.md +++ b/README.md @@ -397,7 +397,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
mykoza

💻 🤔
noodlor

💻 -
Harshad Srinivasan

💻 🐛 +
Harshad Vedartham

💻 🐛
Erick A. Chacón Montalván

🤔
Sam Griesemer

💻 🐛
Charles Pence

💻 diff --git a/plugin/bullets.vim b/plugin/bullets.vim index 3999891..5109d77 100644 --- a/plugin/bullets.vim +++ b/plugin/bullets.vim @@ -61,6 +61,7 @@ end if !exists('g:bullets_max_alpha_characters') let g:bullets_max_alpha_characters = 2 end + " calculate the decimal equivalent to the last alphabetical list item let s:power = g:bullets_max_alpha_characters let s:abc_max = -1 @@ -85,6 +86,10 @@ if !exists('g:bullets_nested_checkboxes') let g:bullets_nested_checkboxes = 1 endif +if !exists('g:bullets_enable_wrapped_lines') + let g:bullets_enable_wrapped_lines = 1 +end + if !exists('g:bullets_checkbox_markers') " The ordered series of markers to use in checkboxes " If only two markers are listed, they represent 'off' and 'on' @@ -116,8 +121,40 @@ endif " ------------------------------------------------------ }}} " Parse Bullet Type ------------------------------------------- {{{ + +" A caching mechanism for bullet +" We add a crude 'reference count' for the cache so we can nest calls +let s:bullet_cache = v:null +let s:bullet_cache_depth = 0 + +fun! s:enable_bullet_cache() + if s:bullet_cache_depth == 0 + let s:bullet_cache = {} + endif + let s:bullet_cache_depth += 1 +endfun + +fun! s:disable_bullet_cache() + if s:bullet_cache_depth == 1 + let s:bullet_cache = v:null + endif + + if s:bullet_cache_depth > 0 + let s:bullet_cache_depth -= 1 + endif +endfun + + fun! s:parse_bullet(line_num, line_text) + if s:bullet_cache isnot v:null + let l:key = a:line_text . a:line_num + let l:cached = get(s:bullet_cache, l:key, v:null) + if l:cached isnot v:null + return l:cached + endif + endif + let l:bullet = s:match_bullet_list_item(a:line_text) " Must be a bullet to be a checkbox let l:check = !empty(l:bullet) ? s:match_checkbox_bullet_item(a:line_text) : {} @@ -133,9 +170,13 @@ fun! s:parse_bullet(line_num, line_text) for l:data in l:kinds let l:data.starting_at_line_num = a:line_num endfor - + + if s:bullet_cache isnot v:null + let l:key = a:line_text . a:line_num + let s:bullet_cache[l:key] = l:kinds + endif + return l:kinds - endfun fun! s:match_numeric_list_item(input_text) @@ -361,17 +402,19 @@ fun! s:closest_bullet_types(from_line_num, max_indent) " Support for wrapped text bullets, even if the wrapped line is not indented " It considers a blank line as the end of a bullet " DEMO: https://raw.githubusercontent.com/dkarter/bullets.vim/master/img/wrapped-bullets.gif - while l:lnum > 1 && (l:curr_indent != 0 || l:bullet_kinds != [] || !(l:ltxt =~# '\v^(\s+$|$)')) - \ && (a:max_indent < l:curr_indent || l:bullet_kinds == []) - if l:bullet_kinds != [] - let l:lnum = l:lnum - g:bullets_line_spacing - else - let l:lnum = l:lnum - 1 - endif - let l:ltxt = getline(l:lnum) - let l:bullet_kinds = s:parse_bullet(l:lnum, l:ltxt) - let l:curr_indent = indent(l:lnum) - endwhile + if g:bullets_enable_wrapped_lines + while l:lnum > 1 && (l:curr_indent != 0 || l:bullet_kinds != [] || !(l:ltxt =~# '\v^(\s+$|$)')) + \ && (a:max_indent < l:curr_indent || l:bullet_kinds == []) + if l:bullet_kinds != [] + let l:lnum = l:lnum - g:bullets_line_spacing + else + let l:lnum = l:lnum - 1 + endif + let l:ltxt = getline(l:lnum) + let l:bullet_kinds = s:parse_bullet(l:lnum, l:ltxt) + let l:curr_indent = indent(l:lnum) + endwhile + endif return l:bullet_kinds endfun @@ -802,6 +845,7 @@ fun! s:renumber_selection() endfun fun! s:renumber_lines(start, end) + call s:enable_bullet_cache() let l:prev_indent = -1 let l:levels = {} " stores all the info about the current outline/list @@ -879,15 +923,18 @@ fun! s:renumber_lines(start, end) endif endif endfor + call s:disable_bullet_cache() endfun " Renumbers the whole list containing the cursor. fun! s:renumber_whole_list() + call s:enable_bullet_cache() let l:first_line = s:first_bullet_line(line('.')) let l:last_line = s:last_bullet_line(line('.')) if l:first_line > 0 && l:last_line > 0 call s:renumber_lines(l:first_line, l:last_line) endif + call s:disable_bullet_cache() endfun command! -range=% RenumberSelection call renumber_selection() From e9fe46a661ad17f31292439256433d9207e38086 Mon Sep 17 00:00:00 2001 From: Harshad Vedartham Date: Fri, 2 Feb 2024 17:33:07 -0800 Subject: [PATCH 2/3] Wrapper function; don't include line number --- plugin/bullets.vim | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/plugin/bullets.vim b/plugin/bullets.vim index 5109d77..395f7c4 100644 --- a/plugin/bullets.vim +++ b/plugin/bullets.vim @@ -144,36 +144,40 @@ fun! s:disable_bullet_cache() endif endfun - fun! s:parse_bullet(line_num, line_text) + let l:kinds = s:parse_bullet_text(a:line_text) + + for l:data in l:kinds + let l:data.starting_at_line_num = a:line_num + endfor + + return l:kinds +endfun + +fun! s:parse_bullet_text(line_text) if s:bullet_cache isnot v:null - let l:key = a:line_text . a:line_num - let l:cached = get(s:bullet_cache, l:key, v:null) + let l:cached = get(s:bullet_cache, l:line_text, v:null) if l:cached isnot v:null - return l:cached + " Return a copy so as not to break the referene + return copy(l:cached) endif endif let l:bullet = s:match_bullet_list_item(a:line_text) " Must be a bullet to be a checkbox - let l:check = !empty(l:bullet) ? s:match_checkbox_bullet_item(a:line_text) : {} + let l:check = !empty(l:bullet) ? s:match_checkbox_bullet_item(a:line_text) : v:null " Cannot be numeric if a bullet - let l:num = empty(l:bullet) ? s:match_numeric_list_item(a:line_text) : {} + let l:num = empty(l:bullet) ? s:match_numeric_list_item(a:line_text) : v:null " Cannot be alphabetic if numeric or a bullet - let l:alpha = empty(l:bullet) && empty(l:num) ? s:match_alphabetical_list_item(a:line_text) : {} + let l:alpha = empty(l:bullet) && empty(l:num) ? s:match_alphabetical_list_item(a:line_text) : v:null " Cannot be roman if numeric or a bullet - let l:roman = empty(l:bullet) && empty(l:num) ? s:match_roman_list_item(a:line_text) : {} - - let l:kinds = s:filter([l:bullet, l:check, l:num, l:alpha, l:roman], '!empty(v:val)') + let l:roman = empty(l:bullet) && empty(l:num) ? s:match_roman_list_item(a:line_text) : v:null - for l:data in l:kinds - let l:data.starting_at_line_num = a:line_num - endfor + let l:kinds = s:filter([l:bullet, l:check, l:num, l:alpha, l:roman], 'v:val isnot v:null') if s:bullet_cache isnot v:null - let l:key = a:line_text . a:line_num - let s:bullet_cache[l:key] = l:kinds + let s:bullet_cache[a:line_text] = l:kinds endif return l:kinds From 3598248ffdc98f6e2acfeecb1df14b517ad57fa9 Mon Sep 17 00:00:00 2001 From: Harshad Vedartham Date: Fri, 2 Feb 2024 17:43:02 -0800 Subject: [PATCH 3/3] Fixed bad empty test --- plugin/bullets.vim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugin/bullets.vim b/plugin/bullets.vim index 395f7c4..bfea5b5 100644 --- a/plugin/bullets.vim +++ b/plugin/bullets.vim @@ -157,7 +157,7 @@ endfun fun! s:parse_bullet_text(line_text) if s:bullet_cache isnot v:null - let l:cached = get(s:bullet_cache, l:line_text, v:null) + let l:cached = get(s:bullet_cache, a:line_text, v:null) if l:cached isnot v:null " Return a copy so as not to break the referene return copy(l:cached) @@ -166,15 +166,15 @@ fun! s:parse_bullet_text(line_text) let l:bullet = s:match_bullet_list_item(a:line_text) " Must be a bullet to be a checkbox - let l:check = !empty(l:bullet) ? s:match_checkbox_bullet_item(a:line_text) : v:null + let l:check = !empty(l:bullet) ? s:match_checkbox_bullet_item(a:line_text) : {} " Cannot be numeric if a bullet - let l:num = empty(l:bullet) ? s:match_numeric_list_item(a:line_text) : v:null + let l:num = empty(l:bullet) ? s:match_numeric_list_item(a:line_text) : {} " Cannot be alphabetic if numeric or a bullet - let l:alpha = empty(l:bullet) && empty(l:num) ? s:match_alphabetical_list_item(a:line_text) : v:null + let l:alpha = empty(l:bullet) && empty(l:num) ? s:match_alphabetical_list_item(a:line_text) : {} " Cannot be roman if numeric or a bullet - let l:roman = empty(l:bullet) && empty(l:num) ? s:match_roman_list_item(a:line_text) : v:null + let l:roman = empty(l:bullet) && empty(l:num) ? s:match_roman_list_item(a:line_text) : {} - let l:kinds = s:filter([l:bullet, l:check, l:num, l:alpha, l:roman], 'v:val isnot v:null') + let l:kinds = s:filter([l:bullet, l:check, l:num, l:alpha, l:roman], '!empty(v:val)') if s:bullet_cache isnot v:null let s:bullet_cache[a:line_text] = l:kinds