├── .luacheckrc ├── LICENSE ├── README.md ├── doc └── lsp_diamove.txt ├── lua └── lsp_diamove.lua └── plugin └── lsp_diamove.vim /.luacheckrc: -------------------------------------------------------------------------------- 1 | read_globals = { 2 | "vim" 3 | } 4 | 5 | -- vim: filetype=lua 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Thore Weilbier 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # !!!DEPRACTED!!! 2 | 3 | **With the development of NeoVim all features of this plugin have become part of the core. Please read the commit message for version [f75be5e](https://github.com/neovim/neovim/commit/f75be5e9d510d5369c572cf98e78d9480df3b0bb) to get further details.** 4 | 5 | --- 6 | 7 | # NeoVim Language Server Diagnostic Movements 8 | 9 | Add the missing navigation commands for the LSP diagnostics in a buffer. 10 | This is an addition to the already existing `:cabove`, `:cbelow`, `:labove` and 11 | `:lbelow` commands (which act on the quickfix and location list). In addition the 12 | diagnostic movements are more secure and precise. 13 | 14 | ## Installation 15 | 16 | Install the plugin with your favorite manager tool. Here is an example using 17 | [dein.vim](https://github.com/Shougo/dein.vim): 18 | 19 | ```vim 20 | call dein#add('weilbith/nvim-lsp-diamove', { 21 | \ 'on_cmd': ['Dabove', 'Dbelow'], 22 | \ }) 23 | ``` 24 | 25 | It is recommended to use the [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig) 26 | plugin to attach the language clients to your buffers. 27 | 28 | ## Usage 29 | 30 | This plugin provides two the commands `:Dabove` and `:Dbelow`. They are 31 | mapped to the convenient keys combos `[d` and `]d` (note that this can be 32 | disabled). All commands and mappings can be prefixed with a count (e.g. `3[d`). 33 | 34 | Please make sure that your buffer has an LSP client attached and the server is 35 | supporting diagnostics. _NeoVim_ enables the pushing of diagnostics per default. 36 | 37 | ## Comparison & Design Decisions 38 | 39 | This plugin attempts to be minimalistic. Therefore it does **not** customize the 40 | callback function for the diagnostics. Rather it reuses the published 41 | [`vim.lsp.util.diagnostics_by_buf`](https://neovim.io/doc/user/lsp.html) table. 42 | The only advanced logic is the correct sort order of the diagnostic 43 | list to guarantee precise jumps. This is for example not the case for `:cabove` 44 | etc. 45 | If you search for a plugin with more features to customize the diagnostic 46 | behavior, checkout the 47 | [diagnostic-nvim](https://github.com/haorenW1025/diagnostic-nvim) plugin. But be 48 | aware that such plugin re-rewrites/overwrites the LSP callback completely (not extending it, at 49 | the [current 50 | state](https://github.com/haorenW1025/diagnostic-nvim/commit/4255eb7697e45550292076c4957028ee4d7232e1)) 51 | and thereby may not profit by future updates of _NeoVim_. 52 | -------------------------------------------------------------------------------- /doc/lsp_diamove.txt: -------------------------------------------------------------------------------- 1 | *lsp_diamove.txt* Move trough the LSP diagnostics 2 | 3 | Version: 0.2 4 | Author: Thore Weilbier 5 | License: MIT 6 | 7 | ============================================================================== 8 | *lsp_diamove_table_of_contents* 9 | TABLE OF CONTENTS~ 10 | 11 | Introduction ...................................... |lsp_diamove_introduction| 12 | Usage .................................................... |lsp_diamove_usage| 13 | Commands .............................................. |lsp_diamove_commands| 14 | Mappings .............................................. |lsp_diamove_mappings| 15 | Variables ............................................ |lsp_diamove_variables| 16 | TODO-List ............................................ |lsp_diamove_todo_list| 17 | 18 | 19 | ============================================================================== 20 | *lsp_diamove_introduction* 21 | INTRODUCTION~ 22 | 23 | This plugin simple adds the missing command to navigate through the 24 | diagnostics by the |lsp| client. To avoid the need of pushing the diagnostics 25 | to the location list to get access to movement commands, this plugin adds them 26 | directly. In addition to |:cabove|, |:cbelow|, |:labove| and |:lbelow| (for 27 | the quickfix and location list respectively), the new commands |:Dabove| and 28 | |:Dbelow| jump in the diagnostics list of the current buffer. There is no need 29 | to save the buffer in-between. These commands always act on the current state 30 | of the last pushed diagnostics. In advantage to the native commands, the ones 31 | for the diagnostics secure the sort order (while the native only assume 32 | a given order). Also are they able to jump between entries within the same 33 | line. 34 | 35 | 36 | ============================================================================== 37 | *lsp_diamove_usage* 38 | USAGE~ 39 | 40 | Simply call the |lsp_diamove_commands| or use the |lsp_diamove_mappings| 41 | directly to jump the next error, hint or any other diagnostic by the language 42 | server. Always relative to the current cursors position. 43 | 44 | 45 | ============================================================================== 46 | *lsp_diamove_commands* 47 | COMMANDS~ 48 | 49 | *:Dabove* 50 | |:[count]Dabove| 51 | 52 | Go to the [count] diagnostic entry above the current cursor position in the 53 | current buffer. If [count] is omitted, then 1 is used. If there are no 54 | diagnostic published, then an error message is displayed. If [count] exceeds 55 | the number of entries above the current position, then it jumps to the first 56 | entry in the file and reports a message. 57 | 58 | 59 | *:Dbelow* 60 | |:[count]Dbelow| 61 | 62 | Go to the [count] diagnostic entry below the current cursor position in the 63 | current buffer. If [count] is omitted, then 1 is used. If there are no 64 | diagnostic published, then an error message is displayed. If [count] exceeds 65 | the number of entries below the current position, then it jumps to the last 66 | entry in the file and reports a message. 67 | 68 | 69 | ============================================================================== 70 | *lsp_diamove_mappings* 71 | 72 | MAPPINGS~ 73 | 74 | |[count][d| 75 | 76 | Mapping for |:Dabove| command, fully capable of getting prefixed with 77 | a count of how many jumps to execute. 78 | 79 | 80 | |[count]]d| 81 | 82 | Mapping for |:Dbelow| command, fully capable of getting prefixed with 83 | a count of how many jumps to execute. 84 | 85 | 86 | ============================================================================== 87 | *lsp_diamove_variables* 88 | VARIABLES~ 89 | 90 | |g:lsp_diamove_disable_default_mapping| boolean (default `v:false`) 91 | 92 | Disables the automatic establishment of the |lsp_diamove_mappings|. 93 | 94 | 95 | ============================================================================== 96 | *lsp_diamove_todo_list* 97 | TODO-List~ 98 | 99 | - allow to merge diagnostics with location list to integrate external 100 | linter as well if available (can be tricky to be clean) 101 | 102 | 103 | ============================================================================== 104 | 105 | vim:tw=78:ts=8:noet:ft=help:norl: 106 | -------------------------------------------------------------------------------- /lua/lsp_diamove.lua: -------------------------------------------------------------------------------- 1 | local vim = vim 2 | local api = vim.api 3 | local lsp = vim.lsp 4 | 5 | local function get_line(diagnostic_entry) 6 | return diagnostic_entry["range"]["start"]["line"] 7 | end 8 | 9 | local function get_character(diagnostic_entry) 10 | return diagnostic_entry["range"]["start"]["character"] 11 | end 12 | 13 | local function compare_positions(line_a, line_b, character_a, character_b) 14 | if line_a < line_b then 15 | return true 16 | elseif line_b < line_a then 17 | return false 18 | elseif character_a < character_b then 19 | return true 20 | else 21 | return false 22 | end 23 | end 24 | 25 | local function compare_diagnostics_entries(entry_a, entry_b) 26 | local line_a = get_line(entry_a) 27 | local line_b = get_line(entry_b) 28 | local character_a = get_character(entry_a) 29 | local character_b = get_character(entry_b) 30 | return compare_positions(line_a, line_b, character_a, character_b) 31 | end 32 | 33 | local function get_sorted_diagnostics() 34 | local buffer_number = api.nvim_get_current_buf() 35 | local diagnostics = lsp.util.diagnostics_by_buf[buffer_number] 36 | 37 | if diagnostics ~= nil then 38 | table.sort(diagnostics, compare_diagnostics_entries) 39 | return diagnostics 40 | else 41 | return {} 42 | end 43 | end 44 | 45 | local function get_above_entry() 46 | local diagnostics = get_sorted_diagnostics() 47 | local cursor = api.nvim_win_get_cursor(0) 48 | local cursor_line = cursor[1] 49 | local cursor_character = cursor[2] - 1 50 | 51 | for i = #diagnostics, 1, -1 do 52 | local entry = diagnostics[i] 53 | local entry_line = get_line(entry) 54 | local entry_character = get_character(entry) 55 | 56 | if not compare_positions(cursor_line - 1, entry_line, cursor_character - 1, entry_character) then 57 | return entry 58 | end 59 | end 60 | 61 | return nil 62 | end 63 | 64 | local function get_below_entry() 65 | local diagnostics = get_sorted_diagnostics() 66 | local cursor = api.nvim_win_get_cursor(0) 67 | local cursor_line = cursor[1] - 1 68 | local cursor_character = cursor[2] 69 | 70 | for _, entry in ipairs(diagnostics) do 71 | local entry_line = get_line(entry) 72 | local entry_character = get_character(entry) 73 | 74 | if compare_positions(cursor_line, entry_line, cursor_character, entry_character) then 75 | return entry 76 | end 77 | end 78 | 79 | return nil 80 | end 81 | 82 | local function jump_to_entry(entry) 83 | local entry_line = get_line(entry) + 1 84 | local entry_character = get_character(entry) 85 | api.nvim_win_set_cursor(0, {entry_line, entry_character}) 86 | end 87 | 88 | local function jump_n_times(count, get_entry_function) 89 | for _ = count, 1, -1 do 90 | local entry = get_entry_function() 91 | 92 | if entry == nil then 93 | print("No diagnostic entry to jump further!") 94 | break 95 | else 96 | jump_to_entry(entry) 97 | end 98 | end 99 | end 100 | 101 | local function jump_above(count) 102 | jump_n_times(count, get_above_entry) 103 | end 104 | 105 | local function jump_below(count) 106 | jump_n_times(count, get_below_entry) 107 | end 108 | 109 | return { 110 | jump_above = jump_above, 111 | jump_below = jump_below 112 | } 113 | -------------------------------------------------------------------------------- /plugin/lsp_diamove.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_lsp_diamove') 2 | finish 3 | endif 4 | 5 | let g:loaded_lsp_diamove = 1 6 | 7 | command! -count=1 Dabove lua require'lsp_diamove'.jump_above() 8 | command! -count=1 Dbelow lua require'lsp_diamove'.jump_below() 9 | 10 | if !get(g:, 'lsp_diamove_disable_default_mapping', v:false) 11 | noremap [d '' . v:count1 . 'Dabove' 12 | noremap ]d '' . v:count1 . 'Dbelow' 13 | endif 14 | --------------------------------------------------------------------------------