diff --git a/lua/lualine.lua b/lua/lualine.lua index 048ee84..cc299e4 100644 --- a/lua/lualine.lua +++ b/lua/lualine.lua @@ -13,6 +13,10 @@ local config -- Stores cureently applied config local new_config = true -- Stores config that will be applied -- Helper for apply_transitional_separators() +--- finds first applied highlight group fter str_checked in status +---@param status string : unprossed statusline string +---@param str_checked number : position of how far status has been checked +---@return string|nil the hl group name or nil local function find_next_hl(status, str_checked) -- Gets the next valid hl group from str_checked local hl_pos_start, hl_pos_end = status:find('%%#.-#', str_checked) @@ -32,6 +36,12 @@ local function find_next_hl(status, str_checked) end -- Helper for apply_transitional_separators() +--- applies transitional separator highlight + transitional separator +---@param status string : unprossed statusline string +---@param str_checked number : position of how far status has been checked +---@param last_hl string : last applied hl group name before str_checked +---@param reverse boolean : reverse the hl group ( true for right separators ) +---@return string|nil concated separator highlight and transitional separator local function fill_section_separator(status, str_checked, last_hl, sep, reverse) -- Inserts transitional separator along with transitional highlight local next_hl = find_next_hl(status, str_checked) @@ -52,6 +62,10 @@ local function fill_section_separator(status, str_checked, last_hl, sep, reverse end end +--- processes statusline string +--- replaces %s/S{sep} with proper left/right separator highlight + sep +---@param status string : unprossed statusline string +---@return string : processed statusline string local function apply_transitional_separators(status) local status_applied = {} -- Collects all the pieces for concatation local last_hl -- Stores lash highligjt group that we found @@ -122,6 +136,11 @@ local function apply_transitional_separators(status) return table.concat(status_applied) end +--- creates the statusline string +---@param sections table : section config where components are replaced with +--- component objects +---@param is_focused boolean : whether being evsluated for focused window or not +---@return string statusline string local function statusline(sections, is_focused) -- The sequence sections should maintain [SECTION_SEQUENCE] local section_sequence = { 'a', 'b', 'c', 'x', 'y', 'z' } @@ -156,7 +175,14 @@ local function statusline(sections, is_focused) return apply_transitional_separators(table.concat(status)) end --- check if any extension matches the filetype and return proper sections +--- check if any extension matches the filetype and return proper sections +---@param current_ft string : filetype name of current file +---@param is_focused boolean : whether being evsluated for focused window or not +---@return table : (section_table) section config where components are replaced with +--- component objects +-- TODO: change this so it uses a hash table instead of iteration over lisr +-- to improve redraws. Add buftype / bufname for extensions +-- or some kind of cond ? local function get_extension_sections(current_ft, is_focused) for _, extension in ipairs(config.extensions) do for _, filetype in ipairs(extension.filetypes) do @@ -171,6 +197,7 @@ local function get_extension_sections(current_ft, is_focused) return nil end +---@return string statusline string for tabline local function tabline() return statusline(config.tabline, true) end @@ -191,6 +218,13 @@ Also provide what colorscheme you're using. modules.utils_notices.add_notice(string.format(message_template, theme_name)) end +--- sets up theme by defining hl groups and setting theme cache in highlight.lua +--- uses options.theme option for theme if it's a string loads theme of that name +--- if it's a table directlybuses it . +--- when theme load fails this fallsback to 'auto' theme if even that fails +--- this falls back to 'gruvbox' theme +--- also sets up auto command to reload lualine on ColorScheme or background +--- change on local function setup_theme() local function get_theme_from_config() local theme_name = config.options.theme @@ -219,6 +253,7 @@ local function setup_theme() autocmd lualine OptionSet background lua require'lualine'.setup()]] end +--- Sets &tabline option to lualine local function set_tabline() if next(config.tabline) ~= nil then vim.go.tabline = "%{%v:lua.require'lualine'.tabline()%}" @@ -226,6 +261,8 @@ local function set_tabline() end end +--- Sets &ststusline option to lualine +--- adds auto command to redraw lualine on VimResized event local function set_statusline() if next(config.sections) ~= nil or next(config.inactive_sections) ~= nil then vim.cmd 'autocmd lualine VimResized * redrawstatus' @@ -234,16 +271,15 @@ local function set_statusline() end end -local function setup_augroup() - vim.cmd [[augroup lualine | autocmd! | augroup END]] -end - +--- reloads lualine using new_config local function reset_lualine() if package.loaded['lualine.utils.notices'] then + -- When notices module is not loaded there are no notices to clear. modules.utils_notices.clear_notices() end - setup_augroup() + vim.cmd [[augroup lualine | autocmd! | augroup END]] setup_theme() + -- load components & extensions modules.loader.load_all(config) set_statusline() set_tabline() @@ -253,33 +289,50 @@ local function reset_lualine() new_config = nil end +-- lualine.statusline function +--- Draw correct statusline for current winwow +---@param focused boolean : force the vale of is_focuased . useful for debugginf +---@return string statusline string local function status_dispatch(focused) - -- disable on specific filetypes + local retval if new_config then + -- reload lualine when config was changed reset_lualine() end local current_ft = vim.bo.filetype local is_focused = focused ~= nil and focused or modules.utils.is_focused() for _, ft in pairs(config.options.disabled_filetypes) do + -- disable on specific filetypes if ft == current_ft then - vim.wo.statusline = '' return '' end end local extension_sections = get_extension_sections(current_ft, is_focused) if is_focused then if extension_sections ~= nil then - return statusline(extension_sections, is_focused) + retval = statusline(extension_sections, is_focused) + else + retval = statusline(config.sections, is_focused) end - return statusline(config.sections, is_focused) else if extension_sections ~= nil then - return statusline(extension_sections, is_focused) + retval = statusline(extension_sections, is_focused) + else + retval = statusline(config.inactive_sections, is_focused) end - return statusline(config.inactive_sections, is_focused) end + return retval end +-- lualine.setup function +--- sets new user config +--- This function doesn't load components/theme etc.. they are done before +--- first statusline redraw after new config. This is more efficient when +--- lualine config is done in several setup calls in chunks. This way +--- we don't intialize components just to throgh them away .Instead they are +--- initialized when we know we will use them. +--- sets &last_status tl 2 +---@param user_config table table local function setup(user_config) new_config = true config = modules.config_module.apply_configuration(user_config) diff --git a/lua/lualine/component.lua b/lua/lualine/component.lua index f461501..930b60a 100644 --- a/lua/lualine/component.lua +++ b/lua/lualine/component.lua @@ -7,6 +7,9 @@ local M = require('lualine.utils.class'):extend() -- Used to provide a unique id for each component local component_no = 1 +-- variable to store component output for manipulation +M.status = '' + function M:__tostring() local str = 'Component: ' .. self.options.component_name if self.debug then @@ -15,7 +18,8 @@ function M:__tostring() return str end --- Initialize new component +---initialize new component +---@param options table options for component function M:init(options) self.options = options or {} component_no = component_no + 1 @@ -27,6 +31,8 @@ function M:init(options) self:create_option_highlights() end +---sets the default separator for component based on whether the component +---is in left sections or right sections when separator option is omited. function M:set_separator() if self.options.separator == nil then if self.options.component_separators then @@ -39,6 +45,7 @@ function M:set_separator() end end +---creates hl group from color option function M:create_option_highlights() -- set custom highlights if self.options.color then @@ -50,7 +57,7 @@ function M:create_option_highlights() end end --- Adds spaces to left and right of a component +---adds spaces to left and right of a component function M:apply_padding() local padding = self.options.padding local l_padding, r_padding @@ -77,7 +84,7 @@ function M:apply_padding() end end --- Applies custom highlights for component +---applies custom highlights for component function M:apply_highlights(default_highlight) if self.options.color_highlight then self.status = highlight.component_format_highlight(self.options.color_highlight) .. self.status @@ -97,15 +104,15 @@ function M:apply_highlights(default_highlight) end end --- Apply icon in front of component +---apply icon in front of component (prepemds component with icon) function M:apply_icon() if self.options.icons_enabled and self.options.icon then self.status = self.options.icon .. ' ' .. self.status end end --- Apply separator at end of component only when --- custom highlights haven't affected background +---apply separator at end of component only when +---custom highlights haven't affected background function M:apply_separator() local separator = self.options.separator if type(separator) == 'table' then @@ -125,6 +132,7 @@ function M:apply_separator() end end +---apply transitional separator for the component function M:apply_section_separators() if type(self.options.separator) ~= 'table' then return @@ -138,6 +146,8 @@ function M:apply_section_separators() end end +---remove separator from tail of this component. +---called by lualine.utils.sections.draw_section to manage unnecessary separators function M:strip_separator() if not self.applied_separator then self.applied_separator = '' @@ -147,14 +157,12 @@ function M:strip_separator() return self.status end --- variable to store component output for manipulation -M.status = '' --- Actual function that updates a component. Must be overwritten with component functionality -- luacheck: push no unused args +---actual function that updates a component. Must be overwritten with component functionality function M:update_status(is_focused) end -- luacheck: pop --- Driver code of the class +---driver code of the class function M:draw(default_highlight, is_focused) self.status = '' self.applied_separator = '' diff --git a/lua/lualine/components/branch/git_branch.lua b/lua/lualine/components/branch/git_branch.lua index 75831ba..ef4a4cd 100644 --- a/lua/lualine/components/branch/git_branch.lua +++ b/lua/lualine/components/branch/git_branch.lua @@ -16,7 +16,8 @@ local sep = package.config:sub(1, 1) local file_changed = sep ~= '\\' and vim.loop.new_fs_event() or vim.loop.new_fs_poll() local git_dir_cache = {} -- Stores git paths that we already know of --- sets git_branch veriable to branch name or commit hash if not on branch +---sets git_branch veriable to branch name or commit hash if not on branch +---@param head_file string full path of .git/HEAD file local function get_git_head(head_file) local f_head = io.open(head_file) if f_head then @@ -32,7 +33,7 @@ local function get_git_head(head_file) return nil end --- Update branch +---update the current value of git_branch and setup file watch on HEAD file local function update_branch() active_bufnr = tostring(vim.fn.bufnr()) file_changed:stop() @@ -55,7 +56,9 @@ local function update_branch() branch_cache[vim.fn.bufnr()] = current_git_branch end --- returns full path to git directory for dir_path or current directory +---returns full path to git directory for dir_path or current directory +---@param dir_path string|nil +---@return string function M.find_git_dir(dir_path) -- get file dir so we can search from that dir local file_dir = dir_path or vim.fn.expand '%:p:h' @@ -103,6 +106,7 @@ function M.find_git_dir(dir_path) return git_dir end +---initialize git_branch ,odule function M.init() -- run watch head on load so branch is present when component is loaded M.find_git_dir() diff --git a/lua/lualine/components/buffers/buffer.lua b/lua/lualine/components/buffers/buffer.lua index 2fd811d..81ae252 100644 --- a/lua/lualine/components/buffers/buffer.lua +++ b/lua/lualine/components/buffers/buffer.lua @@ -1,7 +1,8 @@ local highlight = require 'lualine.highlight' - local Buffer = require('lualine.utils.class'):extend() +---intialize a new buffer from opts +---@param opts table function Buffer:init(opts) assert(opts.bufnr, 'Cannot create Buffer without bufnr') self.bufnr = opts.bufnr @@ -10,6 +11,7 @@ function Buffer:init(opts) self:get_props() end +---setup icons, modified status for buffer function Buffer:get_props() self.file = vim.fn.bufname(self.bufnr) self.buftype = vim.api.nvim_buf_get_option(self.bufnr, 'buftype') @@ -40,21 +42,25 @@ function Buffer:get_props() self.icon = dev .. ' ' end end - return self end +---returns rendered buffer +---@return string function Buffer:render() local name - if self.ellipse then + if self.ellipse then -- show elipsis name = '...' else name = string.format(' %s%s%s ', self.icon, self:name(), self.modified_icon) end self.len = vim.fn.strchars(name) + -- setup for mouse clicks local line = string.format('%%%s@LualineSwitchBuffer@%s%%T', self.bufnr, name) + -- apply highlight line = highlight.component_format_highlight(self.highlights[(self.current and 'active' or 'inactive')]) .. line + -- apply separators if self.options.self.section < 'lualine_x' and not self.first then local sep_before = self:separator_before() line = sep_before .. line @@ -67,6 +73,8 @@ function Buffer:render() return line end +---apply separator before current buffer +---@return string function Buffer:separator_before() if self.current or self.aftercurrent then return '%S{' .. self.options.section_separators.left .. '}' @@ -75,6 +83,8 @@ function Buffer:separator_before() end end +---apply separator after current buffer +---@return string function Buffer:separator_after() if self.current or self.beforecurrent then return '%s{' .. self.options.section_separators.right .. '}' @@ -83,6 +93,8 @@ function Buffer:separator_after() end end +---returns name of current buffer after filtering special buffers +---@return string function Buffer:name() if self.options.filetype_names[self.filetype] then return self.options.filetype_names[self.filetype] diff --git a/lua/lualine/components/buffers/init.lua b/lua/lualine/components/buffers/init.lua index a2f0f87..5aa2b17 100644 --- a/lua/lualine/components/buffers/init.lua +++ b/lua/lualine/components/buffers/init.lua @@ -22,6 +22,11 @@ local default_options = { }, } +-- This function is duplicated in tabs +---returns the proper hl for buffer in section. used for setting default highlights +---@param section string name of section buffers component is in +---@param is_active boolean +---@return string hl name local function get_hl(section, is_active) local suffix = is_active and '_normal' or '_inactive' local section_redirects = { @@ -66,6 +71,8 @@ function M:update_status() end local current_bufnr = vim.fn.bufnr() local current = -2 + -- mark the first, last, current, before current, after current buffers + -- for rendering if buffers[1] then buffers[1].first = true end @@ -95,6 +102,8 @@ function M:update_status() current = i end end + -- start drawing from current buffer and draw left and right of it until + -- all buffers are drawn or max_length has been reached. if current == -2 then local b = Buffer { bufnr = vim.fn.bufnr(), options = self.options, highlights = self.highlights } b.current = true @@ -127,24 +136,26 @@ function M:update_status() if before == nil and after == nil then break end + -- draw left most undrawn buffer if fits in max_length if before then rendered_before = before:render() total_length = total_length + before.len + if total_length > max_length then + break + end + table.insert(data, 1, rendered_before) end + -- draw right most undrawn buffer if fits in max_length if after then rendered_after = after:render() total_length = total_length + after.len - end - if total_length > max_length then - break - end - if before then - table.insert(data, 1, rendered_before) - end - if after then + if total_length > max_length then + break + end data[#data + 1] = rendered_after end end + -- draw elipsis (...) on relevent sides if all buffers don't fit in max_length if total_length > max_length then if before ~= nil then before.ellipse = true diff --git a/lua/lualine/components/diagnostics/config.lua b/lua/lualine/components/diagnostics/config.lua index 4beb9b3..dfaab80 100644 --- a/lua/lualine/components/diagnostics/config.lua +++ b/lua/lualine/components/diagnostics/config.lua @@ -2,6 +2,7 @@ local require = require('lualine_require').require local utils = require 'lualine.utils.utils' local M = {} +-- default symbols for diagnostics component M.symbols = { icons = { error = ' ', -- xf659 @@ -12,6 +13,7 @@ M.symbols = { no_icons = { error = 'E:', warn = 'W:', info = 'I:', hint = 'H:' }, } +-- default options for diagnostics component M.options = { colored = true, update_in_insert = false, diff --git a/lua/lualine/components/diagnostics/init.lua b/lua/lualine/components/diagnostics/init.lua index c5a19fe..7ef416f 100644 --- a/lua/lualine/components/diagnostics/init.lua +++ b/lua/lualine/components/diagnostics/init.lua @@ -69,6 +69,7 @@ function M:update_status() end local error_count, warning_count, info_count, hint_count = 0, 0, 0, 0 local diagnostic_data = modules.sources.get_diagnostics(self.options.sources) + -- sum all the counts for _, data in pairs(diagnostic_data) do error_count = error_count + data.error warning_count = warning_count + data.warn @@ -82,6 +83,7 @@ function M:update_status() info = info_count, hint = hint_count, } + -- format the counts with symbols and highlights if self.options.colored then local colors = {} for name, hl in pairs(self.highlight_groups) do diff --git a/lua/lualine/components/diagnostics/sources.lua b/lua/lualine/components/diagnostics/sources.lua index f221673..a459681 100644 --- a/lua/lualine/components/diagnostics/sources.lua +++ b/lua/lualine/components/diagnostics/sources.lua @@ -1,5 +1,8 @@ local M = {} +---functions that how how to retrieve diagnostics from specific source. +---returns error_count:number, warning_count:number, +--- info_count:number, hint_count:number M.sources = { nvim_lsp = function() local error_count = vim.lsp.diagnostic.get_count(0, 'Error') @@ -45,6 +48,9 @@ M.sources = { end, } +---returns list of diagnostics count from all sources +---@param sources table list of sources +---@return table {{error_count, warning_count, info_count, hint_count}} M.get_diagnostics = function(sources) local result = {} for index, source in ipairs(sources) do diff --git a/lua/lualine/components/diff/git_diff.lua b/lua/lualine/components/diff/git_diff.lua index 8507aa0..c36b254 100644 --- a/lua/lualine/components/diff/git_diff.lua +++ b/lua/lualine/components/diff/git_diff.lua @@ -17,7 +17,8 @@ local diff_job = nil local active_bufnr = '0' local diff_cache = {} -- Stores last known value of diff of a buffer --- initialize the module +---initialize the module +---param opts table function M.init(opts) if type(opts.source) == 'function' then M.src = opts.source @@ -28,14 +29,15 @@ function M.init(opts) end end --- Api to get git sign count --- scheme : --- { --- added = added_count, --- modified = modified_count, --- removed = removed_count, --- } --- error_code = { added = -1, modified = -1, removed = -1 } +---Api to get git sign count +---scheme : +---{ +--- added = added_count, +--- modified = modified_count, +--- removed = removed_count, +---} +---error_code = { added = -1, modified = -1, removed = -1 } +---@param bufnr number|nil function M.get_sign_count(bufnr) if bufnr then return diff_cache[bufnr] @@ -52,7 +54,8 @@ function M.get_sign_count(bufnr) return git_diff end --- process diff data and update git_diff{ added, removed, modified } +---process diff data and update git_diff{ added, removed, modified } +---@param data string output on stdout od git diff job local function process_diff(data) -- Adapted from https://github.com/wbthomason/nvim-vcs.lua local added, removed, modified = 0, 0, 0 @@ -79,7 +82,7 @@ local function process_diff(data) git_diff = { added = added, modified = modified, removed = removed } end --- Updates the job args +---updates the job args function M.update_diff_args() -- Donn't show git diff when current buffer doesn't have a filename active_bufnr = tostring(vim.fn.bufnr()) @@ -118,7 +121,7 @@ function M.update_diff_args() M.update_git_diff() end --- Update git_diff veriable +---update git_diff veriable function M.update_git_diff() if M.diff_args then diff_output_cache = {} diff --git a/lua/lualine/components/filename.lua b/lua/lualine/components/filename.lua index 27346d2..a11324c 100644 --- a/lua/lualine/components/filename.lua +++ b/lua/lualine/components/filename.lua @@ -9,10 +9,18 @@ local default_options = { shorting_target = 40, } +---counts how many times pattern occur in base ( used for counting path-sep ) +---@param base string +---@param pattern string +---@return number local function count(base, pattern) return select(2, string.gsub(base, pattern, '')) end +---shortens path by turning apple/orange -> a/orange +---@param path string +---@param sep string path separator +---@return string local function shorten_path(path, sep) -- ('([^/])[^/]+%/', '%1/', 1) return path:gsub(string.format('([^%s])[^%s]+%%%s', sep, sep, sep), '%1' .. sep, 1) diff --git a/lua/lualine/components/special/eval_func_component.lua b/lua/lualine/components/special/eval_func_component.lua index 94253e3..804a8c7 100644 --- a/lua/lualine/components/special/eval_func_component.lua +++ b/lua/lualine/components/special/eval_func_component.lua @@ -23,12 +23,18 @@ function M:update_status() return status end +---evaluate the lua code and return it's result as string +---@param code string +---@return string function M.lua_eval(code) local result = loadstring('return ' .. code)() assert(result, 'String expected got nil') return tostring(result) end +---call vim function (name) and return it's result as string +---@param name string +---@return string function M.vim_function(name) -- vim function component local ok, return_val = pcall(vim.api.nvim_call_function, name, {}) diff --git a/lua/lualine/components/tabs/init.lua b/lua/lualine/components/tabs/init.lua index 6a521ef..a48cb05 100644 --- a/lua/lualine/components/tabs/init.lua +++ b/lua/lualine/components/tabs/init.lua @@ -14,6 +14,11 @@ local default_options = { }, } +-- This function is duplicated in buffers +---returns the proper hl for tab in section. used for setting default highlights +---@param section string name of section tabs component is in +---@param is_active boolean +---@return string hl name local function get_hl(section, is_active) local suffix = is_active and '_normal' or '_inactive' local section_redirects = { @@ -55,6 +60,8 @@ function M:update_status() for t = 1, vim.fn.tabpagenr '$' do tabs[#tabs + 1] = Tab { tabnr = t, options = self.options, highlights = self.highlights } end + -- mark the first, last, current, before current, after current tabpages + -- for rendering local current = vim.fn.tabpagenr() tabs[1].first = true tabs[#tabs].last = true @@ -79,7 +86,9 @@ function M:update_status() end end local current_tab = tabs[current] - if current_tab == nil then + -- start drawing from current tab and draw left and right of it until + -- all tabpages are drawn or max_length has been reached. + if current_tab == nil then -- maybe redundent code local t = Tab { tabnr = vim.fn.tabpagenr(), options = self.options, highlights = self.highlights } t.current = true t.last = true @@ -97,6 +106,7 @@ function M:update_status() if before == nil and after == nil then break end + -- draw left most undrawn tab if fits in max_length if before then rendered_before = before:render() total_length = total_length + before.len @@ -105,6 +115,7 @@ function M:update_status() end table.insert(data, 1, rendered_before) end + -- draw right most undrawn tab if fits in max_length if after then rendered_after = after:render() total_length = total_length + after.len @@ -114,6 +125,7 @@ function M:update_status() data[#data + 1] = rendered_after end end + -- draw elipsis (...) on relevent sides if all tabs don't fit in max_length if total_length > max_length then if before ~= nil then before.ellipse = true diff --git a/lua/lualine/components/tabs/tab.lua b/lua/lualine/components/tabs/tab.lua index 70d1c89..d176c4f 100644 --- a/lua/lualine/components/tabs/tab.lua +++ b/lua/lualine/components/tabs/tab.lua @@ -1,6 +1,8 @@ local highlight = require 'lualine.highlight' local Tab = require('lualine.utils.class'):extend() +---intialize a new tab from opts +---@param opts table function Tab:init(opts) assert(opts.tabnr, 'Cannot create Tab without tabnr') self.tabnr = opts.tabnr @@ -8,6 +10,9 @@ function Tab:init(opts) self.highlights = opts.highlights end +---returns name for tab. tabs name is the name of buffer in last active window +--- of the tab. +---@return string function Tab:label() local buflist = vim.fn.tabpagebuflist(self.tabnr) local winnr = vim.fn.tabpagewinnr(self.tabnr) @@ -27,11 +32,14 @@ function Tab:label() return vim.fn.fnamemodify(file, ':t') end +---returns rendered tab +---@return string function Tab:render() local name - if self.ellipse then + if self.ellipse then -- show elipsis name = '...' else + -- different formats for different modes if self.options.mode == 0 then name = string.format('%s%s ', (self.last or not self.first) and ' ' or '', tostring(self.tabnr)) elseif self.options.mode == 1 then @@ -40,10 +48,14 @@ function Tab:render() name = string.format('%s%s %s ', (self.last or not self.first) and ' ' or '', tostring(self.tabnr), self:label()) end end - self.len = #name + self.len = vim.fn.strchars(name) + + -- setup for mouse clicks local line = string.format('%%%s@LualineSwitchTab@%s%%T', self.tabnr, name) + -- apply highlight line = highlight.component_format_highlight(self.highlights[(self.current and 'active' or 'inactive')]) .. line + -- apply separators if self.options.self.section < 'lualine_x' and not self.first then local sep_before = self:separator_before() line = sep_before .. line @@ -56,6 +68,8 @@ function Tab:render() return line end +---apply separator before current tab +---@return string function Tab:separator_before() if self.current or self.aftercurrent then return '%S{' .. self.options.section_separators.left .. '}' @@ -64,6 +78,8 @@ function Tab:separator_before() end end +---apply separator after current tab +---@return string function Tab:separator_after() if self.current or self.beforecurrent then return '%s{' .. self.options.section_separators.right .. '}' diff --git a/lua/lualine/config.lua b/lua/lualine/config.lua index ae5527e..1bdf991 100644 --- a/lua/lualine/config.lua +++ b/lua/lualine/config.lua @@ -29,7 +29,9 @@ local config = { extensions = {}, } --- change separator format 'x' to {left='x', right='x'} +--- change separator format 'x' to {left='x', right='x'} +---@param separators string|table +---@return table local function fix_separators(separators) if separators ~= nil then if type(separators) == 'string' then @@ -39,6 +41,9 @@ local function fix_separators(separators) return separators end +---extends config based on configtable +---@param config_table table +---@return table copy of config local function apply_configuration(config_table) if not config_table then return vim.deepcopy(config) @@ -63,6 +68,8 @@ local function apply_configuration(config_table) return vim.deepcopy(config) end +--- returns current active config +---@return table a copy of config local function get_current_config() return vim.deepcopy(config) end diff --git a/lua/lualine/highlight.lua b/lua/lualine/highlight.lua index 5e15cfb..8491410 100644 --- a/lua/lualine/highlight.lua +++ b/lua/lualine/highlight.lua @@ -33,12 +33,14 @@ local mode_to_highlight = { ['TERMINAL'] = '_terminal', } --- determine if an highlight exist and isn't cleared +--- determine if an highlight exist and isn't cleared +---@param highlight_name string +---@return boolean whether hl_group was defined with highlight_name function M.highlight_exists(highlight_name) return loaded_highlights[highlight_name] or false end --- clears loaded_highlights table and highlights +--- clears loaded_highlights table and highlights local function clear_highlights() for highlight_name, _ in pairs(loaded_highlights) do vim.cmd('highlight clear ' .. highlight_name) @@ -46,6 +48,9 @@ local function clear_highlights() end end +---converts cterm, color_name type colors to #rrggbb format +---@param color string|number +---@return string local function sanitize_color(color) if type(color) == 'string' then if color:sub(1, 1) == '#' then @@ -60,6 +65,12 @@ local function sanitize_color(color) end end +--- Define a hl_group +---@param name string +---@param foreground string|number: color +---@param background string|number: color +---@param gui table cterm/gui options like bold/italic ect +---@param link string hl_group name to link new hl to function M.highlight(name, foreground, background, gui, link) local command = { 'highlight!' } if link and #link > 0 then @@ -68,13 +79,13 @@ function M.highlight(name, foreground, background, gui, link) foreground = sanitize_color(foreground) background = sanitize_color(background) table.insert(command, name) - if foreground and foreground ~= 'none' then + if foreground and foreground ~= 'None' then table.insert(command, 'guifg=' .. foreground) if create_cterm_colors then table.insert(command, 'ctermfg=' .. modules.color_utils.rgb2cterm(foreground)) end end - if background and background ~= 'none' then + if background and background ~= 'None' then table.insert(command, 'guibg=' .. background) if create_cterm_colors then table.insert(command, 'ctermbg=' .. modules.color_utils.rgb2cterm(background)) @@ -89,6 +100,8 @@ function M.highlight(name, foreground, background, gui, link) loaded_highlights[name] = true end +---define hl_groups for a theme +---@param theme table function M.create_highlight_groups(theme) clear_highlights() active_theme = theme @@ -105,9 +118,9 @@ function M.create_highlight_groups(theme) end end --- @description: adds '_mode' at end of highlight_group --- @param highlight_group:(string) name of highlight group --- @return: (string) highlight group name with mode +---@description: adds '_mode' at end of highlight_group +---@param highlight_group string name of highlight group +---@return string highlight group name with mode function M.append_mode(highlight_group, is_focused) if is_focused == nil then is_focused = modules.utils.is_focused() @@ -120,12 +133,12 @@ function M.append_mode(highlight_group, is_focused) end -- Helper function for create component highlight --- Handles fall back of colors when crea58ng highlight group --- @param color table color passed for creating component highlight --- @param options_color color set by color option for component --- this is first falk back --- @param default_color Colors et in theme this is 2nd fall back --- @param kind (fg/bg)) +---Handles fall back of colors when creating highlight group +---@param color table color passed for creating component highlight +---@param options_color table color set by color option for component +--- this is first fall back +---@param default_color table colors et in theme this is 2nd fall back +---@param kind string fg/bg local function get_default_component_color(color, options_color, default_color, kind) if color[kind] then return color[kind] @@ -144,15 +157,15 @@ local function get_default_component_color(color, options_color, default_color, end end --- Create highlight group with fg bg and gui from theme --- @color has to be { fg = "#rrggbb", bg="#rrggbb" gui = "effect" } --- all the color elements are optional if fg or bg is not given options must be provided --- So fg and bg can default the themes colors --- @highlight_tag is unique tag for highlight group --- returns the name of highlight group --- @options is parameter of component.init() function --- @return: (string) unique name that can be used by component_format_highlight --- to retrive highlight group +---Create highlight group with fg bg and gui from theme +---@param color table has to be { fg = "#rrggbb", bg="#rrggbb" gui = "effect" } +--- all the color elements are optional if fg or bg is not given options +--- must be provided So fg and bg can default the themes colors +---@param highlight_tag string is unique tag for highlight group +---returns the name of highlight group +---@param options table is parameter of component.init() function +---@return string unique name that can be used by component_format_highlight +--- to retrieve highlight group function M.create_component_highlight_group(color, highlight_tag, options) local tag_id = 0 while @@ -211,11 +224,11 @@ function M.create_component_highlight_group(color, highlight_tag, options) return options.self.section .. '_' .. highlight_tag end --- @description: retrieve highlight_groups for components --- @param highlight_name:(string) highlight group name without mode --- return value of create_component_highlight_group is to be passed in --- this parameter to receive highlight that was created --- @return: (string) formated highlight group name +---@description: retrieve highlight_groups for components +---@param highlight_name string highlight group name without mode +--- return value of create_component_highlight_group is to be passed in +--- this parameter to receive highlight that was created +---@return string formatted highlight group name function M.component_format_highlight(highlight_name) local highlight_group = highlight_name if highlight_name:find 'no_mode' == #highlight_name - #'no_mode' + 1 then @@ -229,6 +242,12 @@ function M.component_format_highlight(highlight_name) end end +---@description: retrieve highlight_groups for section +---@param highlight_group string highlight group name without mode +--- return value of create_component_highlight_group is to be passed in +--- this parameter to receive highlight that was created +---@param is_focused boolean +---@return string formatted highlight group name function M.format_highlight(highlight_group, is_focused) if highlight_group > 'lualine_c' and not M.highlight_exists(highlight_group .. '_normal') then highlight_group = 'lualine_' .. section_highlight_map[highlight_group:match 'lualine_(.)'] @@ -241,11 +260,11 @@ function M.format_highlight(highlight_group, is_focused) return '%#' .. highlight_group .. '_normal#' end --- @description : Provides transitional highlights for section separators. --- @param left_hl :(string) this highlights bg is used for fg of transitional hl --- @param right_hl:(string) this highlights bg is used for bg of transitional hl --- '▶️' and '◀️' ' eeds reverse colors so the caller should swap left and right --- @return: (string) formated highlight group name +---@description : Provides transitional highlights for section separators. +---@param left_hl string this highlights bg is used for fg of transitional hl +---@param right_hl string this highlights bg is used for bg of transitional hl +--- '▶️' and '◀️' ' needs reverse colors so the caller should swap left and right +---@return string formatted highlight group name function M.get_transitional_highlights(left_hl, right_hl) -- When both left and right highlights are same or one is absent -- nothing to transition to. @@ -253,7 +272,7 @@ function M.get_transitional_highlights(left_hl, right_hl) return nil end - -- construct the name of hightlight group + -- construct the name of highlight group local highlight_name = table.concat({ 'lualine_transitional', left_hl, 'to', right_hl }, '_') if not M.highlight_exists(highlight_name) then -- Create the highlight_group if needed diff --git a/lua/lualine/utils/class.lua b/lua/lualine/utils/class.lua index 83700fc..5d4a38b 100644 --- a/lua/lualine/utils/class.lua +++ b/lua/lualine/utils/class.lua @@ -4,11 +4,11 @@ local Object = {} Object.__index = Object -- luacheck: push no unused args --- Initializer +---Initializer function Object:init(...) end -- luacheck: pop --- Extened base class to create a child class +---Extened base class to create a child class function Object:extend() local cls = {} for k, v in pairs(self) do @@ -28,14 +28,14 @@ function Object:__tostring() end -- luacheck: pop --- Creates a new object +---Creates a new object function Object:new(...) local obj = setmetatable({}, self) obj:init(...) return obj end --- Creates a new object +---Creates a new object function Object:__call(...) return self:new(...) end diff --git a/lua/lualine/utils/color_utils.lua b/lua/lualine/utils/color_utils.lua index dc7fc28..8c8a184 100644 --- a/lua/lualine/utils/color_utils.lua +++ b/lua/lualine/utils/color_utils.lua @@ -274,6 +274,9 @@ local color_table = { } -- stylua: ignore end +---converts #rrggbb fomated color to cterm ('0'-'255') color +---@param hex_color string +---@return string function M.rgb2cterm(hex_color) local function get_color_distance(color1, color2) -- returns how much color2 deviates from color1 @@ -300,6 +303,9 @@ function M.rgb2cterm(hex_color) return closest_cterm_color end +---converts color name (only ones supported by neovim) formated colors to #rrggbb +---@param name string like red,green,grey +---@return string function M.color_name2rgb(name) local color_val = vim.api.nvim_get_color_by_name(name) if color_val == -1 then @@ -308,6 +314,9 @@ function M.color_name2rgb(name) return string.format('#%06x', color_val) end +---converts cterm(0-255) to #rrggbb +---@param color number +---@return string function M.cterm2rgb(color) local color_data = color_table[color + 1] if color_data ~= nil then diff --git a/lua/lualine/utils/job.lua b/lua/lualine/utils/job.lua index a5e5586..4e49bde 100644 --- a/lua/lualine/utils/job.lua +++ b/lua/lualine/utils/job.lua @@ -1,12 +1,15 @@ -- Copyright (c) 2020-2021 shadmansaleh -- MIT license, see LICENSE for more details. --- Wrapper arround job api +--- wrapper arround job api +--- creates a job handler when called local Job = setmetatable({ + --- start the job start = function(self) self.job_id = vim.fn.jobstart(self.args.cmd, self.args) return self.job_id > 0 end, + --- stop the job. also imidiately disables io from the job. stop = function(self) if self.killed then return @@ -30,6 +33,10 @@ local Job = setmetatable({ end end, }, { + ---create new job handler + ---@param self table base job table + ---@param args table same args as jobstart except cmd is also passed in part of it + ---@return table new job handler __call = function(self, args) args = vim.deepcopy(args or {}) if type(args.cmd) == 'string' then diff --git a/lua/lualine/utils/loader.lua b/lua/lualine/utils/loader.lua index ef79d13..7711add 100644 --- a/lua/lualine/utils/loader.lua +++ b/lua/lualine/utils/loader.lua @@ -7,13 +7,15 @@ local modules = lualine_require.lazy_require { notice = 'lualine.utils.notices', } local is_valid_filename = lualine_require.is_valid_filename - local sep = lualine_require.sep +--- function that loads specific type of component local component_types = { + --- loads lua functions as component lua_fun = function(component) return require 'lualine.components.special.function_component'(component) end, + --- loads lua modules as components (ones in /lua/lualine/components/) mod = function(component) local ok, loaded_component = pcall(require, 'lualine.components.' .. component[1]) if ok then @@ -27,6 +29,7 @@ local component_types = { return loaded_component end end, + --- loads builtin statusline patterns as component stl = function(component) local stl_expr = component[1] -- Vim's %p %l statusline elements component[1] = function() @@ -34,14 +37,19 @@ local component_types = { end return require 'lualine.components.special.function_component'(component) end, + --- loads variables & options (g:,go:,b:,bo:...) as componenta var = function(component) return require 'lualine.components.special.vim_var_component'(component) end, + --- loads vim functions and lua expressions as components ['_'] = function(component) return require 'lualine.components.special.eval_func_component'(component) end, } +---load a component from component confif +---@param component table component + component options +---@return table the loaded & initialized component local function component_loader(component) if type(component[1]) == 'function' then return component_types.lua_fun(component) @@ -114,6 +122,9 @@ You'll have to change it to this to retain old behavior: end end +---loads all the section from a config +---@param sections table list of sections +---@param options table global options table local function load_sections(sections, options) for section_name, section in pairs(sections) do for index, component in pairs(section) do @@ -130,12 +141,16 @@ local function load_sections(sections, options) end end +---loads all the configs (active, inactive, tabline) +---@param config table user config local function load_components(config) load_sections(config.sections, config.options) load_sections(config.inactive_sections, config.options) load_sections(config.tabline, config.options) end +---loads all the extensions +---@param config table user confif local function load_extensions(config) local loaded_extensions = {} for _, extension in pairs(config.extensions) do @@ -175,11 +190,17 @@ Extension named `%s` was not found . Check if spelling is correct. config.extensions = loaded_extensions end +---loads sections and extensions or entire user config +---@param config table user config local function load_all(config) load_components(config) load_extensions(config) end +---loads a theme from lua module +---priotizes external themes (from user config or other plugins) over the bundled ones +---@param theme_name string +---@return table theme defination from module local function load_theme(theme_name) assert(is_valid_filename(theme_name), 'Invalid filename') local retval diff --git a/lua/lualine/utils/mode.lua b/lua/lualine/utils/mode.lua index a48280f..9f96d4c 100644 --- a/lua/lualine/utils/mode.lua +++ b/lua/lualine/utils/mode.lua @@ -1,6 +1,7 @@ -- Copyright (c) 2020-2021 hoob3rt -- MIT license, see LICENSE for more details. local Mode = {} + -- stylua: ignore Mode.map = { ['n'] = 'NORMAL', @@ -40,6 +41,7 @@ Mode.map = { ['t'] = 'TERMINAL', } +---@return string current mode name function Mode.get_mode() local mode_code = vim.api.nvim_get_mode().mode if Mode.map[mode_code] == nil then diff --git a/lua/lualine/utils/notices.lua b/lua/lualine/utils/notices.lua index ab3ff2c..f762f1f 100644 --- a/lua/lualine/utils/notices.lua +++ b/lua/lualine/utils/notices.lua @@ -6,6 +6,8 @@ local M = {} local notices = {} local persistent_notices = {} +---append new notice +---@param notice string|table table is a list of strings function M.add_notice(notice) if type(notice) == 'string' then notice = vim.split(notice, '\n') @@ -13,6 +15,8 @@ function M.add_notice(notice) table.insert(notices, notice) end +---appends persistent notice. These don't get cleared on setup +---@param notice string|table table is a list of strings function M.add_persistent_notice(notice) if type(notice) == 'string' then notice = vim.split(notice, '\n') @@ -22,6 +26,8 @@ function M.add_persistent_notice(notice) end end +---show setup :LuaLineNotices and show notification about error when there +---are notices available function M.notice_message_startup() if #notices > 0 or #persistent_notices then vim.cmd 'command! -nargs=0 LualineNotices lua require"lualine.utils.notices".show_notices()' @@ -35,6 +41,7 @@ function M.notice_message_startup() end end +---create notice view function M.show_notices() vim.cmd 'silent! keepalt split' @@ -54,7 +61,7 @@ function M.show_notices() local ok, _ = pcall(vim.api.nvim_buf_set_name, 0, 'Lualine Notices') if not ok then - vim.notify('Lualine Notices is already open in another window', vim.log.levels.ERROR, {}) + vim.notify('Lualine Notices is already open in another buffer', vim.log.levels.ERROR, {}) vim.cmd 'normal q' return end diff --git a/lua/lualine/utils/section.lua b/lua/lualine/utils/section.lua index cb5f11b..3d1d42d 100644 --- a/lua/lualine/utils/section.lua +++ b/lua/lualine/utils/section.lua @@ -4,7 +4,16 @@ local M = {} local require = require('lualine_require').require local utils = require 'lualine.utils.utils' local highlight = require 'lualine.highlight' --- Returns formated string for a section + +---runs draw function on components in section +---handles separator edge cases :/ +---also handles default transitional separators at section boundaries +---(why? I don't know) +---@param section table list of components +---@param section_name string used for getting proper hl +---@param is_focused boolean +---@return string formated string for a section +--TODO Clean this up this does lots of messy stuff. function M.draw_section(section, section_name, is_focused) local highlight_name = highlight.format_highlight('lualine_' .. section_name, is_focused) diff --git a/lua/lualine/utils/utils.lua b/lua/lualine/utils/utils.lua index 6337363..b089601 100644 --- a/lua/lualine/utils/utils.lua +++ b/lua/lualine/utils/utils.lua @@ -4,6 +4,10 @@ local M = {} -- Note for now only works for termguicolors scope can be bg or fg or any other -- attr parameter like bold/italic/reverse +---@param color_group string hl_group name +---@param scope string bg | fg +---@return table|string returns #rrggbb formated color when scope is specified +---- or comolete color table when scope isn't specified function M.extract_highlight_colors(color_group, scope) if vim.fn.hlexists(color_group) == 0 then return nil @@ -23,8 +27,12 @@ function M.extract_highlight_colors(color_group, scope) return color end --- retrives color value from highlight group name in syntax_list --- first present highlight is returned +--- retrives color value from highlight group name in syntax_list +--- first present highlight is returned +---@param scope string +---@param syntaxlist table +---@param default string +---@return string|nil function M.extract_color_from_hllist(scope, syntaxlist, default) for _, highlight_name in ipairs(syntaxlist) do if vim.fn.hlexists(highlight_name) ~= 0 then @@ -44,7 +52,9 @@ function M.extract_color_from_hllist(scope, syntaxlist, default) return default end --- remove empty strings from list +---remove empty strings from list +---@param list table +---@return table function M.list_shrink(list) local new_list = {} for i = 1, #list do @@ -55,12 +65,19 @@ function M.list_shrink(list) return new_list end --- Check if a auto command is already defined +--- Check if a auto command is already defined +---@param event string +---@param patern string +---@param command_str string +---@return boolean whether autocmd is already defined local function autocmd_is_defined(event, patern, command_str) return vim.api.nvim_exec(string.format('au lualine %s %s', event, patern), true):find(command_str) ~= nil end --- Define a auto command if it's not already defined +--- Define a auto command if it's not already defined +---@param event string event name +---@param patern string event patern +---@param cmd string command to run on event function M.define_autocmd(event, patern, cmd) if not cmd then cmd = patern @@ -76,6 +93,10 @@ function M.is_focused() return tonumber(vim.g.actual_curwin) == vim.fn.win_getid() end +--- Check what's the charecter at pos +---@param str string +---@param pos number +---@return string charecter at position pos in string str function M.charAt(str, pos) return string.char(str:byte(pos)) end diff --git a/lua/lualine_require.lua b/lua/lualine_require.lua index 6126104..b758180 100644 --- a/lua/lualine_require.lua +++ b/lua/lualine_require.lua @@ -4,6 +4,7 @@ local M = {} M.sep = package.config:sub(1, 1) +-- Figures ou full path of lualine installation local source = debug.getinfo(1, 'S').source if source:sub(1, 1) == '@' then local base_start = source:find(table.concat({ 'lualine.nvim', 'lua', 'lualine_require.lua' }, M.sep)) @@ -15,11 +16,17 @@ if source:sub(1, 1) == '@' then end end +--- checks if name is valied +---@param name string +---@return boolean function M.is_valid_filename(name) local invalid_chars = '[^a-zA-Z0-9_. -]' return name:find(invalid_chars) == nil end +---require module module +---@param module string mogule arraived +---@return any the required module function M.require(module) if package.loaded[module] then return package.loaded[module] @@ -61,6 +68,10 @@ function M.require(module) return require(module) end +---requires modules when they are used +---@param modules table k-v table where v is module path and k is name that will +--- be indexed +---@return table metatable where when a key is indexed it gets required and cached function M.lazy_require(modules) return setmetatable({}, { __index = function(self, key)