mirror of
https://github.com/Myzel394/easytables.nvim.git
synced 2025-06-18 06:55:25 +02:00
fix: Improve options and header toggling; general improvements
This commit is contained in:
parent
25f7a873e8
commit
c6752bd822
@ -1,11 +1,20 @@
|
||||
local o = require("easytables.options")
|
||||
|
||||
local M = {}
|
||||
|
||||
---comment
|
||||
---@param content string
|
||||
---@param width number
|
||||
---@return table
|
||||
---@return string
|
||||
function M:export_cell(content, width)
|
||||
return "| " .. content .. string.rep(" ", width - #content) .. " "
|
||||
local padding = string.rep(" ", o.options.export.markdown.padding)
|
||||
|
||||
return
|
||||
o.options.export.markdown.characters.vertical
|
||||
.. padding
|
||||
.. content
|
||||
.. string.rep(" ", width - #content)
|
||||
.. padding
|
||||
end
|
||||
|
||||
---Exports a line to a string
|
||||
@ -21,7 +30,7 @@ function M:export_line(line, widths)
|
||||
str = str .. self:export_cell(cell, width)
|
||||
end
|
||||
|
||||
return str .. "|"
|
||||
return str .. o.options.export.markdown.characters.vertical
|
||||
end
|
||||
|
||||
---comment
|
||||
@ -32,10 +41,13 @@ function M:create_header_line(widths)
|
||||
|
||||
-- No idea why, but "ipairs" is required otherwise lua complains
|
||||
for _, width in ipairs(widths) do
|
||||
str = str .. "|" .. string.rep("-", width + 2)
|
||||
str =
|
||||
str
|
||||
.. o.options.export.markdown.characters.vertical
|
||||
.. string.rep(o.options.export.markdown.characters.horizontal, width)
|
||||
end
|
||||
|
||||
return str .. "|"
|
||||
return str .. o.options.export.markdown.characters.vertical
|
||||
end
|
||||
|
||||
---comment
|
||||
|
@ -1,7 +1,7 @@
|
||||
local table = require("easytables.table")
|
||||
local window = require("easytables.window")
|
||||
local inputHelper = require("easytables.input")
|
||||
local optionsHelper = require("easytables.options")
|
||||
local o = require("easytables.options")
|
||||
|
||||
local function create_new_table(cols, rows)
|
||||
local markdown_table = table:create(cols, rows)
|
||||
@ -16,7 +16,8 @@ end
|
||||
---Initialize `easytables` with the given options. This function **must** be called.
|
||||
---@param options table See options.lua for available options
|
||||
local function setup(options)
|
||||
optionsHelper.merge_options(options)
|
||||
options = options or {}
|
||||
o.merge_options(options)
|
||||
|
||||
vim.api.nvim_create_user_command(
|
||||
"EasyTablesCreateNew",
|
||||
|
@ -2,7 +2,7 @@ local string = require("string")
|
||||
|
||||
---Extracts the column info from the input
|
||||
---@param raw_input string
|
||||
---@return number, number
|
||||
---@return table
|
||||
local function extract_column_info(raw_input)
|
||||
local _, _, cols, create_singular, rows = string.find(raw_input, "(%d+)(x?)(%d*)")
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
-- All available options are listed below. The default values are shown.
|
||||
local DEFAULT = {
|
||||
local options = {
|
||||
table = {
|
||||
-- Whether to enable the header by default
|
||||
header_enabled_by_default = true,
|
||||
window = {
|
||||
preview_title = "Table Preview",
|
||||
prompt_title = "Cell content",
|
||||
@ -14,9 +16,6 @@ local DEFAULT = {
|
||||
-- Filler character for empty cells
|
||||
filler = " ",
|
||||
align = "left",
|
||||
-- Padding around the cell content, applied BOTH left AND right
|
||||
-- E.g: padding = 1, content = "foo" -> " foo "
|
||||
padding = 1,
|
||||
},
|
||||
-- Characters used to draw the table
|
||||
-- Do not worry about multibyte characters, they are handled correctly
|
||||
@ -39,17 +38,28 @@ local DEFAULT = {
|
||||
header_horizontal = "═",
|
||||
}
|
||||
},
|
||||
export = {
|
||||
markdown = {
|
||||
-- Padding around the cell content, applied BOTH left AND right
|
||||
-- E.g: padding = 1, content = "foo" -> " foo "
|
||||
padding = 1,
|
||||
-- What markdown characters are used for the export, you probably
|
||||
-- don't want to change these
|
||||
characters = {
|
||||
horizontal = "-",
|
||||
vertical = "|",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-- You can ignore everything below this line
|
||||
|
||||
local options = {}
|
||||
|
||||
local function tableMerge(t1, t2)
|
||||
local function merge_tables(t1, t2)
|
||||
for k, v in pairs(t2) do
|
||||
if type(v) == "table" then
|
||||
if type(t1[k] or false) == "table" then
|
||||
tableMerge(t1[k] or {}, t2[k] or {})
|
||||
merge_tables(t1[k] or {}, t2[k] or {})
|
||||
else
|
||||
t1[k] = v
|
||||
end
|
||||
@ -57,11 +67,10 @@ local function tableMerge(t1, t2)
|
||||
t1[k] = v
|
||||
end
|
||||
end
|
||||
return t1
|
||||
end
|
||||
|
||||
local function merge_options(user_options)
|
||||
options = tableMerge(DEFAULT, user_options)
|
||||
merge_tables(options, user_options)
|
||||
end
|
||||
|
||||
return {
|
||||
|
@ -1,3 +1,5 @@
|
||||
local o = require("easytables.options")
|
||||
|
||||
local M = {};
|
||||
|
||||
function M:create(cols, rows)
|
||||
@ -14,7 +16,12 @@ function M:create(cols, rows)
|
||||
col = 1,
|
||||
row = 1,
|
||||
}
|
||||
self.header_enabled = true
|
||||
|
||||
if rows > 1 then
|
||||
self.header_enabled = o.options.table.header_enabled_by_default
|
||||
else
|
||||
self.header_enabled = false
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
@ -28,6 +35,11 @@ function M:value_at(row, col)
|
||||
end
|
||||
|
||||
function M:toggle_header()
|
||||
if #self.table == 1 then
|
||||
error("Cannot toggle header if table has only one row")
|
||||
return
|
||||
end
|
||||
|
||||
self.header_enabled = not self.header_enabled
|
||||
end
|
||||
|
||||
@ -60,14 +72,17 @@ function M:get_largest_length()
|
||||
return largest
|
||||
end
|
||||
|
||||
function M:get_widths_for_columns(
|
||||
min_width --[[ int ]],
|
||||
should_use_strwidth --[[ bool ]]
|
||||
) -- table
|
||||
---
|
||||
---@param should_use_strwidth boolean
|
||||
---@return table
|
||||
function M:get_widths_for_columns(should_use_strwidth)
|
||||
local widths = {}
|
||||
|
||||
for i = 1, #self.table[1] do
|
||||
widths[i] = math.max(min_width, self:get_largest_length_for_column(i, should_use_strwidth))
|
||||
widths[i] = math.max(
|
||||
o.options.table.cell.min_width,
|
||||
self:get_largest_length_for_column(i, should_use_strwidth)
|
||||
)
|
||||
end
|
||||
|
||||
return widths
|
||||
@ -172,7 +187,7 @@ function M:move_highlight_down()
|
||||
end
|
||||
|
||||
function M:get_cell_positions(col, row, widths)
|
||||
local length = #"│"
|
||||
local length = #o.options.table.border.vertical
|
||||
local start_position = 0
|
||||
|
||||
for i, _ in ipairs(self.table[row]) do
|
||||
@ -193,50 +208,55 @@ function M:get_cell_positions(col, row, widths)
|
||||
return start_position, end_position
|
||||
end
|
||||
|
||||
function M:get_horizontal_border_width(
|
||||
col, -- [[ int ]]
|
||||
row, -- [[ int ]]
|
||||
min_value_width -- [[ int ]]
|
||||
)
|
||||
local length = #"─"
|
||||
---
|
||||
---@param col boolean
|
||||
---@param row boolean
|
||||
---@return number, number
|
||||
function M:get_horizontal_border_width(col, row)
|
||||
local length = #o.options.table.border.horizontal
|
||||
local start_position = 0
|
||||
local widths = self:get_widths_for_columns(min_value_width, true)
|
||||
local widths = self:get_widths_for_columns(true)
|
||||
|
||||
for i, _ in ipairs(self.table[1]) do
|
||||
if i == col then
|
||||
break
|
||||
end
|
||||
|
||||
start_position = start_position + math.max(min_value_width, widths[i]) * length
|
||||
start_position =
|
||||
start_position
|
||||
+ math.max(o.options.table.cell.min_width, widths[i]) * length
|
||||
|
||||
if row == 1 then
|
||||
start_position = start_position + #"┬"
|
||||
start_position = start_position + #o.options.table.border.top_t
|
||||
else
|
||||
start_position = start_position + #"┼"
|
||||
start_position = start_position + #o.options.table.border.cross
|
||||
end
|
||||
end
|
||||
|
||||
local end_position = 0
|
||||
|
||||
if col == 1 then
|
||||
end_position = #"┬"
|
||||
end_position = #o.options.table.border.top_t
|
||||
else
|
||||
end_position = #"┤"
|
||||
end_position = #o.options.table.border.right_t
|
||||
end
|
||||
|
||||
end_position = end_position + start_position + math.max(min_value_width, widths[col]) * length
|
||||
end_position =
|
||||
end_position
|
||||
+ start_position
|
||||
+ math.max(o.options.table.cell.min_width, widths[col]) * length
|
||||
|
||||
if row == 1 then
|
||||
if col == 1 then
|
||||
end_position = end_position + #"┬"
|
||||
end_position = end_position + #o.options.table.border.top_t
|
||||
else
|
||||
end_position = end_position + #"┐"
|
||||
end_position = end_position + #o.options.table.border.top_right
|
||||
end
|
||||
else
|
||||
if col == 1 then
|
||||
end_position = end_position + #"├"
|
||||
end_position = end_position + #o.options.table.border.left_t
|
||||
else
|
||||
end_position = end_position + #"┤"
|
||||
end_position = end_position + #o.options.table.border.right_t
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,27 +1,6 @@
|
||||
local M = {};
|
||||
local o = require("easytables.options")
|
||||
|
||||
DEFAULT_DRAW_REPRESENTATION_OPTIONS = {
|
||||
min_width = 3,
|
||||
filler = " ",
|
||||
top_left = "┌",
|
||||
top_right = "┐",
|
||||
bottom_left = "└",
|
||||
bottom_right = "┘",
|
||||
horizontal = "─",
|
||||
vertical = "│",
|
||||
left_t = "├",
|
||||
right_t = "┤",
|
||||
top_t = "┬",
|
||||
bottom_t = "┴",
|
||||
cross = "┼",
|
||||
header_left_t = "╞",
|
||||
header_right_t = "╡",
|
||||
header_bottom_t = "╧",
|
||||
header_cross = "╪",
|
||||
header_horizontal = "═",
|
||||
}
|
||||
|
||||
function create_horizontal_line(cell_widths, left, middle, right, middle_t)
|
||||
local function create_horizontal_line(cell_widths, left, middle, right, middle_t)
|
||||
local string = ""
|
||||
|
||||
string = string .. left
|
||||
@ -39,81 +18,92 @@ function create_horizontal_line(cell_widths, left, middle, right, middle_t)
|
||||
return string
|
||||
end
|
||||
|
||||
-- Creates a horizontal divider like this:
|
||||
-- `create_horizontal_divider(5, 5, {variant = "top"})`:
|
||||
-- ┌─────┬─────┬─────┬─────┬─────┐
|
||||
-- `create_horizontal_divider(5, 5, {variant = "between"})`:
|
||||
-- ├─────┼─────┼─────┼─────┼─────┤
|
||||
-- `create_horizontal_divider(5, 5, {variant = "bottom"})`:
|
||||
-- └─────┴─────┴─────┴─────┴─────┘
|
||||
function create_horizontal_divider(
|
||||
---Creates a horizontal divider like this:
|
||||
---`create_horizontal_divider(5, 5, {variant = "top"})`:
|
||||
---┌─────┬─────┬─────┬─────┬─────┐
|
||||
---`create_horizontal_divider(5, 5, {variant = "between"})`:
|
||||
---├─────┼─────┼─────┼─────┼─────┤
|
||||
---`create_horizontal_divider(5, 5, {variant = "bottom"})`:
|
||||
---└─────┴─────┴─────┴─────┴─────┘
|
||||
---@param table table
|
||||
---@param[opt="between"] variant string Either "top", "between" or "bottom"
|
||||
---@return string
|
||||
local function create_horizontal_divider(
|
||||
table,
|
||||
options -- [[ table ]] -- optional
|
||||
variant
|
||||
)
|
||||
local options = options or {}
|
||||
local top_left = options.top_left or DEFAULT_DRAW_REPRESENTATION_OPTIONS.top_left
|
||||
local top_right = options.top_right or DEFAULT_DRAW_REPRESENTATION_OPTIONS.top_right
|
||||
local bottom_left = options.bottom_left or DEFAULT_DRAW_REPRESENTATION_OPTIONS.bottom_left
|
||||
local bottom_right = options.bottom_right or DEFAULT_DRAW_REPRESENTATION_OPTIONS.bottom_right
|
||||
local horizontal = options.horizontal or DEFAULT_DRAW_REPRESENTATION_OPTIONS.horizontal
|
||||
local left_t = options.left_t or DEFAULT_DRAW_REPRESENTATION_OPTIONS.left_t
|
||||
local right_t = options.right_t or DEFAULT_DRAW_REPRESENTATION_OPTIONS.right_t
|
||||
local top_t = options.top_t or DEFAULT_DRAW_REPRESENTATION_OPTIONS.top_t
|
||||
local bottom_t = options.bottom_t or DEFAULT_DRAW_REPRESENTATION_OPTIONS.bottom_t
|
||||
local cross = options.cross or DEFAULT_DRAW_REPRESENTATION_OPTIONS.cross
|
||||
local header_left_t = options.header_left_t or DEFAULT_DRAW_REPRESENTATION_OPTIONS.header_left_t
|
||||
local header_right_t = options.header_right_t or DEFAULT_DRAW_REPRESENTATION_OPTIONS.header_right_t
|
||||
local header_cross = options.header_cross or DEFAULT_DRAW_REPRESENTATION_OPTIONS.header_cross
|
||||
local header_horizontal = options.header_horizontal or DEFAULT_DRAW_REPRESENTATION_OPTIONS.header_horizontal
|
||||
local min_width = options.min_width or DEFAULT_DRAW_REPRESENTATION_OPTIONS.min_width
|
||||
local variant = options.variant or "between"
|
||||
variant = variant or "between"
|
||||
|
||||
local widths = table:get_widths_for_columns(min_width)
|
||||
local widths = table:get_widths_for_columns()
|
||||
|
||||
if variant == "top" then
|
||||
return create_horizontal_line(widths, top_left, horizontal, top_right, top_t)
|
||||
return create_horizontal_line(
|
||||
widths,
|
||||
o.options.table.border.top_left,
|
||||
o.options.table.border.horizontal,
|
||||
o.options.table.border.top_right,
|
||||
o.options.table.border.top_t
|
||||
)
|
||||
elseif variant == "between" then
|
||||
return create_horizontal_line(widths, left_t, horizontal, right_t, cross)
|
||||
return create_horizontal_line(
|
||||
widths,
|
||||
o.options.table.border.left_t,
|
||||
o.options.table.border.horizontal,
|
||||
o.options.table.border.right_t,
|
||||
o.options.table.border.cross
|
||||
)
|
||||
elseif variant == "bottom" then
|
||||
return create_horizontal_line(widths, bottom_left, horizontal, bottom_right, bottom_t)
|
||||
return create_horizontal_line(
|
||||
widths,
|
||||
o.options.table.border.bottom_left,
|
||||
o.options.table.border.horizontal,
|
||||
o.options.table.border.bottom_right,
|
||||
o.options.table.border.bottom_t
|
||||
)
|
||||
elseif variant == "header" then
|
||||
return create_horizontal_line(widths, header_left_t, header_horizontal, header_right_t, header_cross)
|
||||
return create_horizontal_line(
|
||||
widths,
|
||||
o.options.table.border.header_left_t,
|
||||
o.options.table.border.header_horizontal,
|
||||
o.options.table.border.header_right_t,
|
||||
o.options.table.border.header_cross
|
||||
)
|
||||
end
|
||||
|
||||
return ""
|
||||
end
|
||||
|
||||
function table.draw_representation(
|
||||
table, -- [[ table ]]
|
||||
options -- [[ table ]] -- optional
|
||||
)
|
||||
local options = options or {}
|
||||
local min_width = options.min_width or DEFAULT_DRAW_REPRESENTATION_OPTIONS.min_width
|
||||
local filler = options.filler or DEFAULT_DRAW_REPRESENTATION_OPTIONS.filler
|
||||
local vertical = options.vertical or DEFAULT_DRAW_REPRESENTATION_OPTIONS.vertical
|
||||
|
||||
---Draws a table representation for the preview
|
||||
---@param table table
|
||||
---@return table
|
||||
local function draw_representation(table)
|
||||
local representation = {}
|
||||
|
||||
local horizontal_divider = create_horizontal_divider(table, options)
|
||||
local horizontal_divider = create_horizontal_divider(table, "between")
|
||||
|
||||
representation[#representation + 1] = create_horizontal_divider(table, { variant = "top" })
|
||||
representation[#representation + 1] = create_horizontal_divider(table, "top")
|
||||
|
||||
local column_widths = table:get_widths_for_columns(min_width)
|
||||
local column_widths = table:get_widths_for_columns()
|
||||
|
||||
for i = 1, table:rows_amount() do
|
||||
local line = ""
|
||||
|
||||
for j = 1, table:cols_amount() do
|
||||
local length = column_widths[j]
|
||||
local cell = table:value_at(i, j)
|
||||
local cell_width = vim.api.nvim_strwidth(cell)
|
||||
|
||||
if cell_width < length then
|
||||
cell = cell .. string.rep(filler, length - cell_width)
|
||||
cell = cell
|
||||
.. string.rep(o.options.table.cell.filler, length - cell_width)
|
||||
end
|
||||
|
||||
cell = vertical .. cell
|
||||
-- Add left vertical divider
|
||||
cell = o.options.table.border.vertical .. cell
|
||||
|
||||
-- Add most right vertical divider
|
||||
if j == table:cols_amount() then
|
||||
cell = cell .. vertical
|
||||
cell = cell .. o.options.table.border.vertical
|
||||
end
|
||||
|
||||
line = line .. cell
|
||||
@ -122,25 +112,17 @@ function table.draw_representation(
|
||||
representation[#representation + 1] = line
|
||||
|
||||
if i == 1 and table.header_enabled then
|
||||
representation[#representation + 1] = create_horizontal_divider(table, { variant = "header" })
|
||||
representation[#representation + 1] = create_horizontal_divider(table, "header")
|
||||
elseif i ~= table:rows_amount() then
|
||||
representation[#representation + 1] = horizontal_divider
|
||||
end
|
||||
end
|
||||
|
||||
representation[#representation + 1] = create_horizontal_divider(table, { variant = "bottom" })
|
||||
representation[#representation + 1] = create_horizontal_divider(table, "bottom")
|
||||
|
||||
return representation
|
||||
end
|
||||
|
||||
function table.from_representation(representation, options)
|
||||
local opts = options or {}
|
||||
|
||||
local table = {}
|
||||
|
||||
for i = 1, #representation do
|
||||
local character = representation[i]
|
||||
end
|
||||
end
|
||||
|
||||
return table
|
||||
return {
|
||||
draw_representation = draw_representation
|
||||
}
|
||||
|
@ -1,37 +1,33 @@
|
||||
local table_builder = require("easytables.tablebuilder")
|
||||
local export = require("easytables.export")
|
||||
local o = require("easytables.options")
|
||||
local math = require("math")
|
||||
|
||||
local M = {}
|
||||
|
||||
DEFAULT_OPTIONS = {
|
||||
title = "Table",
|
||||
prompt_title = "Content",
|
||||
width = 60,
|
||||
height = 30,
|
||||
min_value_width = 3,
|
||||
}
|
||||
|
||||
function M:create(table, options)
|
||||
options = options or {}
|
||||
|
||||
self.title = options.title or DEFAULT_OPTIONS.title
|
||||
self.prompt_title = options.prompt_title or DEFAULT_OPTIONS.prompt_title
|
||||
self.width = options.width or DEFAULT_OPTIONS.width
|
||||
self.height = options.height or DEFAULT_OPTIONS.height
|
||||
self.min_value_width = options.min_value_width or DEFAULT_OPTIONS.min_value_width
|
||||
self.table = table
|
||||
self.previous_window = vim.api.nvim_get_current_win()
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function M:_get_width()
|
||||
return 60
|
||||
end
|
||||
|
||||
function M:_get_preview_height()
|
||||
return 20
|
||||
end
|
||||
|
||||
function M:get_x()
|
||||
return math.floor((vim.o.columns - self.width) / 2)
|
||||
return math.floor((vim.o.columns - self:_get_width()) / 2)
|
||||
end
|
||||
|
||||
function M:get_y()
|
||||
return math.floor(((vim.o.lines - self.height) / 2) - 1)
|
||||
return math.floor(((vim.o.lines - self:_get_preview_height()) / 2) - 1)
|
||||
end
|
||||
|
||||
function M:_open_preview_window()
|
||||
@ -40,30 +36,34 @@ function M:_open_preview_window()
|
||||
relative = "win",
|
||||
col = self:get_x(),
|
||||
row = self:get_y(),
|
||||
width = self.width,
|
||||
height = self.height,
|
||||
width = self:_get_width(),
|
||||
height = self:_get_preview_height(),
|
||||
style = "minimal",
|
||||
border = "rounded",
|
||||
title = self.title,
|
||||
title = o.options.table.window.preview_title,
|
||||
title_pos = "center",
|
||||
})
|
||||
|
||||
-- Disable default highlight
|
||||
vim.api.nvim_set_option_value("winhighlight", "Normal:Normal",
|
||||
{ win = self.preview_window })
|
||||
vim.api.nvim_set_option_value(
|
||||
"winhighlight",
|
||||
"Normal:Normal",
|
||||
{ win = self.preview_window }
|
||||
)
|
||||
end
|
||||
|
||||
function M:_open_prompt_window()
|
||||
self.prompt_buffer = vim.api.nvim_create_buf(false, false)
|
||||
self.prompt_window = vim.api.nvim_open_win(self.prompt_buffer, true, {
|
||||
relative = "win",
|
||||
-- No idea why, but the window is shifted one cell to the right by default
|
||||
col = self:get_x() - 1,
|
||||
row = self:get_y() + self.height + 2,
|
||||
width = self.width,
|
||||
row = self:get_y() + self:_get_preview_height() + 2,
|
||||
width = self:_get_width(),
|
||||
height = 2,
|
||||
style = "minimal",
|
||||
border = "rounded",
|
||||
title = self.prompt_title,
|
||||
title = o.options.table.window.prompt_title,
|
||||
title_pos = "center",
|
||||
})
|
||||
|
||||
@ -147,7 +147,9 @@ function M:close()
|
||||
vim.api.nvim_win_close(self.preview_window, true)
|
||||
vim.api.nvim_win_close(self.prompt_window, true)
|
||||
|
||||
vim.api.nvim_set_current_win(self.previous_window)
|
||||
pcall(function()
|
||||
vim.api.nvim_set_current_win(self.previous_window)
|
||||
end)
|
||||
|
||||
self.preview_window = nil
|
||||
self.prompt_window = nil
|
||||
|
Loading…
x
Reference in New Issue
Block a user