aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/filetype
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 /runtime/lua/vim/filetype
parent61ed45486da01dca788f8a444fc2021002f0c947 (diff)
downloadrneovim-c6c21db82b31ea43ce878ab3725dcd901db1e7a1.tar.gz
rneovim-c6c21db82b31ea43ce878ab3725dcd901db1e7a1.tar.bz2
rneovim-c6c21db82b31ea43ce878ab3725dcd901db1e7a1.zip
fix(filetype): add typing and dry (#24573)
Diffstat (limited to 'runtime/lua/vim/filetype')
-rw-r--r--runtime/lua/vim/filetype/detect.lua546
1 files changed, 352 insertions, 194 deletions
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