Initial commit
This commit is contained in:
commit
209ba130c0
4852 changed files with 1517959 additions and 0 deletions
793
.config/lite-xl/plugins/lsp_snippets.lua
Normal file
793
.config/lite-xl/plugins/lsp_snippets.lua
Normal file
|
|
@ -0,0 +1,793 @@
|
|||
-- mod-version:3
|
||||
|
||||
-- LSP style snippet parser
|
||||
-- shamelessly 'inspired by' (stolen from) LuaSnip
|
||||
-- https://github.com/L3MON4D3/LuaSnip/blob/master/lua/luasnip/util/parser/neovim_parser.lua
|
||||
|
||||
local core = require 'core'
|
||||
local common = require 'core.common'
|
||||
local Doc = require 'core.doc'
|
||||
local system = require 'system'
|
||||
local regex = require 'regex'
|
||||
local snippets = require 'plugins.snippets'
|
||||
|
||||
local json do
|
||||
local ok, j
|
||||
for _, p in ipairs {
|
||||
'plugins.json', 'plugins.lsp.json', 'plugins.lintplus.json',
|
||||
'libraries.json'
|
||||
} do
|
||||
ok, j = pcall(require, p)
|
||||
if ok then json = j; break end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local B = snippets.builder
|
||||
|
||||
local LAST_CONVERTED_ID = { }
|
||||
local THREAD_KEY = { }
|
||||
|
||||
|
||||
-- node factories
|
||||
|
||||
local function doc_syntax(doc, k)
|
||||
return doc.syntax and doc.syntax[k]
|
||||
end
|
||||
|
||||
local variables = {
|
||||
-- LSP
|
||||
TM_SELECTED_TEXT = function(ctx) return ctx.selection end,
|
||||
TM_CURRENT_LINE = function(ctx) return ctx.doc.lines[ctx.line] end,
|
||||
TM_CURRENT_WORD = function(ctx) return ctx.partial end,
|
||||
TM_LINE_INDEX = function(ctx) return ctx.line - 1 end,
|
||||
TM_LINE_NUMBER = function(ctx) return ctx.line end,
|
||||
TM_FILENAME = function(ctx) return ctx.doc.filename:match('[^/%\\]*$') or '' end,
|
||||
TM_FILENAME_BASE = function(ctx) return ctx.doc.filename:match('([^/%\\]*)%.%w*$') or ctx.doc.filename end,
|
||||
TM_DIRECTORY = function(ctx) return ctx.doc.filename:match('([^/%\\]*)[/%\\].*$') or '' end,
|
||||
TM_FILEPATH = function(ctx) return common.dirname(ctx.doc.abs_filename) or '' end,
|
||||
-- VSCode
|
||||
RELATIVE_FILEPATH = function(ctx) return core.normalize_to_project_dir(ctx.doc.filename) end,
|
||||
CLIPBOARD = function() return system.get_clipboard() end,
|
||||
-- https://github.com/lite-xl/lite-xl/pull/1455
|
||||
WORKSPACE_NAME = function(ctx) return end,
|
||||
WORKSPACE_FOLDER = function(ctx) return end,
|
||||
CURSOR_INDEX = function(ctx) return ctx.col - 1 end,
|
||||
CURSOR_NUMBER = function(ctx) return ctx.col end,
|
||||
CURRENT_YEAR = function() return os.date('%G') end,
|
||||
CURRENT_YEAR_SHORT = function() return os.date('%g') end,
|
||||
CURRENT_MONTH = function() return os.date('%m') end,
|
||||
CURRENT_MONTH_NAME = function() return os.date('%B') end,
|
||||
CURRENT_MONTH_NAME_SHORT = function() return os.date('%b') end,
|
||||
CURRENT_DATE = function() return os.date('%d') end,
|
||||
CURRENT_DAY_NAME = function() return os.date('%A') end,
|
||||
CURRENT_DAY_NAME_SHORT = function() return os.date('%a') end,
|
||||
CURRENT_HOUR = function() return os.date('%H') end,
|
||||
CURRENT_MINUTE = function() return os.date('%M') end,
|
||||
CURRENT_SECOND = function() return os.date('%S') end,
|
||||
CURRENT_SECONDS_UNIX = function() return os.time() end,
|
||||
RANDOM = function() return string.format('%06d', math.random(999999)) end,
|
||||
RANDOM_HEX = function() return string.format('%06x', math.random(0xFFFFFF)) end,
|
||||
BLOCK_COMMENT_START = function(ctx) return (doc_syntax(ctx.doc, 'block_comment') or { })[1] end,
|
||||
BLOCK_COMMENT_END = function(ctx) return (doc_syntax(ctx.doc, 'block_comment') or { })[2] end,
|
||||
LINE_COMMENT = function(ctx) return doc_syntax(ctx.doc, 'comment') end
|
||||
-- https://code.visualstudio.com/docs/editor/userdefinedsnippets#_variables
|
||||
-- UUID
|
||||
}
|
||||
|
||||
local formatters; formatters = {
|
||||
downcase = string.lower,
|
||||
upcase = string.upper,
|
||||
capitalize = function(str)
|
||||
return str:sub(1, 1):upper() .. str:sub(2)
|
||||
end,
|
||||
pascalcase = function(str)
|
||||
local t = { }
|
||||
for s in str:gmatch('%w+') do
|
||||
table.insert(t, formatters.capitalize(s))
|
||||
end
|
||||
return table.concat(t)
|
||||
end,
|
||||
camelcase = function(str)
|
||||
str = formatters.pascalcase(str)
|
||||
return str:sub(1, 1):lower() .. str:sub(2)
|
||||
end
|
||||
}
|
||||
|
||||
local function to_text(v, _s)
|
||||
return v.esc
|
||||
end
|
||||
|
||||
local function format_fn(v, _s)
|
||||
local id = tonumber(v[2])
|
||||
|
||||
-- $1 | ${1}
|
||||
if #v < 4 then
|
||||
return function(captures)
|
||||
return captures[id] or ''
|
||||
end
|
||||
end
|
||||
|
||||
-- ${1:...}
|
||||
local t = v[3][2][1] -- token after the ':' | (else when no token)
|
||||
local i = v[3][2][2] -- formatter | if | (else when no if)
|
||||
local e = v[3][2][4] -- (else when if)
|
||||
|
||||
if t == '/' then
|
||||
local f = formatters[i]
|
||||
return function(captures)
|
||||
local c = captures[id]
|
||||
return c and f(c) or ''
|
||||
end
|
||||
elseif t == '+' then
|
||||
return function(captures)
|
||||
return captures[id] and i or ''
|
||||
end
|
||||
elseif t == '?' then
|
||||
return function(captures)
|
||||
return captures[id] and i or e
|
||||
end
|
||||
elseif t == '-' then
|
||||
return function(captures)
|
||||
return captures[id] or i
|
||||
end
|
||||
else
|
||||
return function(captures)
|
||||
return captures[id] or t
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function transform_fn(v, _s)
|
||||
local reg = regex.compile(v[2], v[#v])
|
||||
local fmt = v[4]
|
||||
|
||||
if type(fmt) ~= 'table' then
|
||||
return function(str)
|
||||
return reg:gsub(str, '')
|
||||
end
|
||||
end
|
||||
|
||||
local t = { }
|
||||
for _, f in ipairs(fmt) do
|
||||
if type(f) == 'string' then
|
||||
table.insert(t, f)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if #t == #fmt then
|
||||
t = table.concat(t)
|
||||
return function(str)
|
||||
return reg:gsub(str, t)
|
||||
end
|
||||
end
|
||||
|
||||
return function(str)
|
||||
local captures = { reg:match(str) }
|
||||
for k, v in ipairs(captures) do
|
||||
if type(v) ~= 'string' then
|
||||
captures[k] = nil
|
||||
end
|
||||
end
|
||||
local t = { }
|
||||
for _, f in ipairs(fmt) do
|
||||
if type(f) == 'string' then
|
||||
table.insert(t, f)
|
||||
else
|
||||
table.insert(t, f(captures))
|
||||
end
|
||||
end
|
||||
return table.concat(t)
|
||||
end
|
||||
end
|
||||
|
||||
local function text_node(v, _s)
|
||||
return B.static(v.esc)
|
||||
end
|
||||
|
||||
local function variable_node(v, _s)
|
||||
local name = v[2]
|
||||
local var = variables[name]
|
||||
|
||||
local id
|
||||
if not var then
|
||||
if not _s._converted_variables then
|
||||
id = os.time()
|
||||
_s._converted_variables = { [name] = id, [LAST_CONVERTED_ID] = id }
|
||||
else
|
||||
id = _s._converted_variables[name]
|
||||
if not id then
|
||||
id = _s._converted_variables[LAST_CONVERTED_ID] + 1
|
||||
_s._converted_variables[name] = id
|
||||
_s._converted_variables[LAST_CONVERTED_ID] = id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #v ~= 4 then
|
||||
return var and B.static(var) or B.user(id, name)
|
||||
end
|
||||
|
||||
if type(v[3]) == 'table' then
|
||||
-- vscode accepts empty default -> var name
|
||||
return var and B.static(var) or B.user(id, v[3][2] or name)
|
||||
end
|
||||
|
||||
if not var then
|
||||
return B.user(id, nil, v[3])
|
||||
end
|
||||
|
||||
return type(var) ~= 'function' and B.static(var) or B.static(function(ctx)
|
||||
return v[3](var(ctx))
|
||||
end)
|
||||
end
|
||||
|
||||
local function tabstop_node(v, _s)
|
||||
local t = v[3] and v[3] ~= '}' and v[3] or nil
|
||||
return B.user(tonumber(v[2]), nil, t)
|
||||
end
|
||||
|
||||
local function choice_node(v, _s)
|
||||
local id = tonumber(v[2])
|
||||
local c = { [v[4]] = true }
|
||||
if #v == 6 then
|
||||
for _, _c in ipairs(v[5]) do
|
||||
c[_c[2]] = true
|
||||
end
|
||||
end
|
||||
_s:choice(id, c)
|
||||
return B.user(id)
|
||||
end
|
||||
|
||||
local function placeholder_node(v, _s)
|
||||
local id = tonumber(v[2])
|
||||
_s:default(id, v[4])
|
||||
return B.user(id)
|
||||
end
|
||||
|
||||
local function build_snippet(v, _s)
|
||||
for _, n in ipairs(v) do _s:add(n) end
|
||||
return _s:ok()
|
||||
end
|
||||
|
||||
|
||||
-- parser metatable
|
||||
|
||||
local P do
|
||||
local mt = {
|
||||
__call = function(mt, parser, converter)
|
||||
return setmetatable({ parser = parser, converter = converter }, mt)
|
||||
end,
|
||||
-- allows 'lazy arguments'
|
||||
-- i.e can use a yet to be defined rule in a previous rule
|
||||
__index = function(t, k)
|
||||
return function(...) return t[k](...) end
|
||||
end
|
||||
}
|
||||
|
||||
P = setmetatable({
|
||||
__call = function(t, str, at, _s)
|
||||
local r = t.parser(str, at, _s)
|
||||
if r.ok and t.converter then
|
||||
r.value = t.converter(r.value, _s)
|
||||
end
|
||||
return r
|
||||
end
|
||||
}, mt)
|
||||
end
|
||||
|
||||
|
||||
-- utils
|
||||
|
||||
local function toset(t)
|
||||
local r = { }
|
||||
for _, v in pairs(t or { }) do
|
||||
r[v] = true
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
local function fail(at)
|
||||
return { at = at }
|
||||
end
|
||||
|
||||
local function ok(at, v)
|
||||
return { ok = true, at = at, value = v }
|
||||
end
|
||||
|
||||
|
||||
-- base + combinators
|
||||
|
||||
local function token(t)
|
||||
return function(str, at)
|
||||
local to = at + #t
|
||||
return t == str:sub(at, to - 1) and ok(to, t) or fail(at)
|
||||
end
|
||||
end
|
||||
|
||||
local function consume(stops, escapes)
|
||||
stops, escapes = toset(stops), toset(escapes)
|
||||
return function(str, at)
|
||||
local to = at
|
||||
local raw, esc = { }, { }
|
||||
local c = str:sub(to, to)
|
||||
while to <= #str and not stops[c] do
|
||||
if c == '\\' then
|
||||
table.insert(raw, c)
|
||||
to = to + 1
|
||||
c = str:sub(to, to)
|
||||
if not stops[c] and not escapes[c] then
|
||||
table.insert(esc, '\\')
|
||||
end
|
||||
end
|
||||
table.insert(raw, c)
|
||||
table.insert(esc, c)
|
||||
to = to + 1
|
||||
c = str:sub(to, to)
|
||||
end
|
||||
return to ~= at
|
||||
and ok(to, { raw = table.concat(raw), esc = table.concat(esc) })
|
||||
or fail(at)
|
||||
end
|
||||
end
|
||||
|
||||
local function pattern(p)
|
||||
return function(str, at)
|
||||
local r = str:match('^' .. p, at)
|
||||
return r and ok(at + #r, r) or fail(at)
|
||||
end
|
||||
end
|
||||
|
||||
local function maybe(p)
|
||||
return function(str, at, ...)
|
||||
local r = p(str, at, ...)
|
||||
return ok(r.at, r.value)
|
||||
end
|
||||
end
|
||||
|
||||
local function rep(p)
|
||||
return function(str, at, ...)
|
||||
local v, to, r = { }, at, ok(at)
|
||||
while to <= #str and r.ok do
|
||||
table.insert(v, r.value)
|
||||
to = r.at
|
||||
r = p(str, to, ...)
|
||||
end
|
||||
return #v > 0 and ok(to, v) or fail(at)
|
||||
end
|
||||
end
|
||||
|
||||
local function any(...)
|
||||
local t = { ... }
|
||||
return function(str, at, ...)
|
||||
for _, p in ipairs(t) do
|
||||
local r = p(str, at, ...)
|
||||
if r.ok then return r end
|
||||
end
|
||||
return fail(at)
|
||||
end
|
||||
end
|
||||
|
||||
local function seq(...)
|
||||
local t = { ... }
|
||||
return function(str, at, ...)
|
||||
local v, to = { }, at
|
||||
for _, p in ipairs(t) do
|
||||
local r = p(str, to, ...)
|
||||
if r.ok then
|
||||
table.insert(v, r.value)
|
||||
to = r.at
|
||||
else
|
||||
return fail(at)
|
||||
end
|
||||
end
|
||||
return ok(to, v)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- grammar rules
|
||||
|
||||
-- token cache
|
||||
local t = setmetatable({ },
|
||||
{
|
||||
__index = function(t, k)
|
||||
local fn = token(k)
|
||||
rawset(t, k, fn)
|
||||
return fn
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
P.int = pattern('%d+')
|
||||
|
||||
P.var = pattern('[%a_][%w_]*')
|
||||
|
||||
-- '}' needs to be escaped in normal text (i.e #0)
|
||||
local __text0 = consume({ '$' }, { '\\', '}' })
|
||||
local __text1 = consume({ '}' }, { '\\' })
|
||||
local __text2 = consume({ ':' }, { '\\' })
|
||||
local __text3 = consume({ '/' }, { '\\' })
|
||||
local __text4 = consume({ '$', '}' }, { '\\' })
|
||||
local __text5 = consume({ ',', '|' }, { '\\' })
|
||||
local __text6 = consume({ "$", "/" }, { "\\" })
|
||||
|
||||
P._if1 = P(__text1, to_text)
|
||||
P._if2 = P(__text2, to_text)
|
||||
P._else = P(__text1, to_text)
|
||||
|
||||
P.options = pattern('%l*')
|
||||
|
||||
P.regex = P(__text3, to_text)
|
||||
|
||||
P.format = P(any(
|
||||
seq(t['$'], P.int),
|
||||
seq(t['${'], P.int, maybe(seq(t[':'], any(
|
||||
seq(t['/'], any(t['upcase'], t['downcase'], t['capitalize'], t['pascalcase'], t['camelcase'])),
|
||||
seq(t['+'], P._if1),
|
||||
seq(t['?'], P._if2, t[':'], P._else),
|
||||
seq(t['-'], P._else),
|
||||
P._else
|
||||
))), t['}'])
|
||||
), format_fn)
|
||||
|
||||
P.transform_text = P(__text6, to_text)
|
||||
P.transform = P(
|
||||
seq(t['/'], P.regex, t['/'], rep(any(P.format, P.transform_text)), t['/'], P.options),
|
||||
transform_fn
|
||||
)
|
||||
|
||||
P.variable_text = P(__text4, text_node)
|
||||
P.variable = P(any(
|
||||
seq(t['$'], P.var),
|
||||
seq(t['${'], P.var, maybe(any(
|
||||
-- grammar says a single mandatory 'any' for default, vscode seems to accept any*
|
||||
seq(t[':'], maybe(rep(any(P.dollars, P.variable_text)))),
|
||||
P.transform
|
||||
)), t['}'])
|
||||
), variable_node)
|
||||
|
||||
P.choice_text = P(__text5, to_text)
|
||||
P.choice = P(
|
||||
seq(t['${'], P.int, t['|'], P.choice_text, maybe(rep(seq(t[','], P.choice_text))), t['|}']),
|
||||
choice_node
|
||||
)
|
||||
|
||||
P.placeholder_text = P(__text4, text_node)
|
||||
P.placeholder = P(
|
||||
seq(t['${'], P.int, t[':'], maybe(rep(any(P.dollars, P.placeholder_text))), t['}']),
|
||||
placeholder_node
|
||||
)
|
||||
|
||||
P.tabstop = P(any(
|
||||
seq(t['$'], P.int),
|
||||
-- transform isnt specified in the grammar but seems to be supported by vscode
|
||||
seq(t['${'], P.int, maybe(P.transform), t['}'])
|
||||
), tabstop_node)
|
||||
|
||||
|
||||
P.dollars = any(P.tabstop, P.placeholder, P.choice, P.variable)
|
||||
|
||||
P.text = P(__text0, text_node)
|
||||
P.any = any(P.dollars, P.text)
|
||||
|
||||
P.snippet = P(rep(P.any), build_snippet)
|
||||
|
||||
|
||||
-- JSON files
|
||||
|
||||
-- defined at the end of the file
|
||||
local extensions
|
||||
|
||||
local fstate = { NOT_DONE = 'not done', QUEUED = 'queued', DONE = 'done' }
|
||||
local queue = { }
|
||||
local files = { }
|
||||
local files2exts = { }
|
||||
local exts2files = { }
|
||||
|
||||
local function parse_file(file)
|
||||
if files[file] == fstate.DONE then return end
|
||||
files[file] = fstate.DONE
|
||||
|
||||
local _f = io.open(file)
|
||||
if not _f then
|
||||
core.error('[LSP snippets] Could not open \'%s\'', file)
|
||||
return
|
||||
end
|
||||
local ok, r = pcall(json.decode, _f:read('a'))
|
||||
_f:close()
|
||||
if not ok then
|
||||
core.error('[LSP snippets] %s: %s', file, r:match('%d+:%s+(.*)'))
|
||||
return false
|
||||
end
|
||||
|
||||
local exts = file:match('%.json$') and files2exts[file]
|
||||
for i, s in pairs(r) do
|
||||
-- apparently body can be a single string
|
||||
local template = type(s.body) == 'table'
|
||||
and table.concat(s.body, '\n')
|
||||
or s.body
|
||||
if not template or template == '' then
|
||||
core.warn('[LSP snippets] missing \'body\' for %s (%s)', i, file)
|
||||
goto continue
|
||||
end
|
||||
|
||||
-- https://code.visualstudio.com/docs/editor/userdefinedsnippets#_language-snippet-scope
|
||||
local scope
|
||||
if not exts and s.scope then
|
||||
local tmp = { }
|
||||
for _, l in ipairs(s.scope) do
|
||||
for _, e in ipairs(extensions[l:lower()]) do
|
||||
tmp[e] = true
|
||||
end
|
||||
end
|
||||
scope = { }
|
||||
for l in pairs(tmp) do
|
||||
table.insert(scope, l)
|
||||
end
|
||||
end
|
||||
|
||||
-- prefix may be an array
|
||||
local triggers = type(s.prefix) ~= 'table' and { s.prefix } or s.prefix
|
||||
if #triggers == 0 then
|
||||
core.warn('[LSP snippets] missing \'prefix\' for %s (%s)', i, file)
|
||||
goto continue
|
||||
end
|
||||
|
||||
for _, t in ipairs(triggers) do
|
||||
snippets.add {
|
||||
trigger = t,
|
||||
format = 'lsp',
|
||||
files = exts or scope,
|
||||
info = i,
|
||||
desc = s.description,
|
||||
template = template
|
||||
}
|
||||
end
|
||||
|
||||
::continue::
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function pop()
|
||||
while #queue > 0 do
|
||||
repeat until parse_file(table.remove(queue)) ~= nil
|
||||
if #queue > 0 then coroutine.yield() end
|
||||
end
|
||||
end
|
||||
|
||||
local function enqueue(filename)
|
||||
if not core.threads[THREAD_KEY] then
|
||||
core.add_thread(pop, THREAD_KEY)
|
||||
end
|
||||
files[filename] = fstate.QUEUED
|
||||
table.insert(queue, filename)
|
||||
end
|
||||
|
||||
local function add_file(filename, exts)
|
||||
if files[filename] then return end
|
||||
|
||||
if filename:match('%.code%-snippets$') then
|
||||
enqueue(filename)
|
||||
return
|
||||
end
|
||||
|
||||
if not filename:match('%.json$') then return end
|
||||
|
||||
if not exts then
|
||||
local lang_name = filename:match('([^/%\\]*)%.%w*$'):lower()
|
||||
exts = extensions[lang_name]
|
||||
if not exts then return end
|
||||
end
|
||||
|
||||
files[filename] = fstate.NOT_DONE
|
||||
exts = type(exts) == 'string' and { exts } or exts
|
||||
for _, e in ipairs(exts) do
|
||||
files2exts[filename] = files2exts[filename] or { }
|
||||
table.insert(files2exts[filename], '%.' .. e .. '$')
|
||||
exts2files[e] = exts2files[e] or { }
|
||||
table.insert(exts2files[e], filename)
|
||||
end
|
||||
end
|
||||
|
||||
local function for_filename(name)
|
||||
if not name then return end
|
||||
local ext = name:match('%.(.*)$')
|
||||
if not ext then return end
|
||||
local _files = exts2files[ext]
|
||||
if not _files then return end
|
||||
for _, f in ipairs(_files) do
|
||||
if files[f] == fstate.NOT_DONE then
|
||||
enqueue(f)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local doc_new = Doc.new
|
||||
function Doc:new(filename, ...)
|
||||
doc_new(self, filename, ...)
|
||||
for_filename(filename)
|
||||
end
|
||||
|
||||
local doc_set_filename = Doc.set_filename
|
||||
function Doc:set_filename(filename, ...)
|
||||
doc_set_filename(self, filename, ...)
|
||||
for_filename(filename)
|
||||
end
|
||||
|
||||
|
||||
-- API
|
||||
|
||||
local M = { }
|
||||
|
||||
function M.parse(template)
|
||||
local _s = B.new()
|
||||
local r = P.snippet(template, 1, _s)
|
||||
if not r.ok then
|
||||
return B.new():s(template):ok()
|
||||
elseif r.at == #template + 1 then
|
||||
return r.value
|
||||
else
|
||||
return _s:s(template:sub(r.at + 1)):ok()
|
||||
end
|
||||
end
|
||||
|
||||
snippets.parsers.lsp = M.parse
|
||||
|
||||
local warned = false
|
||||
function M.add_paths(paths)
|
||||
if not json then
|
||||
if not warned then
|
||||
core.error(
|
||||
'[LSP snippets] Could not add snippet file(s):' ..
|
||||
'JSON plugin not found'
|
||||
)
|
||||
warned = true
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
paths = type(paths) ~= 'table' and { paths } or paths
|
||||
|
||||
for _, p in ipairs(paths) do
|
||||
-- non absolute paths are treated as relative from USERDIR
|
||||
p = not common.is_absolute_path(p) and (USERDIR .. PATHSEP .. p) or p
|
||||
local finfo = system.get_file_info(p)
|
||||
|
||||
-- if path of a directory, add every file it contains and directories
|
||||
-- whose name is that of a lang
|
||||
if finfo and finfo.type == 'dir' then
|
||||
for _, f in ipairs(system.list_dir(p)) do
|
||||
f = p .. PATHSEP .. f
|
||||
finfo = system.get_file_info(f)
|
||||
if not finfo or finfo.type == 'file' then
|
||||
add_file(f)
|
||||
else
|
||||
-- only if the directory's name matches a language
|
||||
local lang_name = f:match('[^/%\\]*$'):lower()
|
||||
local exts = extensions[lang_name]
|
||||
for _, f2 in ipairs(system.list_dir(f)) do
|
||||
f2 = f .. PATHSEP .. f2
|
||||
finfo = system.get_file_info(f2)
|
||||
if not finfo or finfo.type == 'file' then
|
||||
add_file(f2, exts)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- if path of a file, add the file
|
||||
else
|
||||
add_file(p)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- arbitrarily cleaned up extension dump from https://gist.github.com/ppisarczyk/43962d06686722d26d176fad46879d41
|
||||
-- nothing after this
|
||||
|
||||
-- 90% of these are still useless but cba
|
||||
|
||||
extensions = {
|
||||
['ats'] = { 'dats', 'hats', 'sats', },
|
||||
['ada'] = { 'adb', 'ada', 'ads', },
|
||||
['agda'] = { 'agda', },
|
||||
['asciidoc'] = { 'asciidoc', 'adoc', 'asc', },
|
||||
['assembly'] = { 'asm', 'nasm', },
|
||||
['autohotkey'] = { 'ahk', 'ahkl', },
|
||||
['awk'] = { 'awk', 'auk', 'gawk', 'mawk', 'nawk', },
|
||||
['batchfile'] = { 'bat', 'cmd', },
|
||||
['c'] = { 'c', 'h', },
|
||||
['c#'] = { 'cs', 'cake', 'cshtml', 'csx', },
|
||||
['c++'] = { 'cpp', 'c++', 'cc', 'cp', 'cxx', 'h', 'h++', 'hh', 'hpp', 'hxx', },
|
||||
['cmake'] = { 'cmake', 'cmake.in', },
|
||||
['cobol'] = { 'cob', 'cbl', 'ccp', 'cobol', 'cpy', },
|
||||
['css'] = { 'css', },
|
||||
['clean'] = { 'icl', 'dcl', },
|
||||
['clojure'] = { 'clj', 'boot', 'cl2', 'cljc', 'cljs', 'cljs.hl', 'cljscm', 'cljx', 'hic', },
|
||||
['common lisp'] = { 'lisp', 'asd', 'cl', 'l', 'lsp', 'ny', 'podsl', 'sexp', },
|
||||
['component pascal'] = { 'cp', 'cps', },
|
||||
['coq'] = { 'coq', 'v', },
|
||||
['crystal'] = { 'cr', },
|
||||
['cuda'] = { 'cu', 'cuh', },
|
||||
['d'] = { 'd', 'di', },
|
||||
['dart'] = { 'dart', },
|
||||
['dockerfile'] = { 'dockerfile', },
|
||||
['eiffel'] = { 'e', },
|
||||
['elixir'] = { 'ex', 'exs', },
|
||||
['elm'] = { 'elm', },
|
||||
['emacs lisp'] = { 'el', 'emacs', 'emacs.desktop', },
|
||||
['erlang'] = { 'erl', 'es', 'escript', 'hrl', 'xrl', 'yrl', },
|
||||
['f#'] = { 'fs', 'fsi', 'fsx', },
|
||||
['fortran'] = { 'f90', 'f', 'f03', 'f08', 'f77', 'f95', 'for', 'fpp', },
|
||||
['factor'] = { 'factor', },
|
||||
['forth'] = { 'fth', '4th', 'f', 'for', 'forth', 'fr', 'frt', 'fs', },
|
||||
['go'] = { 'go', },
|
||||
['groff'] = { 'man', '1', '1in', '1m', '1x', '2', '3', '3in', '3m', '3qt', '3x', '4', '5', '6', '7', '8', '9', 'l', 'me', 'ms', 'n', 'rno', 'roff', },
|
||||
['groovy'] = { 'groovy', 'grt', 'gtpl', 'gvy', },
|
||||
['html'] = { 'html', 'htm', 'html.hl', 'xht', 'xhtml', },
|
||||
['haskell'] = { 'hs', 'hsc', },
|
||||
['idris'] = { 'idr', 'lidr', },
|
||||
['jsx'] = { 'jsx', },
|
||||
['java'] = { 'java', },
|
||||
['javascript'] = { 'js', },
|
||||
['julia'] = { 'jl', },
|
||||
['jupyter notebook'] = { 'ipynb', },
|
||||
['kotlin'] = { 'kt', 'ktm', 'kts', },
|
||||
['lean'] = { 'lean', 'hlean', },
|
||||
['less'] = { 'less', },
|
||||
['lua'] = { 'lua', 'fcgi', 'nse', 'pd_lua', 'rbxs', 'wlua', },
|
||||
['markdown'] = { 'md', 'markdown', 'mkd', 'mkdn', 'mkdown', 'ron', },
|
||||
['modula-2'] = { 'mod', },
|
||||
['moonscript'] = { 'moon', },
|
||||
['ocaml'] = { 'ml', 'eliom', 'eliomi', 'ml4', 'mli', 'mll', 'mly', },
|
||||
['objective-c'] = { 'm', 'h', },
|
||||
['objective-c++'] = { 'mm', },
|
||||
['oz'] = { 'oz', },
|
||||
['php'] = { 'php', 'aw', 'ctp', 'fcgi', 'inc', 'php3', 'php4', 'php5', 'phps', 'phpt', },
|
||||
['plsql'] = { 'pls', 'pck', 'pkb', 'pks', 'plb', 'plsql', 'sql', },
|
||||
['plpgsql'] = { 'sql', },
|
||||
['pascal'] = { 'pas', 'dfm', 'dpr', 'inc', 'lpr', 'pp', },
|
||||
['perl'] = { 'pl', 'al', 'cgi', 'fcgi', 'perl', 'ph', 'plx', 'pm', 'pod', 'psgi', 't', },
|
||||
['perl6'] = { '6pl', '6pm', 'nqp', 'p6', 'p6l', 'p6m', 'pl', 'pl6', 'pm', 'pm6', 't', },
|
||||
['picolisp'] = { 'l', },
|
||||
['pike'] = { 'pike', 'pmod', },
|
||||
['pony'] = { 'pony', },
|
||||
['postscript'] = { 'ps', 'eps', },
|
||||
['powershell'] = { 'ps1', 'psd1', 'psm1', },
|
||||
['prolog'] = { 'pl', 'pro', 'prolog', 'yap', },
|
||||
['python'] = { 'py', 'bzl', 'cgi', 'fcgi', 'gyp', 'lmi', 'pyde', 'pyp', 'pyt', 'pyw', 'rpy', 'tac', 'wsgi', 'xpy', },
|
||||
['racket'] = { 'rkt', 'rktd', 'rktl', 'scrbl', },
|
||||
['rebol'] = { 'reb', 'r', 'r2', 'r3', 'rebol', },
|
||||
['ruby'] = { 'rb', 'builder', 'fcgi', 'gemspec', 'god', 'irbrc', 'jbuilder', 'mspec', 'pluginspec', 'podspec', 'rabl', 'rake', 'rbuild', 'rbw', 'rbx', 'ru', 'ruby', 'thor', 'watchr', },
|
||||
['rust'] = { 'rs', 'rs.in', },
|
||||
['scss'] = { 'scss', },
|
||||
['sql'] = { 'sql', 'cql', 'ddl', 'inc', 'prc', 'tab', 'udf', 'viw', },
|
||||
['sqlpl'] = { 'sql', 'db2', },
|
||||
['scala'] = { 'scala', 'sbt', 'sc', },
|
||||
['scheme'] = { 'scm', 'sld', 'sls', 'sps', 'ss', },
|
||||
['self'] = { 'self', },
|
||||
['shell'] = { 'sh', 'bash', 'bats', 'cgi', 'command', 'fcgi', 'ksh', 'sh.in', 'tmux', 'tool', 'zsh', },
|
||||
['smalltalk'] = { 'st', 'cs', },
|
||||
['standard ml'] = { 'ML', 'fun', 'sig', 'sml', },
|
||||
['swift'] = { 'swift', },
|
||||
['tcl'] = { 'tcl', 'adp', 'tm', },
|
||||
['tex'] = { 'tex', 'aux', 'bbx', 'bib', 'cbx', 'cls', 'dtx', 'ins', 'lbx', 'ltx', 'mkii', 'mkiv', 'mkvi', 'sty', 'toc', },
|
||||
['typescript'] = { 'ts', 'tsx', },
|
||||
['vala'] = { 'vala', 'vapi', },
|
||||
['verilog'] = { 'v', 'veo', },
|
||||
['visual basic'] = { 'vb', 'bas', 'cls', 'frm', 'frx', 'vba', 'vbhtml', 'vbs', },
|
||||
}
|
||||
|
||||
extensions.cpp = extensions['c++']
|
||||
extensions.csharp = extensions['c#']
|
||||
extensions.latex = extensions.tex
|
||||
extensions.objc = extensions['objective-c']
|
||||
|
||||
M.extensions = extensions
|
||||
|
||||
return M
|
||||
Loading…
Add table
Add a link
Reference in a new issue