aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim')
-rw-r--r--runtime/lua/vim/filetype.lua102
-rw-r--r--runtime/lua/vim/filetype/detect.lua8
-rw-r--r--runtime/lua/vim/ui.lua4
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)