diff options
Diffstat (limited to 'runtime/lua/vim')
-rw-r--r-- | runtime/lua/vim/filetype.lua | 102 | ||||
-rw-r--r-- | runtime/lua/vim/filetype/detect.lua | 8 | ||||
-rw-r--r-- | runtime/lua/vim/ui.lua | 4 |
3 files changed, 90 insertions, 24 deletions
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua index 320d6a2a5b..73605413ee 100644 --- a/runtime/lua/vim/filetype.lua +++ b/runtime/lua/vim/filetype.lua @@ -33,7 +33,7 @@ end function M.getlines(bufnr, start_lnum, end_lnum) if not end_lnum then -- Return a single line as a string - return api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] + return api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] or '' end return api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false) end @@ -2047,7 +2047,7 @@ local pattern = { end end, { priority = -math.huge + 1 }), ['XF86Config.*'] = starsetf(function(path, bufnr) - return require('vim.filetype.detect').xfree86(bufnr) + return require('vim.filetype.detect').xfree86() end), ['%.zcompdump.*'] = starsetf('zsh'), -- .zlog* and zlog* @@ -2185,17 +2185,24 @@ end local function dispatch(ft, path, bufnr, ...) local on_detect if type(ft) == 'function' then - ft, on_detect = ft(path, bufnr, ...) + if bufnr then + ft, on_detect = ft(path, bufnr, ...) + else + -- If bufnr is nil (meaning we are matching only against the filename), set it to an invalid + -- value (-1) and catch any errors from the filetype detection function. If the function tries + -- to use the buffer then it will fail, but this enables functions which do not need a buffer + -- to still work. + local ok + ok, ft, on_detect = pcall(ft, path, -1, ...) + if not ok then + return + end + end end if type(ft) == 'string' then return ft, on_detect end - - -- Any non-falsey value (that is, anything other than 'nil' or 'false') will - -- end filetype matching. This is useful for e.g. the dist#ft functions that - -- return 0, but set the buffer's filetype themselves - return ft end ---@private @@ -2214,29 +2221,86 @@ local function match_pattern(name, path, tail, pat) return matches end ---- Find the filetype for the given filename and buffer. +--- Perform filetype detection. +--- +--- The filetype can be detected using one of three methods: +--- 1. Using an existing buffer +--- 2. Using only a file name +--- 3. Using only file contents +--- +--- Of these, option 1 provides the most accurate result as it uses both the buffer's filename and +--- (optionally) the buffer contents. Options 2 and 3 can be used without an existing buffer, but +--- may not always provide a match in cases where the filename (or contents) cannot unambiguously +--- determine the filetype. +--- +--- Each of the three options is specified using a key to the single argument of this function. +--- Example: +--- +--- <pre> +--- -- Using a buffer number +--- vim.filetype.match({ buf = 42 }) +--- +--- -- Override the filename of the given buffer +--- vim.filetype.match({ buf = 42, filename = 'foo.c' }) --- ----@param name string File name (can be an absolute or relative path) ----@param bufnr number|nil The buffer to set the filetype for. Defaults to the current buffer. +--- -- Using a filename without a buffer +--- vim.filetype.match({ filename = 'main.lua' }) +--- +--- -- Using file contents +--- vim.filetype.match({ contents = {'#!/usr/bin/env bash'} }) +--- </pre> +--- +---@param arg table Table specifying which matching strategy to use. Accepted keys are: +--- * buf (number): Buffer number to use for matching. Mutually exclusive with +--- {contents} +--- * filename (string): Filename to use for matching. When {buf} is given, +--- defaults to the filename of the given buffer number. The +--- file need not actually exist in the filesystem. When used +--- without {buf} only the name of the file is used for +--- filetype matching. This may result in failure to detect +--- the filetype in cases where the filename alone is not +--- enough to disambiguate the filetype. +--- * contents (table): An array of lines representing file contents to use for +--- matching. Can be used with {filename}. Mutually exclusive +--- with {buf}. ---@return string|nil If a match was found, the matched filetype. ---@return function|nil A function that modifies buffer state when called (for example, to set some --- filetype specific buffer variables). The function accepts a buffer number as --- its only argument. -function M.match(name, bufnr) +function M.match(arg) vim.validate({ - name = { name, 's' }, - bufnr = { bufnr, 'n', true }, + arg = { arg, 't' }, }) - -- When fired from the main filetypedetect autocommand the {bufnr} argument is omitted, so we use - -- the current buffer. The {bufnr} argument is provided to allow extensibility in case callers - -- wish to perform filetype detection on buffers other than the current one. - bufnr = bufnr or api.nvim_get_current_buf() + if not (arg.buf or arg.filename or arg.contents) then + error('At least one of "buf", "filename", or "contents" must be given') + end + + if arg.buf and arg.contents then + error('Only one of "buf" or "contents" must be given') + end + + local bufnr = arg.buf + local name = arg.filename + local contents = arg.contents + + if bufnr and not name then + name = api.nvim_buf_get_name(bufnr) + end - name = normalize_path(name) + if name then + name = normalize_path(name) + end local ft, on_detect + if contents then + -- Sanity check: this should not happen + assert(not bufnr, '"buf" and "contents" are mutually exclusive') + -- TODO: "scripts.lua" content matching + return + end + -- First check for the simple case where the full path exists as a key local path = vim.fn.resolve(vim.fn.fnamemodify(name, ':p')) ft, on_detect = dispatch(filename[path], path, bufnr) diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua index 48dd3cb088..ddef27a0f0 100644 --- a/runtime/lua/vim/filetype/detect.lua +++ b/runtime/lua/vim/filetype/detect.lua @@ -906,9 +906,11 @@ function M.rules(path) local dir = vim.fn.expand(path, ':h') for _, line in ipairs(config_lines) do local match = line:match(udev_rules_pattern) - local udev_rules = line:gsub(udev_rules_pattern, match, 1) - if dir == udev_rules then - return 'udevrules' + if match then + local udev_rules = line:gsub(udev_rules_pattern, match, 1) + if dir == udev_rules then + return 'udevrules' + end end end return 'hog' diff --git a/runtime/lua/vim/ui.lua b/runtime/lua/vim/ui.lua index 77bca7f6c4..6f1ce3089d 100644 --- a/runtime/lua/vim/ui.lua +++ b/runtime/lua/vim/ui.lua @@ -59,7 +59,7 @@ end --- ---@param opts table Additional options. See |input()| --- - prompt (string|nil) ---- Text of the prompt. Defaults to `Input: `. +--- Text of the prompt --- - default (string|nil) --- Default reply to the input --- - completion (string|nil) @@ -87,7 +87,7 @@ function M.input(opts, on_confirm) on_confirm = { on_confirm, 'function', false }, }) - opts = opts or {} + opts = (opts and not vim.tbl_isempty(opts)) and opts or vim.empty_dict() local input = vim.fn.input(opts) if #input > 0 then on_confirm(input) |