summaryrefslogtreecommitdiffstatshomepage
path: root/runtime/lua/vim/filetype.lua
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim/filetype.lua')
-rw-r--r--runtime/lua/vim/filetype.lua134
1 files changed, 82 insertions, 52 deletions
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 8fe631e7ed..2874ea45e7 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -24,18 +24,26 @@ local function starsetf(ft, opts)
end
---@private
---- Get a single line or line-range from the buffer.
+--- Get a single line or line range from the buffer.
+--- If only start_lnum is specified, return a single line as a string.
+--- If both start_lnum and end_lnum are omitted, return all lines from the buffer.
---
---@param bufnr number|nil The buffer to get the lines from
----@param start_lnum number The line number of the first line (inclusive, 1-based)
+---@param start_lnum number|nil The line number of the first line (inclusive, 1-based)
---@param end_lnum number|nil The line number of the last line (inclusive, 1-based)
---@return table<string>|string Array of lines, or string when end_lnum is omitted
function M.getlines(bufnr, start_lnum, end_lnum)
- if not end_lnum then
- -- Return a single line as a string
+ if end_lnum then
+ -- Return a line range
+ return api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false)
+ end
+ if start_lnum then
+ -- Return a single line
return api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] or ''
+ else
+ -- Return all lines
+ return api.nvim_buf_get_lines(bufnr, 0, -1, false)
end
- return api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false)
end
---@private
@@ -600,7 +608,8 @@ local extension = {
end,
quake = 'm3quake',
['m4'] = function(path, bufnr)
- return require('vim.filetype.detect').m4(path)
+ path = path:lower()
+ return not (path:find('html%.m4$') or path:find('fvwm2rc')) and 'm4'
end,
eml = 'mail',
mk = 'make',
@@ -847,22 +856,22 @@ local extension = {
sed = 'sed',
sexp = 'sexplib',
bash = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'bash')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
end,
ebuild = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'bash')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
end,
eclass = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'bash')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
end,
env = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr)
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
end,
ksh = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'ksh')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'ksh')
end,
sh = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr)
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
end,
sieve = 'sieve',
siv = 'sieve',
@@ -1090,7 +1099,7 @@ local extension = {
return require('vim.filetype.detect').scd(bufnr)
end,
tcsh = function(path, bufnr)
- return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
+ return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh')
end,
sql = function(path, bufnr)
return vim.g.filetype_sql and vim.g.filetype_sql or 'sql'
@@ -1510,40 +1519,40 @@ local filename = {
['/etc/serial.conf'] = 'setserial',
['/etc/udev/cdsymlinks.conf'] = 'sh',
['bash.bashrc'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'bash')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
end,
bashrc = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'bash')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
end,
['.bashrc'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'bash')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
end,
['.env'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr)
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
end,
['.kshrc'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'ksh')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'ksh')
end,
['.profile'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr)
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
end,
['/etc/profile'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr)
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
end,
APKBUILD = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'bash')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
end,
PKGBUILD = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'bash')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
end,
['.tcshrc'] = function(path, bufnr)
- return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
+ return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh')
end,
['tcsh.login'] = function(path, bufnr)
- return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
+ return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh')
end,
['tcsh.tcshrc'] = function(path, bufnr)
- return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
+ return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh')
end,
['/etc/slp.conf'] = 'slpconf',
['/etc/slp.reg'] = 'slpreg',
@@ -1934,28 +1943,28 @@ local pattern = {
['.*/etc/serial%.conf'] = 'setserial',
['.*/etc/udev/cdsymlinks%.conf'] = 'sh',
['%.bash[_%-]aliases'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'bash')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
end,
['%.bash[_%-]logout'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'bash')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
end,
['%.bash[_%-]profile'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'bash')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
end,
['%.kshrc.*'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'ksh')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'ksh')
end,
['%.profile.*'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr)
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
end,
['.*/etc/profile'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr)
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
end,
['bash%-fc[%-%.]'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, bufnr, 'bash')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
end,
['%.tcshrc.*'] = function(path, bufnr)
- return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
+ return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'tcsh')
end,
['.*/etc/sudoers%.d/.*'] = starsetf('sudoers'),
['.*%._sst%.meta'] = 'sisu',
@@ -2165,6 +2174,25 @@ end
--- })
--- </pre>
---
+--- To add a fallback match on contents (see |new-filetype-scripts|), use
+--- <pre>
+--- vim.filetype.add {
+--- pattern = {
+--- ['.*'] = {
+--- priority = -math.huge,
+--- function(path, bufnr)
+--- local content = vim.filetype.getlines(bufnr, 1)
+--- if vim.filetype.matchregex(content, { [[^#!.*\\<mine\\>]] }) then
+--- return 'mine'
+--- elseif vim.filetype.matchregex(content, { [[\\<drawing\\>]] }) then
+--- return 'drawing'
+--- end
+--- end,
+--- },
+--- },
+--- }
+--- </pre>
+---
---@param filetypes table A table containing new filetype maps (see example).
function M.add(filetypes)
for k, v in pairs(filetypes.extension or {}) do
@@ -2253,7 +2281,7 @@ end
--- vim.filetype.match({ contents = {'#!/usr/bin/env bash'} })
--- </pre>
---
----@param arg table Table specifying which matching strategy to use. Accepted keys are:
+---@param args 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,
@@ -2270,22 +2298,18 @@ end
---@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(arg)
+function M.match(args)
vim.validate({
- arg = { arg, 't' },
+ arg = { args, 't' },
})
- if not (arg.buf or arg.filename or arg.contents) then
+ if not (args.buf or args.filename or args.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
+ local bufnr = args.buf
+ local name = args.filename
+ local contents = args.contents
if bufnr and not name then
name = api.nvim_buf_get_name(bufnr)
@@ -2297,13 +2321,6 @@ function M.match(arg)
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)
@@ -2345,7 +2362,7 @@ function M.match(arg)
return ft, on_detect
end
- -- Finally, check patterns with negative priority
+ -- Next, check patterns with negative priority
for i = j, #pattern_sorted do
local v = pattern_sorted[i]
local k = next(v)
@@ -2359,6 +2376,19 @@ function M.match(arg)
end
end
end
+
+ -- Finally, check file contents
+ if contents or bufnr then
+ contents = contents or M.getlines(bufnr)
+ -- If name is nil, catch any errors from the contents filetype detection function.
+ -- If the function tries to use the filename that is nil then it will fail,
+ -- but this enables checks which do not need a filename to still work.
+ local ok
+ ok, ft = pcall(require('vim.filetype.detect').match_contents, contents, name)
+ if ok and ft then
+ return ft
+ end
+ end
end
return M