diagflow.lua (4646B)
1 -- { 2 -- bufnr = 1, 3 -- code = "undefined-global", 4 -- col = 24, 5 -- end_col = 30, 6 -- end_lnum = 63, 7 -- lnum = 63, 8 -- message = "Undefined global `config`.", 9 -- namespace = 33, 10 -- severity = 2, 11 -- source = "Lua Diagnostics.", 12 -- user_data = { 13 -- lsp = { 14 -- code = "undefined-global" 15 -- } 16 -- } 17 -- } 18 local enable = true 19 local border_chars = { 20 top_left = '┌', 21 top_right = '┐', 22 bottom_left = '└', 23 bottom_right = '┘', 24 horizontal = '─', 25 vertical = '│', 26 } 27 local ns = vim.api.nvim_create_namespace 'DiagflowHighlight' 28 local severity_hl_map = { 29 [vim.diagnostic.severity.ERROR] = 'DiagnosticError', 30 [vim.diagnostic.severity.WARN] = 'DiagnosticWarn', 31 [vim.diagnostic.severity.INFO] = 'DiagnosticInfo', 32 [vim.diagnostic.severity.HINT] = 'DiagnosticHint', 33 } 34 35 local function get_padding(bufnr, winnr) 36 if not pcall(require, 'treesitter-context.context') then 37 return 0 38 end 39 40 local context_lines = #(require('treesitter-context.context').get(bufnr, winnr) or {}) 41 if context_lines == 0 then 42 return 0 43 end 44 45 return context_lines + 1 -- +1 for the underline 46 end 47 48 local function create_boxed_text(text_lines) 49 if #text_lines == 0 then 50 return text_lines 51 end 52 53 local max_length = 0 54 for _, line in ipairs(text_lines) do 55 max_length = math.max(max_length, #line) 56 end 57 58 local top_border = border_chars.top_left .. string.rep(border_chars.horizontal, max_length) .. border_chars 59 .top_right 60 local bottom_border = border_chars.bottom_left .. string.rep(border_chars.horizontal, max_length) .. 61 border_chars.bottom_right 62 local boxed_lines = { top_border } 63 64 for _, line in ipairs(text_lines) do 65 local padded_line = line .. string.rep(' ', max_length - #line) 66 table.insert(boxed_lines, border_chars.vertical .. padded_line .. border_chars.vertical) 67 end 68 69 table.insert(boxed_lines, bottom_border) 70 return boxed_lines 71 end 72 73 local function clear(bufnr) 74 bufnr = bufnr or vim.api.nvim_get_current_buf() 75 vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1) 76 end 77 78 local function render(diagnostics, bufnr) 79 clear(bufnr) 80 81 if not enable then 82 return 83 end 84 85 bufnr = bufnr or vim.api.nvim_get_current_buf() 86 87 if not vim.diagnostic.is_enabled(bufnr) then 88 return 89 end 90 91 local winnr 92 for _, win in ipairs(vim.api.nvim_list_wins()) do 93 if vim.api.nvim_win_get_buf(win) == bufnr then 94 winnr = win 95 break 96 end 97 end 98 99 if not winnr then 100 return 101 end 102 103 local cursor_lnum = vim.fn.getcurpos(winnr)[2] 104 local padding = get_padding(bufnr, winnr) 105 local line_offset = vim.fn.getwininfo(winnr)[1].topline - 1 + padding 106 local skipped_some = false 107 for _, diagnostic in ipairs(diagnostics) do 108 local message_lines = vim.split(diagnostic.message, '\n') 109 110 -- Enable/Disable boxed text 111 -- message_lines = create_boxed_text(message_lines) 112 113 if ((line_offset + #message_lines) >= cursor_lnum) then 114 skipped_some = true 115 break 116 end 117 118 for _, message in ipairs(message_lines) do 119 local hl_group = severity_hl_map[diagnostic.severity] 120 vim.api.nvim_buf_set_extmark(bufnr, ns, line_offset, 0, { 121 virt_text = { { message, hl_group } }, 122 virt_text_pos = 'right_align', 123 virt_text_hide = true, 124 strict = false, 125 priority = vim.hl.priorities.user, 126 }) 127 line_offset = line_offset + 1 128 end 129 end 130 131 if skipped_some then 132 vim.api.nvim_buf_set_extmark(bufnr, ns, line_offset, 0, { 133 virt_text = { { '...', 'DiagnosticWarn' } }, 134 virt_text_pos = 'right_align', 135 virt_text_hide = true, 136 strict = false, 137 priority = vim.hl.priorities.user, 138 }) 139 end 140 end 141 142 local function reload() 143 if not enable then 144 clear() 145 return 146 end 147 148 local cursor_lnum = vim.api.nvim_win_get_cursor(0)[1] - 1 149 local diagnostics = vim.diagnostic.get(0, { 150 lnum = cursor_lnum }) 151 render(diagnostics) 152 end 153 154 local function toggle(force) 155 enable = force or not enable 156 157 if enable then 158 reload() 159 else 160 clear() 161 end 162 end 163 164 -- vim.api.nvim_create_autocmd('InsertEnter', { 165 -- callback = function() 166 -- toggle(false) 167 -- end, 168 -- }) 169 -- vim.api.nvim_create_autocmd('InsertLeave', { 170 -- callback = function() 171 -- toggle(true) 172 -- end, 173 -- }) 174 -- vim.api.nvim_create_autocmd({ 'DiagnosticChanged', 'CursorMoved', 'CursorMovedI', 'WinScrolled' }, { 175 -- callback = function() 176 -- reload() 177 -- end, 178 -- }) 179 -- vim.api.nvim_create_autocmd({ 'BufLeave' }, { 180 -- callback = function() 181 -- clear() 182 -- end, 183 -- }) 184 185 vim.api.nvim_create_user_command('Diagflow', function() 186 toggle() 187 end, { desc = 'Diagflow Toggle' })