Skip to content

Commit

Permalink
refactor: implement own version of vim.tbl_* without validate
Browse files Browse the repository at this point in the history
Most of the vim.tbl_* functions internally validate the input. This can
be very expensive for hot loops.
This implements an internal version of those functions without
validation.

fix #776
  • Loading branch information
lukas-reineke committed Dec 6, 2023
1 parent dbd90bb commit 9a1fe18
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 15 deletions.
3 changes: 2 additions & 1 deletion lua/ibl/highlights.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
local conf = require "ibl.config"
local hooks = require "ibl.hooks"
local utils = require "ibl.utils"

---@class ibl.highlight
---@field char string
Expand Down Expand Up @@ -27,7 +28,7 @@ end

---@param hl table
local not_set = function(hl)
return not hl or vim.tbl_count(hl) == 0
return not hl or utils.tbl_count(hl) == 0
end

local setup_builtin_hl_groups = function()
Expand Down
2 changes: 1 addition & 1 deletion lua/ibl/hooks.lua
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ end
M.clear = function(id)
vim.validate { id = { id, "string" } }
local type, hook_id = unpack(vim.split(id, "_"))
if not type or not hook_id or not vim.tbl_contains(M.type, type) then
if not type or not hook_id or not utils.tbl_contains(M.type, type) then
return
end
hooks[type][hook_id] = nil
Expand Down
14 changes: 9 additions & 5 deletions lua/ibl/indent.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
local utils = require "ibl.utils"
local M = {}

---@enum ibl.indent.whitespace
Expand Down Expand Up @@ -41,7 +42,7 @@ M.get = function(whitespace, opts, indent_state)
indent_cap = indent_state.stack[1] or 0
indent_state.cap = false
end
local varts = vim.tbl_map(tonumber, vim.split(vartabstop, ",", { trimempty = true }))
local varts = utils.tbl_map(tonumber, vim.split(vartabstop, ",", { trimempty = true }))
if shiftwidth == 0 then
shiftwidth = tabstop
end
Expand Down Expand Up @@ -74,7 +75,7 @@ M.get = function(whitespace, opts, indent_state)
end
else
local mod = (spaces + tabs + extra) % shiftwidth
if vim.tbl_contains(indent_state.stack, spaces + tabs) then
if utils.tbl_contains(indent_state.stack, spaces + tabs) then
table.insert(whitespace_tbl, M.whitespace.INDENT)
extra = extra + mod
elseif mod == 0 then
Expand All @@ -92,7 +93,7 @@ M.get = function(whitespace, opts, indent_state)
end
end

indent_state.stack = vim.tbl_filter(function(a)
indent_state.stack = utils.tbl_filter(function(a)
return a < spaces + tabs
end, indent_state.stack)
table.insert(indent_state.stack, spaces + tabs)
Expand All @@ -104,14 +105,17 @@ end
---
---@param whitespace ibl.indent.whitespace
M.is_indent = function(whitespace)
return vim.tbl_contains({ M.whitespace.INDENT, M.whitespace.TAB_START, M.whitespace.TAB_START_SINGLE }, whitespace)
return utils.tbl_contains(
{ M.whitespace.INDENT, M.whitespace.TAB_START, M.whitespace.TAB_START_SINGLE },
whitespace
)
end

--- Returns true if the passed whitespace belongs to space indent
---
---@param whitespace ibl.indent.whitespace
M.is_space_indent = function(whitespace)
return vim.tbl_contains({ M.whitespace.INDENT, M.whitespace.SPACE }, whitespace)
return utils.tbl_contains({ M.whitespace.INDENT, M.whitespace.SPACE }, whitespace)
end

return M
2 changes: 1 addition & 1 deletion lua/ibl/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ M.refresh = function(bufnr)
if scope_start and scope then
scope_col_start = #whitespace
scope_col_start_single = #whitespace_tbl
scope_index = #vim.tbl_filter(function(w)
scope_index = #utils.tbl_filter(function(w)
return indent.is_indent(w)
end, whitespace_tbl) + 1
for _, fn in
Expand Down
8 changes: 4 additions & 4 deletions lua/ibl/scope.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ M.language_for_range = function(language_tree, range, config)
end
end

if not vim.tbl_contains(config.scope.exclude.language, language_tree:lang()) then
if not utils.tbl_contains(config.scope.exclude.language, language_tree:lang()) then
return language_tree
end
end
Expand Down Expand Up @@ -76,9 +76,9 @@ M.get = function(bufnr, config)
local type = node:type()

if
(scope_lang[lang][type] and not vim.tbl_contains(excluded_node_types, type))
or vim.tbl_contains(include_node_types, type)
or vim.tbl_contains(include_node_types, "*")
(scope_lang[lang][type] and not utils.tbl_contains(excluded_node_types, type))
or utils.tbl_contains(include_node_types, type)
or utils.tbl_contains(include_node_types, "*")
then
return node
else
Expand Down
72 changes: 70 additions & 2 deletions lua/ibl/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,74 @@ M.validate = function(opt, input, path)
end
end

--- copy of vim.tbl_contains without vim.validate
---
---@param t table Table to check
---@param value any Value to compare or predicate function reference
---@param opts table? Keyword arguments |kwargs|:
--- - predicate: (boolean) `value` is a function reference to be checked (default false)
---@return boolean `true` if `t` contains `value`
M.tbl_contains = function(t, value, opts)
local pred
if opts and opts.predicate then
vim.validate { value = { value, "c" } }
pred = value
else
pred = function(v)
return v == value
end
end

for _, v in pairs(t) do
if pred(v) then
return true
end
end
return false
end

--- copy of vim.tbl_count without vim.validate
---
---@param t table Table
---@return integer Number of non-nil values in table
M.tbl_count = function(t)
local count = 0
for _ in pairs(t) do
count = count + 1
end
return count
end

--- copy of vim.tbl_map without vim.validate
---
---@generic T
---@param func fun(value: T): any (function) Function
---@param t table<any, T> (table) Table
---@return table Table of transformed values
M.tbl_map = function(func, t)
local rettab = {}
for k, v in pairs(t) do
rettab[k] = func(v)
end
return rettab
end

--- copy of vim.tbl_filter without vim.validate
---
---@generic T
---@param func fun(value: T): boolean (function) Function
---@param t table<any, T> (table) Table
---@return T[] (table) Table of filtered values
M.tbl_filter = function(func, t)
local rettab = {}
for _, entry in pairs(t) do
if func(entry) then
table.insert(rettab, entry)
end
end
return rettab
end

---@param codepoint integer
M.utf8_encode = function(codepoint)
if codepoint <= 0x7F then
Expand Down Expand Up @@ -239,13 +307,13 @@ end
---@param config ibl.config
M.is_buffer_active = function(bufnr, config)
for _, filetype in ipairs(M.get_filetypes(bufnr)) do
if vim.tbl_contains(config.exclude.filetypes, filetype) then
if M.tbl_contains(config.exclude.filetypes, filetype) then
return false
end
end

local buftype = vim.api.nvim_get_option_value("buftype", { buf = bufnr })
if vim.tbl_contains(config.exclude.buftypes, buftype) then
if M.tbl_contains(config.exclude.buftypes, buftype) then
return false
end

Expand Down
2 changes: 1 addition & 1 deletion lua/ibl/virt_text.lua
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ M.get = function(config, char_map, whitespace_tbl, scope_active, scope_index, sc

table.insert(virt_text, {
char,
vim.tbl_filter(function(v)
utils.tbl_filter(function(v)
return v ~= nil
end, { whitespace_hl, indent_hl, underline_hl }),
})
Expand Down

0 comments on commit 9a1fe18

Please sign in to comment.