refactor(filetype): allow vim.filetype.match to accept buf and filename (#19114)

This is necessary in cases where filetype detection acts recursively.
For example, when matching files that end with .bak, the "root" of
the filename is matched again against the same buffer (e.g. a buffer
named "foo.c.bak" will be matched again with the filename "foo.c", using
the same underlying buffer).
This commit is contained in:
Gregory Anders
2022-06-27 02:03:43 -06:00
committed by GitHub
parent eab8b998e9
commit 6f3508f8ed
2 changed files with 47 additions and 25 deletions

View File

@@ -2086,23 +2086,33 @@ match({arg}) *vim.filetype.match()*
-- Using a buffer number -- Using a buffer number
vim.filetype.match({ buf = 42 }) vim.filetype.match({ buf = 42 })
-- Using a filename -- Override the filename of the given buffer
vim.filetype.match({ filename = "main.lua" }) vim.filetype.match({ buf = 42, filename = 'foo.c' })
-- Using a filename without a buffer
vim.filetype.match({ filename = 'main.lua' })
-- Using file contents -- Using file contents
vim.filetype.match({ contents = {"#!/usr/bin/env bash"} }) vim.filetype.match({ contents = {'#!/usr/bin/env bash'} })
< <
Parameters: ~ Parameters: ~
{arg} (table) Table specifying which matching strategy to {arg} (table) Table specifying which matching strategy to
use. It is an error to provide more than one use. Accepted keys are:
strategy. Accepted keys are: • buf (number): Buffer number to use for matching.
• buf (number): Buffer number to use for matching Mutually exclusive with {contents}
• filename (string): Filename to use for matching. • filename (string): Filename to use for matching.
Note that the file need not actually exist in the When {buf} is given, defaults to the filename of
filesystem, only the name itself is used. the given buffer number. The file need not
actually exist in the filesystem. When used
without {buf} only the name of the file is used
for filetype matching. This may result in failure
to detect the filetype in cases where the
filename alone is not enough to disambiguate the
filetype.
• contents (table): An array of lines representing • contents (table): An array of lines representing
file contents to use for matching. file contents to use for matching. Can be used
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.

View File

@@ -2240,21 +2240,29 @@ end
--- -- Using a buffer number --- -- Using a buffer number
--- vim.filetype.match({ buf = 42 }) --- vim.filetype.match({ buf = 42 })
--- ---
--- -- Using a filename --- -- Override the filename of the given buffer
--- vim.filetype.match({ filename = "main.lua" }) --- vim.filetype.match({ buf = 42, filename = 'foo.c' })
---
--- -- Using a filename without a buffer
--- vim.filetype.match({ filename = 'main.lua' })
--- ---
--- -- Using file contents --- -- Using file contents
--- 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. It is an error to provide more ---@param arg table Table specifying which matching strategy to use. Accepted keys are:
--- than one strategy. Accepted keys are: --- * buf (number): Buffer number to use for matching. Mutually exclusive with
--- * buf (number): Buffer number to use for matching --- {contents}
--- * filename (string): Filename to use for matching. Note that the file need not --- * filename (string): Filename to use for matching. When {buf} is given,
--- actually exist in the filesystem, only the name itself is --- defaults to the filename of the given buffer number. The
--- used. --- file need not actually exist in the filesystem. When used
--- without {buf} only the name of the file is used for
--- filetype matching. This may result in failure to detect
--- the filetype in cases where the filename alone is not
--- enough to disambiguate the filetype.
--- * contents (table): An array of lines representing file contents to use for --- * contents (table): An array of lines representing file contents to use for
--- matching. --- matching. Can be used with {filename}. Mutually exclusive
--- with {buf}.
---@return string|nil If a match was found, the matched filetype. ---@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 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
@@ -2265,26 +2273,30 @@ function M.match(arg)
}) })
if not (arg.buf or arg.filename or arg.contents) then if not (arg.buf or arg.filename or arg.contents) then
error('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.filename) or (arg.buf and arg.contents) or (arg.filename and arg.contents) then if arg.buf and arg.contents then
error('Only one of "buf", "filename", or "contents" must be given') error('Only one of "buf" or "contents" must be given')
end end
local bufnr = arg.buf local bufnr = arg.buf
local name = bufnr and api.nvim_buf_get_name(bufnr) or arg.filename local name = arg.filename
local contents = arg.contents local contents = arg.contents
if bufnr and not name then
name = api.nvim_buf_get_name(bufnr)
end
if name then if name then
name = normalize_path(name) name = normalize_path(name)
end end
local ft, on_detect local ft, on_detect
if not (bufnr or name) then if contents then
-- Sanity check: this should not happen -- Sanity check: this should not happen
assert(contents, 'contents should be non-nil when bufnr and filename are nil') assert(not bufnr, '"buf" and "contents" are mutually exclusive')
-- TODO: "scripts.lua" content matching -- TODO: "scripts.lua" content matching
return return
end end