aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim')
-rw-r--r--runtime/lua/vim/F.lua8
-rw-r--r--runtime/lua/vim/_editor.lua69
-rw-r--r--runtime/lua/vim/_init_packages.lua6
-rw-r--r--runtime/lua/vim/_inspector.lua238
-rw-r--r--runtime/lua/vim/_meta.lua871
-rw-r--r--runtime/lua/vim/compat.lua12
-rw-r--r--runtime/lua/vim/diagnostic.lua358
-rw-r--r--runtime/lua/vim/filetype.lua162
-rw-r--r--runtime/lua/vim/filetype/detect.lua79
-rw-r--r--runtime/lua/vim/fs.lua175
-rw-r--r--runtime/lua/vim/health.lua15
-rw-r--r--runtime/lua/vim/highlight.lua3
-rw-r--r--runtime/lua/vim/inspect.lua32
-rw-r--r--runtime/lua/vim/keymap.lua39
-rw-r--r--runtime/lua/vim/lsp.lua481
-rw-r--r--runtime/lua/vim/lsp/buf.lua316
-rw-r--r--runtime/lua/vim/lsp/codelens.lua27
-rw-r--r--runtime/lua/vim/lsp/diagnostic.lua2
-rw-r--r--runtime/lua/vim/lsp/handlers.lua145
-rw-r--r--runtime/lua/vim/lsp/health.lua16
-rw-r--r--runtime/lua/vim/lsp/log.lua17
-rw-r--r--runtime/lua/vim/lsp/protocol.lua97
-rw-r--r--runtime/lua/vim/lsp/rpc.lua741
-rw-r--r--runtime/lua/vim/lsp/semantic_tokens.lua702
-rw-r--r--runtime/lua/vim/lsp/sync.lua2
-rw-r--r--runtime/lua/vim/lsp/util.lua207
-rw-r--r--runtime/lua/vim/secure.lua188
-rw-r--r--runtime/lua/vim/shared.lua167
-rw-r--r--runtime/lua/vim/treesitter.lua461
-rw-r--r--runtime/lua/vim/treesitter/health.lua21
-rw-r--r--runtime/lua/vim/treesitter/highlighter.lua177
-rw-r--r--runtime/lua/vim/treesitter/language.lua22
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua145
-rw-r--r--runtime/lua/vim/treesitter/playground.lua186
-rw-r--r--runtime/lua/vim/treesitter/query.lua180
-rw-r--r--runtime/lua/vim/ui.lua21
36 files changed, 4349 insertions, 2039 deletions
diff --git a/runtime/lua/vim/F.lua b/runtime/lua/vim/F.lua
index bca5ddf68b..3e370c0a84 100644
--- a/runtime/lua/vim/F.lua
+++ b/runtime/lua/vim/F.lua
@@ -2,8 +2,12 @@ local F = {}
--- Returns {a} if it is not nil, otherwise returns {b}.
---
----@param a
----@param b
+---@generic A
+---@generic B
+---
+---@param a A
+---@param b B
+---@return A | B
function F.if_nil(a, b)
if a == nil then
return b
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index b8a7f71145..da8764fbd4 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -12,21 +12,8 @@
-- Guideline: "If in doubt, put it in the runtime".
--
-- Most functions should live directly in `vim.`, not in submodules.
--- The only "forbidden" names are those claimed by legacy `if_lua`:
--- $ vim
--- :lua for k,v in pairs(vim) do print(k) end
--- buffer
--- open
--- window
--- lastline
--- firstline
--- type
--- line
--- eval
--- dict
--- beep
--- list
--- command
+--
+-- Compatibility with Vim's `if_lua` is explicitly a non-goal.
--
-- Reference (#6580):
-- - https://github.com/luafun/luafun
@@ -36,8 +23,6 @@
-- - https://github.com/bakpakin/Fennel (pretty print, repl)
-- - https://github.com/howl-editor/howl/tree/master/lib/howl/util
-local vim = assert(vim)
-
-- These are for loading runtime modules lazily since they aren't available in
-- the nvim binary as specified in executor.c
for k, v in pairs({
@@ -51,6 +36,7 @@ for k, v in pairs({
ui = true,
health = true,
fs = true,
+ secure = true,
}) do
vim._submodules[k] = v
end
@@ -122,9 +108,7 @@ function vim._os_proc_children(ppid)
return children
end
--- TODO(ZyX-I): Create compatibility layer.
-
---- Return a human-readable representation of the given object.
+--- Gets a human-readable representation of the given object.
---
---@see https://github.com/kikito/inspect.lua
---@see https://github.com/mpeterv/vinspect
@@ -139,7 +123,7 @@ do
--- (such as the |TUI|) pastes text into the editor.
---
--- Example: To remove ANSI color codes when pasting:
- --- <pre>
+ --- <pre>lua
--- vim.paste = (function(overridden)
--- return function(lines, phase)
--- for i,line in ipairs(lines) do
@@ -152,14 +136,15 @@ do
--- </pre>
---
---@see |paste|
+ ---@alias paste_phase -1 | 1 | 2 | 3
---
- ---@param lines |readfile()|-style list of lines to paste. |channel-lines|
- ---@param phase -1: "non-streaming" paste: the call contains all lines.
+ ---@param lines string[] # |readfile()|-style list of lines to paste. |channel-lines|
+ ---@param phase paste_phase -1: "non-streaming" paste: the call contains all lines.
--- If paste is "streamed", `phase` indicates the stream state:
--- - 1: starts the paste (exactly once)
--- - 2: continues the paste (zero or more times)
--- - 3: ends the paste (exactly once)
- ---@returns false if client should cancel the paste.
+ ---@returns boolean # false if client should cancel the paste.
function vim.paste(lines, phase)
local now = vim.loop.now()
local is_first_chunk = phase < 2
@@ -183,7 +168,8 @@ do
local line1 = lines[1]:gsub('(%c)', '\022%1')
-- nvim_input() is affected by mappings,
-- so use nvim_feedkeys() with "n" flag to ignore mappings.
- vim.api.nvim_feedkeys(line1, 'n', true)
+ -- "t" flag is also needed so the pasted text is saved in cmdline history.
+ vim.api.nvim_feedkeys(line1, 'nt', true)
end
return true
end
@@ -255,6 +241,8 @@ end
---@see |lua-loop-callbacks|
---@see |vim.schedule()|
---@see |vim.in_fast_event()|
+---@param cb function
+---@return function
function vim.schedule_wrap(cb)
return function(...)
local args = vim.F.pack_len(...)
@@ -292,7 +280,7 @@ end
--- command.
---
--- Example:
---- <pre>
+--- <pre>lua
--- vim.cmd('echo 42')
--- vim.cmd([[
--- augroup My_group
@@ -399,11 +387,11 @@ end
--- Get a table of lines with start, end columns for a region marked by two points
---
---@param bufnr number of buffer
----@param pos1 (line, column) tuple marking beginning of region
----@param pos2 (line, column) tuple marking end of region
----@param regtype type of selection (:help setreg)
+---@param pos1 integer[] (line, column) tuple marking beginning of region
+---@param pos2 integer[] (line, column) tuple marking end of region
+---@param regtype string type of selection, see |setreg()|
---@param inclusive boolean indicating whether the selection is end-inclusive
----@return region lua table of the form {linenr = {startcol,endcol}}
+---@return table region Table of the form `{linenr = {startcol,endcol}}`
function vim.region(bufnr, pos1, pos2, regtype, inclusive)
if not vim.api.nvim_buf_is_loaded(bufnr) then
vim.fn.bufload(bufnr)
@@ -430,11 +418,16 @@ function vim.region(bufnr, pos1, pos2, regtype, inclusive)
c2 = c1 + regtype:sub(2)
-- and adjust for non-ASCII characters
bufline = vim.api.nvim_buf_get_lines(bufnr, l, l + 1, true)[1]
- if c1 < #bufline then
+ local utflen = vim.str_utfindex(bufline, #bufline)
+ if c1 <= utflen then
c1 = vim.str_byteindex(bufline, c1)
+ else
+ c1 = #bufline + 1
end
- if c2 < #bufline then
+ if c2 <= utflen then
c2 = vim.str_byteindex(bufline, c2)
+ else
+ c2 = #bufline + 1
end
else
c1 = (l == pos1[1]) and pos1[2] or 0
@@ -448,11 +441,11 @@ end
--- Defers calling `fn` until `timeout` ms passes.
---
--- Use to do a one-shot timer that calls `fn`
---- Note: The {fn} is |schedule_wrap|ped automatically, so API functions are
+--- Note: The {fn} is |vim.schedule_wrap()|ped automatically, so API functions are
--- safe to call.
----@param fn Callback to call once `timeout` expires
----@param timeout Number of milliseconds to wait before calling `fn`
----@return timer luv timer object
+---@param fn function Callback to call once `timeout` expires
+---@param timeout integer Number of milliseconds to wait before calling `fn`
+---@return table timer luv timer object
function vim.defer_fn(fn, timeout)
vim.validate({ fn = { fn, 'c', true } })
local timer = vim.loop.new_timer()
@@ -753,12 +746,12 @@ end
---Prints given arguments in human-readable format.
---Example:
----<pre>
+---<pre>lua
--- -- Print highlight group Normal and store it's contents in a variable.
--- local hl_normal = vim.pretty_print(vim.api.nvim_get_hl_by_name("Normal", true))
---</pre>
---@see |vim.inspect()|
----@return given arguments.
+---@return any # given arguments.
function vim.pretty_print(...)
local objects = {}
for i = 1, select('#', ...) do
diff --git a/runtime/lua/vim/_init_packages.lua b/runtime/lua/vim/_init_packages.lua
index 7e3c73667e..0c4ee8636d 100644
--- a/runtime/lua/vim/_init_packages.lua
+++ b/runtime/lua/vim/_init_packages.lua
@@ -1,6 +1,3 @@
--- prevents luacheck from making lints for setting things on vim
-local vim = assert(vim)
-
local pathtrails = {}
vim._so_trails = {}
for s in (package.cpath .. ';'):gmatch('[^;]*;') do
@@ -59,6 +56,9 @@ setmetatable(vim, {
if vim._submodules[key] then
t[key] = require('vim.' .. key)
return t[key]
+ elseif key == 'inspect_pos' or key == 'show_pos' then
+ require('vim._inspector')
+ return t[key]
elseif vim.startswith(key, 'uri_') then
local val = require('vim.uri')[key]
if val ~= nil then
diff --git a/runtime/lua/vim/_inspector.lua b/runtime/lua/vim/_inspector.lua
new file mode 100644
index 0000000000..f46a525910
--- /dev/null
+++ b/runtime/lua/vim/_inspector.lua
@@ -0,0 +1,238 @@
+---@class InspectorFilter
+---@field syntax boolean include syntax based highlight groups (defaults to true)
+---@field treesitter boolean include treesitter based highlight groups (defaults to true)
+---@field extmarks boolean|"all" include extmarks. When `all`, then extmarks without a `hl_group` will also be included (defaults to true)
+---@field semantic_tokens boolean include semantic tokens (defaults to true)
+local defaults = {
+ syntax = true,
+ treesitter = true,
+ extmarks = true,
+ semantic_tokens = true,
+}
+
+---Get all the items at a given buffer position.
+---
+---Can also be pretty-printed with `:Inspect!`. *:Inspect!*
+---
+---@param bufnr? number defaults to the current buffer
+---@param row? number row to inspect, 0-based. Defaults to the row of the current cursor
+---@param col? number col to inspect, 0-based. Defaults to the col of the current cursor
+---@param filter? InspectorFilter (table|nil) a table with key-value pairs to filter the items
+--- - syntax (boolean): include syntax based highlight groups (defaults to true)
+--- - treesitter (boolean): include treesitter based highlight groups (defaults to true)
+--- - extmarks (boolean|"all"): include extmarks. When `all`, then extmarks without a `hl_group` will also be included (defaults to true)
+--- - semantic_tokens (boolean): include semantic tokens (defaults to true)
+---@return {treesitter:table,syntax:table,extmarks:table,semantic_tokens:table,buffer:number,col:number,row:number} (table) a table with the following key-value pairs. Items are in "traversal order":
+--- - treesitter: a list of treesitter captures
+--- - syntax: a list of syntax groups
+--- - semantic_tokens: a list of semantic tokens
+--- - extmarks: a list of extmarks
+--- - buffer: the buffer used to get the items
+--- - row: the row used to get the items
+--- - col: the col used to get the items
+function vim.inspect_pos(bufnr, row, col, filter)
+ filter = vim.tbl_deep_extend('force', defaults, filter or {})
+
+ bufnr = bufnr or 0
+ if row == nil or col == nil then
+ -- get the row/col from the first window displaying the buffer
+ local win = bufnr == 0 and vim.api.nvim_get_current_win() or vim.fn.bufwinid(bufnr)
+ if win == -1 then
+ error('row/col is required for buffers not visible in a window')
+ end
+ local cursor = vim.api.nvim_win_get_cursor(win)
+ row, col = cursor[1] - 1, cursor[2]
+ end
+ bufnr = bufnr == 0 and vim.api.nvim_get_current_buf() or bufnr
+
+ local results = {
+ treesitter = {},
+ syntax = {},
+ extmarks = {},
+ semantic_tokens = {},
+ buffer = bufnr,
+ row = row,
+ col = col,
+ }
+
+ -- resolve hl links
+ ---@private
+ local function resolve_hl(data)
+ if data.hl_group then
+ local hlid = vim.api.nvim_get_hl_id_by_name(data.hl_group)
+ local name = vim.fn.synIDattr(vim.fn.synIDtrans(hlid), 'name')
+ data.hl_group_link = name
+ end
+ return data
+ end
+
+ -- treesitter
+ if filter.treesitter then
+ for _, capture in pairs(vim.treesitter.get_captures_at_pos(bufnr, row, col)) do
+ capture.hl_group = '@' .. capture.capture
+ table.insert(results.treesitter, resolve_hl(capture))
+ end
+ end
+
+ -- syntax
+ if filter.syntax then
+ for _, i1 in ipairs(vim.fn.synstack(row + 1, col + 1)) do
+ table.insert(results.syntax, resolve_hl({ hl_group = vim.fn.synIDattr(i1, 'name') }))
+ end
+ end
+
+ -- semantic tokens
+ if filter.semantic_tokens then
+ for _, token in ipairs(vim.lsp.semantic_tokens.get_at_pos(bufnr, row, col) or {}) do
+ token.hl_groups = {
+ type = resolve_hl({ hl_group = '@' .. token.type }),
+ modifiers = vim.tbl_map(function(modifier)
+ return resolve_hl({ hl_group = '@' .. modifier })
+ end, token.modifiers or {}),
+ }
+ table.insert(results.semantic_tokens, token)
+ end
+ end
+
+ -- extmarks
+ if filter.extmarks then
+ for ns, nsid in pairs(vim.api.nvim_get_namespaces()) do
+ if ns:find('vim_lsp_semantic_tokens') ~= 1 then
+ local extmarks = vim.api.nvim_buf_get_extmarks(bufnr, nsid, 0, -1, { details = true })
+ for _, extmark in ipairs(extmarks) do
+ extmark = {
+ ns_id = nsid,
+ ns = ns,
+ id = extmark[1],
+ row = extmark[2],
+ col = extmark[3],
+ opts = resolve_hl(extmark[4]),
+ }
+ local end_row = extmark.opts.end_row or extmark.row -- inclusive
+ local end_col = extmark.opts.end_col or (extmark.col + 1) -- exclusive
+ if
+ (filter.extmarks == 'all' or extmark.opts.hl_group) -- filter hl_group
+ and (row >= extmark.row and row <= end_row) -- within the rows of the extmark
+ and (row > extmark.row or col >= extmark.col) -- either not the first row, or in range of the col
+ and (row < end_row or col < end_col) -- either not in the last row or in range of the col
+ then
+ table.insert(results.extmarks, extmark)
+ end
+ end
+ end
+ end
+ end
+ return results
+end
+
+---Show all the items at a given buffer position.
+---
+---Can also be shown with `:Inspect`. *:Inspect*
+---
+---@param bufnr? number defaults to the current buffer
+---@param row? number row to inspect, 0-based. Defaults to the row of the current cursor
+---@param col? number col to inspect, 0-based. Defaults to the col of the current cursor
+---@param filter? InspectorFilter (table|nil) see |vim.inspect_pos()|
+function vim.show_pos(bufnr, row, col, filter)
+ local items = vim.inspect_pos(bufnr, row, col, filter)
+
+ local lines = { {} }
+
+ ---@private
+ local function append(str, hl)
+ table.insert(lines[#lines], { str, hl })
+ end
+
+ ---@private
+ local function nl()
+ table.insert(lines, {})
+ end
+
+ ---@private
+ local function item(data, comment)
+ append(' - ')
+ append(data.hl_group, data.hl_group)
+ append(' ')
+ if data.hl_group ~= data.hl_group_link then
+ append('links to ', 'MoreMsg')
+ append(data.hl_group_link, data.hl_group_link)
+ append(' ')
+ end
+ if comment then
+ append(comment, 'Comment')
+ end
+ nl()
+ end
+
+ -- treesitter
+ if #items.treesitter > 0 then
+ append('Treesitter', 'Title')
+ nl()
+ for _, capture in ipairs(items.treesitter) do
+ item(capture, capture.lang)
+ end
+ nl()
+ end
+
+ if #items.semantic_tokens > 0 then
+ append('Semantic Tokens', 'Title')
+ nl()
+ for _, token in ipairs(items.semantic_tokens) do
+ local client = vim.lsp.get_client_by_id(token.client_id)
+ client = client and (' (' .. client.name .. ')') or ''
+ item(token.hl_groups.type, 'type' .. client)
+ for _, modifier in ipairs(token.hl_groups.modifiers) do
+ item(modifier, 'modifier' .. client)
+ end
+ end
+ nl()
+ end
+
+ -- syntax
+ if #items.syntax > 0 then
+ append('Syntax', 'Title')
+ nl()
+ for _, syn in ipairs(items.syntax) do
+ item(syn)
+ end
+ nl()
+ end
+ -- extmarks
+ if #items.extmarks > 0 then
+ append('Extmarks', 'Title')
+ nl()
+ for _, extmark in ipairs(items.extmarks) do
+ if extmark.opts.hl_group then
+ item(extmark.opts, extmark.ns)
+ else
+ append(' - ')
+ append(extmark.ns, 'Comment')
+ nl()
+ end
+ end
+ nl()
+ end
+
+ if #lines[#lines] == 0 then
+ table.remove(lines)
+ end
+
+ local chunks = {}
+ for _, line in ipairs(lines) do
+ vim.list_extend(chunks, line)
+ table.insert(chunks, { '\n' })
+ end
+ if #chunks == 0 then
+ chunks = {
+ {
+ 'No items found at position '
+ .. items.row
+ .. ','
+ .. items.col
+ .. ' in buffer '
+ .. items.buffer,
+ },
+ }
+ end
+ vim.api.nvim_echo(chunks, false, {})
+end
diff --git a/runtime/lua/vim/_meta.lua b/runtime/lua/vim/_meta.lua
index f1652718ee..104f29c4c0 100644
--- a/runtime/lua/vim/_meta.lua
+++ b/runtime/lua/vim/_meta.lua
@@ -1,173 +1,113 @@
--- prevents luacheck from making lints for setting things on vim
-local vim = assert(vim)
-
local a = vim.api
-local validate = vim.validate
-
-local SET_TYPES = setmetatable({
- SET = 0,
- LOCAL = 1,
- GLOBAL = 2,
-}, { __index = error })
-
-local options_info = nil
-local buf_options = nil
-local glb_options = nil
-local win_options = nil
-
-local function _setup()
- if options_info ~= nil then
- return
- end
- options_info = {}
- for _, v in pairs(a.nvim_get_all_options_info()) do
- options_info[v.name] = v
- if v.shortname ~= '' then
- options_info[v.shortname] = v
- end
- end
- local function get_scoped_options(scope)
- local result = {}
- for name, option_info in pairs(options_info) do
- if option_info.scope == scope then
- result[name] = true
+-- TODO(tjdevries): Improve option metadata so that this doesn't have to be hardcoded.
+-- Can be done in a separate PR.
+local key_value_options = {
+ fillchars = true,
+ fcs = true,
+ listchars = true,
+ lcs = true,
+ winhighlight = true,
+ winhl = true,
+}
+
+--- Convert a vimoption_T style dictionary to the correct OptionType associated with it.
+---@return string
+local function get_option_metatype(name, info)
+ if info.type == 'string' then
+ if info.flaglist then
+ return 'set'
+ elseif info.commalist then
+ if key_value_options[name] then
+ return 'map'
end
+ return 'array'
end
-
- return result
+ return 'string'
end
-
- buf_options = get_scoped_options('buf')
- glb_options = get_scoped_options('global')
- win_options = get_scoped_options('win')
+ return info.type
end
-local function make_meta_accessor(get, set, del, validator)
- validator = validator or function()
- return true
- end
-
- validate({
- get = { get, 'f' },
- set = { set, 'f' },
- del = { del, 'f', true },
- validator = { validator, 'f' },
- })
+local options_info = setmetatable({}, {
+ __index = function(t, k)
+ local info = a.nvim_get_option_info(k)
+ info.metatype = get_option_metatype(k, info)
+ rawset(t, k, info)
+ return rawget(t, k)
+ end,
+})
- local mt = {}
- function mt:__newindex(k, v)
- if not validator(k) then
- return
+vim.env = setmetatable({}, {
+ __index = function(_, k)
+ local v = vim.fn.getenv(k)
+ if v == vim.NIL then
+ return nil
end
+ return v
+ end,
- if del and v == nil then
- return del(k)
- end
- return set(k, v)
- end
- function mt:__index(k)
- if not validator(k) then
- return
- end
+ __newindex = function(_, k, v)
+ vim.fn.setenv(k, v)
+ end,
+})
- return get(k)
+local function opt_validate(option_name, target_scope)
+ local scope = options_info[option_name].scope
+ if scope ~= target_scope then
+ local scope_to_string = { buf = 'buffer', win = 'window' }
+ error(
+ string.format(
+ [['%s' is a %s option, not a %s option. See ":help %s"]],
+ option_name,
+ scope_to_string[scope] or scope,
+ scope_to_string[target_scope] or target_scope,
+ option_name
+ )
+ )
end
- return setmetatable({}, mt)
end
-vim.env = make_meta_accessor(function(k)
- local v = vim.fn.getenv(k)
- if v == vim.NIL then
- return nil
- end
- return v
-end, vim.fn.setenv)
-
-do -- buffer option accessor
- local function new_buf_opt_accessor(bufnr)
- local function get(k)
- if bufnr == nil and type(k) == 'number' then
- return new_buf_opt_accessor(k)
- end
-
- return a.nvim_get_option_value(k, { buf = bufnr or 0 })
- end
-
- local function set(k, v)
- return a.nvim_set_option_value(k, v, { buf = bufnr or 0 })
- end
-
- return make_meta_accessor(get, set, nil, function(k)
- if type(k) == 'string' then
- _setup()
- if win_options[k] then
- error(
- string.format([['%s' is a window option, not a buffer option. See ":help %s"]], k, k)
- )
- elseif glb_options[k] then
- error(
- string.format([['%s' is a global option, not a buffer option. See ":help %s"]], k, k)
- )
- end
+local function new_opt_accessor(handle, scope)
+ return setmetatable({}, {
+ __index = function(_, k)
+ if handle == nil and type(k) == 'number' then
+ return new_opt_accessor(k, scope)
end
+ opt_validate(k, scope)
+ return a.nvim_get_option_value(k, { [scope] = handle or 0 })
+ end,
- return true
- end)
- end
-
- vim.bo = new_buf_opt_accessor(nil)
+ __newindex = function(_, k, v)
+ opt_validate(k, scope)
+ return a.nvim_set_option_value(k, v, { [scope] = handle or 0 })
+ end,
+ })
end
-do -- window option accessor
- local function new_win_opt_accessor(winnr)
- local function get(k)
- if winnr == nil and type(k) == 'number' then
- return new_win_opt_accessor(k)
- end
- return a.nvim_get_option_value(k, { win = winnr or 0 })
- end
-
- local function set(k, v)
- return a.nvim_set_option_value(k, v, { win = winnr or 0 })
- end
-
- return make_meta_accessor(get, set, nil, function(k)
- if type(k) == 'string' then
- _setup()
- if buf_options[k] then
- error(
- string.format([['%s' is a buffer option, not a window option. See ":help %s"]], k, k)
- )
- elseif glb_options[k] then
- error(
- string.format([['%s' is a global option, not a window option. See ":help %s"]], k, k)
- )
- end
- end
-
- return true
- end)
- end
-
- vim.wo = new_win_opt_accessor(nil)
-end
+vim.bo = new_opt_accessor(nil, 'buf')
+vim.wo = new_opt_accessor(nil, 'win')
-- vim global option
-- this ONLY sets the global option. like `setglobal`
-vim.go = make_meta_accessor(function(k)
- return a.nvim_get_option_value(k, { scope = 'global' })
-end, function(k, v)
- return a.nvim_set_option_value(k, v, { scope = 'global' })
-end)
+vim.go = setmetatable({}, {
+ __index = function(_, k)
+ return a.nvim_get_option_value(k, { scope = 'global' })
+ end,
+ __newindex = function(_, k, v)
+ return a.nvim_set_option_value(k, v, { scope = 'global' })
+ end,
+})
-- vim `set` style options.
-- it has no additional metamethod magic.
-vim.o = make_meta_accessor(function(k)
- return a.nvim_get_option_value(k, {})
-end, function(k, v)
- return a.nvim_set_option_value(k, v, {})
-end)
+vim.o = setmetatable({}, {
+ __index = function(_, k)
+ return a.nvim_get_option_value(k, {})
+ end,
+ __newindex = function(_, k, v)
+ return a.nvim_set_option_value(k, v, {})
+ end,
+})
---@brief [[
--- vim.opt, vim.opt_local and vim.opt_global implementation
@@ -178,11 +118,8 @@ end)
---@brief ]]
--- Preserves the order and does not mutate the original list
-local remove_duplicate_values = function(t)
+local function remove_duplicate_values(t)
local result, seen = {}, {}
- if type(t) == 'function' then
- error(debug.traceback('asdf'))
- end
for _, v in ipairs(t) do
if not seen[v] then
table.insert(result, v)
@@ -194,61 +131,6 @@ local remove_duplicate_values = function(t)
return result
end
--- TODO(tjdevries): Improve option metadata so that this doesn't have to be hardcoded.
--- Can be done in a separate PR.
-local key_value_options = {
- fillchars = true,
- listchars = true,
- winhl = true,
-}
-
----@class OptionTypes
---- Option Type Enum
-local OptionTypes = setmetatable({
- BOOLEAN = 0,
- NUMBER = 1,
- STRING = 2,
- ARRAY = 3,
- MAP = 4,
- SET = 5,
-}, {
- __index = function(_, k)
- error('Not a valid OptionType: ' .. k)
- end,
- __newindex = function(_, k)
- error('Cannot set a new OptionType: ' .. k)
- end,
-})
-
---- Convert a vimoption_T style dictionary to the correct OptionType associated with it.
----@return OptionType
-local get_option_type = function(name, info)
- if info.type == 'boolean' then
- return OptionTypes.BOOLEAN
- elseif info.type == 'number' then
- return OptionTypes.NUMBER
- elseif info.type == 'string' then
- if not info.commalist and not info.flaglist then
- return OptionTypes.STRING
- end
-
- if key_value_options[name] then
- assert(info.commalist, 'Must be a comma list to use key:value style')
- return OptionTypes.MAP
- end
-
- if info.flaglist then
- return OptionTypes.SET
- elseif info.commalist then
- return OptionTypes.ARRAY
- end
-
- error('Fallthrough in OptionTypes')
- else
- error('Not a known info.type:' .. info.type)
- end
-end
-
-- Check whether the OptionTypes is allowed for vim.opt
-- If it does not match, throw an error which indicates which option causes the error.
local function assert_valid_value(name, value, types)
@@ -269,373 +151,323 @@ local function assert_valid_value(name, value, types)
)
end
+local function passthrough(_, x)
+ return x
+end
+
+local function tbl_merge(left, right)
+ return vim.tbl_extend('force', left, right)
+end
+
+local function tbl_remove(t, value)
+ if type(value) == 'string' then
+ t[value] = nil
+ else
+ for _, v in ipairs(value) do
+ t[v] = nil
+ end
+ end
+
+ return t
+end
+
local valid_types = {
- [OptionTypes.BOOLEAN] = { 'boolean' },
- [OptionTypes.NUMBER] = { 'number' },
- [OptionTypes.STRING] = { 'string' },
- [OptionTypes.SET] = { 'string', 'table' },
- [OptionTypes.ARRAY] = { 'string', 'table' },
- [OptionTypes.MAP] = { 'string', 'table' },
+ boolean = { 'boolean' },
+ number = { 'number' },
+ string = { 'string' },
+ set = { 'string', 'table' },
+ array = { 'string', 'table' },
+ map = { 'string', 'table' },
}
---- Convert a lua value to a vimoption_T value
-local convert_value_to_vim = (function()
- -- Map of functions to take a Lua style value and convert to vimoption_T style value.
- -- Each function takes (info, lua_value) -> vim_value
- local to_vim_value = {
- [OptionTypes.BOOLEAN] = function(_, value)
- return value
- end,
- [OptionTypes.NUMBER] = function(_, value)
- return value
- end,
- [OptionTypes.STRING] = function(_, value)
- return value
- end,
-
- [OptionTypes.SET] = function(info, value)
- if type(value) == 'string' then
- return value
- end