diff --git a/autoload/ale/cursor.vim b/autoload/ale/cursor.vim index 0c5844e7..dfe886fc 100644 --- a/autoload/ale/cursor.vim +++ b/autoload/ale/cursor.vim @@ -18,41 +18,6 @@ function! s:GetMessage(linter, type, text) abort return printf(l:msg, l:text) endfunction -" This function will perform a binary search to find a message from the -" loclist to echo when the cursor moves. -function! s:BinarySearch(loclist, line, column) abort - let l:min = 0 - let l:max = len(a:loclist) - 1 - let l:last_column_match = -1 - - while 1 - if l:max < l:min - return l:last_column_match - endif - - let l:mid = (l:min + l:max) / 2 - let l:obj = a:loclist[l:mid] - - " Binary search to get on the same line - if a:loclist[l:mid]['lnum'] < a:line - let l:min = l:mid + 1 - elseif a:loclist[l:mid]['lnum'] > a:line - let l:max = l:mid - 1 - else - let l:last_column_match = l:mid - - " Binary search to get the same column, or near it - if a:loclist[l:mid]['col'] < a:column - let l:min = l:mid + 1 - elseif a:loclist[l:mid]['col'] > a:column - let l:max = l:mid - 1 - else - return l:mid - endif - endif - endwhile -endfunction - function! ale#cursor#TruncatedEcho(message) abort let l:message = a:message " Change tabs to spaces. @@ -87,7 +52,7 @@ function! ale#cursor#EchoCursorWarning(...) abort let l:pos = getcurpos() let l:loclist = g:ale_buffer_loclist_map[l:buffer] - let l:index = s:BinarySearch(l:loclist, l:pos[1], l:pos[2]) + let l:index = ale#util#BinarySearch(l:loclist, l:pos[1], l:pos[2]) if l:index >= 0 let l:loc = l:loclist[l:index] diff --git a/autoload/ale/util.vim b/autoload/ale/util.vim index 17ce7c44..c218f090 100644 --- a/autoload/ale/util.vim +++ b/autoload/ale/util.vim @@ -63,3 +63,38 @@ function! ale#util#LocItemCompare(left, right) abort return 0 endfunction + +" This function will perform a binary search to find a message from the +" loclist to echo when the cursor moves. +function! ale#util#BinarySearch(loclist, line, column) abort + let l:min = 0 + let l:max = len(a:loclist) - 1 + let l:last_column_match = -1 + + while 1 + if l:max < l:min + return l:last_column_match + endif + + let l:mid = (l:min + l:max) / 2 + let l:obj = a:loclist[l:mid] + + " Binary search to get on the same line + if a:loclist[l:mid]['lnum'] < a:line + let l:min = l:mid + 1 + elseif a:loclist[l:mid]['lnum'] > a:line + let l:max = l:mid - 1 + else + let l:last_column_match = l:mid + + " Binary search to get the same column, or near it + if a:loclist[l:mid]['col'] < a:column + let l:min = l:mid + 1 + elseif a:loclist[l:mid]['col'] > a:column + let l:max = l:mid - 1 + else + return l:mid + endif + endif + endwhile +endfunction diff --git a/test/test_loclist_binary_search.vader b/test/test_loclist_binary_search.vader new file mode 100644 index 00000000..97d8a026 --- /dev/null +++ b/test/test_loclist_binary_search.vader @@ -0,0 +1,26 @@ +Before: + let g:loclist = [ + \ {'lnum': 2, 'col': 10}, + \ {'lnum': 3, 'col': 2}, + \ {'lnum': 3, 'col': 10}, + \ {'lnum': 3, 'col': 12}, + \ {'lnum': 3, 'col': 25}, + \ {'lnum': 5, 'col': 4}, + \ {'lnum': 5, 'col': 5}, + \] + +Execute (Exact column matches should be correct): + AssertEqual ale#util#BinarySearch(g:loclist, 3, 2), 1 + +Execute (Off lines, there should be no match): + AssertEqual ale#util#BinarySearch(g:loclist, 4, 2), -1 + +Execute (Near column matches should be taken): + AssertEqual ale#util#BinarySearch(g:loclist, 3, 11), 2 + AssertEqual ale#util#BinarySearch(g:loclist, 3, 13), 4 + +Execute (Columns before should be taken when the cursor is far ahead): + AssertEqual ale#util#BinarySearch(g:loclist, 3, 300), 4 + +After: + unlet g:loclist