diff --git a/README.md b/README.md index 6d988d5ac..f13ad9a8d 100644 --- a/README.md +++ b/README.md @@ -658,6 +658,26 @@ sections = { } ``` +#### selectioncount component options + +```lua +sections = { + lualine_a = { + { + 'selectioncount', + format = { + -- `%b`: bytes, `%c`: chars, `%l`: lines + single_line_no_multibyte = '[%c]', + single_line_multibyte = '[%c-%b]', + multi_line_no_multibyte = '[%c / %l]', + multi_line_multibyte = '[%c-%b / %l]', + visual_block_mode = '[%cx%l]', + } + } + } +} +``` + #### searchcount component options ```lua diff --git a/lua/lualine/components/selectioncount.lua b/lua/lualine/components/selectioncount.lua index f08bde0c9..fdf6adbe1 100644 --- a/lua/lualine/components/selectioncount.lua +++ b/lua/lualine/components/selectioncount.lua @@ -1,16 +1,68 @@ -local function selectioncount() - local mode = vim.fn.mode(true) - local line_start, col_start = vim.fn.line('v'), vim.fn.col('v') - local line_end, col_end = vim.fn.line('.'), vim.fn.col('.') - if mode:match('') then - return string.format('%dx%d', math.abs(line_start - line_end) + 1, math.abs(col_start - col_end) + 1) - elseif mode:match('V') or line_start ~= line_end then - return math.abs(line_start - line_end) + 1 - elseif mode:match('v') then - return math.abs(col_start - col_end) + 1 +local M = require('lualine.component'):extend() + +local default_format = { + single_line_no_multibyte = '[%c]', + single_line_multibyte = '[%c-%b]', + multi_line_no_multibyte = '[%c / %l]', + multi_line_multibyte = '[%c-%b / %l]', + visual_block_mode = '[%cx%l]', +} + +function M:init(options) + M.super.init(self, options) + self.format = vim.tbl_extend('keep', self.options.format or {}, default_format) +end + +function M:update_status() + local mode = vim.fn.mode() + local lines = math.abs(vim.fn.line('v') - vim.fn.line('.')) + 1 + if mode == 'v' or mode == 'V' then + local wc = vim.fn.wordcount() + local is_multibyte = wc.visual_chars ~= wc.visual_bytes + local is_multiline = lines > 1 + local chars = wc.visual_chars + if is_multiline then + if is_multibyte then + local bytes = wc.visual_bytes + return self.format.multi_line_multibyte + :gsub("^%%b", bytes):gsub("([^%%])%%b", "%1"..bytes) + :gsub("^%%c", chars):gsub("([^%%])%%c", "%1"..chars) + :gsub("^%%l", lines):gsub("([^%%])%%l", "%1"..lines) + else + return self.format.multi_line_no_multibyte + :gsub("^%%c", chars):gsub("([^%%])%%c", "%1"..chars) + :gsub("^%%l", lines):gsub("([^%%])%%l", "%1"..lines) + end + else + if is_multibyte then + local bytes = wc.visual_bytes + return self.format.single_line_multibyte + :gsub("^%%b", bytes):gsub("([^%%])%%b", "%1"..bytes) + :gsub("^%%c", chars):gsub("([^%%])%%c", "%1"..chars) + else + return self.format.single_line_no_multibyte + :gsub("^%%c", chars):gsub("([^%%])%%c", "%1"..chars) + end + end + elseif mode == '' then + local cols = vim.fn.virtcol('.') - vim.fn.virtcol('v') + local line, col + if cols >= 0 then + line = vim.fn.getline('v') + col = vim.fn.charcol('v') - 1 + else + line = vim.fn.getline('.') + col = vim.fn.charcol('.') - 1 + cols = -cols + end + local char1width = vim.fn.strwidth(vim.fn.strcharpart(line, col, 1)) + local chars = cols+char1width + return self.format.visual_block_mode + :gsub("^%%c", chars):gsub("([^%%])%%c", "%1"..chars) + :gsub("^%%l", lines):gsub("([^%%])%%l", "%1"..lines) else return '' end end -return selectioncount +return M