diff options
| author | triethyl <triethylammonium@pm.me> | 2026-03-29 15:00:58 -0400 |
|---|---|---|
| committer | triethyl <triethylammonium@pm.me> | 2026-03-29 15:00:58 -0400 |
| commit | cea89c939028a23e73286c2db3fdf8839d4f3256 (patch) | |
| tree | 001405f2d97f6fdc1878148c5bf0e4acdce1a190 /lua | |
initialized repository
Diffstat (limited to 'lua')
| -rw-r--r-- | lua/lineage.lua | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/lua/lineage.lua b/lua/lineage.lua new file mode 100644 index 0000000..de32717 --- /dev/null +++ b/lua/lineage.lua @@ -0,0 +1,328 @@ +local M = {} + +-- Highlighting Shortcut +local hi_pattern = '%%#%s#%s%%*' +M.hi_pattern = hi_pattern + +-- Use icons? +M.use_icons = false +local use_icons = M.use_icons + +-- Utilities +local utils = {} + +-- The width of the statusline. +utils.linewidth = function () + if vim.o.laststatus == 3 then + return vim.o.columns + else + return vim.api.nvim_win_get_width(0) + end +end + +utils.component_takes_percentage = function (comp_width, percentage) + return comp_width > (percentage/100) * utils.linewidth() +end + +M.utils = utils + +-- Pre-made Statusline Components + +M.components = {} + +M.components.mode = function (args) + args = args or {} + local before = args.before or "" + local after = args.after or "" + + -- Convert mode to string + local mode_to_str = { + ['n'] = 'NORMAL', + ['no'] = 'OP-PENDING', + ['nov'] = 'OP-PENDING', + ['noV'] = 'OP-PENDING', + ['no\22'] = 'OP-PENDING', + ['niI'] = 'NORMAL', + ['niR'] = 'NORMAL', + ['niV'] = 'NORMAL', + ['nt'] = 'NORMAL', + ['ntT'] = 'NORMAL', + ['v'] = 'VISUAL', + ['vs'] = 'VISUAL', + ['V'] = 'VISUAL', + ['Vs'] = 'VISUAL', + ['\22'] = 'VISUAL', + ['\22s'] = 'VISUAL', + ['s'] = 'SELECT', + ['S'] = 'SELECT', + ['\19'] = 'SELECT', + ['i'] = 'INSERT', + ['ic'] = 'INSERT', + ['ix'] = 'INSERT', + ['R'] = 'REPLACE', + ['Rc'] = 'REPLACE', + ['Rx'] = 'REPLACE', + ['Rv'] = 'VIRT REPLACE', + ['Rvc'] = 'VIRT REPLACE', + ['Rvx'] = 'VIRT REPLACE', + ['c'] = 'COMMAND', + ['cv'] = 'VIM EX', + ['ce'] = 'EX', + ['r'] = 'PROMPT', + ['rm'] = 'MORE', + ['r?'] = 'CONFIRM', + ['!'] = 'SHELL', + ['t'] = 'TERMINAL', + } + + -- Get the respective string to display. + local mode = mode_to_str[vim.api.nvim_get_mode().mode] or 'UNKNOWN' + + -- Set the highlight group and text. + local mode_text = "?" + local hl = 'DiagnosticWarn' + + if mode:find 'NORMAL' then + hl = 'DiagnosticInfo' + mode_text = "N" + elseif mode:find 'PENDING' then + hl = 'DiagnosticInfo' + mode_text = "P" + elseif mode:find 'VISUAL' then + hl = 'DiagnosticHint' + mode_text = "V" + elseif mode:find 'REPLACE' then + hl = 'DiagnosticError' + mode_text = "R" + elseif mode:find 'INSERT' or mode:find 'SELECT' then + hl = 'DiagnosticOk' + mode_text = "I" + elseif mode:find 'COMMAND' or mode:find 'TERMINAL' or mode:find 'EX' then + hl = 'DiagnosticHint' + mode_text = "C" + end + + -- Construct the component. + return hi_pattern:format(hl, string.format(before..'%s'..after, mode_text)) +end + +M.components.location = function (args) + args = args or {} + local before = args.before or "" + local after = args.after or "" + + return before.."%(%l/%L%): %c"..after +end + +M.components.progress = function (args) + args = args or {} + local before = args.before or "" + local after = args.after or "" + + -- Neovide breaks this component. + if vim.g.neovide then return "" end + + local sbar = { '🭶', '🭷', '🭸', '🭹', '🭺', '🭻' } + local curr_line = vim.api.nvim_win_get_cursor(0)[1] or 0 + local lines = vim.api.nvim_buf_line_count(0) or 0 + local i = math.floor((curr_line - 1) / lines * #sbar) + 1 + -- if i == nil then return "" end + local prog = string.rep(sbar[i], 2) + return before..hi_pattern:format("Visual", prog)..after +end + +M.components.cwd = function (args) + args = args or {} + local before = args.before or "" + local after = args.after or "" + + local cwd = vim.fn.getcwd(0) + cwd = vim.fn.fnamemodify(cwd, ":~") + if utils.component_takes_percentage(#cwd, 40) then cwd = vim.fn.pathshorten(cwd) end + if utils.component_takes_percentage(#cwd, 80) then return "" end + local trail = cwd:sub(-1) == '/' and '' or "/" + return before..cwd..trail..after +end + +M.components.diagnostics = function (args) + args = args or {} + local before = args.before or "" + local after = args.after or "" + + -- Define icons + local error_icon = use_icons and " " or "E" + local warning_icon = use_icons and " " or "W" + local info_icon = use_icons and " " or "I" + local hint_icon = use_icons and " " or "H" + + -- Create empty diagnostics table + local diagnostics = {} + + -- Count diagnostics + local errors = #vim.diagnostic.get(0, { severity = 1 }) + + if errors > 0 then + table.insert(diagnostics, hi_pattern:format("DiagnosticSignError", ("%s%s"):format(error_icon, errors))) + end + + local warnings = #vim.diagnostic.get(0, { severity = 2 }) + + if warnings > 0 then + table.insert(diagnostics, hi_pattern:format("DiagnosticSignWarn", ("%s%s"):format(warning_icon, warnings))) + end + + local infos = #vim.diagnostic.get(0, { severity = 3 }) + + if infos > 0 then + table.insert(diagnostics, hi_pattern:format("DiagnosticSignInfo", ("%s%s"):format(info_icon, infos))) + end + + local hints = #vim.diagnostic.get(0, { severity = 4 }) + + if hints > 0 then + table.insert(diagnostics, hi_pattern:format("DiagnosticSignHint", ("%s%s"):format(hint_icon, hints))) + end + + -- Don't show diagnostics in insert mode. + if vim.api.nvim_get_mode().mode:find "i" then + return "" + end + + local icon = use_icons and '' or 'diag: ' + + local status = hi_pattern:format("Statusline", table.concat(diagnostics, " ")) + + return before..icon..status..after +end + +M.components.git_branch = function (args) + args = args or {} + local before = args.before or "" + local after = args.after or "" + + if not vim.b.minigit_summary then return "" end + local branch = vim.b.minigit_summary.head_name or "" + local icon = use_icons and " " or "branch: " + return before..icon..branch..after +end + +M.components.git_status = function (args) + args = args or {} + local before = args.before or "" + local after = args.after or "" + + if not vim.b.minidiff_summary then return "" end + + local summary = vim.b.minidiff_summary + + local status = {} + + local add_icon = use_icons and " " or "+" + local change_icon = use_icons and " " or "~" + local delete_icon = use_icons and " " or "-" + + if (summary.add or 0) > 0 then + table.insert(status, hi_pattern:format("Added", ("%s%s"):format(add_icon, summary.add))) + end + if (summary.change or 0) > 0 then + table.insert(status, hi_pattern:format("Changed", ("%s%s"):format(change_icon, summary.change))) + end + if (summary.delete or 0) > 0 then + table.insert(status, hi_pattern:format("Removed", ("%s%s"):format(delete_icon, summary.delete))) + end + + return before..table.concat(status, " ")..after +end + +M.components.tab_counter = function (args) + args = args or {} + local before = args.before or "" + local after = args.after or "" + + local tab_list = vim.api.nvim_list_tabpages() + local num_tabs = #tab_list + local current_tab_name = vim.api.nvim_get_current_tabpage() + + local current_tab_index = 1 + + for i = 1, #tab_list, 1 do + if tab_list[i] == current_tab_name then + current_tab_index = i + end + end + + if num_tabs == 1 then return "" end + + local icon = use_icons and " " or "tab: " + + return before..icon..current_tab_index.."/"..num_tabs..after +end + +M.components.session_name = function (args) + args = args or {} + local before = args.before or "" + local after = args.after or "" + + if not vim.g.loaded_auto_session then + return "" + end + + return before..require("auto-session.lib").current_session_name(true)..after +end + +M.components.markdown_word_count = function (args) + args = args or {} + local before = args.before or "" + local after = args.after or "" + + if vim.bo.filetype ~= "markdown" then + return "" + end + + local word_count = vim.fn.wordcount().visual_words or vim.fn.wordcount().words + + return before..word_count.." words"..after +end + +-- Setup the statusline +function M.setup(opts) + opts = opts or {} + + local statusline_components = opts.components or { + M.components.mode({before = " "}), + M.components.git_branch(), + M.components.cwd(), + + "%=", + + M.components.session_name(), + M.components.markdown_word_count(), + M.components.tab_counter(), + M.components.location({after = vim.g.neovide and " " or ""}), + M.components.progress({after = ""}), + } + + local gaps = opts.gaps or " " + + -- Global function to construct the line + Statusline_builder = function () + --get a table of all the statusline strings + local statusline_strings = statusline_components + + -- Remove empty strings to prevent concat issues + for i = #statusline_strings, 1, -1 do + if statusline_strings[i] == "" then + table.remove(statusline_strings, i) + end + end + + -- Concatentate strings with gaps + return table.concat(statusline_strings, gaps) + end + + -- Tell vim to call the function to construct the line + vim.o.statusline = "%{%v:lua.Statusline_builder()%}" + +end + +return M |
