mirror of
https://github.com/neovim/neovim.git
synced 2025-10-26 04:17:01 +00:00
refactor(runtime): port scripts.vim to lua (#18710)
This commit is contained in:
committed by
GitHub
parent
0313aba77a
commit
acb7a90281
@@ -2059,11 +2059,31 @@ add({filetypes}) *vim.filetype.add()*
|
|||||||
})
|
})
|
||||||
<
|
<
|
||||||
|
|
||||||
|
To add a fallback match on contents (see
|
||||||
|
|new-filetype-scripts|), use >
|
||||||
|
|
||||||
|
vim.filetype.add {
|
||||||
|
pattern = {
|
||||||
|
['.*'] = {
|
||||||
|
priority = -math.huge,
|
||||||
|
function(path, bufnr)
|
||||||
|
local content = vim.filetype.getlines(bufnr, 1)
|
||||||
|
if vim.filetype.matchregex(content, { [[^#!.*\<mine\>]] }) then
|
||||||
|
return 'mine'
|
||||||
|
elseif vim.filetype.matchregex(content, { [[\<drawing\>]] }) then
|
||||||
|
return 'drawing'
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
<
|
||||||
|
|
||||||
Parameters: ~
|
Parameters: ~
|
||||||
{filetypes} (table) A table containing new filetype maps
|
{filetypes} (table) A table containing new filetype maps
|
||||||
(see example).
|
(see example).
|
||||||
|
|
||||||
match({arg}) *vim.filetype.match()*
|
match({args}) *vim.filetype.match()*
|
||||||
Perform filetype detection.
|
Perform filetype detection.
|
||||||
|
|
||||||
The filetype can be detected using one of three methods:
|
The filetype can be detected using one of three methods:
|
||||||
@@ -2096,22 +2116,22 @@ match({arg}) *vim.filetype.match()*
|
|||||||
<
|
<
|
||||||
|
|
||||||
Parameters: ~
|
Parameters: ~
|
||||||
{arg} (table) Table specifying which matching strategy to
|
{args} (table) Table specifying which matching strategy
|
||||||
use. Accepted keys are:
|
to use. Accepted keys are:
|
||||||
• buf (number): Buffer number to use for matching.
|
• buf (number): Buffer number to use for matching.
|
||||||
Mutually exclusive with {contents}
|
Mutually exclusive with {contents}
|
||||||
• filename (string): Filename to use for matching.
|
• filename (string): Filename to use for matching.
|
||||||
When {buf} is given, defaults to the filename of
|
When {buf} is given, defaults to the filename of
|
||||||
the given buffer number. The file need not
|
the given buffer number. The file need not
|
||||||
actually exist in the filesystem. When used
|
actually exist in the filesystem. When used
|
||||||
without {buf} only the name of the file is used
|
without {buf} only the name of the file is used
|
||||||
for filetype matching. This may result in failure
|
for filetype matching. This may result in
|
||||||
to detect the filetype in cases where the
|
failure to detect the filetype in cases where
|
||||||
filename alone is not enough to disambiguate the
|
the filename alone is not enough to disambiguate
|
||||||
filetype.
|
the filetype.
|
||||||
• contents (table): An array of lines representing
|
• contents (table): An array of lines representing
|
||||||
file contents to use for matching. Can be used
|
file contents to use for matching. Can be used
|
||||||
with {filename}. Mutually exclusive with {buf}.
|
with {filename}. Mutually exclusive with {buf}.
|
||||||
|
|
||||||
Return: ~
|
Return: ~
|
||||||
(string|nil) If a match was found, the matched filetype.
|
(string|nil) If a match was found, the matched filetype.
|
||||||
|
|||||||
@@ -24,18 +24,26 @@ local function starsetf(ft, opts)
|
|||||||
end
|
end
|
||||||
|
|
||||||
---@private
|
---@private
|
||||||
--- Get a single line or line-range from the buffer.
|
--- Get a single line or line range from the buffer.
|
||||||
|
--- If only start_lnum is specified, return a single line as a string.
|
||||||
|
--- If both start_lnum and end_lnum are omitted, return all lines from the buffer.
|
||||||
---
|
---
|
||||||
---@param bufnr number|nil The buffer to get the lines from
|
---@param bufnr number|nil The buffer to get the lines from
|
||||||
---@param start_lnum number The line number of the first line (inclusive, 1-based)
|
---@param start_lnum number|nil The line number of the first line (inclusive, 1-based)
|
||||||
---@param end_lnum number|nil The line number of the last line (inclusive, 1-based)
|
---@param end_lnum number|nil The line number of the last line (inclusive, 1-based)
|
||||||
---@return table<string>|string Array of lines, or string when end_lnum is omitted
|
---@return table<string>|string Array of lines, or string when end_lnum is omitted
|
||||||
function M.getlines(bufnr, start_lnum, end_lnum)
|
function M.getlines(bufnr, start_lnum, end_lnum)
|
||||||
if not end_lnum then
|
if end_lnum then
|
||||||
-- Return a single line as a string
|
-- Return a line range
|
||||||
return api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] or ''
|
return api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false)
|
||||||
|
end
|
||||||
|
if start_lnum then
|
||||||
|
-- Return a single line
|
||||||
|
return api.nvim_buf_get_lines(bufnr, start_lnum - 1, start_lnum, false)[1] or ''
|
||||||
|
else
|
||||||
|
-- Return all lines
|
||||||
|
return api.nvim_buf_get_lines(bufnr, 0, -1, false)
|
||||||
end
|
end
|
||||||
return api.nvim_buf_get_lines(bufnr, start_lnum - 1, end_lnum, false)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
---@private
|
---@private
|
||||||
@@ -600,7 +608,8 @@ local extension = {
|
|||||||
end,
|
end,
|
||||||
quake = 'm3quake',
|
quake = 'm3quake',
|
||||||
['m4'] = function(path, bufnr)
|
['m4'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').m4(path)
|
path = path:lower()
|
||||||
|
return not (path:find('html%.m4$') or path:find('fvwm2rc')) and 'm4'
|
||||||
end,
|
end,
|
||||||
eml = 'mail',
|
eml = 'mail',
|
||||||
mk = 'make',
|
mk = 'make',
|
||||||
@@ -847,22 +856,22 @@ local extension = {
|
|||||||
sed = 'sed',
|
sed = 'sed',
|
||||||
sexp = 'sexplib',
|
sexp = 'sexplib',
|
||||||
bash = function(path, bufnr)
|
bash = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'bash')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
|
||||||
end,
|
end,
|
||||||
ebuild = function(path, bufnr)
|
ebuild = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'bash')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
|
||||||
end,
|
end,
|
||||||
eclass = function(path, bufnr)
|
eclass = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'bash')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
|
||||||
end,
|
end,
|
||||||
env = function(path, bufnr)
|
env = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr)
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
|
||||||
end,
|
end,
|
||||||
ksh = function(path, bufnr)
|
ksh = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'ksh')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'ksh')
|
||||||
end,
|
end,
|
||||||
sh = function(path, bufnr)
|
sh = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr)
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
|
||||||
end,
|
end,
|
||||||
sieve = 'sieve',
|
sieve = 'sieve',
|
||||||
siv = 'sieve',
|
siv = 'sieve',
|
||||||
@@ -1090,7 +1099,7 @@ local extension = {
|
|||||||
return require('vim.filetype.detect').scd(bufnr)
|
return require('vim.filetype.detect').scd(bufnr)
|
||||||
end,
|
end,
|
||||||
tcsh = function(path, bufnr)
|
tcsh = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
|
return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh')
|
||||||
end,
|
end,
|
||||||
sql = function(path, bufnr)
|
sql = function(path, bufnr)
|
||||||
return vim.g.filetype_sql and vim.g.filetype_sql or 'sql'
|
return vim.g.filetype_sql and vim.g.filetype_sql or 'sql'
|
||||||
@@ -1510,40 +1519,40 @@ local filename = {
|
|||||||
['/etc/serial.conf'] = 'setserial',
|
['/etc/serial.conf'] = 'setserial',
|
||||||
['/etc/udev/cdsymlinks.conf'] = 'sh',
|
['/etc/udev/cdsymlinks.conf'] = 'sh',
|
||||||
['bash.bashrc'] = function(path, bufnr)
|
['bash.bashrc'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'bash')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
|
||||||
end,
|
end,
|
||||||
bashrc = function(path, bufnr)
|
bashrc = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'bash')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
|
||||||
end,
|
end,
|
||||||
['.bashrc'] = function(path, bufnr)
|
['.bashrc'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'bash')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
|
||||||
end,
|
end,
|
||||||
['.env'] = function(path, bufnr)
|
['.env'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr)
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
|
||||||
end,
|
end,
|
||||||
['.kshrc'] = function(path, bufnr)
|
['.kshrc'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'ksh')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'ksh')
|
||||||
end,
|
end,
|
||||||
['.profile'] = function(path, bufnr)
|
['.profile'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr)
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
|
||||||
end,
|
end,
|
||||||
['/etc/profile'] = function(path, bufnr)
|
['/etc/profile'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr)
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
|
||||||
end,
|
end,
|
||||||
APKBUILD = function(path, bufnr)
|
APKBUILD = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'bash')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
|
||||||
end,
|
end,
|
||||||
PKGBUILD = function(path, bufnr)
|
PKGBUILD = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'bash')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
|
||||||
end,
|
end,
|
||||||
['.tcshrc'] = function(path, bufnr)
|
['.tcshrc'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
|
return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh')
|
||||||
end,
|
end,
|
||||||
['tcsh.login'] = function(path, bufnr)
|
['tcsh.login'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
|
return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh')
|
||||||
end,
|
end,
|
||||||
['tcsh.tcshrc'] = function(path, bufnr)
|
['tcsh.tcshrc'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
|
return require('vim.filetype.detect').shell(path, M.getlines(bufnr), 'tcsh')
|
||||||
end,
|
end,
|
||||||
['/etc/slp.conf'] = 'slpconf',
|
['/etc/slp.conf'] = 'slpconf',
|
||||||
['/etc/slp.reg'] = 'slpreg',
|
['/etc/slp.reg'] = 'slpreg',
|
||||||
@@ -1934,28 +1943,28 @@ local pattern = {
|
|||||||
['.*/etc/serial%.conf'] = 'setserial',
|
['.*/etc/serial%.conf'] = 'setserial',
|
||||||
['.*/etc/udev/cdsymlinks%.conf'] = 'sh',
|
['.*/etc/udev/cdsymlinks%.conf'] = 'sh',
|
||||||
['%.bash[_%-]aliases'] = function(path, bufnr)
|
['%.bash[_%-]aliases'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'bash')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
|
||||||
end,
|
end,
|
||||||
['%.bash[_%-]logout'] = function(path, bufnr)
|
['%.bash[_%-]logout'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'bash')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
|
||||||
end,
|
end,
|
||||||
['%.bash[_%-]profile'] = function(path, bufnr)
|
['%.bash[_%-]profile'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'bash')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
|
||||||
end,
|
end,
|
||||||
['%.kshrc.*'] = function(path, bufnr)
|
['%.kshrc.*'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'ksh')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'ksh')
|
||||||
end,
|
end,
|
||||||
['%.profile.*'] = function(path, bufnr)
|
['%.profile.*'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr)
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
|
||||||
end,
|
end,
|
||||||
['.*/etc/profile'] = function(path, bufnr)
|
['.*/etc/profile'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr)
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr))
|
||||||
end,
|
end,
|
||||||
['bash%-fc[%-%.]'] = function(path, bufnr)
|
['bash%-fc[%-%.]'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').sh(path, bufnr, 'bash')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'bash')
|
||||||
end,
|
end,
|
||||||
['%.tcshrc.*'] = function(path, bufnr)
|
['%.tcshrc.*'] = function(path, bufnr)
|
||||||
return require('vim.filetype.detect').shell(path, bufnr, 'tcsh')
|
return require('vim.filetype.detect').sh(path, M.getlines(bufnr), 'tcsh')
|
||||||
end,
|
end,
|
||||||
['.*/etc/sudoers%.d/.*'] = starsetf('sudoers'),
|
['.*/etc/sudoers%.d/.*'] = starsetf('sudoers'),
|
||||||
['.*%._sst%.meta'] = 'sisu',
|
['.*%._sst%.meta'] = 'sisu',
|
||||||
@@ -2165,6 +2174,25 @@ end
|
|||||||
--- })
|
--- })
|
||||||
--- </pre>
|
--- </pre>
|
||||||
---
|
---
|
||||||
|
--- To add a fallback match on contents (see |new-filetype-scripts|), use
|
||||||
|
--- <pre>
|
||||||
|
--- vim.filetype.add {
|
||||||
|
--- pattern = {
|
||||||
|
--- ['.*'] = {
|
||||||
|
--- priority = -math.huge,
|
||||||
|
--- function(path, bufnr)
|
||||||
|
--- local content = vim.filetype.getlines(bufnr, 1)
|
||||||
|
--- if vim.filetype.matchregex(content, { [[^#!.*\\<mine\\>]] }) then
|
||||||
|
--- return 'mine'
|
||||||
|
--- elseif vim.filetype.matchregex(content, { [[\\<drawing\\>]] }) then
|
||||||
|
--- return 'drawing'
|
||||||
|
--- end
|
||||||
|
--- end,
|
||||||
|
--- },
|
||||||
|
--- },
|
||||||
|
--- }
|
||||||
|
--- </pre>
|
||||||
|
---
|
||||||
---@param filetypes table A table containing new filetype maps (see example).
|
---@param filetypes table A table containing new filetype maps (see example).
|
||||||
function M.add(filetypes)
|
function M.add(filetypes)
|
||||||
for k, v in pairs(filetypes.extension or {}) do
|
for k, v in pairs(filetypes.extension or {}) do
|
||||||
@@ -2253,7 +2281,7 @@ end
|
|||||||
--- vim.filetype.match({ contents = {'#!/usr/bin/env bash'} })
|
--- vim.filetype.match({ contents = {'#!/usr/bin/env bash'} })
|
||||||
--- </pre>
|
--- </pre>
|
||||||
---
|
---
|
||||||
---@param arg table Table specifying which matching strategy to use. Accepted keys are:
|
---@param args table Table specifying which matching strategy to use. Accepted keys are:
|
||||||
--- * buf (number): Buffer number to use for matching. Mutually exclusive with
|
--- * buf (number): Buffer number to use for matching. Mutually exclusive with
|
||||||
--- {contents}
|
--- {contents}
|
||||||
--- * filename (string): Filename to use for matching. When {buf} is given,
|
--- * filename (string): Filename to use for matching. When {buf} is given,
|
||||||
@@ -2270,22 +2298,18 @@ end
|
|||||||
---@return function|nil A function that modifies buffer state when called (for example, to set some
|
---@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
|
--- filetype specific buffer variables). The function accepts a buffer number as
|
||||||
--- its only argument.
|
--- its only argument.
|
||||||
function M.match(arg)
|
function M.match(args)
|
||||||
vim.validate({
|
vim.validate({
|
||||||
arg = { arg, 't' },
|
arg = { args, 't' },
|
||||||
})
|
})
|
||||||
|
|
||||||
if not (arg.buf or arg.filename or arg.contents) then
|
if not (args.buf or args.filename or args.contents) then
|
||||||
error('At least one of "buf", "filename", or "contents" must be given')
|
error('At least one of "buf", "filename", or "contents" must be given')
|
||||||
end
|
end
|
||||||
|
|
||||||
if arg.buf and arg.contents then
|
local bufnr = args.buf
|
||||||
error('Only one of "buf" or "contents" must be given')
|
local name = args.filename
|
||||||
end
|
local contents = args.contents
|
||||||
|
|
||||||
local bufnr = arg.buf
|
|
||||||
local name = arg.filename
|
|
||||||
local contents = arg.contents
|
|
||||||
|
|
||||||
if bufnr and not name then
|
if bufnr and not name then
|
||||||
name = api.nvim_buf_get_name(bufnr)
|
name = api.nvim_buf_get_name(bufnr)
|
||||||
@@ -2297,13 +2321,6 @@ function M.match(arg)
|
|||||||
|
|
||||||
local ft, on_detect
|
local ft, on_detect
|
||||||
|
|
||||||
if contents then
|
|
||||||
-- Sanity check: this should not happen
|
|
||||||
assert(not bufnr, '"buf" and "contents" are mutually exclusive')
|
|
||||||
-- TODO: "scripts.lua" content matching
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- First check for the simple case where the full path exists as a key
|
-- First check for the simple case where the full path exists as a key
|
||||||
local path = vim.fn.resolve(vim.fn.fnamemodify(name, ':p'))
|
local path = vim.fn.resolve(vim.fn.fnamemodify(name, ':p'))
|
||||||
ft, on_detect = dispatch(filename[path], path, bufnr)
|
ft, on_detect = dispatch(filename[path], path, bufnr)
|
||||||
@@ -2345,7 +2362,7 @@ function M.match(arg)
|
|||||||
return ft, on_detect
|
return ft, on_detect
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Finally, check patterns with negative priority
|
-- Next, check patterns with negative priority
|
||||||
for i = j, #pattern_sorted do
|
for i = j, #pattern_sorted do
|
||||||
local v = pattern_sorted[i]
|
local v = pattern_sorted[i]
|
||||||
local k = next(v)
|
local k = next(v)
|
||||||
@@ -2359,6 +2376,19 @@ function M.match(arg)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Finally, check file contents
|
||||||
|
if contents or bufnr then
|
||||||
|
contents = contents or M.getlines(bufnr)
|
||||||
|
-- If name is nil, catch any errors from the contents filetype detection function.
|
||||||
|
-- If the function tries to use the filename that is nil then it will fail,
|
||||||
|
-- but this enables checks which do not need a filename to still work.
|
||||||
|
local ok
|
||||||
|
ok, ft = pcall(require('vim.filetype.detect').match_contents, contents, name)
|
||||||
|
if ok and ft then
|
||||||
|
return ft
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
@@ -206,12 +206,52 @@ function M.csh(path, bufnr)
|
|||||||
-- Filetype was already detected
|
-- Filetype was already detected
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
local contents = getlines(bufnr)
|
||||||
if vim.g.filetype_csh then
|
if vim.g.filetype_csh then
|
||||||
return M.shell(path, bufnr, vim.g.filetype_csh)
|
return M.shell(path, contents, vim.g.filetype_csh)
|
||||||
elseif string.find(vim.o.shell, 'tcsh') then
|
elseif string.find(vim.o.shell, 'tcsh') then
|
||||||
return M.shell(path, bufnr, 'tcsh')
|
return M.shell(path, contents, 'tcsh')
|
||||||
else
|
else
|
||||||
return M.shell(path, bufnr, 'csh')
|
return M.shell(path, contents, 'csh')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function cvs_diff(path, contents)
|
||||||
|
for _, line in ipairs(contents) do
|
||||||
|
if not line:find('^%? ') then
|
||||||
|
if matchregex(line, [[^Index:\s\+\f\+$]]) then
|
||||||
|
-- CVS diff
|
||||||
|
return 'diff'
|
||||||
|
elseif
|
||||||
|
-- Locale input files: Formal Definitions of Cultural Conventions
|
||||||
|
-- Filename must be like en_US, fr_FR@euro or en_US.UTF-8
|
||||||
|
findany(path, { '%a%a_%a%a$', '%a%a_%a%a[%.@]', '%a%a_%a%ai18n$', '%a%a_%a%aPOSIX$', '%a%a_%a%atranslit_' })
|
||||||
|
then
|
||||||
|
-- Only look at the first 100 lines
|
||||||
|
for line_nr = 1, 100 do
|
||||||
|
if not contents[line_nr] then
|
||||||
|
break
|
||||||
|
elseif
|
||||||
|
findany(contents[line_nr], {
|
||||||
|
'^LC_IDENTIFICATION$',
|
||||||
|
'^LC_CTYPE$',
|
||||||
|
'^LC_COLLATE$',
|
||||||
|
'^LC_MONETARY$',
|
||||||
|
'^LC_NUMERIC$',
|
||||||
|
'^LC_TIME$',
|
||||||
|
'^LC_MESSAGES$',
|
||||||
|
'^LC_PAPER$',
|
||||||
|
'^LC_TELEPHONE$',
|
||||||
|
'^LC_MEASUREMENT$',
|
||||||
|
'^LC_NAME$',
|
||||||
|
'^LC_ADDRESS$',
|
||||||
|
})
|
||||||
|
then
|
||||||
|
return 'fdcc'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -270,6 +310,38 @@ function M.dep3patch(path, bufnr)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function diff(contents)
|
||||||
|
if
|
||||||
|
contents[1]:find('^%-%-%- ') and contents[2]:find('^%+%+%+ ')
|
||||||
|
or contents[1]:find('^%* looking for ') and contents[2]:find('^%* comparing to ')
|
||||||
|
or contents[1]:find('^%*%*%* ') and contents[2]:find('^%-%-%- ')
|
||||||
|
or contents[1]:find('^=== ') and ((contents[2]:find('^' .. string.rep('=', 66)) and contents[3]:find('^%-%-% ') and contents[4]:find(
|
||||||
|
'^%+%+%+'
|
||||||
|
)) or (contents[2]:find('^%-%-%- ') and contents[3]:find('^%+%+%+ ')))
|
||||||
|
or findany(contents[1], { '^=== removed', '^=== added', '^=== renamed', '^=== modified' })
|
||||||
|
then
|
||||||
|
return 'diff'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.dns_zone(contents)
|
||||||
|
if
|
||||||
|
findany(
|
||||||
|
contents[1] .. contents[2] .. contents[3] .. contents[4],
|
||||||
|
{ '^; <<>> DiG [0-9%.]+.* <<>>', '%$ORIGIN', '%$TTL', 'IN%s+SOA' }
|
||||||
|
)
|
||||||
|
then
|
||||||
|
return 'bindzone'
|
||||||
|
end
|
||||||
|
-- BAAN
|
||||||
|
if -- Check for 1 to 80 '*' characters
|
||||||
|
contents[1]:find('|%*' .. string.rep('%*?', 79)) and contents[2]:find('VRC ')
|
||||||
|
or contents[2]:find('|%*' .. string.rep('%*?', 79)) and contents[3]:find('VRC ')
|
||||||
|
then
|
||||||
|
return 'baan'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function M.dtrace(bufnr)
|
function M.dtrace(bufnr)
|
||||||
if vim.fn.did_filetype() ~= 0 then
|
if vim.fn.did_filetype() ~= 0 then
|
||||||
-- Filetype was already detected
|
-- Filetype was already detected
|
||||||
@@ -483,7 +555,7 @@ function M.install(path, bufnr)
|
|||||||
if getlines(bufnr, 1):lower():find('<%?php') then
|
if getlines(bufnr, 1):lower():find('<%?php') then
|
||||||
return 'php'
|
return 'php'
|
||||||
end
|
end
|
||||||
return M.sh(path, bufnr, 'bash')
|
return M.sh(path, getlines(bufnr), 'bash')
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Innovation Data Processing
|
-- Innovation Data Processing
|
||||||
@@ -572,10 +644,15 @@ function M.m(bufnr)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.m4(path)
|
local function m4(contents)
|
||||||
path = path:lower()
|
for _, line in ipairs(contents) do
|
||||||
if not path:find('html%.m4$') and not path:find('fvwm2rc') then
|
if matchregex(line, [[^\s*dnl\>]]) then
|
||||||
return 'm4'
|
return 'm4'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if vim.env.TERM == 'amiga' and findany(contents[1]:lower(), { '^;', '^%.bra' }) then
|
||||||
|
-- AmigaDos scripts
|
||||||
|
return 'amiga'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -625,7 +702,7 @@ end
|
|||||||
local function is_lprolog(bufnr)
|
local function is_lprolog(bufnr)
|
||||||
-- Skip apparent comments and blank lines, what looks like
|
-- Skip apparent comments and blank lines, what looks like
|
||||||
-- LambdaProlog comment may be RAPID header
|
-- LambdaProlog comment may be RAPID header
|
||||||
for _, line in ipairs(getlines(bufnr, 1, -1)) do
|
for _, line in ipairs(getlines(bufnr)) do
|
||||||
-- The second pattern matches a LambdaProlog comment
|
-- The second pattern matches a LambdaProlog comment
|
||||||
if not findany(line, { '^%s*$', '^%s*%%' }) then
|
if not findany(line, { '^%s*$', '^%s*%%' }) then
|
||||||
-- The pattern must not catch a go.mod file
|
-- The pattern must not catch a go.mod file
|
||||||
@@ -982,24 +1059,26 @@ function M.sgml(bufnr)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.sh(path, bufnr, name)
|
function M.sh(path, contents, name)
|
||||||
if vim.fn.did_filetype() ~= 0 or path:find(vim.g.ft_ignore_pat) then
|
-- 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
|
||||||
-- Filetype was already detected or detection should be skipped
|
-- Filetype was already detected or detection should be skipped
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local on_detect
|
local on_detect
|
||||||
|
|
||||||
name = name or getlines(bufnr, 1)
|
-- Get the name from the first line if not specified
|
||||||
|
name = name or contents[1]
|
||||||
if matchregex(name, [[\<csh\>]]) then
|
if matchregex(name, [[\<csh\>]]) then
|
||||||
-- Some .sh scripts contain #!/bin/csh.
|
-- Some .sh scripts contain #!/bin/csh.
|
||||||
return M.shell(path, bufnr, 'csh')
|
return M.shell(path, contents, 'csh')
|
||||||
-- Some .sh scripts contain #!/bin/tcsh.
|
-- Some .sh scripts contain #!/bin/tcsh.
|
||||||
elseif matchregex(name, [[\<tcsh\>]]) then
|
elseif matchregex(name, [[\<tcsh\>]]) then
|
||||||
return M.shell(path, bufnr, 'tcsh')
|
return M.shell(path, contents, 'tcsh')
|
||||||
-- Some .sh scripts contain #!/bin/zsh.
|
-- Some .sh scripts contain #!/bin/zsh.
|
||||||
elseif matchregex(name, [[\<zsh\>]]) then
|
elseif matchregex(name, [[\<zsh\>]]) then
|
||||||
return M.shell(path, bufnr, 'zsh')
|
return M.shell(path, contents, 'zsh')
|
||||||
elseif matchregex(name, [[\<ksh\>]]) then
|
elseif matchregex(name, [[\<ksh\>]]) then
|
||||||
on_detect = function(b)
|
on_detect = function(b)
|
||||||
vim.b[b].is_kornshell = 1
|
vim.b[b].is_kornshell = 1
|
||||||
@@ -1019,27 +1098,30 @@ function M.sh(path, bufnr, name)
|
|||||||
vim.b[b].is_bash = nil
|
vim.b[b].is_bash = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return M.shell(path, bufnr, 'sh'), on_detect
|
return M.shell(path, contents, 'sh'), on_detect
|
||||||
end
|
end
|
||||||
|
|
||||||
-- For shell-like file types, check for an "exec" command hidden in a comment, as used for Tcl.
|
-- For shell-like file types, check for an "exec" command hidden in a comment, as used for Tcl.
|
||||||
-- Also called from scripts.vim, thus can't be local to this script. [TODO]
|
function M.shell(path, contents, name)
|
||||||
function M.shell(path, bufnr, name)
|
|
||||||
if vim.fn.did_filetype() ~= 0 or matchregex(path, vim.g.ft_ignore_pat) then
|
if vim.fn.did_filetype() ~= 0 or matchregex(path, vim.g.ft_ignore_pat) then
|
||||||
-- Filetype was already detected or detection should be skipped
|
-- Filetype was already detected or detection should be skipped
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local prev_line = ''
|
local prev_line = ''
|
||||||
for _, line in ipairs(getlines(bufnr, 2, -1)) do
|
for line_nr, line in ipairs(contents) do
|
||||||
line = line:lower()
|
-- Skip the first line
|
||||||
if line:find('%s*exec%s') and not prev_line:find('^%s*#.*\\$') then
|
if line_nr ~= 1 then
|
||||||
-- Found an "exec" line after a comment with continuation
|
line = line:lower()
|
||||||
local n = line:gsub('%s*exec%s+([^ ]*/)?', '', 1)
|
if line:find('%s*exec%s') and not prev_line:find('^%s*#.*\\$') then
|
||||||
if matchregex(n, [[\c\<tclsh\|\<wish]]) then
|
-- Found an "exec" line after a comment with continuation
|
||||||
return 'tcl'
|
local n = line:gsub('%s*exec%s+([^ ]*/)?', '', 1)
|
||||||
|
if matchregex(n, [[\c\<tclsh\|\<wish]]) then
|
||||||
|
return 'tcl'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
prev_line = line
|
||||||
end
|
end
|
||||||
prev_line = line
|
|
||||||
end
|
end
|
||||||
return name
|
return name
|
||||||
end
|
end
|
||||||
@@ -1123,7 +1205,7 @@ end
|
|||||||
|
|
||||||
-- Determine if a *.tf file is TF mud client or terraform
|
-- Determine if a *.tf file is TF mud client or terraform
|
||||||
function M.tf(bufnr)
|
function M.tf(bufnr)
|
||||||
for _, line in ipairs(getlines(bufnr, 1, -1)) do
|
for _, line in ipairs(getlines(bufnr)) do
|
||||||
-- Assume terraform file on a non-empty line (not whitespace-only)
|
-- Assume terraform file on a non-empty line (not whitespace-only)
|
||||||
-- and when the first non-whitespace character is not a ; or /
|
-- and when the first non-whitespace character is not a ; or /
|
||||||
if not line:find('^%s*$') and not line:find('^%s*[;/]') then
|
if not line:find('^%s*$') and not line:find('^%s*[;/]') then
|
||||||
@@ -1204,4 +1286,271 @@ end
|
|||||||
-- luacheck: pop
|
-- luacheck: pop
|
||||||
-- luacheck: pop
|
-- luacheck: pop
|
||||||
|
|
||||||
|
local patterns_hashbang = {
|
||||||
|
['^zsh\\>'] = { 'zsh', { vim_regex = true } },
|
||||||
|
['^\\(tclsh\\|wish\\|expectk\\|itclsh\\|itkwish\\)\\>'] = { 'tcl', { vim_regex = true } },
|
||||||
|
['^expect\\>'] = { 'expect', { vim_regex = true } },
|
||||||
|
['^gnuplot\\>'] = { 'gnuplot', { vim_regex = true } },
|
||||||
|
['make\\>'] = { 'make', { vim_regex = true } },
|
||||||
|
['^pike\\%(\\>\\|[0-9]\\)'] = { 'pike', { vim_regex = true } },
|
||||||
|
lua = 'lua',
|
||||||
|
perl = 'perl',
|
||||||
|
php = 'php',
|
||||||
|
python = 'python',
|
||||||
|
['^groovy\\>'] = { 'groovy', { vim_regex = true } },
|
||||||
|
raku = 'raku',
|
||||||
|
ruby = 'ruby',
|
||||||
|
['node\\(js\\)\\=\\>\\|js\\>'] = { 'javascript', { vim_regex = true } },
|
||||||
|
['rhino\\>'] = { 'javascript', { vim_regex = true } },
|
||||||
|
-- BC calculator
|
||||||
|
['^bc\\>'] = { 'bc', { vim_regex = true } },
|
||||||
|
['sed\\>'] = { 'sed', { vim_regex = true } },
|
||||||
|
ocaml = 'ocaml',
|
||||||
|
-- Awk scripts; also finds "gawk"
|
||||||
|
['awk\\>'] = { 'awk', { vim_regex = true } },
|
||||||
|
wml = 'wml',
|
||||||
|
scheme = 'scheme',
|
||||||
|
cfengine = 'cfengine',
|
||||||
|
escript = 'erlang',
|
||||||
|
haskell = 'haskell',
|
||||||
|
clojure = 'clojure',
|
||||||
|
['scala\\>'] = { 'scala', { vim_regex = true } },
|
||||||
|
-- Free Pascal
|
||||||
|
['instantfpc\\>'] = { 'pascal', { vim_regex = true } },
|
||||||
|
['fennel\\>'] = { 'fennel', { vim_regex = true } },
|
||||||
|
-- MikroTik RouterOS script
|
||||||
|
['rsc\\>'] = { 'routeros', { vim_regex = true } },
|
||||||
|
['fish\\>'] = { 'fish', { vim_regex = true } },
|
||||||
|
['gforth\\>'] = { 'forth', { vim_regex = true } },
|
||||||
|
['icon\\>'] = { 'icon', { vim_regex = true } },
|
||||||
|
}
|
||||||
|
|
||||||
|
---@private
|
||||||
|
-- File starts with "#!".
|
||||||
|
local function match_from_hashbang(contents, path)
|
||||||
|
local first_line = contents[1]
|
||||||
|
-- Check for a line like "#!/usr/bin/env {options} bash". Turn it into
|
||||||
|
-- "#!/usr/bin/bash" to make matching easier.
|
||||||
|
-- Recognize only a few {options} that are commonly used.
|
||||||
|
if matchregex(first_line, [[^#!\s*\S*\<env\s]]) then
|
||||||
|
first_line = first_line:gsub('%S+=%S+', '')
|
||||||
|
first_line = first_line
|
||||||
|
:gsub('%-%-ignore%-environment', '', 1)
|
||||||
|
:gsub('%-%-split%-string', '', 1)
|
||||||
|
:gsub('%-[iS]', '', 1)
|
||||||
|
first_line = vim.fn.substitute(first_line, [[\<env\s\+]], '', '')
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get the program name.
|
||||||
|
-- Only accept spaces in PC style paths: "#!c:/program files/perl [args]".
|
||||||
|
-- If the word env is used, use the first word after the space:
|
||||||
|
-- "#!/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
|
||||||
|
if first_line:find('^#!%s*%a:[/\\]') then
|
||||||
|
name = vim.fn.substitute(first_line, [[^#!.*[/\\]\(\i\+\).*]], '\\1', '')
|
||||||
|
elseif matchregex(first_line, [[^#!.*\<env\>]]) then
|
||||||
|
name = vim.fn.substitute(first_line, [[^#!.*\<env\>\s\+\(\i\+\).*]], '\\1', '')
|
||||||
|
elseif matchregex(first_line, [[^#!\s*[^/\\ ]*\>\([^/\\]\|$\)]]) then
|
||||||
|
name = vim.fn.substitute(first_line, [[^#!\s*\([^/\\ ]*\>\).*]], '\\1', '')
|
||||||
|
else
|
||||||
|
name = vim.fn.substitute(first_line, [[^#!\s*\S*[/\\]\(\i\+\).*]], '\\1', '')
|
||||||
|
end
|
||||||
|
|
||||||
|
-- tcl scripts may have #!/bin/sh in the first line and "exec wish" in the
|
||||||
|
-- third line. Suggested by Steven Atkinson.
|
||||||
|
if contents[3] and contents[3]:find('^exec wish') then
|
||||||
|
name = 'wish'
|
||||||
|
end
|
||||||
|
|
||||||
|
if matchregex(name, [[^\(bash\d*\|\|ksh\d*\|sh\)\>]]) then
|
||||||
|
-- Bourne-like shell scripts: bash bash2 ksh ksh93 sh
|
||||||
|
return require('vim.filetype.detect').sh(path, contents, first_line)
|
||||||
|
elseif matchregex(name, [[^csh\>]]) then
|
||||||
|
return require('vim.filetype.detect').shell(path, contents, vim.g.filetype_csh or 'csh')
|
||||||
|
elseif matchregex(name, [[^tcsh\>]]) then
|
||||||
|
return require('vim.filetype.detect').shell(path, contents, 'tcsh')
|
||||||
|
end
|
||||||
|
|
||||||
|
for k, v in pairs(patterns_hashbang) do
|
||||||
|
local ft = type(v) == 'table' and v[1] or v
|
||||||
|
local opts = type(v) == 'table' and v[2] or {}
|
||||||
|
if opts.vim_regex and matchregex(name, k) or name:find(k) then
|
||||||
|
return ft
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local patterns_text = {
|
||||||
|
['^#compdef\\>'] = { 'zsh', { vim_regex = true } },
|
||||||
|
['^#autoload\\>'] = { 'zsh', { vim_regex = true } },
|
||||||
|
-- ELM Mail files
|
||||||
|
['^From [a-zA-Z][a-zA-Z_0-9%.=%-]*(@[^ ]*)? .* 19%d%d$'] = 'mail',
|
||||||
|
['^From [a-zA-Z][a-zA-Z_0-9%.=%-]*(@[^ ]*)? .* 20%d%d$'] = 'mail',
|
||||||
|
['^From %- .* 19%d%d$'] = 'mail',
|
||||||
|
['^From %- .* 20%d%d$'] = 'mail',
|
||||||
|
-- Mason
|
||||||
|
['^<[%%&].*>'] = 'mason',
|
||||||
|
-- Vim scripts (must have '" vim' as the first line to trigger this)
|
||||||
|
['^" *[vV]im$['] = 'vim',
|
||||||
|
-- libcxx and libstdc++ standard library headers like ["iostream["] do not have
|
||||||
|
-- an extension, recognize the Emacs file mode.
|
||||||
|
['%-%*%-.*[cC]%+%+.*%-%*%-'] = 'cpp',
|
||||||
|
['^\\*\\* LambdaMOO Database, Format Version \\%([1-3]\\>\\)\\@!\\d\\+ \\*\\*$'] = {
|
||||||
|
'moo',
|
||||||
|
{ vim_regex = true },
|
||||||
|
},
|
||||||
|
-- Diff file:
|
||||||
|
-- - "diff" in first line (context diff)
|
||||||
|
-- - "Only in " in first line
|
||||||
|
-- - "--- " in first line and "+++ " in second line (unified diff).
|
||||||
|
-- - "*** " in first line and "--- " in second line (context diff).
|
||||||
|
-- - "# It was generated by makepatch " in the second line (makepatch diff).
|
||||||
|
-- - "Index: <filename>" in the first line (CVS file)
|
||||||
|
-- - "=== ", line of "=", "---", "+++ " (SVK diff)
|
||||||
|
-- - "=== ", "--- ", "+++ " (bzr diff, common case)
|
||||||
|
-- - "=== (removed|added|renamed|modified)" (bzr diff, alternative)
|
||||||
|
-- - "# HG changeset patch" in first line (Mercurial export format)
|
||||||
|
['^\\(diff\\>\\|Only in \\|\\d\\+\\(,\\d\\+\\)\\=[cda]\\d\\+\\>\\|# It was generated by makepatch \\|Index:\\s\\+\\f\\+\\r\\=$\\|===== \\f\\+ \\d\\+\\.\\d\\+ vs edited\\|==== //\\f\\+#\\d\\+\\|# HG changeset patch\\)'] = {
|
||||||
|
'diff',
|
||||||
|
{ vim_regex = true },
|
||||||
|
},
|
||||||
|
function(contents)
|
||||||
|
return diff(contents)
|
||||||
|
end,
|
||||||
|
-- PostScript Files (must have %!PS as the first line, like a2ps output)
|
||||||
|
['^%%![ \t]*PS'] = 'postscr',
|
||||||
|
function(contents)
|
||||||
|
return m4(contents)
|
||||||
|
end,
|
||||||
|
-- SiCAD scripts (must have procn or procd as the first line to trigger this)
|
||||||
|
['^ *proc[nd] *$'] = { 'sicad', { ignore_case = true } },
|
||||||
|
['^%*%*%*%* Purify'] = 'purifylog',
|
||||||
|
-- XML
|
||||||
|
['<%?%s*xml.*%?>'] = 'xml',
|
||||||
|
-- XHTML (e.g.: PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN")
|
||||||
|
['\\<DTD\\s\\+XHTML\\s'] = 'xhtml',
|
||||||
|
-- HTML (e.g.: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN")
|
||||||
|
-- Avoid "doctype html", used by slim.
|
||||||
|
['\\c<!DOCTYPE\\s\\+html\\>'] = { 'html', { vim_regex = true } },
|
||||||
|
-- PDF
|
||||||
|
['^%%PDF%-'] = 'pdf',
|
||||||
|
-- XXD output
|
||||||
|
['^%x%x%x%x%x%x%x: %x%x ?%x%x ?%x%x ?%x%x '] = 'xxd',
|
||||||
|
-- RCS/CVS log output
|
||||||
|
['^RCS file:'] = { 'rcslog', { start_lnum = 1, end_lnum = 2 } },
|
||||||
|
-- CVS commit
|
||||||
|
['^CVS:'] = { 'cvs', { start_lnum = 2 } },
|
||||||
|
['^CVS: '] = { 'cvs', { start_lnum = -1 } },
|
||||||
|
-- Prescribe
|
||||||
|
['^!R!'] = 'prescribe',
|
||||||
|
-- Send-pr
|
||||||
|
['^SEND%-PR:'] = 'sendpr',
|
||||||
|
-- SNNS files
|
||||||
|
['^SNNS network definition file'] = 'snnsnet',
|
||||||
|
['^SNNS pattern definition file'] = 'snnspat',
|
||||||
|
['^SNNS result file'] = 'snnsres',
|
||||||
|
['^%%.-[Vv]irata'] = { 'virata', { start_lnum = 1, end_lnum = 5 } },
|
||||||
|
['[0-9:%.]* *execve%('] = 'strace',
|
||||||
|
['^__libc_start_main'] = 'strace',
|
||||||
|
-- VSE JCL
|
||||||
|
['^\\* $$ JOB\\>'] = { 'vsejcl', { vim_regex = true } },
|
||||||
|
['^// *JOB\\>'] = { 'vsejcl', { vim_regex = true } },
|
||||||
|
-- TAK and SINDA
|
||||||
|
['K & K Associates'] = { 'takout', { start_lnum = 4 } },
|
||||||
|
['TAK 2000'] = { 'takout', { start_lnum = 2 } },
|
||||||
|
['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,
|
||||||
|
-- Valgrind
|
||||||
|
['^==%d+== valgrind'] = 'valgrind',
|
||||||
|
['^==%d+== Using valgrind'] = { 'valgrind', { start_lnum = 3 } },
|
||||||
|
-- Go docs
|
||||||
|
['PACKAGE DOCUMENTATION$'] = 'godoc',
|
||||||
|
-- Renderman Interface Bytestream
|
||||||
|
['^##RenderMan'] = 'rib',
|
||||||
|
-- Scheme scripts
|
||||||
|
['exec%s%+%S*scheme'] = { 'scheme', { start_lnum = 1, end_lnum = 2 } },
|
||||||
|
-- Git output
|
||||||
|
['^\\(commit\\|tree\\|object\\) \\x\\{40,\\}\\>\\|^tag \\S\\+$'] = { 'git', { vim_regex = true } },
|
||||||
|
function(lines)
|
||||||
|
-- Gprof (gnu profiler)
|
||||||
|
if lines[1] == 'Flat profile:' and lines[2] == '' and lines[3]:find('^Each sample counts as .* seconds%.$') then
|
||||||
|
return 'gprof'
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
-- Erlang terms
|
||||||
|
-- (See also: http://www.gnu.org/software/emacs/manual/html_node/emacs/Choosing-Modes.html#Choosing-Modes)
|
||||||
|
['%-%*%-.*erlang.*%-%*%-'] = { 'erlang', { ignore_case = true } },
|
||||||
|
-- YAML
|
||||||
|
['^%%YAML'] = 'yaml',
|
||||||
|
-- MikroTik RouterOS script
|
||||||
|
['^#.*by RouterOS'] = 'routeros',
|
||||||
|
-- Sed scripts
|
||||||
|
-- #ncomment is allowed but most likely a false positive so require a space before any trailing comment text
|
||||||
|
['^#n%s'] = 'sed',
|
||||||
|
['^#n$'] = 'sed',
|
||||||
|
}
|
||||||
|
|
||||||
|
---@private
|
||||||
|
-- File does not start with "#!".
|
||||||
|
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)
|
||||||
|
elseif matchregex('\n' .. table.concat(contents, '\n'), [[\n\s*emulate\s\+\%(-[LR]\s\+\)\=[ckz]\=sh\>]]) then
|
||||||
|
-- Z shell scripts
|
||||||
|
return 'zsh'
|
||||||
|
end
|
||||||
|
|
||||||
|
for k, v in pairs(patterns_text) do
|
||||||
|
if type(v) == 'string' then
|
||||||
|
-- Check the first line only
|
||||||
|
if contents[1]:find(k) then
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
elseif type(v) == 'function' then
|
||||||
|
-- If filetype detection fails, continue with the next pattern
|
||||||
|
local ok, ft = pcall(v, contents)
|
||||||
|
if ok and ft then
|
||||||
|
return ft
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local opts = type(v) == 'table' and v[2] or {}
|
||||||
|
if opts.start_lnum and opts.end_lnum then
|
||||||
|
assert(not opts.ignore_case, 'ignore_case=true is ignored when start_lnum is also present, needs refactor')
|
||||||
|
for i = opts.start_lnum, opts.end_lnum do
|
||||||
|
if not contents[i] then
|
||||||
|
break
|
||||||
|
elseif contents[i]:find(k) then
|
||||||
|
return v[1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local line_nr = opts.start_lnum == -1 and #contents or opts.start_lnum or 1
|
||||||
|
if contents[line_nr] then
|
||||||
|
local line = opts.ignore_case and contents[line_nr]:lower() or contents[line_nr]
|
||||||
|
if opts.vim_regex and matchregex(line, k) or line:find(k) then
|
||||||
|
return v[1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return cvs_diff(path, contents)
|
||||||
|
end
|
||||||
|
|
||||||
|
M.match_contents = function(contents, path)
|
||||||
|
local first_line = contents[1]
|
||||||
|
if first_line:find('^#!') then
|
||||||
|
return match_from_hashbang(contents, path)
|
||||||
|
else
|
||||||
|
return match_from_text(contents, path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
" 'ignorecase' option making a difference. Where case is to be ignored use
|
" 'ignorecase' option making a difference. Where case is to be ignored use
|
||||||
" =~? instead. Do not use =~ anywhere.
|
" =~? instead. Do not use =~ anywhere.
|
||||||
|
|
||||||
|
" Only do the rest when not using Lua filetype detection
|
||||||
" Only do the rest when the FileType autocommand has not been triggered yet.
|
" and the FileType autocommand has not been triggered yet.
|
||||||
if did_filetype()
|
if exists("g:do_filetype_lua") && g:do_filetype_lua || did_filetype()
|
||||||
finish
|
finish
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user