feat: add support for column text alignment (#711)
* feat: add support for column text alignment * refactor(util): replace rpad with pad_align * refactor(columns): whitespace handling in parse_col * refactor: small changes * doc: add align option to doc generation * refactor: replace lpad with pad_align --------- Co-authored-by: Steven Arcangeli <stevearc@stevearc.com>
This commit is contained in:
parent
fbbb2a9872
commit
6b59a6cf62
7 changed files with 64 additions and 46 deletions
|
|
@ -414,6 +414,7 @@ type *column-typ
|
||||||
Parameters:
|
Parameters:
|
||||||
{highlight} `string|fun(value: string): string` Highlight group, or
|
{highlight} `string|fun(value: string): string` Highlight group, or
|
||||||
function that returns a highlight group
|
function that returns a highlight group
|
||||||
|
{align} `"left"|"center"|"right"` Text alignment within the column
|
||||||
{icons} `table<string, string>` Mapping of entry type to icon
|
{icons} `table<string, string>` Mapping of entry type to icon
|
||||||
|
|
||||||
icon *column-icon*
|
icon *column-icon*
|
||||||
|
|
@ -423,6 +424,7 @@ icon *column-ico
|
||||||
Parameters:
|
Parameters:
|
||||||
{highlight} `string|fun(value: string): string` Highlight group, or
|
{highlight} `string|fun(value: string): string` Highlight group, or
|
||||||
function that returns a highlight group
|
function that returns a highlight group
|
||||||
|
{align} `"left"|"center"|"right"` Text alignment within the column
|
||||||
{default_file} `string` Fallback icon for files when nvim-web-devicons
|
{default_file} `string` Fallback icon for files when nvim-web-devicons
|
||||||
returns nil
|
returns nil
|
||||||
{directory} `string` Icon for directories
|
{directory} `string` Icon for directories
|
||||||
|
|
@ -437,6 +439,7 @@ size *column-siz
|
||||||
Parameters:
|
Parameters:
|
||||||
{highlight} `string|fun(value: string): string` Highlight group, or
|
{highlight} `string|fun(value: string): string` Highlight group, or
|
||||||
function that returns a highlight group
|
function that returns a highlight group
|
||||||
|
{align} `"left"|"center"|"right"` Text alignment within the column
|
||||||
|
|
||||||
permissions *column-permissions*
|
permissions *column-permissions*
|
||||||
Adapters: files, ssh
|
Adapters: files, ssh
|
||||||
|
|
@ -446,6 +449,7 @@ permissions *column-permission
|
||||||
Parameters:
|
Parameters:
|
||||||
{highlight} `string|fun(value: string): string` Highlight group, or
|
{highlight} `string|fun(value: string): string` Highlight group, or
|
||||||
function that returns a highlight group
|
function that returns a highlight group
|
||||||
|
{align} `"left"|"center"|"right"` Text alignment within the column
|
||||||
|
|
||||||
ctime *column-ctime*
|
ctime *column-ctime*
|
||||||
Adapters: files
|
Adapters: files
|
||||||
|
|
@ -455,6 +459,7 @@ ctime *column-ctim
|
||||||
Parameters:
|
Parameters:
|
||||||
{highlight} `string|fun(value: string): string` Highlight group, or
|
{highlight} `string|fun(value: string): string` Highlight group, or
|
||||||
function that returns a highlight group
|
function that returns a highlight group
|
||||||
|
{align} `"left"|"center"|"right"` Text alignment within the column
|
||||||
{format} `string` Format string (see :help strftime)
|
{format} `string` Format string (see :help strftime)
|
||||||
|
|
||||||
mtime *column-mtime*
|
mtime *column-mtime*
|
||||||
|
|
@ -465,6 +470,7 @@ mtime *column-mtim
|
||||||
Parameters:
|
Parameters:
|
||||||
{highlight} `string|fun(value: string): string` Highlight group, or
|
{highlight} `string|fun(value: string): string` Highlight group, or
|
||||||
function that returns a highlight group
|
function that returns a highlight group
|
||||||
|
{align} `"left"|"center"|"right"` Text alignment within the column
|
||||||
{format} `string` Format string (see :help strftime)
|
{format} `string` Format string (see :help strftime)
|
||||||
|
|
||||||
atime *column-atime*
|
atime *column-atime*
|
||||||
|
|
@ -475,6 +481,7 @@ atime *column-atim
|
||||||
Parameters:
|
Parameters:
|
||||||
{highlight} `string|fun(value: string): string` Highlight group, or
|
{highlight} `string|fun(value: string): string` Highlight group, or
|
||||||
function that returns a highlight group
|
function that returns a highlight group
|
||||||
|
{align} `"left"|"center"|"right"` Text alignment within the column
|
||||||
{format} `string` Format string (see :help strftime)
|
{format} `string` Format string (see :help strftime)
|
||||||
|
|
||||||
birthtime *column-birthtime*
|
birthtime *column-birthtime*
|
||||||
|
|
@ -485,6 +492,7 @@ birthtime *column-birthtim
|
||||||
Parameters:
|
Parameters:
|
||||||
{highlight} `string|fun(value: string): string` Highlight group, or
|
{highlight} `string|fun(value: string): string` Highlight group, or
|
||||||
function that returns a highlight group
|
function that returns a highlight group
|
||||||
|
{align} `"left"|"center"|"right"` Text alignment within the column
|
||||||
{format} `string` Format string (see :help strftime)
|
{format} `string` Format string (see :help strftime)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -98,13 +98,13 @@ end
|
||||||
M.parse_col = function(adapter, line, col_def)
|
M.parse_col = function(adapter, line, col_def)
|
||||||
local name, conf = util.split_config(col_def)
|
local name, conf = util.split_config(col_def)
|
||||||
-- If rendering failed, there will just be a "-"
|
-- If rendering failed, there will just be a "-"
|
||||||
local empty_col, rem = line:match("^(-%s+)(.*)$")
|
local empty_col, rem = line:match("^%s*(-%s+)(.*)$")
|
||||||
if empty_col then
|
if empty_col then
|
||||||
return nil, rem
|
return nil, rem
|
||||||
end
|
end
|
||||||
local column = M.get_column(adapter, name)
|
local column = M.get_column(adapter, name)
|
||||||
if column then
|
if column then
|
||||||
return column.parse(line, conf)
|
return column.parse(line:gsub("^%s+", ""), conf)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ M.show_help = function(keymaps)
|
||||||
local highlights = {}
|
local highlights = {}
|
||||||
local max_line = 1
|
local max_line = 1
|
||||||
for _, entry in ipairs(keymap_entries) do
|
for _, entry in ipairs(keymap_entries) do
|
||||||
local line = string.format(" %s %s", util.rpad(entry.str, max_lhs), entry.desc)
|
local line = string.format(" %s %s", util.pad_align(entry.str, max_lhs, "left"), entry.desc)
|
||||||
max_line = math.max(max_line, vim.api.nvim_strwidth(line))
|
max_line = math.max(max_line, vim.api.nvim_strwidth(line))
|
||||||
table.insert(lines, line)
|
table.insert(lines, line)
|
||||||
local start = 1
|
local start = 1
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,8 @@ M.set_loading = function(bufnr, is_loading)
|
||||||
M.set_loading(bufnr, false)
|
M.set_loading(bufnr, false)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local lines = { util.lpad("Loading", math.floor(width / 2) - 3), bar_iter() }
|
local lines =
|
||||||
|
{ util.pad_align("Loading", math.floor(width / 2) - 3, "right"), bar_iter() }
|
||||||
util.render_text(bufnr, lines)
|
util.render_text(bufnr, lines)
|
||||||
end)
|
end)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -91,34 +91,28 @@ M.get_adapter = function(bufnr, silent)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param text string
|
---@param text string
|
||||||
---@param length nil|integer
|
---@param width integer|nil
|
||||||
---@return string
|
---@param align oil.ColumnAlign
|
||||||
M.rpad = function(text, length)
|
---@return string padded_text
|
||||||
if not length then
|
---@return integer left_padding
|
||||||
return text
|
M.pad_align = function(text, width, align)
|
||||||
|
if not width then
|
||||||
|
return text, 0
|
||||||
end
|
end
|
||||||
local textlen = vim.api.nvim_strwidth(text)
|
local text_width = vim.api.nvim_strwidth(text)
|
||||||
local delta = length - textlen
|
local total_pad = width - text_width
|
||||||
if delta > 0 then
|
if total_pad <= 0 then
|
||||||
return text .. string.rep(" ", delta)
|
return text, 0
|
||||||
else
|
|
||||||
return text
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
---@param text string
|
if align == "right" then
|
||||||
---@param length nil|integer
|
return string.rep(" ", total_pad) .. text, total_pad
|
||||||
---@return string
|
elseif align == "center" then
|
||||||
M.lpad = function(text, length)
|
local left_pad = math.floor(total_pad / 2)
|
||||||
if not length then
|
local right_pad = total_pad - left_pad
|
||||||
return text
|
return string.rep(" ", left_pad) .. text .. string.rep(" ", right_pad), left_pad
|
||||||
end
|
|
||||||
local textlen = vim.api.nvim_strwidth(text)
|
|
||||||
local delta = length - textlen
|
|
||||||
if delta > 0 then
|
|
||||||
return string.rep(" ", delta) .. text
|
|
||||||
else
|
else
|
||||||
return text
|
return text .. string.rep(" ", total_pad), 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -314,11 +308,15 @@ M.split_config = function(name_or_config)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@alias oil.ColumnAlign "left"|"center"|"right"
|
||||||
|
|
||||||
---@param lines oil.TextChunk[][]
|
---@param lines oil.TextChunk[][]
|
||||||
---@param col_width integer[]
|
---@param col_width integer[]
|
||||||
|
---@param col_align? oil.ColumnAlign[]
|
||||||
---@return string[]
|
---@return string[]
|
||||||
---@return any[][] List of highlights {group, lnum, col_start, col_end}
|
---@return any[][] List of highlights {group, lnum, col_start, col_end}
|
||||||
M.render_table = function(lines, col_width)
|
M.render_table = function(lines, col_width, col_align)
|
||||||
|
col_align = col_align or {}
|
||||||
local str_lines = {}
|
local str_lines = {}
|
||||||
local highlights = {}
|
local highlights = {}
|
||||||
for _, cols in ipairs(lines) do
|
for _, cols in ipairs(lines) do
|
||||||
|
|
@ -332,9 +330,12 @@ M.render_table = function(lines, col_width)
|
||||||
else
|
else
|
||||||
text = chunk
|
text = chunk
|
||||||
end
|
end
|
||||||
text = M.rpad(text, col_width[i])
|
|
||||||
|
local unpadded_len = text:len()
|
||||||
|
local padding
|
||||||
|
text, padding = M.pad_align(text, col_width[i], col_align[i] or "left")
|
||||||
|
|
||||||
table.insert(pieces, text)
|
table.insert(pieces, text)
|
||||||
local col_end = col + text:len() + 1
|
|
||||||
if hl then
|
if hl then
|
||||||
if type(hl) == "table" then
|
if type(hl) == "table" then
|
||||||
-- hl has the form { [1]: hl_name, [2]: col_start, [3]: col_end }[]
|
-- hl has the form { [1]: hl_name, [2]: col_start, [3]: col_end }[]
|
||||||
|
|
@ -344,15 +345,15 @@ M.render_table = function(lines, col_width)
|
||||||
table.insert(highlights, {
|
table.insert(highlights, {
|
||||||
sub_hl[1],
|
sub_hl[1],
|
||||||
#str_lines,
|
#str_lines,
|
||||||
col + sub_hl[2],
|
col + padding + sub_hl[2],
|
||||||
col + sub_hl[3],
|
col + padding + sub_hl[3],
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
table.insert(highlights, { hl, #str_lines, col, col_end })
|
table.insert(highlights, { hl, #str_lines, col + padding, col + padding + unpadded_len })
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
col = col_end
|
col = col + text:len() + 1
|
||||||
end
|
end
|
||||||
table.insert(str_lines, table.concat(pieces, " "))
|
table.insert(str_lines, table.concat(pieces, " "))
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -668,8 +668,11 @@ local function render_buffer(bufnr, opts)
|
||||||
local column_defs = columns.get_supported_columns(scheme)
|
local column_defs = columns.get_supported_columns(scheme)
|
||||||
local line_table = {}
|
local line_table = {}
|
||||||
local col_width = {}
|
local col_width = {}
|
||||||
for i in ipairs(column_defs) do
|
local col_align = {}
|
||||||
|
for i, col_def in ipairs(column_defs) do
|
||||||
col_width[i + 1] = 1
|
col_width[i + 1] = 1
|
||||||
|
local _, conf = util.split_config(col_def)
|
||||||
|
col_align[i + 1] = conf and conf.align or "left"
|
||||||
end
|
end
|
||||||
|
|
||||||
if M.should_display("..", bufnr) then
|
if M.should_display("..", bufnr) then
|
||||||
|
|
@ -692,7 +695,7 @@ local function render_buffer(bufnr, opts)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local lines, highlights = util.render_table(line_table, col_width)
|
local lines, highlights = util.render_table(line_table, col_width, col_align)
|
||||||
|
|
||||||
vim.bo[bufnr].modifiable = true
|
vim.bo[bufnr].modifiable = true
|
||||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, lines)
|
vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, lines)
|
||||||
|
|
|
||||||
|
|
@ -110,11 +110,16 @@ class ColumnDef:
|
||||||
params: List["LuaParam"] = field(default_factory=list)
|
params: List["LuaParam"] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
HL = [
|
UNIVERSAL = [
|
||||||
LuaParam(
|
LuaParam(
|
||||||
"highlight",
|
"highlight",
|
||||||
"string|fun(value: string): string",
|
"string|fun(value: string): string",
|
||||||
"Highlight group, or function that returns a highlight group",
|
"Highlight group, or function that returns a highlight group",
|
||||||
|
),
|
||||||
|
LuaParam(
|
||||||
|
"align",
|
||||||
|
'"left"|"center"|"right"',
|
||||||
|
"Text alignment within the column",
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
TIME = [
|
TIME = [
|
||||||
|
|
@ -127,7 +132,7 @@ COL_DEFS = [
|
||||||
False,
|
False,
|
||||||
True,
|
True,
|
||||||
"The type of the entry (file, directory, link, etc)",
|
"The type of the entry (file, directory, link, etc)",
|
||||||
HL
|
UNIVERSAL
|
||||||
+ [LuaParam("icons", "table<string, string>", "Mapping of entry type to icon")],
|
+ [LuaParam("icons", "table<string, string>", "Mapping of entry type to icon")],
|
||||||
),
|
),
|
||||||
ColumnDef(
|
ColumnDef(
|
||||||
|
|
@ -136,7 +141,7 @@ COL_DEFS = [
|
||||||
False,
|
False,
|
||||||
False,
|
False,
|
||||||
"An icon for the entry's type (requires nvim-web-devicons)",
|
"An icon for the entry's type (requires nvim-web-devicons)",
|
||||||
HL
|
UNIVERSAL
|
||||||
+ [
|
+ [
|
||||||
LuaParam(
|
LuaParam(
|
||||||
"default_file",
|
"default_file",
|
||||||
|
|
@ -151,23 +156,23 @@ COL_DEFS = [
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
ColumnDef("size", "files, ssh, s3", False, True, "The size of the file", HL + []),
|
ColumnDef("size", "files, ssh, s3", False, True, "The size of the file", UNIVERSAL + []),
|
||||||
ColumnDef(
|
ColumnDef(
|
||||||
"permissions",
|
"permissions",
|
||||||
"files, ssh",
|
"files, ssh",
|
||||||
True,
|
True,
|
||||||
False,
|
False,
|
||||||
"Access permissions of the file",
|
"Access permissions of the file",
|
||||||
HL + [],
|
UNIVERSAL + [],
|
||||||
),
|
),
|
||||||
ColumnDef(
|
ColumnDef(
|
||||||
"ctime", "files", False, True, "Change timestamp of the file", HL + TIME + []
|
"ctime", "files", False, True, "Change timestamp of the file", UNIVERSAL + TIME + []
|
||||||
),
|
),
|
||||||
ColumnDef(
|
ColumnDef(
|
||||||
"mtime", "files", False, True, "Last modified time of the file", HL + TIME + []
|
"mtime", "files", False, True, "Last modified time of the file", UNIVERSAL + TIME + []
|
||||||
),
|
),
|
||||||
ColumnDef(
|
ColumnDef(
|
||||||
"atime", "files", False, True, "Last access time of the file", HL + TIME + []
|
"atime", "files", False, True, "Last access time of the file", UNIVERSAL + TIME + []
|
||||||
),
|
),
|
||||||
ColumnDef(
|
ColumnDef(
|
||||||
"birthtime",
|
"birthtime",
|
||||||
|
|
@ -175,7 +180,7 @@ COL_DEFS = [
|
||||||
False,
|
False,
|
||||||
True,
|
True,
|
||||||
"The time the file was created",
|
"The time the file was created",
|
||||||
HL + TIME + [],
|
UNIVERSAL + TIME + [],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue