From 5d85dc785869e63191db6e5c995d59002105b2d0 Mon Sep 17 00:00:00 2001 From: Anthony Ruhier Date: Tue, 17 Oct 2023 11:37:24 +0200 Subject: [PATCH] Add options to the Tabs module to align it with the Buffers module (#920) * Add a path option for tabs Add get_props to align the module on Buffers. * Add option to set the tab max size Shorten dynamically the tab name to minimize its length when needed. * Show modified status --- README.md | 11 ++++ lua/lualine/components/tabs/init.lua | 6 ++ lua/lualine/components/tabs/tab.lua | 92 +++++++++++++++++++++++----- 3 files changed, 92 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 39f792d..8fb021f 100644 --- a/README.md +++ b/README.md @@ -679,6 +679,7 @@ sections = { lualine_a = { { 'tabs', + tab_max_length = 40, -- Maximum width of each tab. The content will be shorten dynamically (example: apple/orange -> a/orange) max_length = vim.o.columns / 3, -- Maximum width of tabs component. -- Note: -- It can also be a function that returns @@ -687,6 +688,11 @@ sections = { -- 1: Shows tab_name -- 2: Shows tab_nr + tab_name + path = 0, -- 0: just shows the filename + -- 1: shows the relative path and shorten $HOME to ~ + -- 2: shows the full path + -- 3: shows the full path and shorten $HOME to ~ + -- Automatically updates active tab color to match color of other components (will be overidden if buffers_color is set) use_mode_colors = false, @@ -696,6 +702,11 @@ sections = { inactive = 'lualine_{section}_inactive', -- Color for inactive tab. }, + show_modified_status = true, -- Shows a symbol next to the tab name if the file has been modified. + symbols = { + modified = '[+]', -- Text to show when the file is modified. + }, + fmt = function(name, context) -- Show + if buffer is modified in tab local buflist = vim.fn.tabpagebuflist(context.tabnr) diff --git a/lua/lualine/components/tabs/init.lua b/lua/lualine/components/tabs/init.lua index b176b45..5d1966e 100644 --- a/lua/lualine/components/tabs/init.lua +++ b/lua/lualine/components/tabs/init.lua @@ -7,12 +7,18 @@ local highlight = require('lualine.highlight') local default_options = { max_length = 0, + tab_max_length = 40, mode = 0, use_mode_colors = false, + path = 0, tabs_color = { active = nil, inactive = nil, }, + show_modified_status = true, + symbols = { + modified = '[+]', + }, } -- This function is duplicated in buffers diff --git a/lua/lualine/components/tabs/tab.lua b/lua/lualine/components/tabs/tab.lua index 8ccdc90..170095a 100644 --- a/lua/lualine/components/tabs/tab.lua +++ b/lua/lualine/components/tabs/tab.lua @@ -13,6 +13,27 @@ function Tab:init(opts) self.tabId = opts.tabId self.options = opts.options self.highlights = opts.highlights + self.modified_icon = '' + self:get_props() +end + +function Tab:get_props() + local buflist = vim.fn.tabpagebuflist(self.tabnr) + local winnr = vim.fn.tabpagewinnr(self.tabnr) + local bufnr = buflist[winnr] + self.file = modules.utils.stl_escape(vim.api.nvim_buf_get_name(bufnr)) + self.filetype = vim.api.nvim_buf_get_option(bufnr, 'filetype') + self.buftype = vim.api.nvim_buf_get_option(bufnr, 'buftype') + + if self.options.show_modified_status then + for _, b in ipairs(buflist) do + if vim.api.nvim_buf_get_option(b, 'modified') then + self.modified_icon = self.options.symbols.modified or '' + break + end + end + end + end ---returns name for tab. Tabs name is the name of buffer in last active window @@ -26,30 +47,61 @@ function Tab:label() if custom_tabname and custom_tabname ~= '' then return modules.utils.stl_escape(custom_tabname) end - local buflist = vim.fn.tabpagebuflist(self.tabnr) - local winnr = vim.fn.tabpagewinnr(self.tabnr) - local bufnr = buflist[winnr] - local file = modules.utils.stl_escape(vim.api.nvim_buf_get_name(bufnr)) - local buftype = vim.fn.getbufvar(bufnr, '&buftype') - if vim.api.nvim_buf_get_option(bufnr, 'filetype') == 'fugitive' then - return 'fugitive: ' .. vim.fn.fnamemodify(file, ':h:h:t') - elseif buftype == 'help' then - return 'help:' .. vim.fn.fnamemodify(file, ':t:r') - elseif buftype == 'terminal' then - local match = string.match(vim.split(file, ' ')[1], 'term:.*:(%a+)') + if self.filetype == 'fugitive' then + return 'fugitive: ' .. vim.fn.fnamemodify(self.file, ':h:h:t') + elseif self.buftype == 'help' then + return 'help:' .. vim.fn.fnamemodify(self.file, ':t:r') + elseif self.buftype == 'terminal' then + local match = string.match(vim.split(self.file, ' ')[1], 'term:.*:(%a+)') return match ~= nil and match or vim.fn.fnamemodify(vim.env.SHELL, ':t') - elseif vim.fn.isdirectory(file) == 1 then - return vim.fn.fnamemodify(file, ':p:.') - elseif file == '' then + elseif self.file == '' then return '[No Name]' end - return vim.fn.fnamemodify(file, ':t') + if self.options.path == 1 then + return vim.fn.fnamemodify(self.file, ':~:.') + elseif self.options.path == 2 then + return vim.fn.fnamemodify(self.file, ':p') + elseif self.options.path == 3 then + return vim.fn.fnamemodify(self.file, ':p:~') + else + return vim.fn.fnamemodify(self.file, ':t') + end +end + +---shortens path by turning apple/orange -> a/orange +---@param path string +---@param sep string path separator +---@param max_len integer maximum length of the full filename string +---@return string +local function shorten_path(path, sep, max_len) + local len = #path + if len <= max_len then + return path + end + + local segments = vim.split(path, sep) + for idx = 1, #segments - 1 do + if len <= max_len then + break + end + + local segment = segments[idx] + local shortened = segment:sub(1, vim.startswith(segment, '.') and 2 or 1) + segments[idx] = shortened + len = len - (#segment - #shortened) + end + + return table.concat(segments, sep) end ---returns rendered tab ---@return string function Tab:render() local name = self:label() + if self.options.tab_max_length ~= 0 then + local path_separator = package.config:sub(1, 1) + name = shorten_path(name, path_separator, self.options.tab_max_length) + end if self.options.fmt then name = self.options.fmt(name or '', self) end @@ -59,12 +111,18 @@ function Tab:render() -- different formats for different modes if self.options.mode == 0 then name = tostring(self.tabnr) + if self.modified_icon ~= '' then + name = string.format('%s%s', name, self.modified_icon) + end elseif self.options.mode == 1 then - name = name + if self.modified_icon ~= '' then + name = string.format('%s %s', self.modified_icon, name) + end else - name = string.format('%s %s', tostring(self.tabnr), name) + name = string.format('%s%s %s', tostring(self.tabnr), self.modified_icon, name) end end + name = Tab.apply_padding(name, self.options.padding) self.len = vim.fn.strchars(name)