-
-
Notifications
You must be signed in to change notification settings - Fork 279
/
filetype.lua
136 lines (109 loc) · 3.49 KB
/
filetype.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
local Path = require('plenary.path')
local os_sep = Path.path.sep
local filetype = {}
local filetype_table = {
extension = {},
file_name = {},
shebang = {},
}
filetype.add_table = function(new_filetypes)
local valid_keys = {'extension', 'file_name', 'shebang'}
local new_keys = {}
-- Validate keys
for k, _ in pairs(new_filetypes) do new_keys[k] = true end
for _, k in ipairs(valid_keys) do new_keys[k] = nil end
for k, v in pairs(new_keys) do
error(debug.traceback("Invalid key / value:" .. tostring(k) .. " / " .. tostring(v)))
end
if new_filetypes.extension then
filetype_table.extension = vim.tbl_extend("force", filetype_table.extension, new_filetypes.extension)
end
if new_filetypes.file_name then
filetype_table.file_name = vim.tbl_extend("force", filetype_table.file_name, new_filetypes.file_name)
end
if new_filetypes.shebang then
filetype_table.shebang = vim.tbl_extend("force", filetype_table.shebang, new_filetypes.shebang)
end
end
filetype.add_file = function(filename)
local filetype_files = vim.api.nvim_get_runtime_file(
string.format(
"data/plenary/filetypes/%s.lua", filename
), true
)
for _, file in ipairs(filetype_files) do
local ok, msg = pcall(filetype.add_table, dofile(file))
if not ok then
error("Unable to add file " .. file .. ":\n" .. msg)
end
end
end
filetype._get_extension = function(filename)
local ext_with_period = filename:match("^.+(%..+)$")
if ext_with_period then
return ext_with_period:sub(2)
end
end
filetype._parse_modeline = function(tail)
if tail:find('vim:') then
return tail:match('.*:ft=([^: ]*):.*$') or ''
end
return ''
end
filetype._parse_shebang = function(head)
if head:sub(1, 2) == '#!' then
local match = filetype_table.shebang[head:sub(3, #head)]
if match then return match end
end
return ''
end
filetype.detect_from_extension = function(filepath)
local ext = filetype._get_extension(filepath)
ext = ext and ext:lower()
local match = ext and filetype_table.extension[ext]
if match then return match end
return ''
end
filetype.detect_from_name = function(filepath)
filepath = filepath:lower()
local split_path = vim.split(filepath, os_sep, true)
local fname = split_path[#split_path]
local match = filetype_table.file_name[fname]
if match then return match end
return ''
end
filetype.detect_from_modeline = function(filepath)
local tail = Path:new(filepath):tail(1)
if not tail then return '' end
return filetype._parse_modeline(tail)
end
filetype.detect_from_shebang = function(filepath)
local head = Path:new(filepath):head(1)
if not head then return '' end
return filetype._parse_shebang(head)
end
--- Detect a filetype from a path.
---
---@param opts table: Table with optional keys
--- - fs_access (bool, default=true): Should check a file if it exists
filetype.detect = function(filepath, opts)
opts = opts or {}
opts.fs_access = opts.fs_access or true
local match = filetype.detect_from_name(filepath)
if match ~= '' then return match end
match = filetype.detect_from_extension(filepath)
if opts.fs_access and Path:new(filepath):exists() then
if match == '' then
match = filetype.detect_from_shebang(filepath)
if match ~= '' then return match end
end
if match == 'text' or match == '' then
match = filetype.detect_from_modeline(filepath)
if match ~= '' then return match end
end
end
return match
end
filetype.add_file("base")
filetype.add_file("builtin")
return filetype