From c59aa999854bc97cfcc39a36a4b202fe3c74f6a7 Mon Sep 17 00:00:00 2001 From: Gabriel Filion Date: Fri, 13 Sep 2024 23:11:19 -0400 Subject: [PATCH] Optimize hashrocket alignment for speed The way the function is currently written, it is processing the same lines over and over again, which can make things very slow if we're processing an entire file that is big. In order to optimize what the function is doing, I made puppet#align#AlignHashrockets report back what line indexes it has worked on and then we accumulate the line indexes already seen so that we can skip over them when we encounter those lines again in our loop. As an example of a slow-to-process file, I've found that in https://github.com/puppetlabs/puppetlabs-apache the file manifests/vhosts.pp, which is 2967 lines long was particularly slow to process with the current code. If I open that file with nvim/vim, then go to the first line and reformat the whole file (gggqG), it takes the plugin: nvim 0.9.5: elapsed time: 48.235387 vim 9.1: elapsed time: 76.116376 With the optimization in place, the plugin takes: nvim 0.9.5: elapsed time: 0.101734 vim 9.1: elapsed time: 0.12892 so about two orders of magnitude faster. The above timings were taken with a CPU 12th Gen Intel(R) Core(TM) i5-1240P and 32 Gb of RAM, so your measurements may vary a bit. --- autoload/puppet/align.vim | 6 ++++-- autoload/puppet/format.vim | 14 +++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/autoload/puppet/align.vim b/autoload/puppet/align.vim index 1275613..2e6002f 100644 --- a/autoload/puppet/align.vim +++ b/autoload/puppet/align.vim @@ -9,9 +9,9 @@ function! puppet#align#LinesInBlock(lnum) abort let marker = a:lnum - 1 while marker >= 1 let line_text = getline(marker) - let line_indent = puppet#align#IndentLevel(marker) if line_text =~? '\v\S' + let line_indent = puppet#align#IndentLevel(marker) if line_indent < indent_level break elseif line_indent == indent_level @@ -25,9 +25,9 @@ function! puppet#align#LinesInBlock(lnum) abort let marker = a:lnum while marker <= line('$') let line_text = getline(marker) - let line_indent = puppet#align#IndentLevel(marker) if line_text =~? '\v\S' + let line_indent = puppet#align#IndentLevel(marker) if line_indent < indent_level break elseif line_indent == indent_level @@ -77,4 +77,6 @@ function! puppet#align#AlignHashrockets(...) abort call setline(line_num, new_line) endif endfor + + return lines_in_block endfunction diff --git a/autoload/puppet/format.vim b/autoload/puppet/format.vim index 7eee7f8..6d01f5e 100644 --- a/autoload/puppet/format.vim +++ b/autoload/puppet/format.vim @@ -23,12 +23,20 @@ endfunction " Format hashrockets expressions in every line in range start_lnum and " end_lnum, both ends included " -" TODO way of using AlignHashrockets function is ineffective, because it -" formats same lines again and again, find better way to do it function! puppet#format#Hashrocket(start_lnum, end_lnum) abort let l:lnum = a:start_lnum + let processed_lines = [] while l:lnum <= a:end_lnum - call puppet#align#AlignHashrockets(l:lnum) + if index(processed_lines, l:lnum) ==# -1 + let line_text = getline(l:lnum) + if line_text =~? '\v\S' + let processed_lines += puppet#align#AlignHashrockets(l:lnum) + else + " empty lines make puppet#align#AlignHashrockets reprocess blocks with + " indentation that were already processed so we just skip them + call add(processed_lines, l:lnum) + endif + endif let l:lnum += 1 endwhile endfunction