summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorw0rp <devw0rp@gmail.com>2016-10-24 22:09:41 +0100
committerw0rp <devw0rp@gmail.com>2016-10-26 10:36:53 +0100
commitc8821fc0495d1d75cb3d716d73c4c28877e3513a (patch)
tree911963ee3e9954b12396bced5e834a6b922c4c50
parent1bcee7ef33ffd2da752e85177bfa215c60f98e71 (diff)
downloadale-c8821fc0495d1d75cb3d716d73c4c28877e3513a.zip
#144 - Implement commands for moving through warnings/errors
-rw-r--r--README.md17
-rw-r--r--autoload/ale/loclist_jumping.vim88
-rw-r--r--doc/ale.txt45
-rw-r--r--plugin/ale.vim12
4 files changed, 156 insertions, 6 deletions
diff --git a/README.md b/README.md
index b54cce19..c297ebcf 100644
--- a/README.md
+++ b/README.md
@@ -30,6 +30,7 @@ In other words, this plugin allows you to lint while you type.
4. [How can I show errors or warnings in my statusline?](#faq-statusline)
5. [How can I change the format for echo messages?](#faq-echo-format)
6. [How can I execute some code when ALE stops linting?](#faq-autocmd)
+ 7. [How can I navigate between errors quickly?](#faq-navigation)
<a name="supported-languages"></a>
@@ -290,3 +291,19 @@ augroup YourGroup
autocmd User ALELint call YourFunction()
augroup END
```
+
+<a name="faq-navigation"></a>
+
+### 4.vii. How can I navigate between errors quickly?
+
+ALE offers some commands with `<Plug>` keybinds for moving between warnings and
+errors quickly. You can map the keys Ctrl+j and Ctrl+k to moving between errors
+for example:
+
+```vim
+nmap <silent> <C-k> <Plug>(ale_previous_wrap)
+nmap <silent> <C-j> <Plug>(ale_next_wrap)
+```
+
+For more information, consult the online documentation with
+`:help ale-navigation-commands`.
diff --git a/autoload/ale/loclist_jumping.vim b/autoload/ale/loclist_jumping.vim
new file mode 100644
index 00000000..b9ea9d13
--- /dev/null
+++ b/autoload/ale/loclist_jumping.vim
@@ -0,0 +1,88 @@
+" Author: w0rp <devw0rp@gmail.com>
+" Description: This file implements functions for jumping around in a file
+" based on errors and warnings in the loclist.
+
+function! s:GetSortedLoclist() abort
+ let l:loclist = []
+
+ for l:item in getloclist(winnr())
+ if l:item.lnum < 1
+ " Remove items we can't even jump to.
+ continue
+ endif
+
+ call add(l:loclist, l:item)
+ endfor
+
+ " We must sort the list again, as the loclist could contain items set
+ " by other plugins.
+ call sort(l:loclist, 'ale#util#LocItemCompare')
+
+ return l:loclist
+endfunction
+
+" Search for the nearest line either before or after the current position
+" in the loclist. The argument 'wrap' can be passed to enable wrapping
+" around the end of the list.
+"
+" If there are no items or we have hit the end with wrapping off, an empty
+" List will be returned, otherwise a pair of [line_number, column_number] will
+" be returned.
+function! ale#loclist_jumping#FindNearest(direction, wrap) abort
+ let l:loclist = s:GetSortedLoclist()
+
+ if empty(l:loclist)
+ " We couldn't find anything, so stop here.
+ return []
+ endif
+
+ let l:search_item = {'lnum': getcurpos()[1], 'col': getcurpos()[2]}
+
+ " When searching backwards, so we can find the next smallest match.
+ if a:direction ==# 'before'
+ call reverse(l:loclist)
+ endif
+
+ " Look for items before or after the current position.
+ for l:item in l:loclist
+ " Compare the cursor with a item where the column number is bounded,
+ " such that it's possible for the cursor to actually be on the given
+ " column number, without modifying the cursor number we return. This
+ " will allow us to move through matches, but still let us move the
+ " cursor to a line without changing the column, in some cases.
+ let l:cmp_value = ale#util#LocItemCompare(
+ \ {
+ \ 'lnum': l:item.lnum,
+ \ 'col': min([max([l:item.col, 1]), len(getline(l:item.lnum))]),
+ \ },
+ \ l:search_item
+ \)
+
+ if a:direction ==# 'before' && l:cmp_value < 0
+ return [l:item.lnum, l:item.col]
+ endif
+
+ if a:direction ==# 'after' && l:cmp_value > 0
+ return [l:item.lnum, l:item.col]
+ endif
+ endfor
+
+ " If we found nothing, and the wrap option is set to 1, then we should
+ " wrap around the list of warnings/errors
+ if a:wrap
+ let l:item = get(l:loclist, 0)
+
+ return [l:item.lnum, l:item.col]
+ endif
+
+ return []
+endfunction
+
+" As before, find the nearest match, but position the cursor at it.
+function! ale#loclist_jumping#Jump(direction, wrap) abort
+ let l:nearest = ale#loclist_jumping#FindNearest(a:direction, a:wrap)
+
+ if !empty(l:nearest)
+ call cursor(l:nearest)
+ endif
+endfunction
diff --git a/doc/ale.txt b/doc/ale.txt
index 16d55f6b..d05b570a 100644
--- a/doc/ale.txt
+++ b/doc/ale.txt
@@ -23,9 +23,10 @@ CONTENTS *ale-contents*
4.11. luacheck..............................|ale-linter-options-luacheck|
4.12. c-cppcheck............................|ale-linter-options-c-cppcheck|
4.13. cpp-cppcheck..........................|ale-linter-options-cpp-cppcheck|
- 5. API........................................|ale-api|
- 6. Special Thanks.............................|ale-special-thanks|
- 7. Contact....................................|ale-contact|
+ 5. Commands/Keybinds..........................|ale-commands|
+ 6. API........................................|ale-api|
+ 7. Special Thanks.............................|ale-special-thanks|
+ 8. Contact....................................|ale-contact|
===============================================================================
1. Introduction *ale-introduction*
@@ -549,7 +550,39 @@ g:ale_cpp_cppcheck_options *g:ale_cpp_cppcheck_options
===============================================================================
-5. API *ale-api*
+5. Commands/Keybinds *ale-commands*
+
+ALEPrevious *ALEPrevious*
+ALEPreviousWrap *ALEPreviousWrap*
+ALENext *ALENext*
+ALENextWrap *ALENextWrap*
+ *ale-navigation-commands*
+
+ Move between warnings or errors in a buffer.
+
+ `ALEPrevious` and `ALENext` will stop at the top and bottom of a file, while
+ `ALEPreviousWrap` and `ALENextWrap` will wrap around the file to find
+ the last or first warning or error in the file, respectively.
+
+ The following |<Plug>| mappings are defined for the commands: >
+ <Plug>(ale_previous) - ALEPrevious
+ <Plug>(ale_previous_wrap) - ALEPreviousWrap
+ <Plug>(ale_next) - ALENext
+ <Plug>(ale_next_wrap) - ALENextWrap
+<
+ For example, these commands could be bound to the keys Ctrl + j
+ and Ctrl + k: >
+
+ " Map movement through errors without wrapping.
+ nmap <silent> <C-k> <Plug>(ale_previous)
+ nmap <silent> <C-j> <Plug>(ale_next)
+ " OR map keys to use wrapping.
+ nmap <silent> <C-k> <Plug>(ale_previous_wrap)
+ nmap <silent> <C-j> <Plug>(ale_next_wrap)
+<
+
+===============================================================================
+6. API *ale-api*
ale#Queue(delay) *ale#Queue()*
Run linters for the current buffer, based on the filetype of the buffer,
@@ -671,13 +704,13 @@ ALELint *ALELint*
===============================================================================
-6. Special Thanks *ale-special-thanks*
+7. Special Thanks *ale-special-thanks*
Special thanks to Mark Grealish (https://www.bhalash.com/) for providing ALE's
snazzy looking ale glass logo. Cheers, Mark!
===============================================================================
-7. Contact *ale-contact*
+8. Contact *ale-contact*
If you like this plugin, and wish to get in touch, check out the GitHub
page for issues and more at https://github.com/w0rp/ale
diff --git a/plugin/ale.vim b/plugin/ale.vim
index 64c20c66..43f38927 100644
--- a/plugin/ale.vim
+++ b/plugin/ale.vim
@@ -131,6 +131,18 @@ let g:ale_statusline_format = get(g:, 'ale_statusline_format',
let g:ale_warn_about_trailing_whitespace =
\ get(g:, 'ale_warn_about_trailing_whitespace', 1)
+" Define commands for moving through warnings and errors.
+command! ALEPrevious :call ale#loclist_jumping#Jump('before', 0)
+command! ALEPreviousWrap :call ale#loclist_jumping#Jump('before', 1)
+command! ALENext :call ale#loclist_jumping#Jump('after', 0)
+command! ALENextWrap :call ale#loclist_jumping#Jump('after', 1)
+
+" <Plug> mappings for commands
+nnoremap <silent> <Plug>(ale_previous) :ALEPrevious<Return>
+nnoremap <silent> <Plug>(ale_previous_wrap) :ALEPreviousWrap<Return>
+nnoremap <silent> <Plug>(ale_next) :ALENext<Return>
+nnoremap <silent> <Plug>(ale_next_wrap) :ALENextWrap<Return>
+
" Housekeeping
augroup ALECleanupGroup