From 4ec9dfc708e32af0982d33832b8845189b82cd14 Mon Sep 17 00:00:00 2001 From: Tran Vo Son Tung Date: Mon, 6 Nov 2023 17:36:55 +0700 Subject: [PATCH 1/7] init branch --- lua/sttusline/utils/array.lua | 51 +++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 lua/sttusline/utils/array.lua diff --git a/lua/sttusline/utils/array.lua b/lua/sttusline/utils/array.lua new file mode 100644 index 0000000..cb039d0 --- /dev/null +++ b/lua/sttusline/utils/array.lua @@ -0,0 +1,51 @@ +local M = {} +local MAX_DEPTH = 10 -- Maximum depth of nested table + +M.foreach = function(array, func, depth) + depth = depth or 0 + for index, value in ipairs(array) do + if type(value) == "table" then + if depth < MAX_DEPTH then + M.foreach(value, func, depth + 1) + else + require("sttusline.utils.notify").error("Maximum depth of nested table exceeded") + end + else + func(index, value) + end + end +end + +M.map = function(array, func, depth) + depth = depth or 0 + local result = {} + for index, value in ipairs(array) do + if type(value) == "table" then + if depth < MAX_DEPTH then result[index] = M.map(value, func, depth + 1) end + else + require("sttusline.utils.notify").error("Maximum depth of nested table exceeded") + end + end + return result +end + +M.extend = function(array, another_array) table.insert(array, another_array) end + +M.concat = function(array, separator, depth) + depth = depth or 0 + local result = {} + for _, value in ipairs(array) do + if type(value) == "table" then + if depth < MAX_DEPTH then + table.insert(result, M.concat(value, separator, depth + 1)) + else + require("sttusline.utils.notify").error("Maximum depth of nested table exceeded") + end + else + table.insert(result, value) + end + end + return table.concat(result, separator) +end + +return M From bafcf921db2b15323c16031746013df9ad120e4d Mon Sep 17 00:00:00 2001 From: Tran Vo Son Tung Date: Mon, 6 Nov 2023 23:45:31 +0700 Subject: [PATCH 2/7] refractor and clean some function --- lua/sttusline/api.lua | 381 ++++++++++++++++++ lua/sttusline/highlight.lua | 42 ++ lua/sttusline/utils/NestedTable.lua | 76 ++++ .../utils/{array.lua => nested_array.lua} | 0 4 files changed, 499 insertions(+) create mode 100644 lua/sttusline/api.lua create mode 100644 lua/sttusline/highlight.lua create mode 100644 lua/sttusline/utils/NestedTable.lua rename lua/sttusline/utils/{array.lua => nested_array.lua} (100%) diff --git a/lua/sttusline/api.lua b/lua/sttusline/api.lua new file mode 100644 index 0000000..dcb2cd6 --- /dev/null +++ b/lua/sttusline/api.lua @@ -0,0 +1,381 @@ +local M = {} + +-- constants +local COMPONENT_PARENT_MODULE = "sttusline.components" +local AUTOCMD_CORE_GROUP = "STTUSLINE_CORE_EVENTS" +local AUTOCMD_COMPONENT_GROUP = "STTUSLINE_COMPONENT_EVENTS" + +local api = vim.api +local opt = vim.opt +local autocmd = api.nvim_create_autocmd +local augroup = api.nvim_create_augroup + +-- module +local highlight = require("sttusline.highlight") +-- local NestedTable = require("sttusline.utils.NestedTable") + +-- local vars +local core_autocmd_group = nil +local component_autocmd_group = nil +local timer = nil +local statusline_hidden = false + +local statusline = {} +-- save the valid component after the first time call M.foreach_component +local components = {} + +local catalog = { + event = { + -- save the index of the component that update when the event trigger + -- the value is the table of the indexs of the component that update when the event trigger + -- example: { BufEnter = { 1, 2, 3 }, BufWritePre = { 1, 2, 3 } } + + -- the key is the name of the default event + nvim = {}, + -- the key is the name of user defined event + user = {}, + }, + + -- save the index of the component that update when the timer trigger + timer = {}, +} + +local update_groups = { + CURSOR_MOVING = { + childs = { + -- the index of the component belong to the group + }, + value = { + event = { "CursorMoved", "CursorMovedI" }, + user_event = { "VeryLazy" }, + timing = false, + }, + }, +} + +M.get_component_autocmd_group = function() + if component_autocmd_group == nil then + component_autocmd_group = augroup(AUTOCMD_COMPONENT_GROUP, { clear = true }) + end + return component_autocmd_group +end + +M.get_core_autocmd_group = function() + if core_autocmd_group == nil then + core_autocmd_group = augroup(AUTOCMD_CORE_GROUP, { clear = true }) + end + return core_autocmd_group +end + +M.update_statusline = function() + local str_statusline = table.concat(statusline, "") + opt.statusline = #str_statusline > 0 and str_statusline or " " +end + +M.eval_func = function(func, ...) + if type(func) == "function" then return func(...) end +end + +M.eval_component_func = function(component, func_name, ...) + local configs = type(component.configs) == "table" and component.configs or {} + local space = nil + + if type(component.space) == "function" then + space = component.space(configs) + elseif type(component.space) == "table" then + space = component.space + end + + return M.eval_func(component[func_name], configs, space, ...) +end + +M.is_sub_table_child = function(child) return type(child) == "table" and type(child[1]) == "string" end + +-- this function will add padding to the updating value of the component +M.add_component_padding = function(component, nums) + if #component == 0 then return component end + + local left_padding = " " -- default left padding is 1 space + local right_padding = " " -- default right padding is 1 space + + if type(nums) == "number" then + if nums < 1 then return component end -- no padding + left_padding = (" "):rep(math.floor(nums)) + right_padding = left_padding + elseif type(nums) == "table" then + local left = type(nums.left) == "number" and nums.left or 1 + local right = type(nums.right) == "number" and nums.right or 1 + left_padding = left < 1 and "" or (" "):rep(math.floor(left)) + right_padding = right < 1 and "" or (" "):rep(math.floor(right)) + end + + if type(component) == "string" then + return left_padding .. component .. right_padding + else -- component is a table + local first_element = component[1] + local last_element = component[#component] + + if type(first_element) == "string" then + component[1] = left_padding .. first_element + elseif M.is_sub_table_child(first_element) then + first_element[1] = left_padding .. first_element[1] + end + + if type(last_element) == "string" then + component[#component] = last_element .. right_padding + elseif M.is_sub_table_child(last_element) then + last_element[1] = last_element[1] .. right_padding + end + return component + end +end + +M.tbl_contains = function(tbl, item) + if type(tbl) ~= "table" then return false end + for _, value in ipairs(tbl) do + if value == item then return true end + end + return false +end + +M.is_in_disabled_opts = function(opts) + return M.tbl_contains(opts.disabled.filetypes, api.nvim_buf_get_option(0, "filetype")) + or M.tbl_contains(opts.disabled.buftypes, api.nvim_buf_get_option(0, "buftype")) +end + +M.disable_for_filetype = function(opts) + local event_trigger = false + autocmd({ "BufEnter", "WinEnter" }, { + group = M.get_core_autocmd_group(), + callback = function() + if not event_trigger then + event_trigger = true + vim.schedule(function() + if M.is_in_disabled_opts(opts) then + M.hide_statusline() + else + M.restore_statusline(opts) + end + end, 0) + end + end, + }) + autocmd({ "BufLeave", "WinLeave" }, { + group = M.get_core_autocmd_group(), + callback = function() event_trigger = false end, + }) +end + +M.hide_statusline = function() + if not statusline_hidden then + statusline_hidden = true + vim.schedule(function() opt.statusline = " " end, 0) + end +end + +M.restore_statusline = function(opts) + if statusline_hidden then + statusline_hidden = false + M.update_all_components(opts) + M.update_statusline() + end +end + +M.foreach_component = function(opts, comp_cb, empty_comp_cb) + if #components > 0 then + for index, component in ipairs(components) do + if type(component) == "string" then + M.eval_func(empty_comp_cb, component, index) + else + comp_cb(component, index) + end + end + else + local index = 0 + + local cache_and_eval_comp_cb = function(component, callback) + index = index + 1 + components[index] = component + M.eval_func(callback, component, index) + end + + local load_default_component = function(component_name, overrides) + local status_ok, real_comp = pcall(require, COMPONENT_PARENT_MODULE .. "." .. component_name) + if status_ok then + if type(overrides) == "table" then + real_comp = vim.tbl_deep_extend("force", real_comp, overrides) + end + cache_and_eval_comp_cb(real_comp, comp_cb) + else + require("sttusline.utils.notify").error("Failed to load component: " .. component_name) + end + end + + for _, component in ipairs(opts.components) do + if type(component) == "string" then + if component == "%=" then -- empty component + cache_and_eval_comp_cb(component, empty_comp_cb) + else -- default component name + load_default_component(component) + end + elseif type(component) == "table" and next(component) then + if type(component[1]) == "string" then -- default component name + load_default_component(component[1], component[2]) + else -- custom component + cache_and_eval_comp_cb(component, comp_cb) + end + end + end + end +end + +M.start_timer = function(opts) + if timer == nil then timer = vim.loop.new_timer() end + timer:start( + 1000, + 1000, + vim.schedule_wrap(function() + if not statusline_hidden then M.run(opts) end + end) + ) +end + +M.init_component_timer = function(opts) + if #catalog.timer > 0 then M.start_timer(opts) end +end + +M.set_component_highlight = function(opts, component, index) + local colors = component.colors + if type(colors) == "table" then + if colors[1] == nil then + highlight.set_hl(highlight.gen_component_hl_name(index), colors, opts.statusline_color) + else + for k, color in ipairs(colors) do + highlight.set_hl(highlight.gen_component_hl_name(index, k), color, opts.statusline_color) + end + end + end + M.eval_component_func(component, "on_highlight") +end + +M.set_all_component_highlight = function(opts) + M.foreach_component( + opts, + function(component, index) M.set_component_highlight(opts, component, index) end + ) +end + +M.refresh_highlight_on_colorscheme = function(opts) + autocmd("ColorScheme", { + group = M.get_core_autocmd_group(), + callback = function() M.set_all_component_highlight(opts) end, + }) +end + +M.update_component_value = function(opts, component, index) + local should_display = M.eval_component_func(component, "condition") + if type(should_display) == "boolean" and not should_display then + statusline[index] = "" + return + end + + local updating_value = M.eval_component_func(component, "update") + -- updating_value is string or table + -- If updating_value is table, then it must be a table of string or table of {string, table (highlight_option)} + -- Example: + -- table of string: { "filename", "filetype_icon" } + -- table of {string, table}: { {"filename", { fg="", bg="" }}, {"filetype_icon", { fg="", bg="" }} } + -- table of {string, nil}: { { "filename" }, { "filetype_icon" } } + + local colors = component.colors + if type(updating_value) == "string" then + updating_value = M.add_component_padding(updating_value, component.padding) + if highlight.is_highlight_option(colors) then + -- if assign colors to component, then add highlight name to component + statusline[index] = + highlight.add_highlight_name(updating_value, highlight.gen_component_hl_name(index)) + elseif highlight.is_highlight_name(colors) then + -- if assign the highlight name to component, then add that highlight name to component + statusline[index] = highlight.add_highlight_name(updating_value, colors) + else + -- if not assign colors to component, then not need to add highlight name + statusline[index] = updating_value + end + elseif type(updating_value) == "table" then + updating_value = M.add_component_padding(updating_value, component.padding) + for k, child in ipairs(updating_value) do + if type(child) == "string" then + -- "filename" + if type(colors) == "table" then -- is assigned colors to component + if highlight.is_highlight_option(colors[k]) then + updating_value[k] = + highlight.add_highlight_name(child, highlight.gen_component_hl_name(index, k)) + elseif highlight.is_highlight_name(colors[k]) then + updating_value[k] = highlight.add_highlight_name(child, colors[k]) + end + else + updating_value[k] = child + end + elseif M.is_sub_table_child(child) then + if highlight.is_highlight_option(child[2]) then + -- { "filename", { fg="", bg="" }} + component.colors = colors or {} + component.colors[k] = child[2] + + local component_hl_name = highlight.gen_component_hl_name(index, k) + updating_value[k] = highlight.add_highlight_name(child[1], component_hl_name) + highlight.set_hl(component_hl_name, child[2], opts.statusline_color) + + M.eval_component_func(component, "on_highlight") + elseif highlight.is_highlight_name(child[2]) then + -- { "filename", "HIGHLIGHT_NAME" } + updating_value[k] = highlight.add_highlight_name(child[1], child[2]) + else + -- {"filename"} + updating_value[k] = child[1] + end + else + statusline[index] = "" + require("sttusline.utils.notify").error( + string.format( + "component %s update() must return string or table of string or table of {string, table}", + component.name or "" + ) + ) + return + end + end + statusline[index] = table.concat(updating_value, "") + else + statusline[index] = "" + require("sttusline.utils.notify").error( + string.format( + "component %s update() must return string or table of string or table of {string, table}", + component.name or "" + ) + ) + end +end + +M.update_all_components = function(opts) + M.foreach_component( + opts, + function(component, index) M.update_component_value(opts, component, index) end + ) +end + +M.update_on_trigger = function(opts, indexs) + for _, index in ipairs(indexs) do + M.update_component_value(opts, components[index], index) + end +end + +M.run = function(opts, event_name, is_user_event) + local event_table = is_user_event and catalog.event.user or catalog.event.nvim + vim.schedule(function() + M.update_on_trigger(opts, event_name and event_table[event_name] or catalog.timer) + if not statusline_hidden then M.update_statusline() end + end, 0) +end + +return M diff --git a/lua/sttusline/highlight.lua b/lua/sttusline/highlight.lua new file mode 100644 index 0000000..0f10a38 --- /dev/null +++ b/lua/sttusline/highlight.lua @@ -0,0 +1,42 @@ +local HIGHLIGHT_COMPONENT_PREFIX = "STTUSLINE_COMPONENT_" + +local api = vim.api +local M = {} + +M.is_highlight_option = function(hl_opts) return type(hl_opts) == "table" and next(hl_opts) ~= nil end + +M.is_highlight_name = function(hl_name) return type(hl_name) == "string" and #hl_name > 0 end + +M.is_color = function(color) return type(color) == "string" and color:match("^#%x%x%x%x%x%x$") end + +M.add_highlight_name = function(str, hl_name) + return #str > 0 and "%#" .. hl_name .. "#" .. str .. "%*" or "" +end + +M.get_hl_name_color = function(hl_name) + local ok, colors = pcall(api.nvim_get_hl_by_name, hl_name, true) + return ok and colors or {} +end + +M.gen_component_hl_name = function(...) return HIGHLIGHT_COMPONENT_PREFIX .. table.concat({ ... }, "_") end + +M.set_hl = function(group, hl_opts, fallback_bg) + if not M.is_highlight_option(hl_opts) then return end + + if hl_opts.fg and not M.is_color(hl_opts.fg) then + hl_opts.fg = M.get_hl_name_color(hl_opts.fg).foreground + end + + if hl_opts.bg then + hl_opts.bg = M.is_color(hl_opts.bg) and hl_opts.bg or M.get_hl_name_color(hl_opts.bg).background + elseif fallback_bg then + -- fallback to fallback_bg if provided + hl_opts.bg = M.is_color(fallback_bg) and fallback_bg or M.get_hl_name_color(fallback_bg).background + else + -- fallback to StatusLine background + hl_opts.bg = M.get_hl_name_color("StatusLine").background + end + pcall(api.nvim_set_hl, 0, group, hl_opts) +end + +return M diff --git a/lua/sttusline/utils/NestedTable.lua b/lua/sttusline/utils/NestedTable.lua new file mode 100644 index 0000000..602fbda --- /dev/null +++ b/lua/sttusline/utils/NestedTable.lua @@ -0,0 +1,76 @@ +local MAX_DEPTH = 10 +local NestedTable = {} +NestedTable.__index = NestedTable + +function NestedTable:new(table) + table = table or {} + if type(table) ~= "table" then error("NestedTable:new() expects a table, got " .. type(table)) end + return setmetatable(table, self) +end + +function NestedTable:mapi(func, depth) + depth = depth or 1 + if depth > MAX_DEPTH then error("NestedTable:mapi() reached max depth") end + local new_table = {} + for k, v in pairs(self) do + if type(v) == "table" then + if getmetatable(v) == NestedTable then + new_table[k] = v:mapi(func, depth + 1) + else + new_table[k] = NestedTable:new(v):mapi(func, depth + 1) + end + else + new_table[k] = func(v, k) + end + end + return NestedTable:new(new_table) +end + +function NestedTable:foreachi(func, depth) + depth = depth or 1 + if depth > MAX_DEPTH then error("NestedTable:foreachi() reached max depth") end + for k, v in ipairs(self) do + if type(v) == "table" then + if getmetatable(v) == NestedTable then + v:foreachi(func, depth + 1) + else + NestedTable:new(v):foreachi(func, depth + 1) + end + else + func(v, k) + end + end +end + +function NestedTable:insert(value, pos) + pos = pos or #self + 1 + if type(value) == "table" then + if getmetatable(value) == NestedTable then + table.insert(self, pos, value) + else + table.insert(self, pos, NestedTable:new(value)) + end + else + table.insert(self, pos, value) + end +end + +function NestedTable:remove(pos) table.remove(self, pos) end + +function NestedTable:concat(sep, i, j) + local t = {} + for k, v in ipairs(self) do + if type(v) == "table" then + if getmetatable(v) == NestedTable then + t[k] = v:concat(sep, i, j) + else + t[k] = NestedTable:new(v):concat(sep, i, j) + end + else + t[k] = v + end + end + return table.concat(t, sep, i, j) +end + +return NestedTable diff --git a/lua/sttusline/utils/array.lua b/lua/sttusline/utils/nested_array.lua similarity index 100% rename from lua/sttusline/utils/array.lua rename to lua/sttusline/utils/nested_array.lua From 0fdfcef3a022d8146dd298d9a0044dbd360806c4 Mon Sep 17 00:00:00 2001 From: Tran Vo Son Tung Date: Wed, 8 Nov 2023 14:40:25 +0700 Subject: [PATCH 3/7] refractor and clean some function --- lua/sttusline.lua | 5 +- lua/sttusline/api.lua | 170 +++++--- lua/sttusline/components/copilot.lua | 6 +- lua/sttusline/components/git-branch.lua | 2 +- lua/sttusline/config.lua | 54 ++- lua/sttusline/runner.lua | 369 ------------------ .../templates/component_template.lua | 3 +- lua/sttusline/utils/NestedTable.lua | 76 ---- lua/sttusline/utils/init.lua | 122 ------ lua/sttusline/utils/nested_array.lua | 51 --- 10 files changed, 152 insertions(+), 706 deletions(-) delete mode 100644 lua/sttusline/runner.lua delete mode 100644 lua/sttusline/utils/NestedTable.lua delete mode 100644 lua/sttusline/utils/init.lua delete mode 100644 lua/sttusline/utils/nested_array.lua diff --git a/lua/sttusline.lua b/lua/sttusline.lua index 8fc3879..d10e238 100644 --- a/lua/sttusline.lua +++ b/lua/sttusline.lua @@ -1,11 +1,10 @@ local config = require("sttusline.config") -local runner = require("sttusline.runner") - +local api = require("sttusline.api") local M = {} M.setup = function(user_opts) local opts = config.setup(user_opts) - runner.setup(opts) + api.setup(opts) end return M diff --git a/lua/sttusline/api.lua b/lua/sttusline/api.lua index dcb2cd6..67895dc 100644 --- a/lua/sttusline/api.lua +++ b/lua/sttusline/api.lua @@ -9,10 +9,10 @@ local api = vim.api local opt = vim.opt local autocmd = api.nvim_create_autocmd local augroup = api.nvim_create_augroup +local concat = table.concat -- module local highlight = require("sttusline.highlight") --- local NestedTable = require("sttusline.utils.NestedTable") -- local vars local core_autocmd_group = nil @@ -20,7 +20,9 @@ local component_autocmd_group = nil local timer = nil local statusline_hidden = false +-- save the updating value of the component local statusline = {} + -- save the valid component after the first time call M.foreach_component local components = {} @@ -31,28 +33,23 @@ local catalog = { -- example: { BufEnter = { 1, 2, 3 }, BufWritePre = { 1, 2, 3 } } -- the key is the name of the default event - nvim = {}, + nvim = { + -- The number of the event that the component listen to + length = 0, + keys = {}, + }, -- the key is the name of user defined event - user = {}, + user = { + -- The number of the event that the component listen to + length = 0, + keys = {}, + }, }, -- save the index of the component that update when the timer trigger timer = {}, } -local update_groups = { - CURSOR_MOVING = { - childs = { - -- the index of the component belong to the group - }, - value = { - event = { "CursorMoved", "CursorMovedI" }, - user_event = { "VeryLazy" }, - timing = false, - }, - }, -} - M.get_component_autocmd_group = function() if component_autocmd_group == nil then component_autocmd_group = augroup(AUTOCMD_COMPONENT_GROUP, { clear = true }) @@ -67,8 +64,52 @@ M.get_core_autocmd_group = function() return core_autocmd_group end +M.create_default_autocmd = function(opts, event) + autocmd(event, { + group = M.get_component_autocmd_group(), + callback = function(e) M.run(opts, e.event) end, + }) +end + +M.create_user_autocmd = function(opts, event) + autocmd("User", { + pattern = event, + group = M.get_component_autocmd_group(), + callback = function(e) M.run(opts, e.match, true) end, + }) +end + +local add_event_index_entry = function(event, index, cache_key) + local event_table = catalog.event[cache_key] + local catalog_event = event_table[event] + if catalog_event == nil then + event_table[event] = { index } + event_table.length = (event_table.length or 0) + 1 + event_table.keys[event_table.length] = event + else + catalog_event[#catalog_event + 1] = index + end +end + +M.index_event_catalog = function(event, index, cache_key) + if type(event) == "table" then + for _, e in ipairs(event) do + add_event_index_entry(e, index, cache_key) + end + elseif type(event) == "string" then + add_event_index_entry(event, index, cache_key) + end +end + +M.init_component_autocmds = function(opts) + local nvim_keys = catalog.event.nvim.keys + local user_keys = catalog.event.user.keys + if next(nvim_keys) then M.create_default_autocmd(opts, nvim_keys) end + if next(user_keys) then M.create_user_autocmd(opts, user_keys) end +end + M.update_statusline = function() - local str_statusline = table.concat(statusline, "") + local str_statusline = concat(statusline, "") opt.statusline = #str_statusline > 0 and str_statusline or " " end @@ -77,16 +118,17 @@ M.eval_func = function(func, ...) end M.eval_component_func = function(component, func_name, ...) - local configs = type(component.configs) == "table" and component.configs or {} + local comp_configs = type(component.configs) == "table" and component.configs or {} + local space = nil if type(component.space) == "function" then - space = component.space(configs) + space = component.space(comp_configs) elseif type(component.space) == "table" then space = component.space end - return M.eval_func(component[func_name], configs, space, ...) + return M.eval_func(component[func_name], comp_configs, space, ...) end M.is_sub_table_child = function(child) return type(child) == "table" and type(child[1]) == "string" end @@ -138,7 +180,7 @@ M.tbl_contains = function(tbl, item) return false end -M.is_in_disabled_opts = function(opts) +M.should_statusline_hidden = function(opts) return M.tbl_contains(opts.disabled.filetypes, api.nvim_buf_get_option(0, "filetype")) or M.tbl_contains(opts.disabled.buftypes, api.nvim_buf_get_option(0, "buftype")) end @@ -151,7 +193,7 @@ M.disable_for_filetype = function(opts) if not event_trigger then event_trigger = true vim.schedule(function() - if M.is_in_disabled_opts(opts) then + if M.should_statusline_hidden(opts) then M.hide_statusline() else M.restore_statusline(opts) @@ -182,8 +224,10 @@ M.restore_statusline = function(opts) end M.foreach_component = function(opts, comp_cb, empty_comp_cb) - if #components > 0 then - for index, component in ipairs(components) do + local component_count = #components + if component_count > 0 then + for index = 1, component_count do + local component = components[index] if type(component) == "string" then M.eval_func(empty_comp_cb, component, index) else @@ -191,12 +235,13 @@ M.foreach_component = function(opts, comp_cb, empty_comp_cb) end end else - local index = 0 - - local cache_and_eval_comp_cb = function(component, callback) - index = index + 1 - components[index] = component - M.eval_func(callback, component, index) + -- Why not call callback in this function? + -- Because i want that the comp_cb always be a function that receive 2 arguments, and empty_comp_cb can be nil + -- And if it not exist, then the compiler will throw an error + -- If we call M.eval_func(cb,component,index) in this function so the comp_cb can be any other types + local cache_component = function(component) + component_count = component_count + 1 + components[component_count] = component end local load_default_component = function(component_name, overrides) @@ -205,7 +250,8 @@ M.foreach_component = function(opts, comp_cb, empty_comp_cb) if type(overrides) == "table" then real_comp = vim.tbl_deep_extend("force", real_comp, overrides) end - cache_and_eval_comp_cb(real_comp, comp_cb) + cache_component(real_comp) + comp_cb(real_comp, component_count) else require("sttusline.utils.notify").error("Failed to load component: " .. component_name) end @@ -214,7 +260,8 @@ M.foreach_component = function(opts, comp_cb, empty_comp_cb) for _, component in ipairs(opts.components) do if type(component) == "string" then if component == "%=" then -- empty component - cache_and_eval_comp_cb(component, empty_comp_cb) + cache_component(component) + M.eval_func(empty_comp_cb, component, component_count) else -- default component name load_default_component(component) end @@ -222,7 +269,8 @@ M.foreach_component = function(opts, comp_cb, empty_comp_cb) if type(component[1]) == "string" then -- default component name load_default_component(component[1], component[2]) else -- custom component - cache_and_eval_comp_cb(component, comp_cb) + cache_component(component) + comp_cb(component, component_count) end end end @@ -231,17 +279,15 @@ end M.start_timer = function(opts) if timer == nil then timer = vim.loop.new_timer() end - timer:start( - 1000, - 1000, - vim.schedule_wrap(function() - if not statusline_hidden then M.run(opts) end - end) - ) + timer:start(1000, 1000, vim.schedule_wrap(function() M.run(opts) end)) +end + +M.index_timer_catalog = function(component, index) + if component.timming == true then catalog.timer[#catalog.timer + 1] = index end end M.init_component_timer = function(opts) - if #catalog.timer > 0 then M.start_timer(opts) end + if next(catalog.timer) then M.start_timer(opts) end end M.set_component_highlight = function(opts, component, index) @@ -284,7 +330,7 @@ M.update_component_value = function(opts, component, index) -- If updating_value is table, then it must be a table of string or table of {string, table (highlight_option)} -- Example: -- table of string: { "filename", "filetype_icon" } - -- table of {string, table}: { {"filename", { fg="", bg="" }}, {"filetype_icon", { fg="", bg="" }} } + -- table of {string, table}: { { "filename", { fg="", bg="" } }, { "filetype_icon", { fg="", bg="" }} } -- table of {string, nil}: { { "filename" }, { "filetype_icon" } } local colors = component.colors @@ -339,19 +385,19 @@ M.update_component_value = function(opts, component, index) require("sttusline.utils.notify").error( string.format( "component %s update() must return string or table of string or table of {string, table}", - component.name or "" + type(component) == "string" and component or component.name or "" ) ) return end end - statusline[index] = table.concat(updating_value, "") + statusline[index] = concat(updating_value, "") else statusline[index] = "" require("sttusline.utils.notify").error( string.format( "component %s update() must return string or table of string or table of {string, table}", - component.name or "" + type(component) == "string" and component or component.name or "" ) ) end @@ -364,18 +410,46 @@ M.update_all_components = function(opts) ) end -M.update_on_trigger = function(opts, indexs) - for _, index in ipairs(indexs) do +M.update_on_trigger = function(opts, update_indexs) + for _, index in ipairs(update_indexs) do M.update_component_value(opts, components[index], index) end end M.run = function(opts, event_name, is_user_event) + if statusline_hidden then return end + local event_table = is_user_event and catalog.event.user or catalog.event.nvim vim.schedule(function() M.update_on_trigger(opts, event_name and event_table[event_name] or catalog.timer) - if not statusline_hidden then M.update_statusline() end + M.update_statusline() end, 0) end +M.init = function(opts) + M.foreach_component(opts, function(component, index) + M.eval_component_func(component, "init") + if component.lazy == false then + M.update_component_value(opts, component, index) + else + statusline[index] = "" + end + + M.index_event_catalog(component.event, index, "nvim") + M.index_event_catalog(component.user_event, index, "user") + M.index_timer_catalog(component, index) + M.set_component_highlight(opts, component, index) + end, function(empty_comp, index) statusline[index] = empty_comp end) + + M.init_component_autocmds(opts) + M.init_component_timer(opts) +end + +M.setup = function(opts) + M.init(opts) + M.update_statusline() + M.refresh_highlight_on_colorscheme(opts) + M.disable_for_filetype(opts) +end + return M diff --git a/lua/sttusline/components/copilot.lua b/lua/sttusline/components/copilot.lua index e924c1c..7d20290 100644 --- a/lua/sttusline/components/copilot.lua +++ b/lua/sttusline/components/copilot.lua @@ -31,7 +31,7 @@ return { cp_api.check_status(copilot_client, {}, function(cserr, status) if cserr then copilot_status = "error" - require("sttusline.utils.notify").warn(cserr) + require("sttusline.utils.notify").warn(cserr.message or vim.inspect(cserr)) return elseif not status.user then copilot_status = "error" @@ -66,7 +66,7 @@ return { end end end - S.get_status = function() return configs.icons[copilot_status] or "" end + S.get_status = function() return configs.icons[copilot_status] or copilot_status or "" end return S end, @@ -78,7 +78,7 @@ return { inprogress = "", }, }, - update = function(_, _, space) + update = function(_, space) if package.loaded["copilot"] then space.register_status_notification_handler() space.check_status() diff --git a/lua/sttusline/components/git-branch.lua b/lua/sttusline/components/git-branch.lua index d642e7e..c5180e2 100644 --- a/lua/sttusline/components/git-branch.lua +++ b/lua/sttusline/components/git-branch.lua @@ -24,7 +24,7 @@ return { return "" end, }, - update = function(configs, _, space) + update = function(configs, space) local branch = space.get_branch() return branch ~= "" and configs.icon .. " " .. branch or "" end, diff --git a/lua/sttusline/config.lua b/lua/sttusline/config.lua index 5448544..ae995c9 100644 --- a/lua/sttusline/config.lua +++ b/lua/sttusline/config.lua @@ -75,7 +75,6 @@ local configs = { }, auto_hide_on_vim_resized = true, }, - padding = 1, update = function(configs) local mode_code = vim.api.nvim_get_mode().mode local mode = configs.modes[mode_code] @@ -164,7 +163,7 @@ local configs = { return "" end, }, - update = function(configs, _, space) + update = function(configs, space) local branch = space.get_branch() return branch ~= "" and configs.icon .. " " .. branch or "" end, @@ -195,16 +194,16 @@ local configs = { local should_add_spacing = false local result = {} - for _, v in ipairs(order) do + for index, v in ipairs(order) do if git_status[v] and git_status[v] > 0 then if should_add_spacing then - table.insert(result, " " .. icons[v] .. " " .. git_status[v]) + result[index] = " " .. icons[v] .. " " .. git_status[v] else should_add_spacing = true - table.insert(result, icons[v] .. " " .. git_status[v]) + result[index] = icons[v] .. " " .. git_status[v] end else - table.insert(result, "") + result[index] = "" end end return result @@ -238,18 +237,18 @@ local configs = { local order = configs.order local should_add_spacing = false - for _, key in ipairs(order) do + for index, key in ipairs(order) do local count = #vim.diagnostic.get(0, { severity = vim.diagnostic.severity[key] }) if count > 0 then if should_add_spacing then - table.insert(result, " " .. icons[key] .. " " .. count) + result[index] = " " .. icons[key] .. " " .. count else should_add_spacing = true - table.insert(result, icons[key] .. " " .. count) + result[index] = icons[key] .. " " .. count end else - table.insert(result, "") + result[index] = "" end end return result @@ -271,7 +270,7 @@ local configs = { for _, client in pairs(buf_clients) do local client_name = client.name - if not ignore_lsp_servers[client_name] then table.insert(server_names, client_name) end + if not ignore_lsp_servers[client_name] then server_names[#server_names + 1] = client_name end end if package.loaded["null-ls"] then @@ -307,9 +306,9 @@ local configs = { for _, method in ipairs(methods) do if source.methods[method] then if name_only then - table.insert(source_results, source.name) + source_results[#source_results + 1] = source.name else - table.insert(source_results, source) + source_results[#source_results + 1] = source end break end @@ -372,29 +371,19 @@ local configs = { cp_api.check_status(copilot_client, {}, function(cserr, status) if cserr then copilot_status = "error" - require("sttusline.utils.notify").warn(cserr) return elseif not status.user then copilot_status = "error" - require("sttusline.utils.notify").warn("Copilot: No user found") return elseif status.status == "NoTelemetryConsent" then copilot_status = "error" - require("sttusline.utils.notify").warn("Copilot: No telemetry consent") return elseif status.status == "NotAuthorized" then copilot_status = "error" - require("sttusline.utils.notify").warn("Copilot: Not authorized") return end - local attached = cp_client.buf_is_attached(0) - if not attached then - copilot_status = "error" - require("sttusline.utils.notify").warn("Copilot: Not attached") - else - copilot_status = "normal" - end + copilot_status = cp_client.buf_is_attached(0) and "normal" or "error" end) end @@ -407,10 +396,9 @@ local configs = { end end end - S.get_status = function() return configs.icons[copilot_status] or "" end + S.get_status = function() return configs.icons[copilot_status] or copilot_status or "" end return S end, - configs = { icons = { normal = "", @@ -419,7 +407,7 @@ local configs = { inprogress = "", }, }, - update = function(_, _, space) + update = function(_, space) if package.loaded["copilot"] then space.register_status_notification_handler() space.check_status() @@ -478,11 +466,13 @@ local configs = { } M.setup = function(user_opts) - user_opts = M.apply_user_config(user_opts) - if user_opts.statusline_color then - require("sttusline.utils").set_hl("StatusLine", { bg = user_opts.statusline_color }) + M.apply_user_config(user_opts) + + if configs.statusline_color then + require("sttusline.highlight").set_hl("StatusLine", { bg = user_opts.statusline_color }) end - return user_opts + + return configs end M.apply_user_config = function(opts) @@ -506,4 +496,6 @@ M.apply_user_config = function(opts) return configs end +M.get_config = function() return configs end + return M diff --git a/lua/sttusline/runner.lua b/lua/sttusline/runner.lua deleted file mode 100644 index a60a213..0000000 --- a/lua/sttusline/runner.lua +++ /dev/null @@ -1,369 +0,0 @@ -local M = {} - -local api = vim.api -local opt = vim.opt -local autocmd = api.nvim_create_autocmd -local augroup = api.nvim_create_augroup - -local COMPONENT_PARENT_MODULE = "sttusline.components" -local AUTOCMD_CORE_GROUP = "STTUSLINE_CORE_EVENTS" -local AUTOCMD_COMPONENT_GROUP = "STTUSLINE_COMPONENT_EVENTS" -local HIGHLIGHT_COMPONENT_PREFIX = "STTUSLINE_COMPONENT_" - -local utils = require("sttusline.utils") -local eval_component_func = utils.eval_component_func -local is_highlight_option = utils.is_highlight_option -local is_highlight_name = utils.is_highlight_name - -local core_autocmd_group = nil -local component_autocmd_group = nil -local timer = nil -local statusline_hidden = false - -local statusline = {} -local component_cache = {} -local event_component_index_cache = { - default = { - -- ... - -- [event_name] = { component_index, ... } - }, - user = { - -- ... - -- [event_name] = { component_index, ... } - }, -} -local timming_component_index_cache = { - -- ... - -- component_index -} - -M.update_statusline = function() - local str_statusline = table.concat(statusline, "") - if str_statusline == "" then str_statusline = " " end - opt.statusline = str_statusline -end - -M.setup = function(opts) - M.init(opts) - M.update_statusline() - M.refresh_highlight_on_colorscheme(opts) - M.disable_for_filetype(opts) -end - -M.foreach_component = function(opts, comp_cb, empty_comp_cb) - if #component_cache > 0 then - for index, component in ipairs(component_cache) do - if type(component) == "string" then - utils.eval_func(empty_comp_cb, component, index) - else - comp_cb(component, index) - end - end - else - local index = 0 - for _, component in ipairs(opts.components) do - if type(component) == "string" and #component > 0 then - if component == "%=" then -- empty component - index = index + 1 - component_cache[index] = component - utils.eval_func(empty_comp_cb, component, index) - else -- default component name - local status_ok, real_comp = pcall(require, COMPONENT_PARENT_MODULE .. "." .. component) - if status_ok then - index = index + 1 - component_cache[index] = real_comp - comp_cb(real_comp, index) - else - require("sttusline.utils.notify").error("Failed to load component: " .. component) - end - end - elseif type(component) == "table" and next(component) then - if type(component[1]) == "string" then -- default component name - local status_ok, real_comp = pcall(require, COMPONENT_PARENT_MODULE .. "." .. component[1]) - if status_ok then - if type(component[2]) == "table" then -- override component - real_comp = vim.tbl_deep_extend("force", real_comp, component[2]) - end - index = index + 1 - component_cache[index] = real_comp - comp_cb(real_comp, index) - else - require("sttusline.utils.notify").error("Failed to load component: " .. component[1]) - end - else -- custom component - index = index + 1 - component_cache[index] = component - comp_cb(component, index) - end - end - end - end -end - -M.refresh_highlight_on_colorscheme = function(opts) - autocmd("ColorScheme", { - pattern = "*", - group = M.get_core_autocmd_group(), - callback = function() M.set_all_component_highlight(opts) end, - }) -end - -M.disable_for_filetype = function(opts) - local event_trigger = false - autocmd({ "BufEnter", "WinEnter" }, { - pattern = "*", - group = M.get_core_autocmd_group(), - callback = function() - if not event_trigger then - event_trigger = true - vim.schedule(function() - if utils.is_disabled(opts) then - M.hide_statusline() - else - M.restore_statusline(opts) - end - end, 0) - end - end, - }) - autocmd({ "BufLeave", "WinLeave" }, { - pattern = "*", - group = M.get_core_autocmd_group(), - callback = function() event_trigger = false end, - }) -end - -M.hide_statusline = function() - if not statusline_hidden then - statusline_hidden = true - vim.schedule(function() opt.statusline = " " end) - end -end - -M.restore_statusline = function(opts) - if statusline_hidden then - statusline_hidden = false - M.update_all_components(opts) - M.update_statusline() - end -end - -M.start_timer = function(opts) - if timer == nil then timer = vim.loop.new_timer() end - timer:start( - 1000, - 1000, - vim.schedule_wrap(function() - if not statusline_hidden then M.run(opts) end - end) - ) -end - -M.init_component_timer = function(opts) - if #timming_component_index_cache > 0 then M.start_timer(opts) end -end - -M.set_component_highlight = function(opts, component, index) - local colors = component.colors - if type(colors) == "table" then - local is_list = false - for k, color in ipairs(colors) do - is_list = true - utils.set_hl(HIGHLIGHT_COMPONENT_PREFIX .. index .. "_" .. k, color, opts.statusline_color) - end - if not is_list then - utils.set_hl(HIGHLIGHT_COMPONENT_PREFIX .. index, colors, opts.statusline_color) - end - end - eval_component_func(component, "on_highlight") -end - -M.set_all_component_highlight = function(opts) - M.foreach_component( - opts, - function(component, index) M.set_component_highlight(opts, component, index) end - ) -end - -M.get_component_autocmd_group = function() - if component_autocmd_group == nil then - component_autocmd_group = augroup(AUTOCMD_COMPONENT_GROUP, { clear = true }) - end - return component_autocmd_group -end - -M.get_core_autocmd_group = function() - if core_autocmd_group == nil then - core_autocmd_group = augroup(AUTOCMD_CORE_GROUP, { clear = true }) - end - return core_autocmd_group -end - -M.create_default_autocmd = function(opts, event) - autocmd(event, { - pattern = "*", - group = M.get_component_autocmd_group(), - callback = function(e) - if not statusline_hidden then M.run(opts, e.event) end - end, - }) -end - -M.create_user_autocmd = function(opts, event) - autocmd("User", { - pattern = event, - group = M.get_component_autocmd_group(), - callback = function(e) - if not statusline_hidden then M.run(opts, e.match, true) end - end, - }) -end - -M.cache_timming_component_index = function(component, index) - if component.timming == true then table.insert(timming_component_index_cache, index) end -end - -M.cache_event_component_index = function(event, index, cache_key) - if type(event) == "string" then - event_component_index_cache[cache_key][event] = event_component_index_cache[cache_key][event] or {} - table.insert(event_component_index_cache[cache_key][event], index) - elseif type(event) == "table" then - for _, e in ipairs(event) do - event_component_index_cache[cache_key][e] = event_component_index_cache[cache_key][e] or {} - table.insert(event_component_index_cache[cache_key][e], index) - end - end -end - -M.init_component_autocmds = function(opts) - if next(event_component_index_cache.default) then - M.create_default_autocmd(opts, vim.tbl_keys(event_component_index_cache.default)) - end - if next(event_component_index_cache.user) then - M.create_user_autocmd(opts, vim.tbl_keys(event_component_index_cache.user)) - end -end - -M.init = function(opts) - M.foreach_component(opts, function(component, index) - if component.lazy == false then - M.update_component_value(opts, component, index) - else - statusline[index] = "" - end - eval_component_func(component, "init") - - M.cache_event_component_index(component.event, index, "default") - M.cache_event_component_index(component.user_event, index, "user") - M.cache_timming_component_index(component, index) - M.set_component_highlight(opts, component, index) - end, function(empty_comp, index) statusline[index] = empty_comp end) - M.init_component_autocmds(opts) - M.init_component_timer(opts) -end - -M.update_component_value = function(opts, component, index) - local should_display = eval_component_func(component, "condition") - if type(should_display) == "boolean" and not should_display then - statusline[index] = "" - return - end - - local updating_value = eval_component_func(component, "update") - -- updating_value must be string or table - -- if updating_value is table, then it must be a list of string or list of - -- two elements table, the first element is string, the second element is the - -- colors option of component - -- example: - -- { "filetype_icon", "filename" } - -- { {"filetype_icon", { fg="", bg="" }}, "filename" } - -- { {"filetype_icon"} } - - local colors = component.colors - if type(updating_value) == "string" then - updating_value = utils.add_padding(updating_value, component.padding) - if is_highlight_option(colors) then - -- if assign colors to component, then add highlight name to component - statusline[index] = utils.add_highlight_name(updating_value, HIGHLIGHT_COMPONENT_PREFIX .. index) - elseif is_highlight_name(colors) then - -- if assign the highlight name to component, then add that highlight name to component - statusline[index] = utils.add_highlight_name(updating_value, colors) - else - -- if not assign colors to component, then not need to add highlight name - statusline[index] = updating_value - end - elseif type(updating_value) == "table" then - updating_value = utils.add_padding(updating_value, component.padding) - for k, v in ipairs(updating_value) do - if type(v) == "string" then - -- "filename" - if type(colors) == "table" then - if is_highlight_option(colors[k]) then - updating_value[k] = - utils.add_highlight_name(v, HIGHLIGHT_COMPONENT_PREFIX .. index .. "_" .. k) - elseif is_highlight_name(colors[k]) then - updating_value[k] = utils.add_highlight_name(v, colors[k]) - end - else - updating_value[k] = v - end - elseif type(v) == "table" and type(v[1]) == "string" then - if is_highlight_option(v[2]) then - -- { "filename", { fg="", bg="" }} - component.colors = colors or {} - component.colors[k] = v[2] - updating_value[k] = - utils.add_highlight_name(v[1], HIGHLIGHT_COMPONENT_PREFIX .. index .. "_" .. k) - utils.set_hl(HIGHLIGHT_COMPONENT_PREFIX .. index .. "_" .. k, v[2], opts.statusline_color) - eval_component_func(component, "on_highlight") - elseif is_highlight_name(v[2]) then - -- { "filename", "HIGHLIGHT_NAME" } - updating_value[k] = utils.add_highlight_name(v[1], v[2]) - else - -- {"filename"} - updating_value[k] = v[1] - end - else - statusline[index] = "" - require("sttusline.utils.notify").error( - "component " - .. (component.name and component.name .. " " or "") - .. "update() must return string or table of string or table of {string, table}" - ) - return - end - end - statusline[index] = table.concat(updating_value, "") - else - statusline[index] = "" - require("sttusline.utils.notify").error( - "component " - .. (component.name and component.name .. " " or "") - .. "update() must return string or table of string or table of {string, table}" - ) - end -end - -M.update_all_components = function(opts) - M.foreach_component( - opts, - function(component, index) M.update_component_value(opts, component, index) end - ) -end - -M.update_on_trigger = function(opts, indexs) - for _, index in ipairs(indexs) do - M.update_component_value(opts, component_cache[index], index) - end -end - -M.run = function(opts, event_name, is_user_event) - local event_table = is_user_event and event_component_index_cache.user - or event_component_index_cache.default - vim.schedule(function() - M.update_on_trigger(opts, event_name and event_table[event_name] or timming_component_index_cache) - if not statusline_hidden then M.update_statusline() end - end, 0) -end - -return M diff --git a/lua/sttusline/templates/component_template.lua b/lua/sttusline/templates/component_template.lua index c5855be..5998180 100644 --- a/lua/sttusline/templates/component_template.lua +++ b/lua/sttusline/templates/component_template.lua @@ -8,9 +8,8 @@ return { lazy = true, - utils = {}, + space = {}, configs = {}, - override_glob_colors = {}, -- number or table padding = 1, -- { left = 1, right = 1 } diff --git a/lua/sttusline/utils/NestedTable.lua b/lua/sttusline/utils/NestedTable.lua deleted file mode 100644 index 602fbda..0000000 --- a/lua/sttusline/utils/NestedTable.lua +++ /dev/null @@ -1,76 +0,0 @@ -local MAX_DEPTH = 10 -local NestedTable = {} -NestedTable.__index = NestedTable - -function NestedTable:new(table) - table = table or {} - if type(table) ~= "table" then error("NestedTable:new() expects a table, got " .. type(table)) end - return setmetatable(table, self) -end - -function NestedTable:mapi(func, depth) - depth = depth or 1 - if depth > MAX_DEPTH then error("NestedTable:mapi() reached max depth") end - local new_table = {} - for k, v in pairs(self) do - if type(v) == "table" then - if getmetatable(v) == NestedTable then - new_table[k] = v:mapi(func, depth + 1) - else - new_table[k] = NestedTable:new(v):mapi(func, depth + 1) - end - else - new_table[k] = func(v, k) - end - end - return NestedTable:new(new_table) -end - -function NestedTable:foreachi(func, depth) - depth = depth or 1 - if depth > MAX_DEPTH then error("NestedTable:foreachi() reached max depth") end - for k, v in ipairs(self) do - if type(v) == "table" then - if getmetatable(v) == NestedTable then - v:foreachi(func, depth + 1) - else - NestedTable:new(v):foreachi(func, depth + 1) - end - else - func(v, k) - end - end -end - -function NestedTable:insert(value, pos) - pos = pos or #self + 1 - if type(value) == "table" then - if getmetatable(value) == NestedTable then - table.insert(self, pos, value) - else - table.insert(self, pos, NestedTable:new(value)) - end - else - table.insert(self, pos, value) - end -end - -function NestedTable:remove(pos) table.remove(self, pos) end - -function NestedTable:concat(sep, i, j) - local t = {} - for k, v in ipairs(self) do - if type(v) == "table" then - if getmetatable(v) == NestedTable then - t[k] = v:concat(sep, i, j) - else - t[k] = NestedTable:new(v):concat(sep, i, j) - end - else - t[k] = v - end - end - return table.concat(t, sep, i, j) -end - -return NestedTable diff --git a/lua/sttusline/utils/init.lua b/lua/sttusline/utils/init.lua deleted file mode 100644 index bafc81b..0000000 --- a/lua/sttusline/utils/init.lua +++ /dev/null @@ -1,122 +0,0 @@ -local api = vim.api -local color_utils = require("sttusline.utils.color") -local M = {} - -M.eval_func = function(func, ...) - if type(func) == "function" then return func(...) end -end - -M.eval_component_func = function(component, func_name, ...) - local configs = type(component.configs) == "table" and component.configs or {} - local override_colors = vim.tbl_deep_extend("force", color_utils, component.override_glob_colors or {}) - local space = nil - - if type(component.space) == "function" then - space = component.space(configs, override_colors) - elseif type(component.space) == "table" then - space = component.space - end - - return M.eval_func(component[func_name], configs, override_colors, space, ...) -end - -M.add_padding = function(str, value) - if #str == 0 then return str end - value = value or 1 - - if type(value) == "number" then - if value < 1 then return str end - local padding = (" "):rep(math.floor(value)) - - if type(str) == "string" then - return padding .. str .. padding - else -- table - local first_element = str[1] - local last_element = str[#str] - - if type(first_element) == "string" then - str[1] = padding .. first_element - elseif type(first_element) == "table" and type(first_element[1]) == "string" then - first_element[1] = padding .. first_element[1] - end - - if type(last_element) == "string" then - str[#str] = last_element .. padding - elseif type(last_element) == "table" and type(last_element[1]) == "string" then - last_element[1] = last_element[1] .. padding - end - return str - end - return str - elseif type(value) == "table" then - local left_padding = type(value.left) == "number" - and value.left >= 0 - and (" "):rep(math.floor(value.left)) - or " " - local right_padding = type(value.right) == "number" - and value.right >= 0 - and (" "):rep(math.floor(value.right)) - or " " - - if type(str) == "string" then - return left_padding .. str .. right_padding - elseif type(str) == "table" then - local first_element = str[1] - local last_element = str[#str] - - if type(first_element) == "string" then - str[1] = left_padding .. first_element - elseif type(first_element) == "table" and type(first_element[1]) == "string" then - first_element[1] = left_padding .. first_element[1] - end - - if type(last_element) == "string" then - str[#str] = last_element .. right_padding - elseif type(last_element) == "table" and type(last_element[1]) == "string" then - last_element[1] = last_element[1] .. right_padding - end - - return str - end - return str - end -end - -M.add_highlight_name = function(str, highlight_name) - return #str > 0 and "%#" .. highlight_name .. "#" .. str .. "%*" or "" -end - -M.is_color = function(color) return type(color) == "string" and color:match("^#%x%x%x%x%x%x$") end - -M.is_disabled = function(opts) - return vim.tbl_contains(opts.disabled.filetypes or {}, api.nvim_buf_get_option(0, "filetype")) - or vim.tbl_contains(opts.disabled.buftypes or {}, api.nvim_buf_get_option(0, "buftype")) -end - -M.get_hl_name_color = function(hl_name) - local ok, colors = pcall(api.nvim_get_hl_by_name, hl_name, true) - return ok and colors or {} -end - -M.set_hl = function(group, opts, global_background) - if M.is_highlight_option(opts) then - if opts.fg and not M.is_color(opts.fg) then opts.fg = M.get_hl_name_color(opts.fg).foreground end - - if opts.bg then - opts.bg = M.is_color(opts.bg) and opts.bg or M.get_hl_name_color(opts.bg).background - elseif global_background then - opts.bg = M.is_color(global_background) and global_background - or M.get_hl_name_color(global_background).background - else - -- fallback to StatusLine background - opts.bg = M.get_hl_name_color("StatusLine").background - end - pcall(api.nvim_set_hl, 0, group, opts) - end -end - -M.is_highlight_option = function(hl_opts) return type(hl_opts) == "table" and next(hl_opts) ~= nil end - -M.is_highlight_name = function(hl_name) return type(hl_name) == "string" and #hl_name > 0 end - -return M diff --git a/lua/sttusline/utils/nested_array.lua b/lua/sttusline/utils/nested_array.lua deleted file mode 100644 index cb039d0..0000000 --- a/lua/sttusline/utils/nested_array.lua +++ /dev/null @@ -1,51 +0,0 @@ -local M = {} -local MAX_DEPTH = 10 -- Maximum depth of nested table - -M.foreach = function(array, func, depth) - depth = depth or 0 - for index, value in ipairs(array) do - if type(value) == "table" then - if depth < MAX_DEPTH then - M.foreach(value, func, depth + 1) - else - require("sttusline.utils.notify").error("Maximum depth of nested table exceeded") - end - else - func(index, value) - end - end -end - -M.map = function(array, func, depth) - depth = depth or 0 - local result = {} - for index, value in ipairs(array) do - if type(value) == "table" then - if depth < MAX_DEPTH then result[index] = M.map(value, func, depth + 1) end - else - require("sttusline.utils.notify").error("Maximum depth of nested table exceeded") - end - end - return result -end - -M.extend = function(array, another_array) table.insert(array, another_array) end - -M.concat = function(array, separator, depth) - depth = depth or 0 - local result = {} - for _, value in ipairs(array) do - if type(value) == "table" then - if depth < MAX_DEPTH then - table.insert(result, M.concat(value, separator, depth + 1)) - else - require("sttusline.utils.notify").error("Maximum depth of nested table exceeded") - end - else - table.insert(result, value) - end - end - return table.concat(result, separator) -end - -return M From e5282d3a5f87afc09e9cda4a9c11b2bf3a9fa164 Mon Sep 17 00:00:00 2001 From: Tran Vo Son Tung Date: Wed, 8 Nov 2023 15:04:51 +0700 Subject: [PATCH 4/7] docs: update README --- README.md | 50 ++++++++++------------------ lua/sttusline/components/copilot.lua | 5 --- 2 files changed, 17 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index e52f2c4..d4e1b2d 100644 --- a/README.md +++ b/README.md @@ -144,10 +144,10 @@ Use default component and override default configs. I allow you to do any thing configs = {}, padding = 1, -- { left = 1, right = 1 } colors = {}, -- { fg = colors.black, bg = colors.white } - init = function(configs,colors,space) end, - update = function(configs,colors,space)return "" end, - condition = function(configs,colors,space)return true end, - on_highlight= function(configs,colors,space) end, + init = function(config,space) end, + update = function(configs,space)return "" end, + condition = function(configs,space)return true end, + on_highlight= function(configs,space) end, } }, }, @@ -181,15 +181,14 @@ To add the empty space between components, you need to add `%=` to `components` user_event = { "VeryLazy" }, timing = false, -- The component will be update every time interval lazy = true, - override_glob_colors = {}, space ={} configs = {}, padding = 1, -- { left = 1, right = 1 } colors = {}, -- { fg = colors.black, bg = colors.white } - init = function(configs,colors,space) end, - update = function(configs,colors,space)return "" end, - condition = function(configs,colors,space)return true end, - on_highlight= function(configs,colors,space) end, + init = function(configs,space) end, + update = function(configs,space)return "" end, + condition = function(config,space)return true end, + on_highlight= function(configs,space) end, } }, } @@ -205,7 +204,6 @@ To add the empty space between components, you need to add `%=` to `components` | [lazy](#lazy) | boolean | Load component on startup(not recommended) | | [configs](#configs) | table | The configs of components, it will be pass to the first parameter of each function | | [space](#space) | table or function | If space is the table it will be pass to the third parameter of each function, if it is a function the return value of that function will be pass to the third parameter of each function | -| [override_glob_colors](#override_glob_colors) | table | Override colors pass to the second parameter of each function | | [init](#init) | function | The function will call on the first time component load | | [colors](#colors) | table | Colors highlight | | [update](#update) | function(must return string or table) | The function will return the value of the component to display on the statusline | @@ -283,16 +281,6 @@ To add the empty space between components, you need to add `%=` to `components` } ``` -- `override_glob_colors`: Override colors pass to the second parameter of each function(optional). Default is false - NOTE: default the second parameter of each function is the colors in lua.utils.color module - -```lua - { - override_glob_colors = { - }, - } -``` - `configs`: The configs of components, it will be pass to the first parameter of each function(optional). Default is nil ```lua @@ -304,12 +292,11 @@ To add the empty space between components, you need to add `%=` to `components` - `init`: The function will call on the first time component load(optional). Default is nil - configs is the [configs](#configs) table - - colors is the colors in lua.utils.color.lua file - space is the [space](#space) table ```lua { - init = function(configs,colors,space) end, + init = function(configs,space) end, } ``` @@ -318,7 +305,7 @@ To add the empty space between components, you need to add `%=` to `components` You should use it to add the algorithm function for your component or constant variables - configs is the [configs](#configs) table - - colors is the colors in lua.utils.color.lua file + ```lua { @@ -409,14 +396,13 @@ OR Return value must be string or table - configs is the [configs](#configs) table - - colors is the colors in lua.utils.color.lua file - space is the [space](#space) table Return string ```lua { - update = function(configs,colors,space)return "" end, + update = function(configs,space)return "" end, } ``` @@ -424,7 +410,7 @@ Return the table with all values is string ```lua { - update = function(configs,colors,space)return { "string1", "string2" } end, + update = function(configs,space)return { "string1", "string2" } end, } ``` @@ -434,7 +420,7 @@ This element will be highlight with new colors options or highlight name when th ```lua -- you can use the colors options { - update = function(configs,colors,space)return { { "string1", {fg = "#000000", bg ="#fdfdfd"} }, "string3", "string4" } end, + update = function(configs,space)return { { "string1", {fg = "#000000", bg ="#fdfdfd"} }, "string3", "string4" } end, } ``` @@ -443,7 +429,7 @@ OR ```lua -- only use the foreground color of the DiagnosticsSignError highlight { - update = function(configs,colors,space)return { { "string1", {fg = "DiagnosticsSignError", bg ="#000000"} }, "string3", "string4" } end, + update = function(configs,space)return { { "string1", {fg = "DiagnosticsSignError", bg ="#000000"} }, "string3", "string4" } end, } ``` @@ -452,7 +438,7 @@ OR ```lua -- use same colors options of the DiagnosticsSignError highlight { - update = function(configs,colors,space)return { { "string1", "DiagnosticsSignError" }, "string3", "string4" } end, + update = function(configs,space)return { { "string1", "DiagnosticsSignError" }, "string3", "string4" } end, } ``` @@ -517,24 +503,22 @@ NOTE: The colors options can be the colors name or the colors options Return value must be boolean - configs is the [configs](#configs) table - - colors is the colors in lua.utils.color.lua file - space is the [space](#space) table ```lua { - condition = function(configs,colors,space)return true end, + condition = function(configs,space)return true end, } ``` - `on_highlight`: The function will call when the component is set highlight(optional). - configs is the [configs](#configs) table - - colors is the colors in lua.utils.color.lua file - space is the [space](#space) table ```lua { - on_highlight= function(configs,colors,space) end, + on_highlight= function(configs,space) end, } ``` diff --git a/lua/sttusline/components/copilot.lua b/lua/sttusline/components/copilot.lua index 7d20290..922511c 100644 --- a/lua/sttusline/components/copilot.lua +++ b/lua/sttusline/components/copilot.lua @@ -31,26 +31,21 @@ return { cp_api.check_status(copilot_client, {}, function(cserr, status) if cserr then copilot_status = "error" - require("sttusline.utils.notify").warn(cserr.message or vim.inspect(cserr)) return elseif not status.user then copilot_status = "error" - require("sttusline.utils.notify").warn("Copilot: No user found") return elseif status.status == "NoTelemetryConsent" then copilot_status = "error" - require("sttusline.utils.notify").warn("Copilot: No telemetry consent") return elseif status.status == "NotAuthorized" then copilot_status = "error" - require("sttusline.utils.notify").warn("Copilot: Not authorized") return end local attached = cp_client.buf_is_attached(0) if not attached then copilot_status = "error" - require("sttusline.utils.notify").warn("Copilot: Not attached") else copilot_status = "normal" end From b0e6c0125426cb69b8106ac423a735be71cfb880 Mon Sep 17 00:00:00 2001 From: Tran Vo Son Tung Date: Wed, 8 Nov 2023 19:08:08 +0700 Subject: [PATCH 5/7] feat: group the component which has the same update condition --- lua/sttusline/api.lua | 154 ++++++++++++------ lua/sttusline/config.lua | 28 ++-- lua/sttusline/highlight.lua | 4 + .../templates/component_template.lua | 6 +- 4 files changed, 127 insertions(+), 65 deletions(-) diff --git a/lua/sttusline/api.lua b/lua/sttusline/api.lua index 67895dc..66fea4e 100644 --- a/lua/sttusline/api.lua +++ b/lua/sttusline/api.lua @@ -5,14 +5,25 @@ local COMPONENT_PARENT_MODULE = "sttusline.components" local AUTOCMD_CORE_GROUP = "STTUSLINE_CORE_EVENTS" local AUTOCMD_COMPONENT_GROUP = "STTUSLINE_COMPONENT_EVENTS" +local vim = vim local api = vim.api local opt = vim.opt +local schedule = vim.schedule local autocmd = api.nvim_create_autocmd local augroup = api.nvim_create_augroup local concat = table.concat +local pairs = pairs +local ipairs = ipairs +local next = next +local type = type +local require = require -- module local highlight = require("sttusline.highlight") +local gen_component_hl_name = highlight.gen_component_hl_name +local add_highlight_name = highlight.add_highlight_name +local is_highlight_option = highlight.is_highlight_option +local is_highlight_name = highlight.is_highlight_name -- local vars local core_autocmd_group = nil @@ -50,6 +61,30 @@ local catalog = { timer = {}, } +local update_groups = { + CURSOR_MOVING = { + members = {}, + opts = { + event = { "CursorMoved", "CursorMovedI" }, + user_event = "VeryLazy", + }, + }, + BUF_WIN_ENTER_AND_VERY_LAZY = { + members = {}, + opts = { + event = { "BufEnter", "WinEnter" }, + user_event = "VeryLazy", + }, + }, +} + +M.create_update_group = function(group_name, opts) + vim.validate { group_name = { group_name, "string" }, opts = { opts, "table" } } + update_groups[group_name] = update_groups[group_name] or { members = {} } + update_groups[group_name].opts = opts + return group_name +end + M.get_component_autocmd_group = function() if component_autocmd_group == nil then component_autocmd_group = augroup(AUTOCMD_COMPONENT_GROUP, { clear = true }) @@ -79,28 +114,6 @@ M.create_user_autocmd = function(opts, event) }) end -local add_event_index_entry = function(event, index, cache_key) - local event_table = catalog.event[cache_key] - local catalog_event = event_table[event] - if catalog_event == nil then - event_table[event] = { index } - event_table.length = (event_table.length or 0) + 1 - event_table.keys[event_table.length] = event - else - catalog_event[#catalog_event + 1] = index - end -end - -M.index_event_catalog = function(event, index, cache_key) - if type(event) == "table" then - for _, e in ipairs(event) do - add_event_index_entry(e, index, cache_key) - end - elseif type(event) == "string" then - add_event_index_entry(event, index, cache_key) - end -end - M.init_component_autocmds = function(opts) local nvim_keys = catalog.event.nvim.keys local user_keys = catalog.event.user.keys @@ -180,9 +193,9 @@ M.tbl_contains = function(tbl, item) return false end -M.should_statusline_hidden = function(opts) - return M.tbl_contains(opts.disabled.filetypes, api.nvim_buf_get_option(0, "filetype")) - or M.tbl_contains(opts.disabled.buftypes, api.nvim_buf_get_option(0, "buftype")) +M.should_statusline_hidden = function(disabled_list) + return M.tbl_contains(disabled_list.filetypes, api.nvim_buf_get_option(0, "filetype")) + or M.tbl_contains(disabled_list.buftypes, api.nvim_buf_get_option(0, "buftype")) end M.disable_for_filetype = function(opts) @@ -192,8 +205,8 @@ M.disable_for_filetype = function(opts) callback = function() if not event_trigger then event_trigger = true - vim.schedule(function() - if M.should_statusline_hidden(opts) then + schedule(function() + if M.should_statusline_hidden(opts.disabled) then M.hide_statusline() else M.restore_statusline(opts) @@ -211,7 +224,7 @@ end M.hide_statusline = function() if not statusline_hidden then statusline_hidden = true - vim.schedule(function() opt.statusline = " " end, 0) + schedule(function() opt.statusline = " " end, 0) end end @@ -294,10 +307,10 @@ M.set_component_highlight = function(opts, component, index) local colors = component.colors if type(colors) == "table" then if colors[1] == nil then - highlight.set_hl(highlight.gen_component_hl_name(index), colors, opts.statusline_color) + highlight.set_hl(gen_component_hl_name(index), colors, opts.statusline_color) else for k, color in ipairs(colors) do - highlight.set_hl(highlight.gen_component_hl_name(index, k), color, opts.statusline_color) + highlight.set_hl(gen_component_hl_name(index, k), color, opts.statusline_color) end end end @@ -336,13 +349,12 @@ M.update_component_value = function(opts, component, index) local colors = component.colors if type(updating_value) == "string" then updating_value = M.add_component_padding(updating_value, component.padding) - if highlight.is_highlight_option(colors) then + if is_highlight_option(colors) then -- if assign colors to component, then add highlight name to component - statusline[index] = - highlight.add_highlight_name(updating_value, highlight.gen_component_hl_name(index)) - elseif highlight.is_highlight_name(colors) then + statusline[index] = add_highlight_name(updating_value, gen_component_hl_name(index)) + elseif is_highlight_name(colors) then -- if assign the highlight name to component, then add that highlight name to component - statusline[index] = highlight.add_highlight_name(updating_value, colors) + statusline[index] = add_highlight_name(updating_value, colors) else -- if not assign colors to component, then not need to add highlight name statusline[index] = updating_value @@ -353,29 +365,28 @@ M.update_component_value = function(opts, component, index) if type(child) == "string" then -- "filename" if type(colors) == "table" then -- is assigned colors to component - if highlight.is_highlight_option(colors[k]) then - updating_value[k] = - highlight.add_highlight_name(child, highlight.gen_component_hl_name(index, k)) - elseif highlight.is_highlight_name(colors[k]) then - updating_value[k] = highlight.add_highlight_name(child, colors[k]) + if is_highlight_option(colors[k]) then + updating_value[k] = add_highlight_name(child, gen_component_hl_name(index, k)) + elseif is_highlight_name(colors[k]) then + updating_value[k] = add_highlight_name(child, colors[k]) end else updating_value[k] = child end elseif M.is_sub_table_child(child) then - if highlight.is_highlight_option(child[2]) then + if is_highlight_option(child[2]) then -- { "filename", { fg="", bg="" }} component.colors = colors or {} component.colors[k] = child[2] - local component_hl_name = highlight.gen_component_hl_name(index, k) - updating_value[k] = highlight.add_highlight_name(child[1], component_hl_name) + local component_hl_name = gen_component_hl_name(index, k) + updating_value[k] = add_highlight_name(child[1], component_hl_name) highlight.set_hl(component_hl_name, child[2], opts.statusline_color) M.eval_component_func(component, "on_highlight") - elseif highlight.is_highlight_name(child[2]) then + elseif is_highlight_name(child[2]) then -- { "filename", "HIGHLIGHT_NAME" } - updating_value[k] = highlight.add_highlight_name(child[1], child[2]) + updating_value[k] = add_highlight_name(child[1], child[2]) else -- {"filename"} updating_value[k] = child[1] @@ -412,7 +423,13 @@ end M.update_on_trigger = function(opts, update_indexs) for _, index in ipairs(update_indexs) do - M.update_component_value(opts, components[index], index) + if type(index) == "table" then + for _, i in ipairs(index) do + M.update_component_value(opts, components[i], i) + end + else + M.update_component_value(opts, components[index], index) + end end end @@ -420,12 +437,34 @@ M.run = function(opts, event_name, is_user_event) if statusline_hidden then return end local event_table = is_user_event and catalog.event.user or catalog.event.nvim - vim.schedule(function() + schedule(function() M.update_on_trigger(opts, event_name and event_table[event_name] or catalog.timer) M.update_statusline() end, 0) end +local add_event_index_entry = function(event, index, cache_key) + local event_table = catalog.event[cache_key] + local catalog_event = event_table[event] + if catalog_event == nil then + event_table[event] = { index } + event_table.length = (event_table.length or 0) + 1 + event_table.keys[event_table.length] = event + else + catalog_event[#catalog_event + 1] = index + end +end + +M.index_event_catalog = function(event, index, cache_key) + if type(event) == "string" then + add_event_index_entry(event, index, cache_key) + elseif type(event) == "table" then + for _, e in ipairs(event) do + add_event_index_entry(e, index, cache_key) + end + end +end + M.init = function(opts) M.foreach_component(opts, function(component, index) M.eval_component_func(component, "init") @@ -435,12 +474,27 @@ M.init = function(opts) statusline[index] = "" end - M.index_event_catalog(component.event, index, "nvim") - M.index_event_catalog(component.user_event, index, "user") - M.index_timer_catalog(component, index) + local update_group = update_groups[component.update_group] + if type(update_group) == "table" then + update_group.members[#update_group.members + 1] = index + else + M.index_event_catalog(component.event, index, "nvim") + M.index_event_catalog(component.user_event, index, "user") + M.index_timer_catalog(component, index) + end M.set_component_highlight(opts, component, index) end, function(empty_comp, index) statusline[index] = empty_comp end) + for _, group in pairs(update_groups) do + local members = group.members + if #members > 0 then + local group_opts = group.opts + M.index_event_catalog(group_opts.event, members, "nvim") + M.index_event_catalog(group_opts.user_event, members, "user") + M.index_timer_catalog(group_opts, members) + end + end + M.init_component_autocmds(opts) M.init_component_timer(opts) end diff --git a/lua/sttusline/config.lua b/lua/sttusline/config.lua index ae995c9..456b2e9 100644 --- a/lua/sttusline/config.lua +++ b/lua/sttusline/config.lua @@ -14,7 +14,7 @@ local configs = { { name = "mode", event = { "ModeChanged", "VimResized" }, - user_event = { "VeryLazy" }, + user_event = "VeryLazy", configs = { modes = { ["n"] = { "NORMAL", "STTUSLINE_NORMAL_MODE" }, @@ -93,8 +93,7 @@ local configs = { }, { name = "filename", - event = { "BufEnter", "WinEnter" }, - user_event = { "VeryLazy" }, + update_group = "BUF_WIN_ENTER_AND_VERY_LAZY", colors = { {}, { fg = colors.orange }, @@ -141,7 +140,7 @@ local configs = { }, { name = "git-branch", - event = { "BufEnter" }, + event = "BufEnter", user_event = { "VeryLazy", "GitSignsUpdate" }, configs = { icon = "", @@ -172,7 +171,7 @@ local configs = { { name = "git-diff", event = { "BufWritePost", "VimResized", "BufEnter" }, - user_event = { "GitSignsUpdate" }, + user_event = "GitSignsUpdate", colors = { { fg = colors.tokyo_diagnostics_hint }, { fg = colors.tokyo_diagnostics_info }, @@ -213,9 +212,8 @@ local configs = { "%=", { name = "diagnostics", - event = { "DiagnosticChanged" }, + event = "DiagnosticChanged", colors = { - { fg = colors.tokyo_diagnostics_error }, { fg = colors.tokyo_diagnostics_warn }, { fg = colors.tokyo_diagnostics_hint }, @@ -417,14 +415,13 @@ local configs = { }, { name = "indent", - event = { "BufEnter" }, - user_event = { "VeryLazy" }, + update_group = "BUF_WIN_ENTER_AND_VERY_LAZY", colors = { fg = colors.cyan }, update = function() return "Tab: " .. vim.api.nvim_buf_get_option(0, "shiftwidth") .. "" end, }, { name = "encoding", - user_event = { "VeryLazy" }, + update_group = "BUF_WIN_ENTER_AND_VERY_LAZY", configs = { ["utf-8"] = "󰉿", ["utf-16"] = "", @@ -441,8 +438,7 @@ local configs = { }, { name = "pos-cursor", - event = { "CursorMoved", "CursorMovedI" }, - user_event = { "VeryLazy" }, + update_group = "CURSOR_MOVING", colors = { fg = colors.fg }, update = function() local pos = vim.api.nvim_win_get_cursor(0) @@ -451,8 +447,7 @@ local configs = { }, { name = "pos-cursor-progress", - event = { "CursorMoved", "CursorMovedI" }, - user_event = { "VeryLazy" }, + update_group = "CURSOR_MOVING", configs = { chars = { "_", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█" }, }, @@ -468,6 +463,11 @@ local configs = { M.setup = function(user_opts) M.apply_user_config(user_opts) + if type(configs.on_attach) == "function" then + local create_update_group = require("sttusline.api").create_update_group + configs.on_attach(create_update_group) + end + if configs.statusline_color then require("sttusline.highlight").set_hl("StatusLine", { bg = user_opts.statusline_color }) end diff --git a/lua/sttusline/highlight.lua b/lua/sttusline/highlight.lua index 0f10a38..4342123 100644 --- a/lua/sttusline/highlight.lua +++ b/lua/sttusline/highlight.lua @@ -1,6 +1,10 @@ local HIGHLIGHT_COMPONENT_PREFIX = "STTUSLINE_COMPONENT_" local api = vim.api +local next = next +local type = type +local pcall = pcall + local M = {} M.is_highlight_option = function(hl_opts) return type(hl_opts) == "table" and next(hl_opts) ~= nil end diff --git a/lua/sttusline/templates/component_template.lua b/lua/sttusline/templates/component_template.lua index 5998180..a3ef649 100644 --- a/lua/sttusline/templates/component_template.lua +++ b/lua/sttusline/templates/component_template.lua @@ -1,9 +1,13 @@ return { name = "form", + -- The component in same group will be update in the same time + update_group = "group_name", + + -- If update_group is set the event, user_event and timing will be ignored + -- It will update in the same option as update_group event = {}, -- The component will be update when the event is triggered user_event = { "VeryLazy" }, - timing = false, -- The component will be update every time interval lazy = true, From 2b217027a7ebbbe2de69775492ab0cfaa816cce9 Mon Sep 17 00:00:00 2001 From: Tran Vo Son Tung Date: Wed, 8 Nov 2023 19:30:51 +0700 Subject: [PATCH 6/7] docs: update README --- README.md | 111 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index d4e1b2d..ca293c8 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ any idea to create a new component, please open an issue or pull request. event = { "BufEnter" }, config = function(_, opts) require("sttusline").setup { + on_attach = function(create_update_group) end + -- the colors of statusline will be set follow the colors of the active buffer -- statusline_color = "#fdff00", statusline_color = "StatusLine", @@ -135,7 +137,8 @@ Use default component and override default configs. I allow you to do any thing "mode", -- override default component { - name = "form", + name = "component_name", + update_group = "group_name", event = {}, -- The component will be update when the event is triggered user_event = { "VeryLazy" }, timing = false, -- The component will be update every time interval @@ -144,10 +147,10 @@ Use default component and override default configs. I allow you to do any thing configs = {}, padding = 1, -- { left = 1, right = 1 } colors = {}, -- { fg = colors.black, bg = colors.white } - init = function(config,space) end, - update = function(configs,space)return "" end, - condition = function(configs,space)return true end, - on_highlight= function(configs,space) end, + init = function(config, space) end, + update = function(configs, space)return "" end, + condition = function(configs, space)return true end, + on_highlight= function(configs, space) end, } }, }, @@ -176,7 +179,8 @@ To add the empty space between components, you need to add `%=` to `components` -- ... { -- new component - name = "form", + name = "component_name", + update_group = "group_name", event = {}, -- The component will be update when the event is triggered user_event = { "VeryLazy" }, timing = false, -- The component will be update every time interval @@ -185,30 +189,31 @@ To add the empty space between components, you need to add `%=` to `components` configs = {}, padding = 1, -- { left = 1, right = 1 } colors = {}, -- { fg = colors.black, bg = colors.white } - init = function(configs,space) end, - update = function(configs,space)return "" end, - condition = function(config,space)return true end, - on_highlight= function(configs,space) end, + init = function(configs, space) end, + update = function(configs, space)return "" end, + condition = function(config, space)return true end, + on_highlight= function(configs, space) end, } }, } ``` -| **Keys** | Type of args | **Description** | -| --------------------------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [name](#name) | string | The name of component | -| [event](#event) | table or string | The component will be update when the [event](https://neovim.io/doc/user/autocmd.html) is triggered | -| [user_event](#user_event) | table or string | Same as event buf for [User](https://neovim.io/doc/user/autocmd.html) autocmd | -| [timing](#timing) | boolean | If set_timing(true), component will update after 1 second | -| [padding](#padding) | number or table | The number of spaces to add before and after the component | -| [lazy](#lazy) | boolean | Load component on startup(not recommended) | -| [configs](#configs) | table | The configs of components, it will be pass to the first parameter of each function | -| [space](#space) | table or function | If space is the table it will be pass to the third parameter of each function, if it is a function the return value of that function will be pass to the third parameter of each function | -| [init](#init) | function | The function will call on the first time component load | -| [colors](#colors) | table | Colors highlight | -| [update](#update) | function(must return string or table) | The function will return the value of the component to display on the statusline | -| [condition](#condition) | function(must return boolean) | The function will return the condition to display the component when the component is update | -| [on_highlight](#on_highlight) | function | The function will call when the component is set highlight | +| **Keys** | Type of args | **Description** | +| ----------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [name](#name) | string | The name of component | +| [update_group](#update_group) | string | The update group of component | +| [event](#event) | table or string | The component will be update when the [event](https://neovim.io/doc/user/autocmd.html) is triggered | +| [user_event](#user_event) | table or string | Same as event buf for [User](https://neovim.io/doc/user/autocmd.html) autocmd | +| [timing](#timing) | boolean | If set_timing(true), component will update after 1 second | +| [padding](#padding) | number or table | The number of spaces to add before and after the component | +| [lazy](#lazy) | boolean | Load component on startup(not recommended) | +| [configs](#configs) | table | The configs of components, it will be pass to the first parameter of each function | +| [space](#space) | table or function | If space is the table it will be pass to the third parameter of each function, if it is a function the return value of that function will be pass to the third parameter of each function | +| [init](#init) | function | The function will call on the first time component load | +| [colors](#colors) | table | Colors highlight | +| [update](#update) | function(must return string or table) | The function will return the value of the component to display on the statusline | +| [condition](#condition) | function(must return boolean) | The function will return the condition to display the component when the component is update | +| [on_highlight](#on_highlight) | function | The function will call when the component is set highlight | ### Detail of each key @@ -220,6 +225,39 @@ To add the empty space between components, you need to add `%=` to `components` } ``` +- `update_group`: The update group of component(optional). Default is `nil` + +If you set it, then all the components in the same group will be update in the same time + +NOTE: If group is set, then the event, user_event, timing will be ignored + +Please make sure that you create group by using: + +```lua + require("sttusline").setup { + on_attach = function(create_update_group) + create_update_group("GROUP_NAME", { + event = { "BufEnter" }, + user_event = { "VeryLazy" }, + timing = false, + }) + end + } +``` + +We provide you some default group: + +| **Group** | **Description** | +| --------------- | --------------------------------------------------------------------------------- | +| `CURSOR_MOVING` | event = {"CursorMoved", "CursorMoveI"}, user_event = {"VeryLazy"}, timing = false | +| `BUF_WIN_ENTER` | event = {"BufEnter", "WinEnter"}, user_event = {"VeryLazy"}, timing = false | + +```lua + { + update_group = "CURSOR_MOVING", + } +``` + - `event`: The component will be update when the event is triggered(optional). Default is `nil` ```lua @@ -296,7 +334,7 @@ To add the empty space between components, you need to add `%=` to `components` ```lua { - init = function(configs,space) end, + init = function(configs, space) end, } ``` @@ -306,14 +344,13 @@ To add the empty space between components, you need to add `%=` to `components` - configs is the [configs](#configs) table - ```lua { space = {} } -- or { - space = function(configs, colors) + space = function(configs) return {} end, } @@ -345,7 +382,7 @@ Example return "" end, }, - update = function(configs, colors, space) + update = function(configs, space) local branch = space.get_branch() return branch ~= "" and configs.icon .. " " .. branch or "" end, @@ -383,7 +420,7 @@ OR get_branch = get_branch, } end, - update = function(configs, _, space) + update = function(configs, space) local branch = space.get_branch() return branch ~= "" and configs.icon .. " " .. branch or "" end, @@ -402,7 +439,7 @@ Return string ```lua { - update = function(configs,space)return "" end, + update = function(configs, space)return "" end, } ``` @@ -410,7 +447,7 @@ Return the table with all values is string ```lua { - update = function(configs,space)return { "string1", "string2" } end, + update = function(configs, space)return { "string1", "string2" } end, } ``` @@ -420,7 +457,7 @@ This element will be highlight with new colors options or highlight name when th ```lua -- you can use the colors options { - update = function(configs,space)return { { "string1", {fg = "#000000", bg ="#fdfdfd"} }, "string3", "string4" } end, + update = function(configs, space)return { { "string1", {fg = "#000000", bg ="#fdfdfd"} }, "string3", "string4" } end, } ``` @@ -429,7 +466,7 @@ OR ```lua -- only use the foreground color of the DiagnosticsSignError highlight { - update = function(configs,space)return { { "string1", {fg = "DiagnosticsSignError", bg ="#000000"} }, "string3", "string4" } end, + update = function(configs, space)return { { "string1", {fg = "DiagnosticsSignError", bg ="#000000"} }, "string3", "string4" } end, } ``` @@ -438,7 +475,7 @@ OR ```lua -- use same colors options of the DiagnosticsSignError highlight { - update = function(configs,space)return { { "string1", "DiagnosticsSignError" }, "string3", "string4" } end, + update = function(configs, space)return { { "string1", "DiagnosticsSignError" }, "string3", "string4" } end, } ``` @@ -507,7 +544,7 @@ NOTE: The colors options can be the colors name or the colors options ```lua { - condition = function(configs,space)return true end, + condition = function(configs, space)return true end, } ``` @@ -518,7 +555,7 @@ NOTE: The colors options can be the colors name or the colors options ```lua { - on_highlight= function(configs,space) end, + on_highlight= function(configs, space) end, } ``` From 2302a15f267638ac54a41813553e3d9b032ec7ad Mon Sep 17 00:00:00 2001 From: Tran Vo Son Tung Date: Wed, 8 Nov 2023 19:31:29 +0700 Subject: [PATCH 7/7] fix: rename BUF_WIN_ENTER_AND_VERY_LAZY to BUF_WIN_ENTER --- lua/sttusline/api.lua | 2 +- lua/sttusline/config.lua | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lua/sttusline/api.lua b/lua/sttusline/api.lua index 66fea4e..1c6ed63 100644 --- a/lua/sttusline/api.lua +++ b/lua/sttusline/api.lua @@ -69,7 +69,7 @@ local update_groups = { user_event = "VeryLazy", }, }, - BUF_WIN_ENTER_AND_VERY_LAZY = { + BUF_WIN_ENTER = { members = {}, opts = { event = { "BufEnter", "WinEnter" }, diff --git a/lua/sttusline/config.lua b/lua/sttusline/config.lua index 456b2e9..bddbc4a 100644 --- a/lua/sttusline/config.lua +++ b/lua/sttusline/config.lua @@ -4,6 +4,7 @@ local M = {} local configs = { -- statusline_color = "#1e2030", -- statusline_color = "StatusLine", + -- on_attach = function(create_update_group) end disabled = { filetypes = {}, buftypes = { @@ -93,7 +94,7 @@ local configs = { }, { name = "filename", - update_group = "BUF_WIN_ENTER_AND_VERY_LAZY", + update_group = "BUF_WIN_ENTER", colors = { {}, { fg = colors.orange }, @@ -415,13 +416,13 @@ local configs = { }, { name = "indent", - update_group = "BUF_WIN_ENTER_AND_VERY_LAZY", + update_group = "BUF_WIN_ENTER", colors = { fg = colors.cyan }, update = function() return "Tab: " .. vim.api.nvim_buf_get_option(0, "shiftwidth") .. "" end, }, { name = "encoding", - update_group = "BUF_WIN_ENTER_AND_VERY_LAZY", + update_group = "BUF_WIN_ENTER", configs = { ["utf-8"] = "󰉿", ["utf-16"] = "",