From a568a964fd6a9efba388b2b4919339c0b7dfe51d Mon Sep 17 00:00:00 2001 From: venomade Date: Mon, 16 Feb 2026 17:31:16 +0000 Subject: MacOS Nix Asahi is just not perfectly usable yet. Moved stuff, went nix. --- .config/nvim/lua/scripts/diagnostics.lua | 760 ------------------------------- 1 file changed, 760 deletions(-) delete mode 100644 .config/nvim/lua/scripts/diagnostics.lua (limited to '.config/nvim/lua/scripts/diagnostics.lua') diff --git a/.config/nvim/lua/scripts/diagnostics.lua b/.config/nvim/lua/scripts/diagnostics.lua deleted file mode 100644 index 0855af1..0000000 --- a/.config/nvim/lua/scripts/diagnostics.lua +++ /dev/null @@ -1,760 +0,0 @@ ---[[ -*Fancy* diagnostics for `Neovim`. - -## Usage - -```lua -require("diagnostics").setup(); -``` - -You can then hit `D` to show diagnostics for the current line. - -## Highlight groups - -This script uses highlight groups provided by [highlights.lua](https://github.com/OXY2DEV/nvim/blob/main/lua/scripts/highlights.lua). - -The used groups are, -- `FancyDiagnostic`, Default group for diagnostics. -- `FancyDiagnosticIcon`, Default group for the icons of diagnostics. -- `FancyDiagnosticInfo`, Group for `information` diagnostics. -- `FancyDiagnosticInfoIcon`, Group for the icons of `information` diagnostics. -- `FancyDiagnosticHint`, Group for `hint` diagnostics. -- `FancyDiagnosticHintIcon`, Group for the icons of `hint` diagnostics. -- `FancyDiagnosticWarn`, Group for `warning` diagnostics. -- `FancyDiagnosticWarnIcon`, Group for the icons of `warning` diagnostics. -- `FancyDiagnosticError`, Group for `error` diagnostics. -- `FancyDiagnosticErrorIcon`, Group for the icons of `error` diagnostics. - -## Dependencies - -- [beacon.lua](https://github.com/OXY2DEV/nvim/blob/main/lua/scripts/beacon.lua), For highlighting cursor. -- [highlights.lua](https://github.com/OXY2DEV/nvim/blob/main/lua/scripts/highlights.lua), For highlight groups. -- [types/diagnostics.lua](https://github.com/OXY2DEV/nvim/blob/main/lua/scripts/types/diagnostics.lua), For type definition. - -## Configuration - -Use `setup()` for setting configuration. See [types/diagnostics.lua#diagnostics.config](https://github.com/OXY2DEV/nvim/blob/main/lua/scripts/types/diagnostics.lua#L3-L19) for the type definition. -]] -local diagnostics = {}; - ----@param level string ----@param icon string ----@return table -local function handle_diagnostic_level (level, icon) - ---|fS - - local default = string.format("FancyDiagnostic%s", "Default"); - local default_icon_hl = string.format("FancyDiagnostic%sIcon", "Default"); - - local bg = string.format("FancyDiagnostic%s", level); - local icon_hl = string.format("FancyDiagnostic%sIcon", level); - - return { - width = 3, - - line_hl_group = function (_, current) - return current and bg or default; - end, - icon = function (_, current) - return { - { "▌", current and icon_hl or default_icon_hl }, - { icon, current and icon_hl or default_icon_hl }, - { " ", current and bg or default }, - } - end, - padding = function (_, current) - return { - { "▌", current and icon_hl or default_icon_hl }, - { " ", current and icon_hl or default_icon_hl }, - { " ", current and bg or default }, - } - end - }; - - ---|fE -end - ----@class diagnostics.config -diagnostics.config = { - ---|fS - - keymap = "D", - - decoration_width = 4, - width = function (items) - local max = math.floor(vim.o.columns * 0.4); - local use = 1 - - for _, item in ipairs(items) do - local width = vim.fn.strdisplaywidth(item.message or ""); - - use = math.min( - math.max(width, 0), - max - ); - end - - return use; - end, - - max_height = function () - return math.floor(vim.o.lines * 0.4); - end, - - beacon = { - ---|fS - - default = { - from = function () - local fg = vim.api.nvim_get_hl(0, { name = "@comment", link = false }).fg; - return fg and string.format("#%06x", fg) or "#9399b2"; - end, - to = function () - local bg = vim.api.nvim_get_hl(0, { name = vim.o.statusline and "Cursorline" or "Normal", link = false }).bg; - return bg and string.format("#%06x", bg) or "#1e1e2e"; - end, - - steps = 10, - interval = 100, - }, - - [vim.diagnostic.severity.INFO] = { - from = function () - local fg = vim.api.nvim_get_hl(0, { name = "FancyDiagnosticInfoIcon", link = false }).fg; - return fg and string.format("#%06x", fg) or "#94e2d5"; - end - }, - [vim.diagnostic.severity.HINT] = { - from = function () - local fg = vim.api.nvim_get_hl(0, { name = "FancyDiagnosticHintIcon", link = false }).fg; - return fg and string.format("#%06x", fg) or "#94e2d5"; - end - }, - [vim.diagnostic.severity.WARN] = { - from = function () - local fg = vim.api.nvim_get_hl(0, { name = "FancyDiagnosticWarnIcon", link = false }).fg; - return fg and string.format("#%06x", fg) or "#f9e2af"; - end - }, - [vim.diagnostic.severity.ERROR] = { - from = function () - local fg = vim.api.nvim_get_hl(0, { name = "FancyDiagnosticErrorIcon", link = false }).fg; - return fg and string.format("#%06x", fg) or "#f38ba8"; - end - }, - - ---|fE - }, - - decorations = { - ---|fS - - [vim.diagnostic.severity.INFO] = handle_diagnostic_level("Info", "󰀨 "), - [vim.diagnostic.severity.HINT] = handle_diagnostic_level("Hint", "󰁨 "), - [vim.diagnostic.severity.WARN] = handle_diagnostic_level("Warn", " "), - [vim.diagnostic.severity.ERROR] = handle_diagnostic_level("Error", "󰅙 "), - - ---|fE - }, - - ---|fE -}; - ---[[ Evaluates `val`. ]] ----@param val any ----@param ... any ----@return any -local function eval(val, ...) - ---|fS - - if type(val) ~= "function" then - return val; - else - local can_call, new_val = pcall(val, ...); - - if can_call and new_val ~= nil then - return new_val; - end - end - - ---|fE -end - ---[[ Gets diagnostic item `decoration`. ]] ----@param level vim.diagnostic.Severity | "default" Diagnostic severity. ----@param ... any Extra arguments to be used for value evaluation. ----@return diagnostics.decorations__static decoration Static version of the diagnostic item's decoration. -local function get_decorations (level, ...) - ---|fS - - local output = {}; - - for k, v in pairs(diagnostics.config.decorations[level]) do - output[k] = eval(v, ...); - end - - return output; - - ---|fE -end - ---[[ Gets `beacon` configuration. ]] ----@param level? vim.diagnostic.Severity | "default" Diagnostic level. ----@param ... any Extra arguments to be used for value evaluation. ----@return table? -local function get_beacon_config (level, ...) - ---|fS - - if not level or not diagnostics.config.beacon then - return; - end - - local output = {}; - - for k, v in pairs(diagnostics.config.beacon[level]) do - output[k] = eval(v, ...); - end - - return output; - - ---|fE -end - ---[[ Turns given **virtual text** into **format string** for the statusline. ]] ----@param virt_text diagnostics.decoration_fragment[] Virtual text. ----@return string sign Virtual text as a sign(use in `statuscolumn`, `statusline`, `tabline` or `winbar`) -local function virt_text_to_sign (virt_text) - ---|fS - - local output = ""; - - for _, item in ipairs(virt_text) do - if type(item[2]) == "string" then - output = output .. string.format("%%#%s#%s", item[2], item[1]) .. "%#Normal#"; - else - output = output .. item[1]; - end - end - - return output; - - ---|fE -end - ------------------------------------------------------------------------------- - ----@type integer Decoration namespace. -diagnostics.ns = vim.api.nvim_create_namespace("fancy_diagnostics"); - ----@type integer, integer Diagnostics buffer & window. -diagnostics.buffer, diagnostics.window = nil, nil; - ---[[ Which *quadrant* the diagnostics window is currently using? ]] ----@type ----| "top_left" ----| "top_right" ----| "bottom_left" ----| "bottom_right" ----| "center" -diagnostics.quad = nil; - ----@type diagnostics.signs.entry[] -diagnostics.sign_data = {}; - ---[[ Prepares the buffer for the diagnostics window. ]] -diagnostics.__prepare = function () - ---|fS - - if not diagnostics.buffer or not vim.api.nvim_buf_is_valid(diagnostics.buffer) then - diagnostics.buffer = vim.api.nvim_create_buf(false, true); - end - - ---|fE -end - ---[[ Updates the *quadrant* which is being used by the diagnostics window. ]] ----@param quad ----| "top_left" ----| "top_right" ----| "bottom_left" ----| "bottom_right" ----| "center" ----@param state boolean -diagnostics.update_quad = function (quad, state) - ---|fS - - if not _G.__used_quads then - -- NIT: Should this set a default state value? - return; - end - - _G.__used_quads[quad] = state; - - ---|fE -end - ---[[ Returns `{opts}` for `nvim_open_win()` based on the parameters. ]] ----@param window integer Window ID. ----@param w integer Window width. ----@param h integer Window height. ----@return string | string[] border Window border. ----@return "editor" | "cursor" relative Relative position for floating window. ----@return "NE" | "NW" | "SE" | "SW" anchor Anchor position. ----@return integer row Window position in Y-axis. ----@return integer col Window position in X-axis. -diagnostics.__win_args = function (window, w, h) - ---|fS - - ---@type [ integer, integer ] - local cursor = vim.api.nvim_win_get_cursor(window); - ---@type table - local screenpos = vim.fn.screenpos(window, cursor[1], cursor[2]); - - local screen_width = vim.o.columns - 2; - local screen_height = vim.o.lines - vim.o.cmdheight - 2; - - local quad_pref = { "bottom_right", "top_right", "bottom_left", "top_left" }; - local quads = { - ---|fS - - center = { - relative = "editor", - anchor = "NW", - - row = math.ceil((vim.o.lines - h) / 2), - col = math.ceil((vim.o.columns - w) / 2), - border = "rounded" - }, - - top_left = { - condition = function () - if h >= screenpos.row then - -- Not enough space above. - return false; - elseif screenpos.curscol <= w then - -- Not enough space before. - return false; - end - - return true; - end, - - relative = "cursor", - border = { "╭", "─", "╮", "│", "┤", "─", "╰", "│" }, - anchor = "SE", - row = 0, - col = 1 - }, - top_right = { - condition = function () - if h >= screenpos.row then - -- Not enough space above. - return false; - elseif screenpos.curscol + w > screen_width then - -- Not enough space after. - return false; - end - - return true; - end, - - relative = "cursor", - border = { "╭", "─", "╮", "│", "╯", "─", "├", "│" }, - anchor = "SW", - row = 0, - col = 0 - }, - - bottom_left = { - condition = function () - if screenpos.row + h > screen_height then - -- Not enough space below. - return false; - elseif screenpos.curscol <= w then - -- Not enough space before. - return false; - end - - return true; - end, - - relative = "cursor", - border = { "╭", "─", "┤", "│", "╯", "─", "╰", "│" }, - anchor = "NE", - row = 1, - col = 1 - }, - bottom_right = { - condition = function () - if screenpos.row + h > screen_height then - -- Not enough space below. - return false; - elseif screenpos.curscol + w > screen_width then - -- Nor enough space after. - return false; - end - - return true; - end, - - relative = "cursor", - border = { "├", "─", "╮", "│", "╯", "─", "╰", "│" }, - anchor = "NW", - row = 1, - col = 0 - } - - ---|fE - }; - - for _, pref in ipairs(quad_pref) do - if _G.__used_quads and _G.__used_quads[pref] == true then - goto continue; - elseif not quads[pref] then - goto continue; - end - - local quad = quads[pref]; - local ran_cond, cond = pcall(quad.condition); - - if ran_cond and cond then - diagnostics.quad = pref; - return quad.border, quad.cursor, quad.anchor, quad.row, quad.col; - end - - ::continue:: - end - - diagnostics.quad = "center"; - - local fallback = quads.center; - return fallback.border, fallback.cursor, fallback.anchor, fallback.row, fallback.col; - - ---|fE -end - ------------------------------------------------------------------------------- - ---[[ Closes diagnostics window. ]] -diagnostics.close = function () - ---|fS - - if diagnostics.window and vim.api.nvim_win_is_valid(diagnostics.window) then - pcall(vim.api.nvim_win_close, diagnostics.window, true); - diagnostics.window = nil; - - if diagnostics.quad then - diagnostics.update_quad(diagnostics.quad, false); - diagnostics.quad = nil; - end - end - - ---|fE -end - ----@type beacon.instance Beacon instance to use for the Cursor. -diagnostics.__beacon = nil; - ---[[ External integrations. ]] ----@param window integer Window Id. ----@param beacon_config beacon.instance.config Configuration for `beacon`. -diagnostics.__integration = function (window, beacon_config) - ---|fS - - -- Markdown rendering. - if package.loaded["markview"] then - package.loaded["markview"].render(diagnostics.buffer, { - enable = true, - hybrid_mode = false - }, { - markdown_inline = { - inline_codes = { - virtual = true - } - } - }); - end - - -- Beacon. - if package.loaded["scripts.beacon"] then - if not diagnostics.__beacon then - diagnostics.__beacon = require("scripts.beacon").new(window, beacon_config); - else - diagnostics.__beacon:update(window, beacon_config); - end - - diagnostics.__beacon:start(); - end - - ---|fE -end - ---- Custom statuscolumn. ----@return string -_G.fancy_diagnostics_statuscolumn = function () - ---|fS - - if vim.tbl_isempty(diagnostics.sign_data) then - return ""; - end - - local lnum = vim.v.lnum; - - local data = diagnostics.sign_data[lnum]; - local start = data.start_row; - - if not data then - return ""; - elseif vim.v.virtnum == 0 and start == lnum then - return virt_text_to_sign(data.icon); - else - return virt_text_to_sign(data.padding or data.icon); - end - - ---|fE -end - ---- Hover function for diagnostics. ----@param window integer -diagnostics.hover = function (window) - ---|fS - - window = window or vim.api.nvim_get_current_win(); - - ---@type integer Source buffer. - local buffer = vim.api.nvim_win_get_buf(window); - ---@type [ integer, integer ] - local cursor = vim.api.nvim_win_get_cursor(window); - - local items = vim.diagnostic.get(buffer, { lnum = cursor[1] - 1 }); - - ---@type boolean Is the window already open? - local already_open = diagnostics.window and vim.api.nvim_win_is_valid(diagnostics.window); - - if #items == 0 then - -- No diagnostics available. - diagnostics.close(); - vim.api.nvim_echo({ - { " 󰾕 diagnostics.lua ", "DiagnosticVirtualTextWarn" }, - { ": ", "@comment" }, - { "No diagnostic under cursor", "@comment" }, - }, true, {}); - return; - elseif already_open then - vim.api.nvim_set_current_win(diagnostics.window); - return; - end - - if diagnostics.quad then - -- If the old window's quadrant wasn't freed, we free it here. - diagnostics.update_quad(diagnostics.quad, false) - end - - diagnostics.__prepare(); - vim.bo[diagnostics.buffer].ft = "markdown"; - - -- Clear old decorations. - vim.api.nvim_buf_clear_namespace(diagnostics.buffer, diagnostics.ns, 0, -1); - vim.api.nvim_buf_set_lines(diagnostics.buffer, 0, -1, false, {}); - - local W = eval(diagnostics.config.width, items); - local D = eval(diagnostics.config.decoration_width, items); - - ---@type table Configuration used for calculating window height. - local height_calc_config = { - relative = "editor", - - row = 0, col = 1, - width = W - D, height = 2, - - style = "minimal", - hide = true, - }; - - if not diagnostics.window or not vim.api.nvim_win_is_valid(diagnostics.window) then - diagnostics.window = vim.api.nvim_open_win(diagnostics.buffer, false, height_calc_config); - else - vim.api.nvim_win_set_config(diagnostics.window, height_calc_config); - end - - vim.wo[diagnostics.window].wrap = true; - vim.wo[diagnostics.window].linebreak = true; - vim.wo[diagnostics.window].breakindent = true; - - local diagnostic_lines = 0; - - ---@type integer Line where the cursor should be placed. - local cursor_y = 1; - local ranges = {}; - - local start_row = 1; - ---@type vim.diagnostic.Severity | nil - local level; - - diagnostics.sign_data = {}; - - for i, item in ipairs(items) do - ---|fS - - local from = i == 1 and 0 or -1; - local lines = vim.split(item.message, "\n", { trimempty = true }) - - local start = item.col; - local stop = item.end_col; - - local current = false; - - if cursor[2] >= start and cursor[2] <= stop then - cursor_y = i; - current = true; - end - - vim.api.nvim_buf_set_lines(diagnostics.buffer, from, -1, false, lines); - local decorations = get_decorations(item.severity, item, current); - - ranges[i] = { item.lnum, item.col }; - - vim.api.nvim_buf_set_extmark(diagnostics.buffer, diagnostics.ns, diagnostic_lines, 0, { - end_row = diagnostic_lines + #lines, - line_hl_group = decorations.line_hl_group, - }); - - diagnostic_lines = diagnostic_lines + #lines; - - if current == true and ( not level or item.severity < level ) then - level = item.severity; - end - - for _ = 1, #lines do - -- Signs - table.insert(diagnostics.sign_data, { - start_row = start_row, - - current = current, - width = decorations.width, - - icon = decorations.icon, - line_hl_group = decorations.line_hl_group, - padding = decorations.padding, - }); - end - - start_row = start_row + #lines; - - ---|fE - end - - local beacon_config = vim.tbl_extend("force", - get_beacon_config("default", {}, true), - get_beacon_config(level, {}, true) or {} - ); - - local H = vim.api.nvim_win_text_height(diagnostics.window, { start_row = 0, end_row = -1 }).all; - - local _, relative, anchor, row, col = diagnostics.__win_args(window, W, H); - - local win_config = { - relative = relative or "cursor", - - row = row or 0, col = col or 0, - width = W, height = H, - - anchor = anchor, - border = "none", - - style = "minimal", - hide = false, - }; - - vim.api.nvim_win_set_config(diagnostics.window, win_config); - vim.api.nvim_win_set_cursor(diagnostics.window, { cursor_y, 0 }); - - -- Update quadrant state. - diagnostics.update_quad(diagnostics.quad, true); - - -- Set necessary options. - vim.wo[diagnostics.window].signcolumn = "no"; - vim.wo[diagnostics.window].statuscolumn = "%!v:lua.fancy_diagnostics_statuscolumn()"; - - vim.wo[diagnostics.window].conceallevel = 3; - vim.wo[diagnostics.window].concealcursor = "ncv"; - - vim.wo[diagnostics.window].winhl = "FloatBorder:@comment,Normal:Normal"; - - diagnostics.__integration(window, beacon_config); - - ---|fS - - - vim.api.nvim_buf_set_keymap(diagnostics.buffer, "n", "", "", { - desc = "Go to diagnostic location", - callback = function () - ---|fS - - ---@type [ integer, integer ] Selected item. - local _cursor = vim.api.nvim_win_get_cursor(diagnostics.window); - ---@type [ integer, integer ]? Diagnostic location. - local location = ranges[_cursor[1]]; - - if location then - location[1] = location[1] + 1; - - vim.api.nvim_win_set_cursor(window, location); - vim.api.nvim_set_current_win(window); - - diagnostics.close(); - end - - ---|fE - end - }); - - vim.api.nvim_buf_set_keymap(diagnostics.buffer, "n", "q", "", { - desc = "Exit diagnostics window", - callback = function () - pcall(vim.api.nvim_set_current_win, window); - diagnostics.close(); - end - }); - - ---|fE - - ---|fE -end - ---- Configuration for the diagnostics module. ----@param config? diagnostics.config -diagnostics.setup = function (config) - ---|fS - - if type(config) == "table" then - diagnostics.config = vim.tbl_extend("force", diagnostics.config, config); - end - - if diagnostics.config.keymap then - vim.api.nvim_set_keymap("n", diagnostics.config.keymap, "", { - callback = diagnostics.hover - }); - end - - vim.api.nvim_create_autocmd({ - "CursorMoved", "CursorMovedI" - }, { - callback = function () - local win = vim.api.nvim_get_current_win(); - - if diagnostics.window and win ~= diagnostics.window then - diagnostics.close(); - - if diagnostics.quad then - diagnostics.update_quad(diagnostics.quad, false); - diagnostics.quad = nil; - end - end - end - }); - - ---|fE -end - -return diagnostics; -- cgit 1.4.1-2-gfad0