aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLewis Russell <lewis6991@gmail.com>2023-08-08 16:36:06 +0100
committerGitHub <noreply@github.com>2023-08-08 16:36:06 +0100
commitc6c21db82b31ea43ce878ab3725dcd901db1e7a1 (patch)
tree6002ddf7e9ef9d2ca40ef0029f501864ff43cbd9
parent61ed45486da01dca788f8a444fc2021002f0c947 (diff)
downloadrneovim-c6c21db82b31ea43ce878ab3725dcd901db1e7a1.tar.gz
rneovim-c6c21db82b31ea43ce878ab3725dcd901db1e7a1.tar.bz2
rneovim-c6c21db82b31ea43ce878ab3725dcd901db1e7a1.zip
fix(filetype): add typing and dry (#24573)
-rw-r--r--runtime/doc/lua.txt6
-rw-r--r--runtime/lua/vim/_editor.lua7
-rw-r--r--runtime/lua/vim/filetype.lua1205
-rw-r--r--runtime/lua/vim/filetype/detect.lua546
-rw-r--r--scripts/lua2dox.lua6
5 files changed, 823 insertions, 947 deletions
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index efde69c8f4..c3e540a4ae 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -2654,10 +2654,10 @@ vim.filetype.add({filetypes}) *vim.filetype.add()*
['.*'] = {
priority = -math.huge,
function(path, bufnr)
- local content = vim.filetype.getlines(bufnr, 1)
- if vim.filetype.matchregex(content, [[^#!.*\<mine\>]]) then
+ local content = vim.api.nvim_buf_get_lines(bufnr, 0, 1, false)[1] or ''
+ if vim.regex([[^#!.*\<mine\>]]):match_str(content) ~= nil then
return 'mine'
- elseif vim.filetype.matchregex(content, [[\<drawing\>]]) then
+ elseif vim.regex([[\<drawing\>]]):match_str(content) ~= nil then
return 'drawing'
end
end,
diff --git a/runtime/lua/vim/_editor.lua b/runtime/lua/vim/_editor.lua
index 6182270708..d81464a3ca 100644
--- a/runtime/lua/vim/_editor.lua
+++ b/runtime/lua/vim/_editor.lua
@@ -428,10 +428,17 @@ vim.cmd = setmetatable({}, {
end,
})
+--- @class vim.var_accessor
+--- @field [string] any
+--- @field [integer] vim.var_accessor
+
-- These are the vim.env/v/g/o/bo/wo variable magic accessors.
do
local validate = vim.validate
+ --- @param scope string
+ --- @param handle? false|integer
+ --- @return vim.var_accessor
local function make_dict_accessor(scope, handle)
validate({
scope = { scope, 's' },
diff --git a/runtime/lua/vim/filetype.lua b/runtime/lua/vim/filetype.lua
index 66e224ce69..a53216f8ea 100644
--- a/runtime/lua/vim/filetype.lua
+++ b/runtime/lua/vim/filetype.lua
@@ -1,7 +1,16 @@
local api = vim.api
+local fn = vim.fn
local M = {}
+--- @alias vim.filetype.mapfn fun(path:string,bufnr:integer, ...):string?, fun(b:integer)?
+--- @alias vim.filetype.maptbl {[1]:string|vim.filetype.mapfn, [2]:{priority:integer}}
+--- @alias vim.filetype.mapping.value string|vim.filetype.mapfn|vim.filetype.maptbl
+--- @alias vim.filetype.mapping table<string,vim.filetype.mapping.value>
+
+--- @param ft string|vim.filetype.mapfn
+--- @param opts? {priority:integer}
+--- @return vim.filetype.maptbl
local function starsetf(ft, opts)
return {
function(path, bufnr)
@@ -23,36 +32,38 @@ local function starsetf(ft, opts)
end
---@private
---- 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.
----
+--- Get a line range from the buffer.
---@param bufnr integer The buffer to get the lines from
---@param start_lnum integer|nil The line number of the first line (inclusive, 1-based)
---@param end_lnum integer|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 end_lnum then
- -- Return a line range
- return api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false)
- end
+---@return string[] # Array of lines
+function M._getlines(bufnr, start_lnum, end_lnum)
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)
+ return api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum or start_lnum, false)
end
+
+ -- Return all lines
+ return api.nvim_buf_get_lines(bufnr, 0, -1, false)
+end
+
+---@private
+--- Get a single line from the buffer.
+---@param bufnr integer The buffer to get the lines from
+---@param start_lnum integer The line number of the first line (inclusive, 1-based)
+---@return string
+function M._getline(bufnr, start_lnum)
+ -- Return a single line
+ return api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] or ''
end
---@private
--- Check whether a string matches any of the given Lua patterns.
---
----@param s string The string to check
----@param patterns table<string> A list of Lua patterns
+---@param s string? The string to check
+---@param patterns string[] A list of Lua patterns
---@return boolean `true` if s matched a pattern, else `false`
-function M.findany(s, patterns)
- if s == nil then
+function M._findany(s, patterns)
+ if not s then
return false
end
for _, v in ipairs(patterns) do
@@ -69,8 +80,8 @@ end
---@param bufnr integer The buffer to get the line from
---@param start_lnum integer The line number of the first line to start from (inclusive, 1-based)
---@return string|nil The first non-blank line if found or `nil` otherwise
-function M.nextnonblank(bufnr, start_lnum)
- for _, line in ipairs(M.getlines(bufnr, start_lnum, -1)) do
+function M._nextnonblank(bufnr, start_lnum)
+ for _, line in ipairs(M._getlines(bufnr, start_lnum, -1)) do
if not line:find('^%s*$') then
return line
end
@@ -78,30 +89,93 @@ function M.nextnonblank(bufnr, start_lnum)
return nil
end
----@private
---- Check whether the given string matches the Vim regex pattern.
-M.matchregex = (function()
- local cache = {}
- return function(s, pattern)
- if s == nil then
- return nil
+do
+ --- @type table<string,vim.regex>
+ local regex_cache = {}
+
+ ---@private
+ --- Check whether the given string matches the Vim regex pattern.
+ --- @param s string?
+ --- @param pattern string
+ --- @return boolean
+ function M._matchregex(s, pattern)
+ if not s then
+ return false
+ end
+ if not regex_cache[pattern] then
+ regex_cache[pattern] = vim.regex(pattern)
+ end
+ return regex_cache[pattern]:match_str(s) ~= nil
+ end
+end
+
+--- @module 'vim.filetype.detect'
+local detect = setmetatable({}, {
+ --- @param k string
+ --- @param t table<string,function>
+ --- @return function
+ __index = function(t, k)
+ t[k] = function(...)
+ return require('vim.filetype.detect')[k](...)
+ end
+ return t[k]
+ end,
+})
+
+--- @param ... string|vim.filetype.mapfn
+--- @return vim.filetype.mapfn
+local function detect_seq(...)
+ local candidates = { ... }
+ return function(...)
+ for _, c in ipairs(candidates) do
+ if type(c) == 'string' then
+ return c
+ end
+ if type(c) == 'function' then
+ local r = c(...)
+ if r then
+ return r
+ end
+ end
end
- if not cache[pattern] then
- cache[pattern] = vim.regex(pattern)
+ end
+end
+
+local function detect_noext(path, bufnr)
+ local root = fn.fnamemodify(path, ':r')
+ return M.match({ buf = bufnr, filename = root })
+end
+
+--- @param pat string
+--- @param a string?
+--- @param b string?
+--- @return vim.filetype.mapfn
+local function detect_line1(pat, a, b)
+ return function(_path, bufnr)
+ if M._getline(bufnr, 1):find(pat) then
+ return a
end
- return cache[pattern]:match_str(s)
+ return b
end
-end)()
+end
+
+--- @type vim.filetype.mapfn
+local detect_rc = function(path, _bufnr)
+ if not path:find('/etc/Muttrc%.d/') then
+ return 'rc'
+ end
+end
-- luacheck: push no unused args
-- luacheck: push ignore 122
-- Filetypes based on file extension
---@diagnostic disable: unused-local
+--- @type vim.filetype.mapping
local extension = {
-- BEGIN EXTENSION
['8th'] = '8th',
- ['a65'] = 'a65',
+ a65 = 'a65',
aap = 'aap',
abap = 'abap',
abc = 'abc',
@@ -127,51 +201,33 @@ local extension = {
end
return 'aspvbs'
end,
- asm = function(path, bufnr)
- return require('vim.filetype.detect').asm(bufnr)
- end,
- lst = function(path, bufnr)
- return require('vim.filetype.detect').asm(bufnr)
- end,
- mac = function(path, bufnr)
- return require('vim.filetype.detect').asm(bufnr)
- end,
- ['asn1'] = 'asn',
+ asm = detect.asm,
+ lst = detect.asm,
+ mac = detect.asm,
+ asn1 = 'asn',
asn = 'asn',
- asp = function(path, bufnr)
- return require('vim.filetype.detect').asp(bufnr)
- end,
+ asp = detect.asp,
astro = 'astro',
atl = 'atlas',
as = 'atlas',
ahk = 'autohotkey',
- ['au3'] = 'autoit',
+ au3 = 'autoit',
ave = 'ave',
gawk = 'awk',
awk = 'awk',
ref = 'b',
imp = 'b',
mch = 'b',
- bas = function(path, bufnr)
- return require('vim.filetype.detect').bas(bufnr)
- end,
+ bas = detect.bas,
bass = 'bass',
- bi = function(path, bufnr)
- return require('vim.filetype.detect').bas(bufnr)
- end,
- bm = function(path, bufnr)
- return require('vim.filetype.detect').bas(bufnr)
- end,
+ bi = detect.bas,
+ bm = detect.bas,
bc = 'bc',
bdf = 'bdf',
beancount = 'beancount',
bib = 'bib',
- com = function(path, bufnr)
- return require('vim.filetype.detect').bindzone(bufnr, 'dcl')
- end,
- db = function(path, bufnr)
- return require('vim.filetype.detect').bindzone(bufnr)
- end,
+ com = detect_seq(detect.bindzone, 'dcl'),
+ db = detect.bindzone,
bicep = 'bicep',
bb = 'bitbake',
bbappend = 'bitbake',
@@ -201,9 +257,7 @@ local extension = {
hgrc = 'cfg',
chf = 'ch',
chai = 'chaiscript',
- ch = function(path, bufnr)
- return require('vim.filetype.detect').change(bufnr)
- end,
+ ch = detect.change,
chs = 'chaskell',
chatito = 'chatito',
chopro = 'chordpro',
@@ -226,7 +280,7 @@ local extension = {
atg = 'coco',
recipe = 'conaryrecipe',
hook = function(path, bufnr)
- return M.getlines(bufnr, 1) == '[Trigger]' and 'conf'
+ return M._getline(bufnr, 1) == '[Trigger]' and 'conf' or nil
end,
nmconnection = 'confini',
mklx = 'context',
@@ -234,16 +288,10 @@ local extension = {
mkii = 'context',
mkxl = 'context',
mkvi = 'context',
- control = function(path, bufnr)
- return require('vim.filetype.detect').control(bufnr)
- end,
- copyright = function(path, bufnr)
- return require('vim.filetype.detect').copyright(bufnr)
- end,
+ control = detect.control,
+ copyright = detect.copyright,
corn = 'corn',
- csh = function(path, bufnr)
- return require('vim.filetype.detect').csh(path, bufnr)
- end,
+ csh = detect.csh,
cpon = 'cpon',
moc = 'cpp',
hh = 'cpp',
@@ -261,12 +309,8 @@ local extension = {
cppm = 'cpp',
cxxm = 'cpp',
['c++m'] = 'cpp',
- cpp = function(path, bufnr)
- return vim.g.cynlib_syntax_for_cpp and 'cynlib' or 'cpp'
- end,
- cc = function(path, bufnr)
- return vim.g.cynlib_syntax_for_cc and 'cynlib' or 'cpp'
- end,
+ cpp = detect.cpp,
+ cc = detect.cpp,
cql = 'cqlang',
crm = 'crm',
cr = 'crystal',
@@ -291,15 +335,9 @@ local extension = {
drt = 'dart',
ds = 'datascript',
dcd = 'dcd',
- decl = function(path, bufnr)
- return require('vim.filetype.detect').decl(bufnr)
- end,
- dec = function(path, bufnr)
- return require('vim.filetype.detect').decl(bufnr)
- end,
- dcl = function(path, bufnr)
- return require('vim.filetype.detect').decl(bufnr) or 'clean'
- end,
+ decl = detect.decl,
+ dec = detect.decl,
+ dcl = detect_seq(detect.decl, 'clean'),
def = 'def',
desc = 'desc',
directory = 'desktop',
@@ -317,27 +355,19 @@ local extension = {
drac = 'dracula',
drc = 'dracula',
dtd = 'dtd',
- d = function(path, bufnr)
- return require('vim.filetype.detect').dtrace(bufnr)
- end,
+ d = detect.dtrace,
dts = 'dts',
dtsi = 'dts',
dylan = 'dylan',
intr = 'dylanintr',
lid = 'dylanlid',
- e = function(path, bufnr)
- return require('vim.filetype.detect').e(bufnr)
- end,
- E = function(path, bufnr)
- return require('vim.filetype.detect').e(bufnr)
- end,
+ e = detect.e,
+ E = detect.e,
ecd = 'ecd',
edf = 'edif',
edif = 'edif',
edo = 'edif',
- edn = function(path, bufnr)
- return require('vim.filetype.detect').edn(bufnr)
- end,
+ edn = detect.edn,
eex = 'eelixir',
leex = 'eelixir',
am = 'elf',
@@ -345,9 +375,7 @@ local extension = {
elm = 'elm',
lc = 'elsa',
elv = 'elvish',
- ent = function(path, bufnr)
- return require('vim.filetype.detect').ent(bufnr)
- end,
+ ent = detect.ent,
epp = 'epuppet',
erl = 'erlang',
hrl = 'erlang',
@@ -358,43 +386,23 @@ local extension = {
ec = 'esqlc',
EC = 'esqlc',
strl = 'esterel',
- eu = function(path, bufnr)
- return vim.g.filetype_euphoria or 'euphoria3'
- end,
- EU = function(path, bufnr)
- return vim.g.filetype_euphoria or 'euphoria3'
- end,
- ew = function(path, bufnr)
- return vim.g.filetype_euphoria or 'euphoria3'
- end,
- EW = function(path, bufnr)
- return vim.g.filetype_euphoria or 'euphoria3'
- end,
- EX = function(path, bufnr)
- return vim.g.filetype_euphoria or 'euphoria3'
- end,
- exu = function(path, bufnr)
- return vim.g.filetype_euphoria or 'euphoria3'
- end,
- EXU = function(path, bufnr)
- return vim.g.filetype_euphoria or 'euphoria3'
- end,
- exw = function(path, bufnr)
- return vim.g.filetype_euphoria or 'euphoria3'
- end,
- EXW = function(path, bufnr)
- return vim.g.filetype_euphoria or 'euphoria3'
- end,
- ex = function(path, bufnr)
- return require('vim.filetype.detect').ex(bufnr)
- end,
+ eu = detect.euphoria,
+ EU = detect.euphoria,
+ ew = detect.euphoria,
+ EW = detect.euphoria,
+ EX = detect.euphoria,
+ exu = detect.euphoria,
+ EXU = detect.euphoria,
+ exw = detect.euphoria,
+ EXW = detect.euphoria,
+ ex = detect.ex,
exp = 'expect',
factor = 'factor',
fal = 'falcon',
fan = 'fan',
fwt = 'fan',
fnl = 'fennel',
- ['m4gl'] = 'fgl',
+ m4gl = 'fgl',
['4gl'] = 'fgl',
['4gh'] = 'fgl',
fir = 'firrtl',
@@ -404,33 +412,29 @@ local extension = {
fth = 'forth',
ft = 'forth',
FOR = 'fortran',
- ['f77'] = 'fortran',
- ['f03'] = 'fortran',
+ f77 = 'fortran',
+ f03 = 'fortran',
fortran = 'fortran',
- ['F95'] = 'fortran',
- ['f90'] = 'fortran',
- ['F03'] = 'fortran',
+ F95 = 'fortran',
+ f90 = 'fortran',
+ F03 = 'fortran',
fpp = 'fortran',
FTN = 'fortran',
ftn = 'fortran',
['for'] = 'fortran',
- ['F90'] = 'fortran',
- ['F77'] = 'fortran',
- ['f95'] = 'fortran',
+ F90 = 'fortran',
+ F77 = 'fortran',
+ f95 = 'fortran',
FPP = 'fortran',
f = 'fortran',
F = 'fortran',
- ['F08'] = 'fortran',
- ['f08'] = 'fortran',
+ F08 = 'fortran',
+ f08 = 'fortran',
fpc = 'fpcmake',
fsl = 'framescript',
- frm = function(path, bufnr)
- return require('vim.filetype.detect').frm(bufnr)
- end,
+ frm = detect.frm,
fb = 'freebasic',
- fs = function(path, bufnr)
- return require('vim.filetype.detect').fs(bufnr)
- end,
+ fs = detect.fs,
fsh = 'fsh',
fsi = 'fsharp',
fsx = 'fsharp',
@@ -478,9 +482,7 @@ local extension = {
ht = 'haste',
htpp = 'hastepreproc',
hb = 'hb',
- h = function(path, bufnr)
- return require('vim.filetype.detect').header(bufnr)
- end,
+ h = detect.header,
sum = 'hercules',
errsum = 'hercules',
ev = 'hercules',
@@ -495,56 +497,28 @@ local extension = {
hog = 'hog',
hws = 'hollywood',
hoon = 'hoon',
- cpt = function(path, bufnr)
- return require('vim.filetype.detect').html(bufnr)
- end,
- dtml = function(path, bufnr)
- return require('vim.filetype.detect').html(bufnr)
- end,
- htm = function(path, bufnr)
- return require('vim.filetype.detect').html(bufnr)
- end,
- html = function(path, bufnr)
- return require('vim.filetype.detect').html(bufnr)
- end,
- pt = function(path, bufnr)
- return require('vim.filetype.detect').html(bufnr)
- end,
- shtml = function(path, bufnr)
- return require('vim.filetype.detect').html(bufnr)
- end,
- stm = function(path, bufnr)
- return require('vim.filetype.detect').html(bufnr)
- end,
+ cpt = detect.html,
+ dtml = detect.html,
+ htm = detect.html,
+ html = detect.html,
+ pt = detect.html,
+ shtml = detect.html,
+ stm = detect.html,
htt = 'httest',
htb = 'httest',
- hw = function(path, bufnr)
- return require('vim.filetype.detect').hw(bufnr)
- end,
- module = function(path, bufnr)
- return require('vim.filetype.detect').hw(bufnr)
- end,
- pkg = function(path, bufnr)
- return require('vim.filetype.detect').hw(bufnr)
- end,
+ hw = detect.hw,
+ module = detect.hw,
+ pkg = detect.hw,
iba = 'ibasic',
ibi = 'ibasic',
icn = 'icon',
- idl = function(path, bufnr)
- return require('vim.filetype.detect').idl(bufnr)
- end,
- inc = function(path, bufnr)
- return require('vim.filetype.detect').inc(bufnr)
- end,
+ idl = detect.idl,
+ inc = detect.inc,
inf = 'inform',
INF = 'inform',
ii = 'initng',
- inp = function(path, bufnr)
- return require('vim.filetype.detect').inp(bufnr)
- end,
- ms = function(path, bufnr)
- return require('vim.filetype.detect').nroff(bufnr) or 'xmath'
- end,
+ inp = detect.inp,
+ ms = detect_seq(detect.nroff, 'xmath'),
iss = 'iss',
mst = 'ist',
ist = 'ist',
@@ -566,7 +540,7 @@ local extension = {
jsx = 'javascriptreact',
clp = 'jess',
jgr = 'jgraph',
- ['j73'] = 'jovial',
+ j73 = 'jovial',
jov = 'jovial',
jovial = 'jovial',
properties = 'jproperties',
@@ -628,29 +602,21 @@ local extension = {
lou = 'lout',
ulpc = 'lpc',
lpc = 'lpc',
- c = function(path, bufnr)
- return require('vim.filetype.detect').lpc(bufnr)
- end,
- lsl = function(path, bufnr)
- return require('vim.filetype.detect').lsl(bufnr)
- end,
+ c = detect.lpc,
+ lsl = detect.lsl,
lss = 'lss',
nse = 'lua',
rockspec = 'lua',
lua = 'lua',
luau = 'luau',
lrc = 'lyrics',
- m = function(path, bufnr)
- return require('vim.filetype.detect').m(bufnr)
- end,
+ m = detect.m,
at = 'm4',
- mc = function(path, bufnr)
- return require('vim.filetype.detect').mc(bufnr)
- end,
+ mc = detect.mc,
quake = 'm3quake',
- ['m4'] = function(path, bufnr)
+ m4 = function(path, bufnr)
path = path:lower()
- return not (path:find('html%.m4$') or path:find('fvwm2rc')) and 'm4'
+ return not (path:find('html%.m4$') or path:find('fvwm2rc')) and 'm4' or nil
end,
eml = 'mail',
mk = 'make',
@@ -689,16 +655,12 @@ local extension = {
mib = 'mib',
mix = 'mix',
mixal = 'mix',
- mm = function(path, bufnr)
- return require('vim.filetype.detect').mm(bufnr)
- end,
+ mm = detect.mm,
nb = 'mma',
mmp = 'mmp',
- mms = function(path, bufnr)
- return require('vim.filetype.detect').mms(bufnr)
- end,
+ mms = detect.mms,
DEF = 'modula2',
- ['m2'] = 'modula2',
+ m2 = 'modula2',
mi = 'modula2',
lm3 = 'modula3',
ssc = 'monk',
@@ -709,28 +671,16 @@ local extension = {
moon = 'moonscript',
move = 'move',
mp = 'mp',
- mpiv = function(path, bufnr)
- return 'mp', function(b)
- vim.b[b].mp_metafun = 1
- end
- end,
- mpvi = function(path, bufnr)
- return 'mp', function(b)
- vim.b[b].mp_metafun = 1
- end
- end,
- mpxl = function(path, bufnr)
- return 'mp', function(b)
- vim.b[b].mp_metafun = 1
- end
- end,
+ mpiv = detect.mp,
+ mpvi = detect.mp,
+ mpxl = detect.mp,
mof = 'msidl',
odl = 'msidl',
msql = 'msql',
mu = 'mupad',
mush = 'mush',
mysql = 'mysql',
- ['n1ql'] = 'n1ql',
+ n1ql = 'n1ql',
nql = 'n1ql',
nanorc = 'nanorc',
ncf = 'ncf',
@@ -798,12 +748,10 @@ local extension = {
pike = 'pike',
pmod = 'pike',
rcp = 'pilrc',
- PL = function(path, bufnr)
- return require('vim.filetype.detect').pl(bufnr)
- end,
+ PL = detect.pl,
pli = 'pli',
- ['pl1'] = 'pli',
- ['p36'] = 'plm',
+ pl1 = 'pli',
+ p36 = 'plm',
plm = 'plm',
pac = 'plm',
plp = 'plp',
@@ -832,11 +780,11 @@ local extension = {
pml = 'promela',
proto = 'proto',
prql = 'prql',
- ['psd1'] = 'ps1',
- ['psm1'] = 'ps1',
- ['ps1'] = 'ps1',
+ psd1 = 'ps1',
+ psm1 = 'ps1',
+ ps1 = 'ps1',
pssc = 'ps1',
- ['ps1xml'] = 'ps1xml',
+ ps1xml = 'ps1xml',
psf = 'psf',
psl = 'psl',
pug = 'pug',
@@ -850,22 +798,20 @@ local extension = {
ql = 'ql',
qll = 'ql',
qmd = 'quarto',
- R = function(path, bufnr)
- return require('vim.filetype.detect').r(bufnr)
- end,
+ R = detect.r,
rkt = 'racket',
rktd = 'racket',
rktl = 'racket',
rad = 'radiance',
mat = 'radiance',
- ['pod6'] = 'raku',
+ pod6 = 'raku',
rakudoc = 'raku',
rakutest = 'raku',
rakumod = 'raku',
- ['pm6'] = 'raku',
+ pm6 = 'raku',
raku = 'raku',
- ['t6'] = 'raku',
- ['p6'] = 'raku',
+ t6 = 'raku',
+ p6 = 'raku',
raml = 'raml',
rbs = 'rbs',
rego = 'rego',
@@ -938,34 +884,18 @@ local extension = {
sdl = 'sdl',
sed = 'sed',
sexp = 'sexplib',
- bash = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
- end,
- ebuild = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
- end,
- eclass = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
- end,
- env = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
- end,
- ksh = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'ksh')
- end,
- sh = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
- end,
+ bash = detect.bash,
+ ebuild = detect.bash,
+ eclass = detect.bash,
+ env = detect.sh,
+ ksh = detect.ksh,
+ sh = detect.sh,
sieve = 'sieve',
siv = 'sieve',
- sig = function(path, bufnr)
- return require('vim.filetype.detect').sig(bufnr)
- end,
- sil = function(path, bufnr)
- return require('vim.filetype.detect').sil(bufnr)
- end,
+ sig = detect.sig,
+ sil = detect.sil,
sim = 'simula',
- ['s85'] = 'sinda',
+ s85 = 'sinda',
sin = 'sinda',
ssm = 'sisu',
sst = 'sisu',
@@ -1002,9 +932,7 @@ local extension = {
spi = 'spyce',
spy = 'spyce',
tyc = 'sql',
- typ = function(path, bufnr)
- return require('vim.filetype.detect').typ(bufnr)
- end,
+ typ = detect.typ,
pkb = 'sql',
tyb = 'sql',
pks = 'sql',
@@ -1012,11 +940,11 @@ local extension = {
sqi = 'sqr',
sqr = 'sqr',
nut = 'squirrel',
- ['s28'] = 'srec',
- ['s37'] = 'srec',
+ s28 = 'srec',
+ s37 = 'srec',
srec = 'srec',
mot = 'srec',
- ['s19'] = 'srec',
+ s19 = 'srec',
srt = 'srt',
ssa = 'ssa',
ass = 'ssa',
@@ -1056,9 +984,7 @@ local extension = {
bbl = 'tex',
latex = 'tex',
sty = 'tex',
- cls = function(path, bufnr)
- return require('vim.filetype.detect').cls(bufnr)
- end,
+ cls = detect.cls,
texi = 'texinfo',
txi = 'texinfo',
texinfo = 'texinfo',
@@ -1077,9 +1003,7 @@ local extension = {
tsv = 'tsv',
tutor = 'tutor',
twig = 'twig',
- ts = function(path, bufnr)
- return M.getlines(bufnr, 1):find('<%?xml') and 'xml' or 'typescript'
- end,
+ ts = detect_line1('<%?xml', 'xml', 'typescript'),
mts = 'typescript',
cts = 'typescript',
tsx = 'typescriptreact',
@@ -1104,9 +1028,7 @@ local extension = {
vr = 'vera',
vri = 'vera',
vrh = 'vera',
- v = function(path, bufnr)
- return require('vim.filetype.detect').v(bufnr)
- end,
+ v = detect.v,
va = 'verilogams',
vams = 'verilogams',
vhdl = 'vhdl',
@@ -1136,7 +1058,7 @@ local extension = {
xht = 'xhtml',
msc = 'xmath',
msf = 'xmath',
- ['psc1'] = 'xml',
+ psc1 = 'xml',
tpm = 'xml',
xliff = 'xml',
atom = 'xml',
@@ -1152,10 +1074,8 @@ local extension = {
csproj = 'xml',
wpl = 'xml',
xmi = 'xml',
- xpm = function(path, bufnr)
- return M.getlines(bufnr, 1):find('XPM2') and 'xpm2' or 'xpm'
- end,
- ['xpm2'] = 'xpm2',
+ xpm = detect_line1('XPM2', 'xpm2', 'xpm'),
+ xpm2 = 'xpm2',
xqy = 'xquery',
xqm = 'xquery',
xquery = 'xquery',
@@ -1172,7 +1092,7 @@ local extension = {
yaml = 'yaml',
yang = 'yang',
yuck = 'yuck',
- ['z8a'] = 'z8a',
+ z8a = 'z8a',
zig = 'zig',
zir = 'zir',
zu = 'zimbu',
@@ -1180,183 +1100,69 @@ local extension = {
zs = 'zserio',
zsh = 'zsh',
vala = 'vala',
- web = function(path, bufnr)
- return require('vim.filetype.detect').web(bufnr)
- end,
- pl = function(path, bufnr)
- return require('vim.filetype.detect').pl(bufnr)
- end,
- pp = function(path, bufnr)
- return require('vim.filetype.detect').pp(bufnr)
- end,
- i = function(path, bufnr)
- return require('vim.filetype.detect').progress_asm(bufnr)
- end,
- w = function(path, bufnr)
- return require('vim.filetype.detect').progress_cweb(bufnr)
- end,
- p = function(path, bufnr)
- return require('vim.filetype.detect').progress_pascal(bufnr)
- end,
- pro = function(path, bufnr)
- return require('vim.filetype.detect').proto(bufnr, 'idlang')
- end,
- patch = function(path, bufnr)
- return require('vim.filetype.detect').patch(bufnr)
- end,
- r = function(path, bufnr)
- return require('vim.filetype.detect').r(bufnr)
- end,
- rdf = function(path, bufnr)
- return require('vim.filetype.detect').redif(bufnr)
- end,
- rules = function(path, bufnr)
- return require('vim.filetype.detect').rules(path)
- end,
- sc = function(path, bufnr)
- return require('vim.filetype.detect').sc(bufnr)
- end,
- scd = function(path, bufnr)
- return require('vim.filetype.detect').scd(bufnr)
- end,
+ web = detect.web,
+ pl = detect.pl,
+ pp = detect.pp,
+ i = detect.progress_asm,
+ w = detect.progress_cweb,
+ p = detect.progress_pascal,
+ pro = detect_seq(detect.proto, 'idlang'),
+ patch = detect.patch,
+ r = detect.r,
+ rdf = detect.redif,
+ rules = detect.rules,
+ sc = detect.sc,
+ scd = detect.scd,
tcsh = function(path, bufnr)
- 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'
- end,
- zsql = function(path, bufnr)
- return vim.g.filetype_sql and vim.g.filetype_sql or 'sql'
- end,
- tex = function(path, bufnr)
- return require('vim.filetype.detect').tex(path, bufnr)
- end,
- tf = function(path, bufnr)
- return require('vim.filetype.detect').tf(bufnr)
- end,
- txt = function(path, bufnr)
- return require('vim.filetype.detect').txt(bufnr)
- end,
- xml = function(path, bufnr)
- return require('vim.filetype.detect').xml(bufnr)
- end,
- y = function(path, bufnr)
- return require('vim.filetype.detect').y(bufnr)
- end,
- cmd = function(path, bufnr)
- return M.getlines(bufnr, 1):find('^/%*') and 'rexx' or 'dosbatch'
- end,
- rul = function(path, bufnr)
- return require('vim.filetype.detect').rul(bufnr)
- end,
- cpy = function(path, bufnr)
- return M.getlines(bufnr, 1):find('^##') and 'python' or 'cobol'
- end,
- dsl = function(path, bufnr)
- return M.getlines(bufnr, 1):find('^%s*<!') and 'dsl' or 'structurizr'
- end,
- smil = function(path, bufnr)
- return M.getlines(bufnr, 1):find('<%?%s*xml.*%?>') and 'xml' or 'smil'
- end,
- smi = function(path, bufnr)
- return require('vim.filetype.detect').smi(bufnr)
- end,
- install = function(path, bufnr)
- return require('vim.filetype.detect').install(path, bufnr)
- end,
- pm = function(path, bufnr)
- return require('vim.filetype.detect').pm(bufnr)
- end,
- me = function(path, bufnr)
- return require('vim.filetype.detect').me(path)
- end,
- reg = function(path, bufnr)
- return require('vim.filetype.detect').reg(bufnr)
- end,
- ttl = function(path, bufnr)
- return require('vim.filetype.detect').ttl(bufnr)
- end,
- rc = function(path, bufnr)
- if not path:find('/etc/Muttrc%.d/') then
- return 'rc'
- end
- end,
- rch = function(path, bufnr)
- if not path:find('/etc/Muttrc%.d/') then
- return 'rc'
- end
- end,
- class = function(path, bufnr)
- require('vim.filetype.detect').class(bufnr)
- end,
- sgml = function(path, bufnr)
- return require('vim.filetype.detect').sgml(bufnr)
- end,
- sgm = function(path, bufnr)
- return require('vim.filetype.detect').sgml(bufnr)
- end,
- t = function(path, bufnr)
- local nroff = require('vim.filetype.detect').nroff(bufnr)
- return nroff or require('vim.filetype.detect').perl(path, bufnr) or 'tads'
- end,
+ return require('vim.filetype.detect').shell(path, M._getlines(bufnr), 'tcsh')
+ end,
+ sql = detect.sql,
+ zsql = detect.sql,
+ tex = detect.tex,
+ tf = detect.tf,
+ txt = detect.txt,
+ xml = detect.xml,
+ y = detect.y,
+ cmd = detect_line1('^/%*', 'rexx', 'dosbatch'),
+ rul = detect.rul,
+ cpy = detect_line1('^##', 'python', 'cobol'),
+ dsl = detect_line1('^%s*<!', 'dsl', 'structurizr'),
+ smil = detect_line1('<%?%s*xml.*%?>', 'xml', 'smil'),
+ smi = detect.smi,
+ install = detect.install,
+ pm = detect.pm,
+ me = detect.me,
+ reg = detect.reg,
+ ttl = detect.ttl,
+ rc = detect_rc,
+ rch = detect_rc,
+ class = detect.class,
+ sgml = detect.sgml,
+ sgm = detect.sgml,
+ t = detect_seq(detect.nroff, detect.perl, 'tads'),
-- Ignored extensions
- bak = function(path, bufnr)
- local root = vim.fn.fnamemodify(path, ':r')
- return M.match({ buf = bufnr, filename = root })
- end,
- ['dpkg-bak'] = function(path, bufnr)
- local root = vim.fn.fnamemodify(path, ':r')
- return M.match({ buf = bufnr, filename = root })
- end,
- ['dpkg-dist'] = function(path, bufnr)
- local root = vim.fn.fnamemodify(path, ':r')
- return M.match({ buf = bufnr, filename = root })
- end,
- ['dpkg-old'] = function(path, bufnr)
- local root = vim.fn.fnamemodify(path, ':r')
- return M.match({ buf = bufnr, filename = root })
- end,
- ['dpkg-new'] = function(path, bufnr)
- local root = vim.fn.fnamemodify(path, ':r')
- return M.match({ buf = bufnr, filename = root })
- end,
+ bak = detect_noext,
+ ['dpkg-bak'] = detect_noext,
+ ['dpkg-dist'] = detect_noext,
+ ['dpkg-old'] = detect_noext,
+ ['dpkg-new'] = detect_noext,
['in'] = function(path, bufnr)
if vim.fs.basename(path) ~= 'configure.in' then
- local root = vim.fn.fnamemodify(path, ':r')
+ local root = fn.fnamemodify(path, ':r')
return M.match({ buf = bufnr, filename = root })
end
end,
- new = function(path, bufnr)
- local root = vim.fn.fnamemodify(path, ':r')
- return M.match({ buf = bufnr, filename = root })
- end,
- old = function(path, bufnr)
- local root = vim.fn.fnamemodify(path, ':r')
- return M.match({ buf = bufnr, filename = root })
- end,
- orig = function(path, bufnr)
- local root = vim.fn.fnamemodify(path, ':r')
- return M.match({ buf = bufnr, filename = root })
- end,
- pacsave = function(path, bufnr)
- local root = vim.fn.fnamemodify(path, ':r')
- return M.match({ buf = bufnr, filename = root })
- end,
- pacnew = function(path, bufnr)
- local root = vim.fn.fnamemodify(path, ':r')
- return M.match({ buf = bufnr, filename = root })
- end,
- rpmsave = function(path, bufnr)
- local root = vim.fn.fnamemodify(path, ':r')
- return M.match({ buf = bufnr, filename = root })
- end,
- rmpnew = function(path, bufnr)
- local root = vim.fn.fnamemodify(path, ':r')
- return M.match({ buf = bufnr, filename = root })
- end,
+ new = detect_noext,
+ old = detect_noext,
+ orig = detect_noext,
+ pacsave = detect_noext,
+ pacnew = detect_noext,
+ rpmsave = detect_noext,
+ rmpnew = detect_noext,
-- END EXTENSION
}
+--- @type vim.filetype.mapping
local filename = {
-- BEGIN FILENAME
['a2psrc'] = 'a2ps',
@@ -1387,24 +1193,12 @@ local filename = {
['/etc/defaults/cdrdao'] = 'cdrdaoconf',
['cfengine.conf'] = 'cfengine',
['CMakeLists.txt'] = 'cmake',
- ['.alias'] = function(path, bufnr)
- return require('vim.filetype.detect').csh(path, bufnr)
- end,
- ['.cshrc'] = function(path, bufnr)
- return require('vim.filetype.detect').csh(path, bufnr)
- end,
- ['.login'] = function(path, bufnr)
- return require('vim.filetype.detect').csh(path, bufnr)
- end,
- ['csh.cshrc'] = function(path, bufnr)
- return require('vim.filetype.detect').csh(path, bufnr)
- end,
- ['csh.login'] = function(path, bufnr)
- return require('vim.filetype.detect').csh(path, bufnr)
- end,
- ['csh.logout'] = function(path, bufnr)
- return require('vim.filetype.detect').csh(path, bufnr)
- end,
+ ['.alias'] = detect.csh,
+ ['.cshrc'] = detect.csh,
+ ['.login'] = detect.csh,
+ ['csh.cshrc'] = detect.csh,
+ ['csh.login'] = detect.csh,
+ ['csh.logout'] = detect.csh,
['auto.master'] = 'conf',
['configure.in'] = 'config',
['configure.ac'] = 'config',
@@ -1444,18 +1238,10 @@ local filename = {
['exim.conf'] = 'exim',
exports = 'exports',
['.fetchmailrc'] = 'fetchmail',
- fvSchemes = function(path, bufnr)
- return require('vim.filetype.detect').foam(bufnr)
- end,
- fvSolution = function(path, bufnr)
- return require('vim.filetype.detect').foam(bufnr)
- end,
- fvConstraints = function(path, bufnr)
- return require('vim.filetype.detect').foam(bufnr)
- end,
- fvModels = function(path, bufnr)
- return require('vim.filetype.detect').foam(bufnr)
- end,
+ fvSchemes = detect.foam,
+ fvSolution = detect.foam,
+ fvConstraints = detect.foam,
+ fvModels = detect.foam,
fstab = 'fstab',
mtab = 'fstab',
['.gdbinit'] = 'gdb',
@@ -1463,11 +1249,11 @@ local filename = {
['.gdbearlyinit'] = 'gdb',
gdbearlyinit = 'gdb',
['lltxxxxx.txt'] = 'gedcom',
- ['TAG_EDITMSG'] = 'gitcommit',
- ['MERGE_MSG'] = 'gitcommit',
- ['COMMIT_EDITMSG'] = 'gitcommit',
- ['NOTES_EDITMSG'] = 'gitcommit',
- ['EDIT_DESCRIPTION'] = 'gitcommit',
+ TAG_EDITMSG = 'gitcommit',
+ MERGE_MSG = 'gitcommit',
+ COMMIT_EDITMSG = 'gitcommit',
+ NOTES_EDITMSG = 'gitcommit',
+ EDIT_DESCRIPTION = 'gitcommit',
['.gitconfig'] = 'gitconfig',
['.gitmodules'] = 'gitconfig',
['.gitattributes'] = 'gitattributes',
@@ -1486,7 +1272,7 @@ local filename = {
['.gprc'] = 'gp',
['/.gnupg/gpg.conf'] = 'gpg',
['/.gnupg/options'] = 'gpg',
- ['Jenkinsfile'] = 'groovy',
+ Jenkinsfile = 'groovy',
['/var/backups/gshadow.bak'] = 'group',
['/etc/gshadow'] = 'group',
['/etc/group-'] = 'group',
@@ -1536,9 +1322,7 @@ local filename = {
['.sawfishrc'] = 'lisp',
['/etc/login.access'] = 'loginaccess',
['/etc/login.defs'] = 'logindefs',
- ['.lsl'] = function(path, bufnr)
- return require('vim.filetype.detect').lsl(bufnr)
- end,
+ ['.lsl'] = detect.lsl,
['.busted'] = 'lua',
['.luacheckrc'] = 'lua',
['lynx.cfg'] = 'lynx',
@@ -1568,9 +1352,7 @@ local filename = {
['/etc/nanorc'] = 'nanorc',
Neomuttrc = 'neomuttrc',
['.netrc'] = 'netrc',
- NEWS = function(path, bufnr)
- return require('vim.filetype.detect').news(bufnr)
- end,
+ NEWS = detect.news,
['env.nu'] = 'nu',
['config.nu'] = 'nu',
['.ocamlinit'] = 'ocaml',
@@ -1601,34 +1383,28 @@ local filename = {
['/etc/pinforc'] = 'pinfo',
['/.pinforc'] = 'pinfo',
['.povrayrc'] = 'povini',
- ['printcap'] = function(path, bufnr)
+ printcap = function(path, bufnr)
return 'ptcap', function(b)
vim.b[b].ptcap_type = 'print'
end
end,
- ['termcap'] = function(path, bufnr)
+ termcap = function(path, bufnr)
return 'ptcap', function(b)
vim.b[b].ptcap_type = 'term'
end
end,
['.procmailrc'] = 'procmail',
['.procmail'] = 'procmail',
- ['indent.pro'] = function(path, bufnr)
- return require('vim.filetype.detect').proto(bufnr, 'indent')
- end,
+ ['indent.pro'] = detect_seq(detect.proto, 'indent'),
['/etc/protocols'] = 'protocols',
- ['INDEX'] = function(path, bufnr)
- return require('vim.filetype.detect').psf(bufnr)
- end,
- ['INFO'] = function(path, bufnr)
- return require('vim.filetype.detect').psf(bufnr)
- end,
+ INDEX = detect.psf,
+ INFO = detect.psf,
['.pythonstartup'] = 'python',
['.pythonrc'] = 'python',
SConstruct = 'python',
qmldir = 'qmldir',
['.Rprofile'] = 'r',
- ['Rprofile'] = 'r',
+ Rprofile = 'r',
['Rprofile.site'] = 'r',
ratpoisonrc = 'ratpoison',
['.ratpoisonrc'] = 'ratpoison',
@@ -1650,42 +1426,18 @@ local filename = {
['/etc/services'] = 'services',
['/etc/serial.conf'] = 'setserial',
['/etc/udev/cdsymlinks.conf'] = 'sh',
- ['bash.bashrc'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
- end,
- bashrc = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
- end,
- ['.bashrc'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
- end,
- ['.env'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
- end,
- ['.kshrc'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'ksh')
- end,
- ['.profile'] = function(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, M.getlines(bufnr))
- end,
- APKBUILD = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
- end,
- PKGBUILD = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
- end,
- ['.tcshrc'] = function(path, bufnr)
- return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh')
- end,
- ['tcsh.login'] = function(path, bufnr)
- return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh')
- end,
- ['tcsh.tcshrc'] = function(path, bufnr)
- return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh')
- end,
+ ['bash.bashrc'] = detect.bash,
+ bashrc = detect.bash,
+ ['.bashrc'] = detect.bash,
+ ['.env'] = detect.sh,
+ ['.kshrc'] = detect.ksh,
+ ['.profile'] = detect.sh,
+ ['/etc/profile'] = detect.sh,
+ APKBUILD = detect.bash,
+ PKGBUILD = detect.bash,
+ ['.tcshrc'] = detect.tcsh,
+ ['tcsh.login'] = detect.tcsh,
+ ['tcsh.tcshrc'] = detect.tcsh,
['/etc/slp.conf'] = 'slpconf',
['/etc/slp.reg'] = 'slpreg',
['/etc/slp.spi'] = 'slpspi',
@@ -1739,19 +1491,9 @@ local filename = {
['.Xpdefaults'] = 'xdefaults',
['xdm-config'] = 'xdefaults',
['.Xdefaults'] = 'xdefaults',
- ['xorg.conf'] = function(path, bufnr)
- return 'xf86conf', function(b)
- vim.b[b].xf86conf_xfree86_version = 4
- end
- end,
- ['xorg.conf-4'] = function(path, bufnr)
- return 'xf86conf', function(b)
- vim.b[b].xf86conf_xfree86_version = 4
- end
- end,
- ['XF86Config'] = function(path, bufnr)
- return require('vim.filetype.detect').xfree86()
- end,
+ ['xorg.conf'] = detect.xfree86_v4,
+ ['xorg.conf-4'] = detect.xfree86_v4,
+ ['XF86Config'] = detect.xfree86_v3,
['/etc/xinetd.conf'] = 'xinetd',
fglrxrc = 'xml',
['/etc/blkid.tab'] = 'xml',
@@ -1770,6 +1512,12 @@ local filename = {
-- END FILENAME
}
+-- Re-use closures as much as possible
+local detect_apache = starsetf('apache')
+local detect_muttrc = starsetf('muttrc')
+local detect_neomuttrc = starsetf('neomuttrc')
+
+--- @type vim.filetype.mapping
local pattern = {
-- BEGIN PATTERN
['.*/etc/a2ps/.*%.cfg'] = 'a2ps',
@@ -1778,31 +1526,27 @@ local pattern = {
['.*/etc/asound%.conf'] = 'alsaconf',
['.*/etc/apache2/sites%-.*/.*%.com'] = 'apache',
['.*/etc/httpd/.*%.conf'] = 'apache',
- ['.*/etc/apache2/.*%.conf.*'] = starsetf('apache'),
- ['.*/etc/apache2/conf%..*/.*'] = starsetf('apache'),
- ['.*/etc/apache2/mods%-.*/.*'] = starsetf('apache'),
- ['.*/etc/apache2/sites%-.*/.*'] = starsetf('apache'),
- ['access%.conf.*'] = starsetf('apache'),
- ['apache%.conf.*'] = starsetf('apache'),
- ['apache2%.conf.*'] = starsetf('apache'),
- ['httpd%.conf.*'] = starsetf('apache'),
- ['srm%.conf.*'] = starsetf('apache'),
- ['.*/etc/httpd/conf%..*/.*'] = starsetf('apache'),
- ['.*/etc/httpd/conf%.d/.*%.conf.*'] = starsetf('apache'),
- ['.*/etc/httpd/mods%-.*/.*'] = starsetf('apache'),
- ['.*/etc/httpd/sites%-.*/.*'] = starsetf('apache'),
+ ['.*/etc/apache2/.*%.conf.*'] = detect_apache,
+ ['.*/etc/apache2/conf%..*/.*'] = detect_apache,
+ ['.*/etc/apache2/mods%-.*/.*'] = detect_apache,
+ ['.*/etc/apache2/sites%-.*/.*'] = detect_apache,
+ ['access%.conf.*'] = detect_apache,
+ ['apache%.conf.*'] = detect_apache,
+ ['apache2%.conf.*'] = detect_apache,
+ ['httpd%.conf.*'] = detect_apache,
+ ['srm%.conf.*'] = detect_apache,
+ ['.*/etc/httpd/conf%..*/.*'] = detect_apache,
+ ['.*/etc/httpd/conf%.d/.*%.conf.*'] = detect_apache,
+ ['.*/etc/httpd/mods%-.*/.*'] = detect_apache,
+ ['.*/etc/httpd/sites%-.*/.*'] = detect_apache,
['.*/etc/proftpd/.*%.conf.*'] = starsetf('apachestyle'),
['.*/etc/proftpd/conf%..*/.*'] = starsetf('apachestyle'),
['proftpd%.conf.*'] = starsetf('apachestyle'),
['.*asterisk/.*%.conf.*'] = starsetf('asterisk'),
['.*asterisk.*/.*voicemail%.conf.*'] = starsetf('asteriskvm'),
['.*/%.aptitude/config'] = 'aptconf',
- ['.*%.[aA]'] = function(path, bufnr)
- return require('vim.filetype.detect').asm(bufnr)
- end,
- ['.*%.[sS]'] = function(path, bufnr)
- return require('vim.filetype.detect').asm(bufnr)
- end,
+ ['.*%.[aA]'] = detect.asm,
+ ['.*%.[sS]'] = detect.asm,
['[mM]akefile%.am'] = 'automake',
['.*/bind/db%..*'] = starsetf('bindzone'),
['.*/named/db%..*'] = starsetf('bindzone'),
@@ -1825,16 +1569,12 @@ local pattern = {
['.*/etc/default/cdrdao'] = 'cdrdaoconf',
['.*hgrc'] = 'cfg',
['.*%.[Cc][Ff][Gg]'] = {
- function(path, bufnr)
- return require('vim.filetype.detect').cfg(bufnr)
- end,
+ detect.cfg,
-- Decrease priority to avoid conflicts with more specific patterns
-- such as '.*/etc/a2ps/.*%.cfg', '.*enlightenment/.*%.cfg', etc.
{ priority = -1 },
},
- ['[cC]hange[lL]og.*'] = starsetf(function(path, bufnr)
- return require('vim.filetype.detect').changelog(bufnr)
- end),
+ ['[cC]hange[lL]og.*'] = starsetf(detect.changelog),
['.*%.%.ch'] = 'chill',
['.*%.cmake%.in'] = 'cmake',
-- */cmus/rc and */.cmus/rc
@@ -1846,19 +1586,11 @@ local pattern = {
['.*/etc/hostname%..*'] = starsetf('config'),
['crontab%..*'] = starsetf('crontab'),
['.*/etc/cron%.d/.*'] = starsetf('crontab'),
- ['%.cshrc.*'] = function(path, bufnr)
- return require('vim.filetype.detect').csh(path, bufnr)
- end,
- ['%.login.*'] = function(path, bufnr)
- return require('vim.filetype.detect').csh(path, bufnr)
- end,
+ ['%.cshrc.*'] = detect.csh,
+ ['%.login.*'] = detect.csh,
['cvs%d+'] = 'cvs',
- ['.*%.[Dd][Aa][Tt]'] = function(path, bufnr)
- return require('vim.filetype.detect').dat(path, bufnr)
- end,
- ['.*/debian/patches/.*'] = function(path, bufnr)
- return require('vim.filetype.detect').dep3patch(path, bufnr)
- end,
+ ['.*%.[Dd][Aa][Tt]'] = detect.dat,
+ ['.*/debian/patches/.*'] = detect.dep3patch,
['.*/etc/dnsmasq%.d/.*'] = starsetf('dnsmasq'),
['Containerfile%..*'] = starsetf('dockerfile'),
['Dockerfile%..*'] = starsetf('dockerfile'),
@@ -1884,53 +1616,25 @@ local pattern = {
['.*/dtrace/.*%.d'] = 'dtrace',
['.*esmtprc'] = 'esmtprc',
['.*Eterm/.*%.cfg'] = 'eterm',
- ['[a-zA-Z0-9].*Dict'] = function(path, bufnr)
- return require('vim.filetype.detect').foam(bufnr)
- end,
- ['[a-zA-Z0-9].*Dict%..*'] = function(path, bufnr)
- return require('vim.filetype.detect').foam(bufnr)
- end,
- ['[a-zA-Z].*Properties'] = function(path, bufnr)
- return require('vim.filetype.detect').foam(bufnr)
- end,
- ['[a-zA-Z].*Properties%..*'] = function(path, bufnr)
- return require('vim.filetype.detect').foam(bufnr)
- end,
- ['.*Transport%..*'] = function(path, bufnr)
- return require('vim.filetype.detect').foam(bufnr)
- end,
- ['.*/constant/g'] = function(path, bufnr)
- return require('vim.filetype.detect').foam(bufnr)
- end,
- ['.*/0/.*'] = function(path, bufnr)
- return require('vim.filetype.detect').foam(bufnr)
- end,
- ['.*/0%.orig/.*'] = function(path, bufnr)
- return require('vim.filetype.detect').foam(bufnr)
- end,
+ ['[a-zA-Z0-9].*Dict'] = detect.foam,
+ ['[a-zA-Z0-9].*Dict%..*'] = detect.foam,
+ ['[a-zA-Z].*Properties'] = detect.foam,
+ ['[a-zA-Z].*Properties%..*'] = detect.foam,
+ ['.*Transport%..*'] = detect.foam,
+ ['.*/constant/g'] = detect.foam,
+ ['.*/0/.*'] = detect.foam,
+ ['.*/0%.orig/.*'] = detect.foam,
['.*/%.fvwm/.*'] = starsetf('fvwm'),
- ['.*fvwmrc.*'] = starsetf(function(path, bufnr)
- return 'fvwm', function(b)
- vim.b[b].fvwm_version = 1
- end
- end),
- ['.*fvwm95.*%.hook'] = starsetf(function(path, bufnr)
- return 'fvwm', function(b)
- vim.b[b].fvwm_version = 1
- end
- end),
- ['.*fvwm2rc.*'] = starsetf(function(path, bufnr)
- return require('vim.filetype.detect').fvwm(path)
- end),
+ ['.*fvwmrc.*'] = starsetf(detect.fvwm_v1),
+ ['.*fvwm95.*%.hook'] = starsetf(detect.fvwm_v1),
+ ['.*fvwm2rc.*'] = starsetf(detect.fvwm_v2),
['.*/tmp/lltmp.*'] = starsetf('gedcom'),
['.*/etc/gitconfig%.d/.*'] = starsetf('gitconfig'),
['.*/gitolite%-admin/conf/.*'] = starsetf('gitolite'),
['tmac%..*'] = starsetf('nroff'),
['.*/%.gitconfig%.d/.*'] = starsetf('gitconfig'),
['.*%.git/.*'] = {
- function(path, bufnr)
- return require('vim.filetype.detect').git(bufnr)
- end,
+ detect.git,
-- Decrease priority to run after simple pattern checks
{ priority = -1 },
},
@@ -2093,15 +1797,13 @@ local pattern = {
['.*/log/news/news%.notice'] = 'messages',
['.*/log/syslog%.notice'] = 'messages',
['.*/log/user%.notice'] = 'messages',
- ['.*%.[Mm][Oo][Dd]'] = function(path, bufnr)
- return require('vim.filetype.detect').mod(path, bufnr)
- end,
+ ['.*%.[Mm][Oo][Dd]'] = detect.mod,
['.*/etc/modules%.conf'] = 'modconf',
['.*/etc/conf%.modules'] = 'modconf',
['.*/etc/modules'] = 'modconf',
['.*/etc/modprobe%..*'] = starsetf('modconf'),
['.*/etc/modutils/.*'] = starsetf(function(path, bufnr)
- if vim.fn.executable(vim.fn.expand(path)) ~= 1 then
+ if fn.executable(fn.expand(path)) ~= 1 then
return 'modconf'
end
end),
@@ -2110,32 +1812,30 @@ local pattern = {
['Muttngrc'] = 'muttrc',
['.*/etc/Muttrc%.d/.*'] = starsetf('muttrc'),
['.*/%.mplayer/config'] = 'mplayerconf',
- ['Muttrc.*'] = starsetf('muttrc'),
- ['Muttngrc.*'] = starsetf('muttrc'),
+ ['Muttrc.*'] = detect_muttrc,
+ ['Muttngrc.*'] = detect_muttrc,
-- muttrc* and .muttrc*
- ['%.?muttrc.*'] = starsetf('muttrc'),
+ ['%.?muttrc.*'] = detect_muttrc,
-- muttngrc* and .muttngrc*
- ['%.?muttngrc.*'] = starsetf('muttrc'),
- ['.*/%.mutt/muttrc.*'] = starsetf('muttrc'),
- ['.*/%.muttng/muttrc.*'] = starsetf('muttrc'),
- ['.*/%.muttng/muttngrc.*'] = starsetf('muttrc'),
+ ['%.?muttngrc.*'] = detect_muttrc,
+ ['.*/%.mutt/muttrc.*'] = detect_muttrc,
+ ['.*/%.muttng/muttrc.*'] = detect_muttrc,
+ ['.*/%.muttng/muttngrc.*'] = detect_muttrc,
['rndc.*%.conf'] = 'named',
['rndc.*%.key'] = 'named',
['named.*%.conf'] = 'named',
['.*/etc/nanorc'] = 'nanorc',
['.*%.NS[ACGLMNPS]'] = 'natural',
- ['Neomuttrc.*'] = starsetf('neomuttrc'),
+ ['Neomuttrc.*'] = detect_neomuttrc,
-- neomuttrc* and .neomuttrc*
- ['%.?neomuttrc.*'] = starsetf('neomuttrc'),
- ['.*/%.neomutt/neomuttrc.*'] = starsetf('neomuttrc'),
+ ['%.?neomuttrc.*'] = detect_neomuttrc,
+ ['.*/%.neomutt/neomuttrc.*'] = detect_neomuttrc,
['nginx.*%.conf'] = 'nginx',
['.*/etc/nginx/.*'] = 'nginx',
['.*nginx%.conf'] = 'nginx',
['.*/nginx/.*%.conf'] = 'nginx',
['.*/usr/local/nginx/conf/.*'] = 'nginx',
- ['.*%.[1-9]'] = function(path, bufnr)
- return require('vim.filetype.detect').nroff(bufnr)
- end,
+ ['.*%.[1-9]'] = detect.nroff,
['.*%.ml%.cppo'] = 'ocaml',
['.*%.mli%.cppo'] = 'ocaml',
['.*%.opam%.template'] = 'opam',
@@ -2156,9 +1856,7 @@ local pattern = {
['.*%.php%d'] = 'php',
['.*/%.pinforc'] = 'pinfo',
['.*/etc/pinforc'] = 'pinfo',
- ['.*%.[Pp][Rr][Gg]'] = function(path, bufnr)
- return require('vim.filetype.detect').prg(bufnr)
- end,
+ ['.*%.[Pp][Rr][Gg]'] = detect.prg,
['.*/etc/protocols'] = 'protocols',
['.*printcap.*'] = starsetf(function(path, bufnr)
return require('vim.filetype.detect').printcap('print')
@@ -2178,30 +1876,14 @@ local pattern = {
['.*/etc/services'] = 'services',
['.*/etc/serial%.conf'] = 'setserial',
['.*/etc/udev/cdsymlinks%.conf'] = 'sh',
- ['%.bash[_%-]aliases'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
- end,
- ['%.bash[_%-]logout'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
- end,
- ['%.bash[_%-]profile'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
- end,
- ['%.kshrc.*'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'ksh')
- end,
- ['%.profile.*'] = function(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, M.getlines(bufnr))
- end,
- ['bash%-fc[%-%.].*'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
- end,
- ['%.tcshrc.*'] = function(path, bufnr)
- return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'tcsh')
- end,
+ ['%.bash[_%-]aliases'] = detect.bash,
+ ['%.bash[_%-]logout'] = detect.bash,
+ ['%.bash[_%-]profile'] = detect.bash,
+ ['%.kshrc.*'] = detect.ksh,
+ ['%.profile.*'] = detect.sh,
+ ['.*/etc/profile'] = detect.sh,
+ ['bash%-fc[%-%.].*'] = detect.bash,
+ ['%.tcshrc.*'] = detect.tcsh,
['.*/etc/sudoers%.d/.*'] = starsetf('sudoers'),
['.*%._sst%.meta'] = 'sisu',
['.*%.%-sst%.meta'] = 'sisu',
@@ -2213,17 +1895,13 @@ local pattern = {
['.*/%.ssh/config'] = 'sshconfig',
['.*/%.ssh/.*%.conf'] = 'sshconfig',
['.*/etc/ssh/sshd_config%.d/.*%.conf'] = 'sshdconfig',
- ['.*%.[Ss][Rr][Cc]'] = function(path, bufnr)
- return require('vim.filetype.detect').src(bufnr)
- end,
+ ['.*%.[Ss][Rr][Cc]'] = detect.src,
['.*/etc/sudoers'] = 'sudoers',
['svn%-commit.*%.tmp'] = 'svn',
['.*/sway/config'] = 'swayconfig',
['.*/%.sway/config'] = 'swayconfig',
['.*%.swift%.gyb'] = 'swiftgyb',
- ['.*%.[Ss][Yy][Ss]'] = function(path, bufnr)
- return require('vim.filetype.detect').sys(bufnr)
- end,
+ ['.*%.[Ss][Yy][Ss]'] = detect.sys,
['.*/etc/sysctl%.conf'] = 'sysctl',
['.*/etc/sysctl%.d/.*%.conf'] = 'sysctl',
['.*/systemd/.*%.automount'] = 'systemd',
@@ -2266,9 +1944,7 @@ local pattern = {
['.*/%.config/upstart/.*%.conf'] = 'upstart',
['.*/%.init/.*%.conf'] = 'upstart',
['.*/usr/share/upstart/.*%.override'] = 'upstart',
- ['.*%.[Ll][Oo][Gg]'] = function(path, bufnr)
- return require('vim.filetype.detect').log(path)
- end,
+ ['.*%.[Ll][Oo][Gg]'] = detect.log,
['.*%.vhdl_[0-9].*'] = starsetf('vhdl'),
['.*%.ws[fc]'] = 'wsh',
['.*/Xresources/.*'] = starsetf('xdefaults'),
@@ -2286,20 +1962,10 @@ local pattern = {
['Xresources.*'] = starsetf('xdefaults'),
['.*/etc/xinetd%.d/.*'] = starsetf('xinetd'),
['.*xmodmap.*'] = starsetf('xmodmap'),
- ['.*/xorg%.conf%.d/.*%.conf'] = function(path, bufnr)
- return 'xf86config', function(b)
- vim.b[b].xf86conf_xfree86_version = 4
- end
- end,
+ ['.*/xorg%.conf%.d/.*%.conf'] = detect.xfree86_v4,
-- Increase priority to run before the pattern below
- ['XF86Config%-4.*'] = starsetf(function(path, bufnr)
- return 'xf86conf', function(b)
- vim.b[b].xf86conf_xfree86_version = 4
- end
- end, { priority = -math.huge + 1 }),
- ['XF86Config.*'] = starsetf(function(path, bufnr)
- return require('vim.filetype.detect').xfree86()
- end),
+ ['XF86Config%-4.*'] = starsetf(detect.xfree86_v4, { priority = -math.huge + 1 }),
+ ['XF86Config.*'] = starsetf(detect.xfree86_v3),
['%.zcompdump.*'] = starsetf('zsh'),
-- .zlog* and zlog*
['%.?zlog.*'] = starsetf('zsh'),
@@ -2309,7 +1975,7 @@ local pattern = {
['.*~'] = function(path, bufnr)
local short = path:gsub('~$', '', 1)
if path ~= short and short ~= '' then
- return M.match({ buf = bufnr, filename = vim.fn.fnameescape(short) })
+ return M.match({ buf = bufnr, filename = fn.fnameescape(short) })
end
end,
-- END PATTERN
@@ -2317,8 +1983,10 @@ local pattern = {
-- luacheck: pop
-- luacheck: pop
+--- @param t vim.filetype.mapping
+--- @return vim.filetype.mapping[]
local function sort_by_priority(t)
- local sorted = {}
+ local sorted = {} --- @type vim.filetype.mapping[]
for k, v in pairs(t) do
local ft = type(v) == 'table' and v[1] or v
assert(
@@ -2340,6 +2008,9 @@ end
local pattern_sorted = sort_by_priority(pattern)
+--- @param path string
+--- @param as_pattern? true
+--- @return string
local function normalize_path(path, as_pattern)
local normal = path:gsub('\\', '/')
if normal:find('^~') then
@@ -2348,12 +2019,17 @@ local function normalize_path(path, as_pattern)
-- The rest of path should already be properly escaped.
normal = vim.pesc(vim.env.HOME) .. normal:sub(2)
else
- normal = vim.env.HOME .. normal:sub(2)
+ normal = vim.env.HOME .. normal:sub(2) --- @type string
end
end
return normal
end
+--- @class vim.filetype.add.filetypes
+--- @field pattern vim.filetype.mapping
+--- @field extension vim.filetype.mapping
+--- @field filename vim.filetype.mapping
+
--- Add new filetype mappings.
---
--- Filetype mappings can be added either by extension or by filename (either
@@ -2423,10 +2099,10 @@ end
--- ['.*'] = {
--- priority = -math.huge,
--- function(path, bufnr)
---- local content = vim.filetype.getlines(bufnr, 1)
---- if vim.filetype.matchregex(content, [[^#!.*\\<mine\\>]]) then
+--- local content = vim.api.nvim_buf_get_lines(bufnr, 0, 1, false)[1] or ''
+--- if vim.regex([[^#!.*\\<mine\\>]]):match_str(content) ~= nil then
--- return 'mine'
---- elseif vim.filetype.matchregex(content, [[\\<drawing\\>]]) then
+--- elseif vim.regex([[\\<drawing\\>]]):match_str(content) ~= nil then
--- return 'drawing'
--- end
--- end,
@@ -2435,7 +2111,7 @@ end
--- }
--- </pre>
---
----@param filetypes table A table containing new filetype maps (see example).
+---@param filetypes vim.filetype.add.filetypes A table containing new filetype maps (see example).
function M.add(filetypes)
for k, v in pairs(filetypes.extension or {}) do
extension[k] = v
@@ -2454,38 +2130,62 @@ function M.add(filetypes)
end
end
+--- @param ft vim.filetype.mapping.value
+--- @param path? string
+--- @param bufnr? integer
+--- @param ... any
+--- @return string?
+--- @return fun(b: integer)?
local function dispatch(ft, path, bufnr, ...)
- local on_detect
- if type(ft) == 'function' then
- 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
+ if type(ft) == 'string' then
+ return ft
+ end
+
+ if type(ft) ~= 'function' then
+ return
+ end
+
+ assert(path)
+
+ ---@type string|false?, fun(b: integer)?
+ local ft0, on_detect
+ if bufnr then
+ ft0, 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, ft0, on_detect = pcall(ft, path, -1, ...)
+ if not ok then
+ return
end
end
- if type(ft) == 'string' then
- return ft, on_detect
+ if not ft0 then
+ return
end
+
+ return ft0, on_detect
end
--- Lookup table/cache for patterns that contain an environment variable pattern, e.g. ${SOME_VAR}.
+--- Lookup table/cache for patterns that contain an environment variable pattern, e.g. ${SOME_VAR}.
+--- @type table<string,boolean>
local expand_env_lookup = {}
+--- @param name string
+--- @param path string
+--- @param tail string
+--- @param pat string
+--- @return string|false?
local function match_pattern(name, path, tail, pat)
if expand_env_lookup[pat] == nil then
expand_env_lookup[pat] = pat:find('%${') ~= nil
end
if expand_env_lookup[pat] then
- local return_early
+ local return_early --- @type true?
+ --- @type string
pat = pat:gsub('%${(%S-)}', function(env)
-- If an environment variable is present in the pattern but not set, there is no match
if not vim.env[env] then
@@ -2501,18 +2201,22 @@ local function match_pattern(name, path, tail, pat)
-- If the pattern contains a / match against the full path, otherwise just the tail
local fullpat = '^' .. pat .. '$'
- local matches
+
if pat:find('/') then
-- Similar to |autocmd-pattern|, if the pattern contains a '/' then check for a match against
-- both the short file name (as typed) and the full file name (after expanding to full path
-- and resolving symlinks)
- matches = name:match(fullpat) or path:match(fullpat)
- else
- matches = tail:match(fullpat)
+ return (name:match(fullpat) or path:match(fullpat))
end
- return matches
+
+ return (tail:match(fullpat))
end
+--- @class vim.filetype.match.args
+--- @field buf? integer
+--- @field filename? string
+--- @field contents? string[]
+
--- Perform filetype detection.
---
--- The filetype can be detected using one of three methods:
@@ -2542,7 +2246,8 @@ end
--- vim.filetype.match({ contents = {'#!/usr/bin/env bash'} })
--- </pre>
---
----@param args table Table specifying which matching strategy to use. Accepted keys are:
+---@param args vim.filetype.match.args 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,
@@ -2555,8 +2260,8 @@ end
--- * 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
+---@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(args)
@@ -2576,20 +2281,21 @@ function M.match(args)
name = api.nvim_buf_get_name(bufnr)
end
+ --- @type string?, fun(b: integer)?
local ft, on_detect
if name then
name = normalize_path(name)
-- First check for the simple case where the full path exists as a key
- local path = vim.fn.fnamemodify(name, ':p')
+ local path = fn.fnamemodify(name, ':p')
ft, on_detect = dispatch(filename[path], path, bufnr)
if ft then
return ft, on_detect
end
-- Next check against just the file name
- local tail = vim.fn.fnamemodify(name, ':t')
+ local tail = fn.fnamemodify(name, ':t')
ft, on_detect = dispatch(filename[tail], path, bufnr)
if ft then
return ft, on_detect
@@ -2616,7 +2322,7 @@ function M.match(args)
end
-- Next, check file extension
- local ext = vim.fn.fnamemodify(name, ':e')
+ local ext = fn.fnamemodify(name, ':e')
ft, on_detect = dispatch(extension[ext], path, bufnr)
if ft then
return ft, on_detect
@@ -2641,12 +2347,13 @@ function M.match(args)
-- Finally, check file contents
if contents or bufnr then
if contents == nil then
+ assert(bufnr)
if api.nvim_buf_line_count(bufnr) > 101 then
-- only need first 100 and last line for current checks
- contents = M.getlines(bufnr, 1, 100)
- contents[#contents + 1] = M.getlines(bufnr, -1)
+ contents = M._getlines(bufnr, 1, 100)
+ contents[#contents + 1] = M._getline(bufnr, -1)
else
- contents = M.getlines(bufnr)
+ contents = M._getlines(bufnr)
end
end
-- If name is nil, catch any errors from the contents filetype detection function.
diff --git a/runtime/lua/vim/filetype/detect.lua b/runtime/lua/vim/filetype/detect.lua
index 4e18ed190a..59b50f2288 100644
--- a/runtime/lua/vim/filetype/detect.lua
+++ b/runtime/lua/vim/filetype/detect.lua
@@ -17,22 +17,26 @@
-- Example:
-- `if line =~ '^\s*unwind_protect\>'` => `if matchregex(line, [[\c^\s*unwind_protect\>]])`
+local fn = vim.fn
+
local M = {}
-local getlines = vim.filetype.getlines
-local findany = vim.filetype.findany
-local nextnonblank = vim.filetype.nextnonblank
-local matchregex = vim.filetype.matchregex
+local getlines = vim.filetype._getlines
+local getline = vim.filetype._getline
+local findany = vim.filetype._findany
+local nextnonblank = vim.filetype._nextnonblank
+local matchregex = vim.filetype._matchregex
-- luacheck: push no unused args
-- luacheck: push ignore 122
-- This function checks for the kind of assembly that is wanted by the user, or
-- can be detected from the first five lines of the file.
-function M.asm(bufnr)
+--- @type vim.filetype.mapfn
+function M.asm(path, bufnr)
local syntax = vim.b[bufnr].asmsyntax
if not syntax or syntax == '' then
- syntax = M.asm_syntax(bufnr)
+ syntax = M.asm_syntax(path, bufnr)
end
-- If b:asmsyntax still isn't set, default to asmsyntax or GNU
@@ -48,20 +52,21 @@ function M.asm(bufnr)
end
end
--- Active Server Pages (with Perl or Visual Basic Script)
-function M.asp(bufnr)
+--- Active Server Pages (with Perl or Visual Basic Script)
+--- @type vim.filetype.mapfn
+function M.asp(_, bufnr)
if vim.g.filetype_asp then
return vim.g.filetype_asp
elseif table.concat(getlines(bufnr, 1, 3)):lower():find('perlscript') then
return 'aspperl'
- else
- return 'aspvbs'
end
+ return 'aspvbs'
end
-- Checks the first 5 lines for a asmsyntax=foo override.
-- Only whitespace characters can be present immediately before or after this statement.
-function M.asm_syntax(bufnr)
+--- @type vim.filetype.mapfn
+function M.asm_syntax(_, bufnr)
local lines = ' ' .. table.concat(getlines(bufnr, 1, 5), ' '):lower() .. ' '
local match = lines:match('%sasmsyntax=([a-zA-Z0-9]+)%s')
if match then
@@ -75,7 +80,8 @@ local visual_basic_content =
{ 'vb_name', 'begin vb%.form', 'begin vb%.mdiform', 'begin vb%.usercontrol' }
-- See frm() for Visual Basic form file detection
-function M.bas(bufnr)
+--- @type vim.filetype.mapfn
+function M.bas(_, bufnr)
if vim.g.filetype_bas then
return vim.g.filetype_bas
end
@@ -106,18 +112,21 @@ function M.bas(bufnr)
return 'basic'
end
-function M.bindzone(bufnr, default)
+--- @type vim.filetype.mapfn
+function M.bindzone(_, bufnr)
local lines = table.concat(getlines(bufnr, 1, 4))
if findany(lines, { '^; <<>> DiG [0-9%.]+.* <<>>', '%$ORIGIN', '%$TTL', 'IN%s+SOA' }) then
return 'bindzone'
end
- return default
end
-- Returns true if file content looks like RAPID
+--- @param bufnr integer
+--- @param extension? string
+--- @return string|boolean?
local function is_rapid(bufnr, extension)
if extension == 'cfg' then
- local line = getlines(bufnr, 1):lower()
+ local line = getline(bufnr, 1):lower()
return findany(line, { 'eio:cfg', 'mmc:cfg', 'moc:cfg', 'proc:cfg', 'sio:cfg', 'sys:cfg' })
end
local line = nextnonblank(bufnr, 1)
@@ -128,23 +137,24 @@ local function is_rapid(bufnr, extension)
return false
end
-function M.cfg(bufnr)
+--- @type vim.filetype.mapfn
+function M.cfg(_, bufnr)
if vim.g.filetype_cfg then
- return vim.g.filetype_cfg
+ return vim.g.filetype_cfg --[[@as string]]
elseif is_rapid(bufnr, 'cfg') then
return 'rapid'
- else
- return 'cfg'
end
+ return 'cfg'
end
--- This function checks if one of the first ten lines start with a '@'. In
--- that case it is probably a change file.
--- If the first line starts with # or ! it's probably a ch file.
--- If a line has "main", "include", "//" or "/*" it's probably ch.
--- Otherwise CHILL is assumed.
-function M.change(bufnr)
- local first_line = getlines(bufnr, 1)
+--- This function checks if one of the first ten lines start with a '@'. In
+--- that case it is probably a change file.
+--- If the first line starts with # or ! it's probably a ch file.
+--- If a line has "main", "include", "//" or "/*" it's probably ch.
+--- Otherwise CHILL is assumed.
+--- @type vim.filetype.mapfn
+function M.change(_, bufnr)
+ local first_line = getline(bufnr, 1)
if findany(first_line, { '^#', '^!' }) then
return 'ch'
end
@@ -161,39 +171,42 @@ function M.change(bufnr)
return 'chill'
end
-function M.changelog(bufnr)
- local line = getlines(bufnr, 1):lower()
+--- @type vim.filetype.mapfn
+function M.changelog(_, bufnr)
+ local line = getline(bufnr, 1):lower()
if line:find('; urgency=') then
return 'debchangelog'
end
return 'changelog'
end
-function M.class(bufnr)
+--- @type vim.filetype.mapfn
+function M.class(_, bufnr)
-- Check if not a Java class (starts with '\xca\xfe\xba\xbe')
- if not getlines(bufnr, 1):find('^\202\254\186\190') then
+ if not getline(bufnr, 1):find('^\202\254\186\190') then
return 'stata'
end
end
-function M.cls(bufnr)
+--- @type vim.filetype.mapfn
+function M.cls(_, bufnr)
if vim.g.filetype_cls then
return vim.g.filetype_cls
end
- local line = getlines(bufnr, 1)
+ local line = getline(bufnr, 1)
if line:find('^[%%\\]') then
return 'tex'
elseif line:find('^#') and line:lower():find('rexx') then
return 'rexx'
elseif line == 'VERSION 1.0 CLASS' then
return 'vb'
- else
- return 'st'
end
+ return 'st'
end
+--- @type vim.filetype.mapfn
function M.conf(path, bufnr)
- if vim.fn.did_filetype() ~= 0 or path:find(vim.g.ft_ignore_pat) then
+ if fn.did_filetype() ~= 0 or path:find(vim.g.ft_ignore_pat) then
return
end
if path:find('%.conf$') then
@@ -206,22 +219,30 @@ function M.conf(path, bufnr)
end
end
--- Debian Control
-function M.control(bufnr)
- if getlines(bufnr, 1):find('^Source:') then
+--- Debian Control
+--- @type vim.filetype.mapfn
+function M.control(_, bufnr)
+ if getline(bufnr, 1):find('^Source:') then
return 'debcontrol'
end
end
--- Debian Copyright
-function M.copyright(bufnr)
- if getlines(bufnr, 1):find('^Format:') then
+--- Debian Copyright
+--- @type vim.filetype.mapfn
+function M.copyright(_, bufnr)
+ if getline(bufnr, 1):find('^Format:') then
return 'debcopyright'
end
end
+--- @type vim.filetype.mapfn
+function M.cpp(_, _)
+ return vim.g.cynlib_syntax_for_cpp and 'cynlib' or 'cpp'
+end
+
+--- @type vim.filetype.mapfn
function M.csh(path, bufnr)
- if vim.fn.did_filetype() ~= 0 then
+ if fn.did_filetype() ~= 0 then
-- Filetype was already detected
return
end
@@ -235,6 +256,9 @@ function M.csh(path, bufnr)
end
end
+--- @param path string
+--- @param contents string[]
+--- @return string?
local function cvs_diff(path, contents)
for _, line in ipairs(contents) do
if not line:find('^%? ') then
@@ -280,8 +304,9 @@ local function cvs_diff(path, contents)
end
end
+--- @type vim.filetype.mapfn
function M.dat(path, bufnr)
- local file_name = vim.fn.fnamemodify(path, ':t'):lower()
+ local file_name = fn.fnamemodify(path, ':t'):lower()
-- Innovation data processing
if findany(file_name, { '^upstream%.dat$', '^upstream%..*%.dat$', '^.*%.upstream%.dat$' }) then
return 'upstreamdat'
@@ -296,7 +321,8 @@ function M.dat(path, bufnr)
end
end
-function M.decl(bufnr)
+--- @type vim.filetype.mapfn
+function M.decl(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 3)) do
if line:lower():find('^<!sgml') then
return 'sgmldecl'
@@ -306,8 +332,9 @@ end
-- This function is called for all files under */debian/patches/*, make sure not
-- to non-dep3patch files, such as README and other text files.
+--- @type vim.filetype.mapfn
function M.dep3patch(path, bufnr)
- local file_name = vim.fn.fnamemodify(path, ':t')
+ local file_name = fn.fnamemodify(path, ':t')
if file_name == 'series' then
return
end
@@ -352,7 +379,7 @@ local function diff(contents)
end
end
-function M.dns_zone(contents)
+local function dns_zone(contents)
if
findany(
contents[1] .. contents[2] .. contents[3] .. contents[4],
@@ -370,8 +397,9 @@ function M.dns_zone(contents)
end
end
-function M.dtrace(bufnr)
- if vim.fn.did_filetype() ~= 0 then
+--- @type vim.filetype.mapfn
+function M.dtrace(_, bufnr)
+ if fn.did_filetype() ~= 0 then
-- Filetype was already detected
return
end
@@ -386,7 +414,8 @@ function M.dtrace(bufnr)
return 'd'
end
-function M.e(bufnr)
+--- @type vim.filetype.mapfn
+function M.e(_, bufnr)
if vim.g.filetype_euphoria then
return vim.g.filetype_euphoria
end
@@ -398,8 +427,9 @@ function M.e(bufnr)
return 'eiffel'
end
-function M.edn(bufnr)
- local line = getlines(bufnr, 1)
+--- @type vim.filetype.mapfn
+function M.edn(_, bufnr)
+ local line = getline(bufnr, 1)
if matchregex(line, [[\c^\s*(\s*edif\>]]) then
return 'edif'
else
@@ -410,7 +440,8 @@ end
-- This function checks for valid cl syntax in the first five lines.
-- Look for either an opening comment, '#', or a block start, '{'.
-- If not found, assume SGML.
-function M.ent(bufnr)
+--- @type vim.filetype.mapfn
+function M.ent(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 5)) do
if line:find('^%s*[#{]') then
return 'cl'
@@ -423,7 +454,13 @@ function M.ent(bufnr)
return 'dtd'
end
-function M.ex(bufnr)
+--- @type vim.filetype.mapfn
+function M.euphoria(_, _)
+ return vim.g.filetype_euphoria or 'euphoria3'
+end
+
+--- @type vim.filetype.mapfn
+function M.ex(_, bufnr)
if vim.g.filetype_euphoria then
return vim.g.filetype_euphoria
else
@@ -439,7 +476,8 @@ end
-- This function checks the first 15 lines for appearance of 'FoamFile'
-- and then 'object' in a following line.
-- In that case, it's probably an OpenFOAM file
-function M.foam(bufnr)
+--- @type vim.filetype.mapfn
+function M.foam(_, bufnr)
local foam_file = false
for _, line in ipairs(getlines(bufnr, 1, 15)) do
if line:find('^FoamFile') then
@@ -450,7 +488,8 @@ function M.foam(bufnr)
end
end
-function M.frm(bufnr)
+--- @type vim.filetype.mapfn
+function M.frm(_, bufnr)
if vim.g.filetype_frm then
return vim.g.filetype_frm
end
@@ -462,8 +501,16 @@ function M.frm(bufnr)
end
end
-function M.fvwm(path)
- if vim.fn.fnamemodify(path, ':e') == 'm4' then
+--- @type vim.filetype.mapfn
+function M.fvwm_1(_, _)
+ return 'fvwm', function(bufnr)
+ vim.b[bufnr].fvwm_version = 1
+ end
+end
+
+--- @type vim.filetype.mapfn
+function M.fvwm_v2(path, _)
+ if fn.fnamemodify(path, ':e') == 'm4' then
return 'fvwm2m4'
end
return 'fvwm', function(bufnr)
@@ -472,7 +519,8 @@ function M.fvwm(path)
end
-- Distinguish between Forth and F#.
-function M.fs(bufnr)
+--- @type vim.filetype.mapfn
+function M.fs(_, bufnr)
if vim.g.filetype_fs then
return vim.g.filetype_fs
end
@@ -484,14 +532,16 @@ function M.fs(bufnr)
return 'fsharp'
end
-function M.git(bufnr)
- local line = getlines(bufnr, 1)
+--- @type vim.filetype.mapfn
+function M.git(_, bufnr)
+ local line = getline(bufnr, 1)
if matchregex(line, [[^\x\{40,\}\>\|^ref: ]]) then
return 'git'
end
end
-function M.header(bufnr)
+--- @type vim.filetype.mapfn
+function M.header(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 200)) do
if findany(line:lower(), { '^@interface', '^@end', '^@class' }) then
if vim.g.c_syntax_for_h then
@@ -510,7 +560,8 @@ function M.header(bufnr)
end
end
-function M.html(bufnr)
+--- @type vim.filetype.mapfn
+function M.html(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 10)) do
if matchregex(line, [[\<DTD\s\+XHTML\s]]) then
return 'xhtml'
@@ -522,14 +573,16 @@ function M.html(bufnr)
end
-- Virata Config Script File or Drupal module
-function M.hw(bufnr)
- if getlines(bufnr, 1):lower():find('<%?php') then
+--- @type vim.filetype.mapfn
+function M.hw(_, bufnr)
+ if getline(bufnr, 1):lower():find('<%?php') then
return 'php'
end
return 'virata'
end
-function M.idl(bufnr)
+--- @type vim.filetype.mapfn
+function M.idl(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 50)) do
if findany(line:lower(), { '^%s*import%s+"unknwn"%.idl', '^%s*import%s+"objidl"%.idl' }) then
return 'msidl'
@@ -542,7 +595,8 @@ local pascal_comments = { '^%s*{', '^%s*%(%*', '^%s*//' }
local pascal_keywords =
[[\c^\s*\%(program\|unit\|library\|uses\|begin\|procedure\|function\|const\|type\|var\)\>]]
-function M.inc(bufnr)
+--- @type vim.filetype.mapfn
+function M.inc(path, bufnr)
if vim.g.filetype_inc then
return vim.g.filetype_inc
end
@@ -560,7 +614,7 @@ function M.inc(bufnr)
elseif findany(lines, { '^%s*inherit ', '^%s*require ', '^%s*%u[%w_:${}]*%s+%??[?:+]?= ' }) then
return 'bitbake'
else
- local syntax = M.asm_syntax(bufnr)
+ local syntax = M.asm_syntax(path, bufnr)
if not syntax or syntax == '' then
return 'pov'
end
@@ -570,8 +624,9 @@ function M.inc(bufnr)
end
end
-function M.inp(bufnr)
- if getlines(bufnr, 1):find('^%*') then
+--- @type vim.filetype.mapfn
+function M.inp(_, bufnr)
+ if getline(bufnr, 1):find('^%*') then
return 'abaqus'
else
for _, line in ipairs(getlines(bufnr, 1, 500)) do
@@ -582,16 +637,18 @@ function M.inp(bufnr)
end
end
+--- @type vim.filetype.mapfn
function M.install(path, bufnr)
- if getlines(bufnr, 1):lower():find('<%?php') then
+ if getline(bufnr, 1):lower():find('<%?php') then
return 'php'
end
- return M.sh(path, getlines(bufnr), 'bash')
+ return M.bash(path, bufnr)
end
--- Innovation Data Processing
--- (refactor of filetype.vim since the patterns are case-insensitive)
-function M.log(path)
+--- Innovation Data Processing
+--- (refactor of filetype.vim since the patterns are case-insensitive)
+--- @type vim.filetype.mapfn
+function M.log(path, _)
path = path:lower()
if
findany(
@@ -614,7 +671,8 @@ function M.log(path)
end
end
-function M.lpc(bufnr)
+--- @type vim.filetype.mapfn
+function M.lpc(_, bufnr)
if vim.g.lpc_syntax_for_c then
for _, line in ipairs(getlines(bufnr, 1, 12)) do
if
@@ -637,7 +695,8 @@ function M.lpc(bufnr)
return 'c'
end
-function M.lsl(bufnr)
+--- @type vim.filetype.mapfn
+function M.lsl(_, bufnr)
if vim.g.filetype_lsl then
return vim.g.filetype_lsl
end
@@ -650,7 +709,8 @@ function M.lsl(bufnr)
end
end
-function M.m(bufnr)
+--- @type vim.filetype.mapfn
+function M.m(_, bufnr)
if vim.g.filetype_m then
return vim.g.filetype_m
end
@@ -703,6 +763,8 @@ function M.m(bufnr)
end
end
+--- @param contents string[]
+--- @return string?
local function m4(contents)
for _, line in ipairs(contents) do
if matchregex(line, [[^\s*dnl\>]]) then
@@ -715,9 +777,10 @@ local function m4(contents)
end
end
--- Rely on the file to start with a comment.
--- MS message text files use ';', Sendmail files use '#' or 'dnl'
-function M.mc(bufnr)
+--- Rely on the file to start with a comment.
+--- MS message text files use ';', Sendmail files use '#' or 'dnl'
+--- @type vim.filetype.mapfn
+function M.mc(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 20)) do
if findany(line:lower(), { '^%s*#', '^%s*dnl' }) then
-- Sendmail .mc file
@@ -730,14 +793,17 @@ function M.mc(bufnr)
return 'm4'
end
+--- @param path string
+--- @return string?
function M.me(path)
- local filename = vim.fn.fnamemodify(path, ':t'):lower()
+ local filename = fn.fnamemodify(path, ':t'):lower()
if filename ~= 'read.me' and filename ~= 'click.me' then
return 'nroff'
end
end
-function M.mm(bufnr)
+--- @type vim.filetype.mapfn
+function M.mm(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 20)) do
if matchregex(line, [[\c^\s*\(#\s*\(include\|import\)\>\|@import\>\|/\*\)]]) then
return 'objcpp'
@@ -746,7 +812,8 @@ function M.mm(bufnr)
return 'nroff'
end
-function M.mms(bufnr)
+--- @type vim.filetype.mapfn
+function M.mms(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 20)) do
if findany(line, { '^%s*%%', '^%s*//', '^%*' }) then
return 'mmix'
@@ -757,7 +824,9 @@ function M.mms(bufnr)
return 'mmix'
end
--- Returns true if file content looks like LambdaProlog
+--- Returns true if file content looks like LambdaProlog
+--- @param bufnr integer
+--- @return boolean
local function is_lprolog(bufnr)
-- Skip apparent comments and blank lines, what looks like
-- LambdaProlog comment may be RAPID header
@@ -765,12 +834,14 @@ local function is_lprolog(bufnr)
-- The second pattern matches a LambdaProlog comment
if not findany(line, { '^%s*$', '^%s*%%' }) then
-- The pattern must not catch a go.mod file
- return matchregex(line, [[\c\<module\s\+\w\+\s*\.\s*\(%\|$\)]]) ~= nil
+ return matchregex(line, [[\c\<module\s\+\w\+\s*\.\s*\(%\|$\)]])
end
end
+ return false
end
--- Determine if *.mod is ABB RAPID, LambdaProlog, Modula-2, Modsim III or go.mod
+--- Determine if *.mod is ABB RAPID, LambdaProlog, Modula-2, Modsim III or go.mod
+--- @type vim.filetype.mapfn
function M.mod(path, bufnr)
if vim.g.filetype_mod then
return vim.g.filetype_mod
@@ -782,21 +853,30 @@ function M.mod(path, bufnr)
return 'modula2'
elseif is_rapid(bufnr) then
return 'rapid'
- else
- -- Nothing recognized, assume modsim3
- return 'modsim3'
+ end
+ -- Nothing recognized, assume modsim3
+ return 'modsim3'
+end
+
+--- Determine if *.mod is ABB RAPID, LambdaProlog, Modula-2, Modsim III or go.mod
+--- @type vim.filetype.mapfn
+function M.mp(_, _)
+ return 'mp', function(b)
+ vim.b[b].mp_metafun = 1
end
end
-function M.news(bufnr)
- if getlines(bufnr, 1):lower():find('; urgency=') then
+--- @type vim.filetype.mapfn
+function M.news(_, bufnr)
+ if getline(bufnr, 1):lower():find('; urgency=') then
return 'debchangelog'
end
end
--- This function checks if one of the first five lines start with a dot. In
--- that case it is probably an nroff file.
-function M.nroff(bufnr)
+--- This function checks if one of the first five lines start with a dot. In
+--- that case it is probably an nroff file.
+--- @type vim.filetype.mapfn
+function M.nroff(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 5)) do
if line:find('^%.') then
return 'nroff'
@@ -804,25 +884,26 @@ function M.nroff(bufnr)
end
end
-function M.patch(bufnr)
- local firstline = getlines(bufnr, 1)
+--- @type vim.filetype.mapfn
+function M.patch(_, bufnr)
+ local firstline = getline(bufnr, 1)
if string.find(firstline, '^From ' .. string.rep('%x', 40) .. '+ Mon Sep 17 00:00:00 2001$') then
return 'gitsendemail'
- else
- return 'diff'
end
+ return 'diff'
end
--- If the file has an extension of 't' and is in a directory 't' or 'xt' then
--- it is almost certainly a Perl test file.
--- If the first line starts with '#' and contains 'perl' it's probably a Perl file.
--- (Slow test) If a file contains a 'use' statement then it is almost certainly a Perl file.
+--- If the file has an extension of 't' and is in a directory 't' or 'xt' then
+--- it is almost certainly a Perl test file.
+--- If the first line starts with '#' and contains 'perl' it's probably a Perl file.
+--- (Slow test) If a file contains a 'use' statement then it is almost certainly a Perl file.
+--- @type vim.filetype.mapfn
function M.perl(path, bufnr)
local dir_name = vim.fs.dirname(path)
- if vim.fn.expand(path, '%:e') == 't' and (dir_name == 't' or dir_name == 'xt') then
+ if fn.expand(path, '%:e') == 't' and (dir_name == 't' or dir_name == 'xt') then
return 'perl'
end
- local first_line = getlines(bufnr, 1)
+ local first_line = getline(bufnr, 1)
if first_line:find('^#') and first_line:lower():find('perl') then
return 'perl'
end
@@ -833,7 +914,8 @@ function M.perl(path, bufnr)
end
end
-function M.pl(bufnr)
+--- @type vim.filetype.mapfn
+function M.pl(_, bufnr)
if vim.g.filetype_pl then
return vim.g.filetype_pl
end
@@ -851,8 +933,9 @@ function M.pl(bufnr)
end
end
-function M.pm(bufnr)
- local line = getlines(bufnr, 1)
+--- @type vim.filetype.mapfn
+function M.pm(_, bufnr)
+ local line = getline(bufnr, 1)
if line:find('XPM2') then
return 'xpm2'
elseif line:find('XPM') then
@@ -862,7 +945,8 @@ function M.pm(bufnr)
end
end
-function M.pp(bufnr)
+--- @type vim.filetype.mapfn
+function M.pp(_, bufnr)
if vim.g.filetype_pp then
return vim.g.filetype_pp
end
@@ -874,7 +958,8 @@ function M.pp(bufnr)
end
end
-function M.prg(bufnr)
+--- @type vim.filetype.mapfn
+function M.prg(_, bufnr)
if vim.g.filetype_prg then
return vim.g.filetype_prg
elseif is_rapid(bufnr) then
@@ -886,7 +971,7 @@ function M.prg(bufnr)
end
function M.printcap(ptcap_type)
- if vim.fn.did_filetype() == 0 then
+ if fn.did_filetype() == 0 then
return 'ptcap', function(bufnr)
vim.b[bufnr].ptcap_type = ptcap_type
end
@@ -895,14 +980,15 @@ end
-- This function checks for an assembly comment in the first ten lines.
-- If not found, assume Progress.
-function M.progress_asm(bufnr)
+--- @type vim.filetype.mapfn
+function M.progress_asm(path, bufnr)
if vim.g.filetype_i then
return vim.g.filetype_i
end
for _, line in ipairs(getlines(bufnr, 1, 10)) do
if line:find('^%s*;') or line:find('^/%*') then
- return M.asm(bufnr)
+ return M.asm(path, bufnr)
elseif not line:find('^%s*$') or line:find('^/%*') then
-- Not an empty line: doesn't look like valid assembly code
-- or it looks like a Progress /* comment.
@@ -912,13 +998,14 @@ function M.progress_asm(bufnr)
return 'progress'
end
-function M.progress_cweb(bufnr)
+--- @type vim.filetype.mapfn
+function M.progress_cweb(_, bufnr)
if vim.g.filetype_w then
return vim.g.filetype_w
else
if
- getlines(bufnr, 1):lower():find('^&analyze')
- or getlines(bufnr, 3):lower():find('^&global%-define')
+ getline(bufnr, 1):lower():find('^&analyze')
+ or getline(bufnr, 3):lower():find('^&global%-define')
then
return 'progress'
else
@@ -930,7 +1017,8 @@ end
-- This function checks for valid Pascal syntax in the first 10 lines.
-- Look for either an opening comment or a program start.
-- If not found, assume Progress.
-function M.progress_pascal(bufnr)
+--- @type vim.filetype.mapfn
+function M.progress_pascal(_, bufnr)
if vim.g.filetype_p then
return vim.g.filetype_p
end
@@ -946,34 +1034,33 @@ function M.progress_pascal(bufnr)
return 'progress'
end
--- Distinguish between "default", Prolog and Cproto prototype file.
-function M.proto(bufnr, default)
+--- Distinguish between "default", Prolog and Cproto prototype file.
+--- @type vim.filetype.mapfn
+function M.proto(_, bufnr)
-- Cproto files have a comment in the first line and a function prototype in
-- the second line, it always ends in ";". Indent files may also have
-- comments, thus we can't match comments to see the difference.
-- IDL files can have a single ';' in the second line, require at least one
-- character before the ';'.
- if getlines(bufnr, 2):find('.;$') then
+ if getline(bufnr, 2):find('.;$') then
return 'cpp'
- else
- -- Recognize Prolog by specific text in the first non-empty line;
- -- require a blank after the '%' because Perl uses "%list" and "%translate"
- local line = nextnonblank(bufnr, 1)
- if
- line and line:find(':%-')
- or matchregex(line, [[\c\<prolog\>]])
- or findany(line, { '^%s*%%+%s', '^%s*%%+$', '^%s*/%*' })
- then
- return 'prolog'
- else
- return default
- end
+ end
+ -- Recognize Prolog by specific text in the first non-empty line;
+ -- require a blank after the '%' because Perl uses "%list" and "%translate"
+ local line = nextnonblank(bufnr, 1)
+ if
+ line and line:find(':%-')
+ or matchregex(line, [[\c\<prolog\>]])
+ or findany(line, { '^%s*%%+%s', '^%s*%%+$', '^%s*/%*' })
+ then
+ return 'prolog'
end
end
-- Software Distributor Product Specification File (POSIX 1387.2-1995)
-function M.psf(bufnr)
- local line = getlines(bufnr, 1):lower()
+--- @type vim.filetype.mapfn
+function M.psf(_, bufnr)
+ local line = getline(bufnr, 1):lower()
if
findany(line, {
'^%s*distribution%s*$',
@@ -987,7 +1074,8 @@ function M.psf(bufnr)
end
end
-function M.r(bufnr)
+--- @type vim.filetype.mapfn
+function M.r(_, bufnr)
local lines = getlines(bufnr, 1, 50)
-- Rebol is easy to recognize, check for that first
if matchregex(table.concat(lines), [[\c\<rebol\>]]) then
@@ -1008,13 +1096,13 @@ function M.r(bufnr)
-- Nothing recognized, use user default or assume R
if vim.g.filetype_r then
return vim.g.filetype_r
- else
- -- Rexx used to be the default, but R appears to be much more popular.
- return 'r'
end
+ -- Rexx used to be the default, but R appears to be much more popular.
+ return 'r'
end
-function M.redif(bufnr)
+--- @type vim.filetype.mapfn
+function M.redif(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 5)) do
if line:lower():find('^template%-type:') then
return 'redif'
@@ -1022,8 +1110,9 @@ function M.redif(bufnr)
end
end
-function M.reg(bufnr)
- local line = getlines(bufnr, 1):lower()
+--- @type vim.filetype.mapfn
+function M.reg(_, bufnr)
+ local line = getline(bufnr, 1):lower()
if
line:find('^regedit[0-9]*%s*$') or line:find('^windows registry editor version %d*%.%d*%s*$')
then
@@ -1032,7 +1121,8 @@ function M.reg(bufnr)
end
-- Diva (with Skill) or InstallShield
-function M.rul(bufnr)
+--- @type vim.filetype.mapfn
+function M.rul(_, bufnr)
if table.concat(getlines(bufnr, 1, 6)):lower():find('installshield') then
return 'ishd'
end
@@ -1040,6 +1130,7 @@ function M.rul(bufnr)
end
local udev_rules_pattern = '^%s*udev_rules%s*=%s*"([%^"]+)/*".*'
+--- @type vim.filetype.mapfn
function M.rules(path)
path = path:lower()
if
@@ -1059,11 +1150,12 @@ function M.rules(path)
elseif findany(path, { '^/etc/polkit%-1/rules%.d', '/usr/share/polkit%-1/rules%.d' }) then
return 'javascript'
else
- local ok, config_lines = pcall(vim.fn.readfile, '/etc/udev/udev.conf')
+ local ok, config_lines = pcall(fn.readfile, '/etc/udev/udev.conf')
+ --- @cast config_lines +string[]
if not ok then
return 'hog'
end
- local dir = vim.fn.expand(path, ':h')
+ local dir = fn.expand(path, ':h')
for _, line in ipairs(config_lines) do
local match = line:match(udev_rules_pattern)
if match then
@@ -1078,7 +1170,8 @@ function M.rules(path)
end
-- LambdaProlog and Standard ML signature files
-function M.sig(bufnr)
+--- @type vim.filetype.mapfn
+function M.sig(_, bufnr)
if vim.g.filetype_sig then
return vim.g.filetype_sig
end
@@ -1096,7 +1189,8 @@ end
-- This function checks the first 25 lines of file extension "sc" to resolve
-- detection between scala and SuperCollider
-function M.sc(bufnr)
+--- @type vim.filetype.mapfn
+function M.sc(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 25)) do
if
findany(line, {
@@ -1116,18 +1210,19 @@ end
-- This function checks the first line of file extension "scd" to resolve
-- detection between scdoc and SuperCollider
-function M.scd(bufnr)
+--- @type vim.filetype.mapfn
+function M.scd(_, bufnr)
local first = '^%S+%(%d[0-9A-Za-z]*%)'
local opt = [[%s+"[^"]*"]]
- local line = getlines(bufnr, 1)
+ local line = getline(bufnr, 1)
if findany(line, { first .. '$', first .. opt .. '$', first .. opt .. opt .. '$' }) then
return 'scdoc'
- else
- return 'supercollider'
end
+ return 'supercollider'
end
-function M.sgml(bufnr)
+--- @type vim.filetype.mapfn
+function M.sgml(_, bufnr)
local lines = table.concat(getlines(bufnr, 1, 5))
if lines:find('linuxdoc') then
return 'smgllnx'
@@ -1142,15 +1237,17 @@ function M.sgml(bufnr)
end
end
-function M.sh(path, contents, name)
+--- @param path string
+--- @param contents string[]
+--- @param name? string
+--- @return string?, fun(b: integer)?
+local function sh(path, contents, name)
-- Path may be nil, do not fail in that case
- if vim.fn.did_filetype() ~= 0 or (path or ''):find(vim.g.ft_ignore_pat) then
+ if fn.did_filetype() ~= 0 or (path or ''):find(vim.g.ft_ignore_pat) then
-- Filetype was already detected or detection should be skipped
return
end
- local on_detect
-
-- Get the name from the first line if not specified
name = name or contents[1]
if matchregex(name, [[\<csh\>]]) then
@@ -1162,7 +1259,11 @@ function M.sh(path, contents, name)
-- Some .sh scripts contain #!/bin/zsh.
elseif matchregex(name, [[\<zsh\>]]) then
return M.shell(path, contents, 'zsh')
- elseif matchregex(name, [[\<ksh\>]]) then
+ end
+
+ local on_detect --- @type fun(b: integer)?
+
+ if matchregex(name, [[\<ksh\>]]) then
on_detect = function(b)
vim.b[b].is_kornshell = 1
vim.b[b].is_bash = nil
@@ -1185,9 +1286,26 @@ function M.sh(path, contents, name)
return M.shell(path, contents, 'sh'), on_detect
end
--- For shell-like file types, check for an "exec" command hidden in a comment, as used for Tcl.
+--- @param name? string
+--- @return vim.filetype.mapfn
+local function sh_with(name)
+ return function(path, bufnr)
+ return sh(path, getlines(bufnr), name)
+ end
+end
+
+M.sh = sh_with()
+M.bash = sh_with('bash')
+M.ksh = sh_with('ksh')
+M.tcsh = sh_with('tcsh')
+
+--- For shell-like file types, check for an "exec" command hidden in a comment, as used for Tcl.
+--- @param path string
+--- @param contents string[]
+--- @param name? string
+--- @return string?
function M.shell(path, contents, name)
- if vim.fn.did_filetype() ~= 0 or matchregex(path, vim.g.ft_ignore_pat) then
+ if fn.did_filetype() ~= 0 or matchregex(path, vim.g.ft_ignore_pat) then
-- Filetype was already detected or detection should be skipped
return
end
@@ -1196,6 +1314,7 @@ function M.shell(path, contents, name)
for line_nr, line in ipairs(contents) do
-- Skip the first line
if line_nr ~= 1 then
+ --- @type string
line = line:lower()
if line:find('%s*exec%s') and not prev_line:find('^%s*#.*\\$') then
-- Found an "exec" line after a comment with continuation
@@ -1211,7 +1330,8 @@ function M.shell(path, contents, name)
end
-- Swift Intermediate Language or SILE
-function M.sil(bufnr)
+--- @type vim.filetype.mapfn
+function M.sil(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 100)) do
if line:find('^%s*[\\%%]') then
return 'sile'
@@ -1224,8 +1344,9 @@ function M.sil(bufnr)
end
-- SMIL or SNMP MIB file
-function M.smi(bufnr)
- local line = getlines(bufnr, 1)
+--- @type vim.filetype.mapfn
+function M.smi(_, bufnr)
+ local line = getline(bufnr, 1)
if matchregex(line, [[\c\<smil\>]]) then
return 'smil'
else
@@ -1233,8 +1354,14 @@ function M.smi(bufnr)
end
end
+--- @type vim.filetype.mapfn
+function M.sql(_, _)
+ return vim.g.filetype_sql and vim.g.filetype_sql or 'sql'
+end
+
-- Determine if a *.src file is Kuka Robot Language
-function M.src(bufnr)
+--- @type vim.filetype.mapfn
+function M.src(_, bufnr)
if vim.g.filetype_src then
return vim.g.filetype_src
end
@@ -1244,23 +1371,25 @@ function M.src(bufnr)
end
end
-function M.sys(bufnr)
+--- @type vim.filetype.mapfn
+function M.sys(_, bufnr)
if vim.g.filetype_sys then
return vim.g.filetype_sys
elseif is_rapid(bufnr) then
return 'rapid'
- else
- return 'bat'
end
+ return 'bat'
end
-- Choose context, plaintex, or tex (LaTeX) based on these rules:
-- 1. Check the first line of the file for "%&<format>".
-- 2. Check the first 1000 non-comment lines for LaTeX or ConTeXt keywords.
-- 3. Default to "plain" or to g:tex_flavor, can be set in user's vimrc.
+--- @type vim.filetype.mapfn
function M.tex(path, bufnr)
- local matched, _, format = getlines(bufnr, 1):find('^%%&%s*(%a+)')
+ local matched, _, format = getline(bufnr, 1):find('^%%&%s*(%a+)')
if matched then
+ --- @type string
format = format:lower():gsub('pdf', '', 1)
elseif path:lower():find('tex/context/.*/.*%.tex') then
return 'context'
@@ -1299,7 +1428,8 @@ function M.tex(path, bufnr)
end
-- Determine if a *.tf file is TF mud client or terraform
-function M.tf(bufnr)
+--- @type vim.filetype.mapfn
+function M.tf(_, bufnr)
for _, line in ipairs(getlines(bufnr)) do
-- Assume terraform file on a non-empty line (not whitespace-only)
-- and when the first non-whitespace character is not a ; or /
@@ -1310,22 +1440,25 @@ function M.tf(bufnr)
return 'tf'
end
-function M.ttl(bufnr)
- local line = getlines(bufnr, 1):lower()
+--- @type vim.filetype.mapfn
+function M.ttl(_, bufnr)
+ local line = getline(bufnr, 1):lower()
if line:find('^@?prefix') or line:find('^@?base') then
return 'turtle'
end
return 'teraterm'
end
-function M.txt(bufnr)
+--- @type vim.filetype.mapfn
+function M.txt(_, bufnr)
-- helpfiles match *.txt, but should have a modeline as last line
- if not getlines(bufnr, -1):find('vim:.*ft=help') then
+ if not getline(bufnr, -1):find('vim:.*ft=help') then
return 'text'
end
end
-function M.typ(bufnr)
+--- @type vim.filetype.mapfn
+function M.typ(_, bufnr)
if vim.g.filetype_typ then
return vim.g.filetype_typ
end
@@ -1348,8 +1481,9 @@ function M.typ(bufnr)
end
-- Determine if a .v file is Verilog, V, or Coq
-function M.v(bufnr)
- if vim.fn.did_filetype() ~= 0 then
+--- @type vim.filetype.mapfn
+function M.v(_, bufnr)
+ if fn.did_filetype() ~= 0 then
-- Filetype was already detected
return
end
@@ -1367,7 +1501,8 @@ end
-- WEB (*.web is also used for Winbatch: Guess, based on expecting "%" comment
-- lines in a WEB file).
-function M.web(bufnr)
+--- @type vim.filetype.mapfn
+function M.web(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 5)) do
if line:find('^%%') then
return 'web'
@@ -1377,17 +1512,27 @@ function M.web(bufnr)
end
-- XFree86 config
-function M.xfree86()
+--- @type vim.filetype.mapfn
+function M.xfree86_v3(_, _)
return 'xf86conf',
function(bufnr)
- local line = getlines(bufnr, 1)
+ local line = getline(bufnr, 1)
if matchregex(line, [[\<XConfigurator\>]]) then
vim.b[bufnr].xf86conf_xfree86_version = 3
end
end
end
-function M.xml(bufnr)
+-- XFree86 config
+--- @type vim.filetype.mapfn
+function M.xfree86_v4(_, _)
+ return 'xf86conf', function(b)
+ vim.b[b].xf86conf_xfree86_version = 4
+ end
+end
+
+--- @type vim.filetype.mapfn
+function M.xml(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 100)) do
local is_docbook4 = line:find('<!DOCTYPE.*DocBook')
line = line:lower()
@@ -1406,7 +1551,8 @@ function M.xml(bufnr)
return 'xml'
end
-function M.y(bufnr)
+--- @type vim.filetype.mapfn
+function M.y(_, bufnr)
for _, line in ipairs(getlines(bufnr, 1, 100)) do
if line:find('^%s*%%') then
return 'yacc'
@@ -1463,7 +1609,12 @@ local patterns_hashbang = {
}
---@private
--- File starts with "#!".
+--- File starts with "#!".
+--- @param contents string[]
+--- @param path string
+--- @param dispatch_extension fun(name: string): string?, fun(b: integer)?
+--- @return string?
+--- @return fun(b: integer)?
local function match_from_hashbang(contents, path, dispatch_extension)
local first_line = contents[1]
-- Check for a line like "#!/usr/bin/env {options} bash". Turn it into
@@ -1475,7 +1626,7 @@ local function match_from_hashbang(contents, path, dispatch_extension)
:gsub('%-%-ignore%-environment', '', 1)
:gsub('%-%-split%-string', '', 1)
:gsub('%-[iS]', '', 1)
- first_line = vim.fn.substitute(first_line, [[\<env\s\+]], '', '')
+ first_line = fn.substitute(first_line, [[\<env\s\+]], '', '')
end
-- Get the program name.
@@ -1484,15 +1635,15 @@ local function match_from_hashbang(contents, path, dispatch_extension)
-- "#!/usr/bin/env perl [path/args]"
-- If there is no path use the first word: "#!perl [path/args]".
-- Otherwise get the last word after a slash: "#!/usr/bin/perl [path/args]".
- local name
+ local name --- @type string
if first_line:find('^#!%s*%a:[/\\]') then
- name = vim.fn.substitute(first_line, [[^#!.*[/\\]\(\i\+\).*]], '\\1', '')
+ name = fn.substitute(first_line, [[^#!.*[/\\]\(\i\+\).*]], '\\1', '')
elseif matchregex(first_line, [[^#!.*\<env\>]]) then
- name = vim.fn.substitute(first_line, [[^#!.*\<env\>\s\+\(\i\+\).*]], '\\1', '')
+ name = fn.substitute(first_line, [[^#!.*\<env\>\s\+\(\i\+\).*]], '\\1', '')
elseif matchregex(first_line, [[^#!\s*[^/\\ ]*\>\([^/\\]\|$\)]]) then
- name = vim.fn.substitute(first_line, [[^#!\s*\([^/\\ ]*\>\).*]], '\\1', '')
+ name = fn.substitute(first_line, [[^#!\s*\([^/\\ ]*\>\).*]], '\\1', '')
else
- name = vim.fn.substitute(first_line, [[^#!\s*\S*[/\\]\(\f\+\).*]], '\\1', '')
+ name = fn.substitute(first_line, [[^#!\s*\S*[/\\]\(\f\+\).*]], '\\1', '')
end
-- tcl scripts may have #!/bin/sh in the first line and "exec wish" in the
@@ -1503,11 +1654,11 @@ local function match_from_hashbang(contents, path, dispatch_extension)
if matchregex(name, [[^\(bash\d*\|dash\|ksh\d*\|sh\)\>]]) then
-- Bourne-like shell scripts: bash bash2 dash ksh ksh93 sh
- return require('vim.filetype.detect').sh(path, contents, first_line)
+ return sh(path, contents, first_line)
elseif matchregex(name, [[^csh\>]]) then
- return require('vim.filetype.detect').shell(path, contents, vim.g.filetype_csh or 'csh')
+ return M.shell(path, contents, vim.g.filetype_csh or 'csh')
elseif matchregex(name, [[^tcsh\>]]) then
- return require('vim.filetype.detect').shell(path, contents, 'tcsh')
+ return M.shell(path, contents, 'tcsh')
end
for k, v in pairs(patterns_hashbang) do
@@ -1612,9 +1763,7 @@ local patterns_text = {
['S Y S T E M S I M P R O V E D '] = { 'syndaout', { start_lnum = 3 } },
['Run Date: '] = { 'takcmp', { start_lnum = 6 } },
['Node File 1'] = { 'sindacmp', { start_lnum = 9 } },
- function(contents)
- require('vim.filetype.detect').dns_zone(contents)
- end,
+ dns_zone,
-- Valgrind
['^==%d+== valgrind'] = 'valgrind',
['^==%d+== Using valgrind'] = { 'valgrind', { start_lnum = 3 } },
@@ -1653,11 +1802,15 @@ local patterns_text = {
}
---@private
--- File does not start with "#!".
+--- File does not start with "#!".
+--- @param contents string[]
+--- @param path string
+--- @return string?
+--- @return fun(b: integer)?
local function match_from_text(contents, path)
if contents[1]:find('^:$') then
-- Bourne-like shell scripts: sh ksh bash bash2
- return M.sh(path, contents)
+ return sh(path, contents)
elseif
matchregex(
'\n' .. table.concat(contents, '\n'),
@@ -1708,6 +1861,11 @@ local function match_from_text(contents, path)
return cvs_diff(path, contents)
end
+--- @param contents string[]
+--- @param path string
+--- @param dispatch_extension fun(name: string): string?, fun(b: integer)?
+--- @return string?
+--- @return fun(b: integer)?
function M.match_contents(contents, path, dispatch_extension)
local first_line = contents[1]
if first_line:find('^#!') then
diff --git a/scripts/lua2dox.lua b/scripts/lua2dox.lua
index 01bb8ab57a..7594a0e7df 100644
--- a/scripts/lua2dox.lua
+++ b/scripts/lua2dox.lua
@@ -58,7 +58,11 @@ local TYPES = { 'integer', 'number', 'string', 'table', 'list', 'boolean', 'func
local TAGGED_TYPES = { 'TSNode', 'LanguageTree' }
-- Document these as 'table'
-local ALIAS_TYPES = { 'Range', 'Range4', 'Range6', 'TSMetadata' }
+local ALIAS_TYPES = {
+ 'Range', 'Range4', 'Range6', 'TSMetadata',
+ 'vim.filetype.add.filetypes',
+ 'vim.filetype.match.args'
+}
local debug_outfile = nil --- @type string?
local debug_output = {}