summaryrefslogtreecommitdiff
path: root/start/indent-blankline-2.20.4/lua/indent_blankline/utils.lua
diff options
context:
space:
mode:
Diffstat (limited to 'start/indent-blankline-2.20.4/lua/indent_blankline/utils.lua')
-rw-r--r--start/indent-blankline-2.20.4/lua/indent_blankline/utils.lua341
1 files changed, 341 insertions, 0 deletions
diff --git a/start/indent-blankline-2.20.4/lua/indent_blankline/utils.lua b/start/indent-blankline-2.20.4/lua/indent_blankline/utils.lua
new file mode 100644
index 0000000..e21a5c9
--- /dev/null
+++ b/start/indent-blankline-2.20.4/lua/indent_blankline/utils.lua
@@ -0,0 +1,341 @@
+local M = {}
+
+M.memo = setmetatable({
+ put = function(cache, params, result)
+ local node = cache
+ for i = 1, #params do
+ local param = vim.inspect(params[i])
+ node.children = node.children or {}
+ node.children[param] = node.children[param] or {}
+ node = node.children[param]
+ end
+ node.result = result
+ end,
+ get = function(cache, params)
+ local node = cache
+ for i = 1, #params do
+ local param = vim.inspect(params[i])
+ node = node.children and node.children[param]
+ if not node then
+ return nil
+ end
+ end
+ return node.result
+ end,
+}, {
+ __call = function(memo, func)
+ local cache = {}
+
+ return function(...)
+ local params = { ... }
+ local result = memo.get(cache, params)
+ if not result then
+ result = { func(...) }
+ memo.put(cache, params, result)
+ end
+ return unpack(result)
+ end
+ end,
+})
+
+M.error_handler = function(err, level)
+ if err:match "Invalid buffer id.*" then
+ return
+ end
+ if not pcall(require, "notify") then
+ err = string.format("indent-blankline: %s", err)
+ end
+ vim.notify_once(err, level or vim.log.levels.DEBUG, {
+ title = "indent-blankline",
+ })
+end
+
+M.is_indent_blankline_enabled = M.memo(
+ function(
+ b_enabled,
+ g_enabled,
+ disable_with_nolist,
+ opt_list,
+ filetype,
+ filetype_include,
+ filetype_exclude,
+ buftype,
+ buftype_exclude,
+ bufname_exclude,
+ bufname
+ )
+ if b_enabled ~= nil then
+ return b_enabled
+ end
+ if g_enabled ~= true then
+ return false
+ end
+ if disable_with_nolist and not opt_list then
+ return false
+ end
+
+ local plain = M._if(vim.fn.has "nvim-0.6.0" == 1, { plain = true }, true)
+ local undotted_filetypes = vim.split(filetype, ".", plain)
+ table.insert(undotted_filetypes, filetype)
+
+ for _, ft in ipairs(filetype_exclude) do
+ for _, undotted_filetype in ipairs(undotted_filetypes) do
+ if undotted_filetype == ft then
+ return false
+ end
+ end
+ end
+
+ for _, bt in ipairs(buftype_exclude) do
+ if bt == buftype then
+ return false
+ end
+ end
+
+ for _, bn in ipairs(bufname_exclude) do
+ if vim.fn["matchstr"](bufname, bn) == bufname then
+ return false
+ end
+ end
+
+ if #filetype_include > 0 then
+ for _, ft in ipairs(filetype_include) do
+ if ft == filetype then
+ return true
+ end
+ end
+ return false
+ end
+
+ return true
+ end
+)
+
+M.clear_line_indent = function(buf, lnum)
+ xpcall(vim.api.nvim_buf_clear_namespace, M.error_handler, buf, vim.g.indent_blankline_namespace, lnum - 1, lnum)
+end
+
+M.clear_buf_indent = function(buf)
+ xpcall(vim.api.nvim_buf_clear_namespace, M.error_handler, buf, vim.g.indent_blankline_namespace, 0, -1)
+end
+
+M.get_from_list = function(list, i, default)
+ if not list or #list == 0 then
+ return default
+ end
+ return list[((i - 1) % #list) + 1]
+end
+
+M._if = function(bool, a, b)
+ if bool then
+ return a
+ else
+ return b
+ end
+end
+
+M.find_indent = function(whitespace, only_whitespace, shiftwidth, strict_tabs, list_chars)
+ local indent = 0
+ local spaces = 0
+ local tab_width
+ local virtual_string = {}
+
+ if whitespace then
+ for ch in whitespace:gmatch "." do
+ if ch == "\t" then
+ if strict_tabs and indent == 0 and spaces ~= 0 then
+ return 0, false, {}
+ end
+ indent = indent + math.floor(spaces / shiftwidth) + 1
+ spaces = 0
+ -- replace dynamic-width tab with fixed-width string (ta..ab)
+ tab_width = shiftwidth - table.maxn(virtual_string) % shiftwidth
+ -- check if tab_char_end is set, see :help listchars
+ if list_chars["tab_char_end"] then
+ if tab_width == 1 then
+ table.insert(virtual_string, list_chars["tab_char_end"])
+ else
+ table.insert(virtual_string, list_chars["tab_char_start"])
+ for _ = 1, (tab_width - 2) do
+ table.insert(virtual_string, list_chars["tab_char_fill"])
+ end
+ table.insert(virtual_string, list_chars["tab_char_end"])
+ end
+ else
+ table.insert(virtual_string, list_chars["tab_char_start"])
+ for _ = 1, (tab_width - 1) do
+ table.insert(virtual_string, list_chars["tab_char_fill"])
+ end
+ end
+ else
+ if strict_tabs and indent ~= 0 then
+ -- return early when no more tabs are found
+ return indent, true, virtual_string
+ end
+ if only_whitespace then
+ -- if the entire line is only whitespace use trail_char instead of lead_char
+ table.insert(virtual_string, list_chars["trail_char"])
+ else
+ table.insert(virtual_string, list_chars["lead_char"])
+ end
+ spaces = spaces + 1
+ end
+ end
+ end
+
+ return indent + math.floor(spaces / shiftwidth), table.maxn(virtual_string) % shiftwidth ~= 0, virtual_string
+end
+
+M.get_current_context = function(type_patterns, use_treesitter_scope)
+ local ts_utils_status, ts_utils = pcall(require, "nvim-treesitter.ts_utils")
+ if not ts_utils_status then
+ vim.schedule_wrap(function()
+ M.error_handler("nvim-treesitter not found. Context will not work", vim.log.levels.WARN)
+ end)()
+ return false
+ end
+ local locals = require "nvim-treesitter.locals"
+ local cursor_node = ts_utils.get_node_at_cursor()
+
+ if use_treesitter_scope then
+ local current_scope = locals.containing_scope(cursor_node, 0)
+ if not current_scope then
+ return false
+ end
+ local node_start, _, node_end, _ = current_scope:range()
+ if node_start == node_end then
+ return false
+ end
+ return true, node_start + 1, node_end + 1, current_scope:type()
+ end
+
+ while cursor_node do
+ local node_type = cursor_node:type()
+ for _, rgx in ipairs(type_patterns) do
+ if node_type:find(rgx) then
+ local node_start, _, node_end, _ = cursor_node:range()
+ if node_start ~= node_end then
+ return true, node_start + 1, node_end + 1, rgx
+ end
+ end
+ end
+ cursor_node = cursor_node:parent()
+ end
+
+ return false
+end
+
+M.reset_highlights = function()
+ local whitespace_highlight = vim.fn.synIDtrans(vim.fn.hlID "Whitespace")
+ local label_highlight = vim.fn.synIDtrans(vim.fn.hlID "Label")
+
+ local whitespace_fg = {
+ vim.fn.synIDattr(whitespace_highlight, "fg", "gui"),
+ vim.fn.synIDattr(whitespace_highlight, "fg", "cterm"),
+ }
+ local label_fg = {
+ vim.fn.synIDattr(label_highlight, "fg", "gui"),
+ vim.fn.synIDattr(label_highlight, "fg", "cterm"),
+ }
+
+ for highlight_name, highlight in pairs {
+ IndentBlanklineChar = whitespace_fg,
+ IndentBlanklineSpaceChar = whitespace_fg,
+ IndentBlanklineSpaceCharBlankline = whitespace_fg,
+ IndentBlanklineContextChar = label_fg,
+ IndentBlanklineContextStart = label_fg,
+ } do
+ local current_highlight = vim.fn.synIDtrans(vim.fn.hlID(highlight_name))
+ if
+ vim.fn.synIDattr(current_highlight, "fg") == ""
+ and vim.fn.synIDattr(current_highlight, "bg") == ""
+ and vim.fn.synIDattr(current_highlight, "sp") == ""
+ then
+ if highlight_name == "IndentBlanklineContextStart" then
+ vim.cmd(
+ string.format(
+ "highlight %s guisp=%s gui=underline cterm=underline",
+ highlight_name,
+ M._if(highlight[1] == "", "NONE", highlight[1])
+ )
+ )
+ else
+ vim.cmd(
+ string.format(
+ "highlight %s guifg=%s ctermfg=%s gui=nocombine cterm=nocombine",
+ highlight_name,
+ M._if(highlight[1] == "", "NONE", highlight[1]),
+ M._if(highlight[2] == "", "NONE", highlight[2])
+ )
+ )
+ end
+ end
+ end
+end
+
+M.first_not_nil = function(...)
+ for _, value in pairs { ... } do -- luacheck: ignore
+ return value
+ end
+end
+
+M.get_variable = function(key)
+ if vim.b[key] ~= nil then
+ return vim.b[key]
+ end
+ if vim.t[key] ~= nil then
+ return vim.t[key]
+ end
+ return vim.g[key]
+end
+
+M.merge_ranges = function(ranges)
+ local merged_ranges = { { unpack(ranges[1]) } }
+
+ for i = 2, #ranges do
+ local current_end = merged_ranges[#merged_ranges][2]
+ local next_start, next_end = unpack(ranges[i])
+ if current_end >= next_start - 1 then
+ if current_end < next_end then
+ merged_ranges[#merged_ranges][2] = next_end
+ end
+ else
+ table.insert(merged_ranges, { next_start, next_end })
+ end
+ end
+
+ return merged_ranges
+end
+
+M.binary_search_ranges = function(ranges, target_range)
+ local exact_match = false
+ local idx_start = 1
+ local idx_end = #ranges
+ local idx_mid
+
+ local range_start
+ local target_start = target_range[1]
+
+ while idx_start < idx_end do
+ idx_mid = math.ceil((idx_start + idx_end) / 2)
+ range_start = ranges[idx_mid][1]
+
+ if range_start == target_start then
+ exact_match = true
+ break
+ elseif range_start < target_start then
+ idx_start = idx_mid -- it's important to make the low-end inclusive
+ else
+ idx_end = idx_mid - 1
+ end
+ end
+
+ -- if we don't have an exact match, choose the smallest index
+ if not exact_match then
+ idx_mid = idx_start
+ end
+
+ return idx_mid
+end
+
+return M