neovim

Personal neovim configuration files
git clone git://gtms.dev/neovim
Log | Files | Refs

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' })