fix(parser): detect filetype from file content (shebang/modeline)
When a file has no extension but contains a shebang (e.g., `#!/bin/bash`),
filetype detection now reads the first 10 lines from disk and uses
`vim.filetype.match({ filename, contents })` for content-based detection.
This enables syntax highlighting for files like `build` scripts that rely
on shebang detection, even when the file isn't open in a buffer.
Detection order:
1. Existing buffer's filetype (already implemented in #69)
2. File content (shebang/modeline) - NEW
3. Filename extension only
Also adds `filetype on` to test helpers to ensure `vim.g.ft_ignore_pat`
is set, which is required for shell detection.
This commit is contained in:
parent
0e6871b167
commit
0dc8a0ec0f
3 changed files with 94 additions and 0 deletions
|
|
@ -13,12 +13,33 @@ local M = {}
|
|||
|
||||
local dbg = require('diffs.log').dbg
|
||||
|
||||
---@param filepath string
|
||||
---@param n integer
|
||||
---@return string[]?
|
||||
local function read_first_lines(filepath, n)
|
||||
local f = io.open(filepath, 'r')
|
||||
if not f then
|
||||
return nil
|
||||
end
|
||||
local lines = {}
|
||||
for _ = 1, n do
|
||||
local line = f:read('*l')
|
||||
if not line then
|
||||
break
|
||||
end
|
||||
table.insert(lines, line)
|
||||
end
|
||||
f:close()
|
||||
return #lines > 0 and lines or nil
|
||||
end
|
||||
|
||||
---@param filename string
|
||||
---@param repo_root string?
|
||||
---@return string?
|
||||
local function get_ft_from_filename(filename, repo_root)
|
||||
if repo_root then
|
||||
local full_path = vim.fs.joinpath(repo_root, filename)
|
||||
|
||||
local buf = vim.fn.bufnr(full_path)
|
||||
if buf ~= -1 then
|
||||
local ft = vim.api.nvim_get_option_value('filetype', { buf = buf })
|
||||
|
|
@ -27,6 +48,15 @@ local function get_ft_from_filename(filename, repo_root)
|
|||
return ft
|
||||
end
|
||||
end
|
||||
|
||||
local contents = read_first_lines(full_path, 10)
|
||||
if contents then
|
||||
local ft = vim.filetype.match({ filename = filename, contents = contents })
|
||||
if ft then
|
||||
dbg('filetype from file content: %s', ft)
|
||||
return ft
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local ft = vim.filetype.match({ filename = filename })
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue