non-working checkpoint
This commit is contained in:
123
lua/plugins/filetree.lua
Normal file
123
lua/plugins/filetree.lua
Normal file
@@ -0,0 +1,123 @@
|
||||
local function my_on_attach(bufnr)
|
||||
local api = require('nvim-tree.api')
|
||||
local opts = { buffer = bufnr }
|
||||
|
||||
-- basics: copy/cut/paste/create/rename/remove
|
||||
vim.keymap.set('n', 'c', api.fs.copy.node, opts)
|
||||
vim.keymap.set('n', 'x', api.fs.cut, opts)
|
||||
vim.keymap.set('n', 'p', api.fs.paste, opts)
|
||||
vim.keymap.set('n', 'a', api.fs.create, opts)
|
||||
vim.keymap.set('n', 'r', api.fs.rename, opts)
|
||||
vim.keymap.set('n', 'R', api.fs.rename_basename, opts)
|
||||
vim.keymap.set('n', 'd', api.fs.remove, opts)
|
||||
|
||||
-- bulk mark and delete/move
|
||||
vim.keymap.set('n', 's', api.marks.toggle, opts)
|
||||
vim.keymap.set('n', 'S', api.marks.clear, opts)
|
||||
vim.keymap.set('n', 'bd', api.marks.bulk.delete, opts)
|
||||
vim.keymap.set('n', 'bm', api.marks.bulk.move, opts)
|
||||
|
||||
-- copy filename/path
|
||||
vim.keymap.set('n', 'y', api.fs.copy.filename, opts)
|
||||
vim.keymap.set('n', 'Y', api.fs.copy.relative_path, opts)
|
||||
vim.keymap.set('n', 'gy', api.fs.copy.absolute_path, opts)
|
||||
vim.keymap.set('n', 'ge', api.fs.copy.basename, opts)
|
||||
|
||||
-- expand/collapse
|
||||
vim.keymap.set('n', 'e', api.tree.expand_all, opts)
|
||||
vim.keymap.set('n', 'E', api.tree.collapse_all, opts)
|
||||
|
||||
-- filter
|
||||
vim.keymap.set('n', 'f', api.live_filter.start, opts)
|
||||
vim.keymap.set('n', 'F', api.live_filter.clear, opts)
|
||||
|
||||
-- navigate
|
||||
vim.keymap.set('n', 'J', api.node.navigate.sibling.last, opts)
|
||||
vim.keymap.set('n', 'K', api.node.navigate.sibling.first, opts)
|
||||
vim.keymap.set('n', 'P', api.node.navigate.parent, opts)
|
||||
|
||||
-- open
|
||||
vim.keymap.set('n', '<CR>', api.node.open.edit, opts)
|
||||
vim.keymap.set('n', 'o', api.node.open.edit, opts)
|
||||
vim.keymap.set('n', 'O', api.node.open.no_window_picker, opts)
|
||||
|
||||
-- miscellaneous
|
||||
vim.keymap.set('n', 'K', api.node.show_info_popup, opts)
|
||||
vim.keymap.set('n', 'U', api.tree.reload, opts)
|
||||
end
|
||||
|
||||
require('nvim-tree').setup({
|
||||
on_attach = my_on_attach,
|
||||
view = { signcolumn = 'no' },
|
||||
actions = { file_popup = { open_win_config = { border = 'rounded' } } },
|
||||
renderer = {
|
||||
root_folder_label = false,
|
||||
special_files = {},
|
||||
|
||||
highlight_hidden = 'all',
|
||||
highlight_clipboard = 'all',
|
||||
|
||||
indent_markers = {
|
||||
enable = true,
|
||||
inline_arrows = false,
|
||||
icons = { corner = '│', none = '│', bottom = ' ' },
|
||||
},
|
||||
icons = {
|
||||
bookmarks_placement = 'after',
|
||||
git_placement = 'after',
|
||||
show = {
|
||||
file = false,
|
||||
folder = false,
|
||||
folder_arrow = false,
|
||||
git = true,
|
||||
modified = false,
|
||||
hidden = false,
|
||||
diagnostics = false,
|
||||
bookmarks = true,
|
||||
},
|
||||
glyphs = {
|
||||
git = {
|
||||
unstaged = '◇',
|
||||
staged = '',
|
||||
unmerged = '',
|
||||
renamed = '',
|
||||
untracked = '',
|
||||
deleted = '',
|
||||
ignored = '',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
hijack_cursor = true,
|
||||
prefer_startup_root = true,
|
||||
update_focused_file = {
|
||||
enable = true,
|
||||
update_root = { enable = true, ignore_list = {} },
|
||||
exclude = false,
|
||||
},
|
||||
modified = { enable = true, show_on_dirs = true, show_on_open_dirs = true },
|
||||
filters = {
|
||||
enable = true,
|
||||
git_ignored = true,
|
||||
dotfiles = false,
|
||||
git_clean = false,
|
||||
no_buffer = false,
|
||||
no_bookmark = false,
|
||||
custom = {},
|
||||
exclude = {},
|
||||
},
|
||||
filesystem_watchers = {
|
||||
enable = true,
|
||||
debounce_delay = 50,
|
||||
ignore_dirs = {
|
||||
'/.git',
|
||||
'/.DS_Store',
|
||||
'/build',
|
||||
'/dist',
|
||||
'/public',
|
||||
'/node_modules',
|
||||
'/target',
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -1,24 +1,16 @@
|
||||
--[[
|
||||
local lm = require('language_manager')
|
||||
lm.install() or .install({'ts_parsers','language_servers','linters','formatters'})
|
||||
- treesitter.install specs.ts_parsers
|
||||
- mason.install mason-registry.get_package(name):install()
|
||||
lm.generate_specs() or {use_cache=true, only_installed=true}
|
||||
lm.delete_cache()
|
||||
lm.enable()
|
||||
--]]
|
||||
|
||||
|
||||
vim.pack.add({ 'https://github.com/mason-org/mason.nvim' })
|
||||
|
||||
local M = {}
|
||||
M.lsp = {}
|
||||
M.ts = {}
|
||||
M.lint = {}
|
||||
M.format = {}
|
||||
local M = {
|
||||
lsp = {},
|
||||
ts = {},
|
||||
lint = {},
|
||||
format = {},
|
||||
}
|
||||
|
||||
M.group = vim.api.nvim_create_augroup('language-manager', { clear = true })
|
||||
|
||||
-- ======== Helpers ========
|
||||
|
||||
local cache_path = vim.fn.stdpath('cache') .. '/language-manager.json'
|
||||
|
||||
local function wrap(item)
|
||||
if type(item) == 'string' then
|
||||
return { item }
|
||||
@@ -31,7 +23,7 @@ end
|
||||
|
||||
local function create_set()
|
||||
local seen = {}
|
||||
return function(ref, item) -- unique()
|
||||
return function(ref, item)
|
||||
if not seen[ref] then
|
||||
seen[ref] = {}
|
||||
end
|
||||
@@ -43,6 +35,69 @@ local function create_set()
|
||||
end
|
||||
end
|
||||
|
||||
local function read_file(path)
|
||||
local f = io.open(path, 'r')
|
||||
if not f then
|
||||
return nil
|
||||
end
|
||||
local content = f:read('*a')
|
||||
f:close()
|
||||
return content
|
||||
end
|
||||
|
||||
local function write_file(path, content)
|
||||
local f = io.open(path, 'w')
|
||||
if not f then
|
||||
return false
|
||||
end
|
||||
f:write(content)
|
||||
f:close()
|
||||
return true
|
||||
end
|
||||
|
||||
local function to_json(tbl)
|
||||
local ok, result = pcall(vim.json.encode, tbl)
|
||||
return ok and result or nil
|
||||
end
|
||||
|
||||
local function from_json(str)
|
||||
local ok, result = pcall(vim.json.decode, str)
|
||||
return ok and result or nil
|
||||
end
|
||||
|
||||
local function hash_spec(tbl)
|
||||
local encoded = to_json(tbl) or ''
|
||||
if vim.fn.exists('*sha256') == 1 then
|
||||
return vim.fn.sha256(encoded)
|
||||
else
|
||||
local tmp = vim.fn.tempname()
|
||||
write_file(tmp, encoded)
|
||||
local handle = io.popen('openssl dgst -sha256 ' .. tmp)
|
||||
local result = handle and handle:read('*a') or ''
|
||||
if handle then
|
||||
handle:close()
|
||||
end
|
||||
return result:match('([a-f0-9]+)') or ''
|
||||
end
|
||||
end
|
||||
|
||||
local function save_cache(data)
|
||||
local encoded = to_json(data)
|
||||
if encoded then
|
||||
write_file(cache_path, encoded)
|
||||
end
|
||||
end
|
||||
|
||||
local function load_cache()
|
||||
local raw = read_file(cache_path)
|
||||
if not raw then
|
||||
return nil
|
||||
end
|
||||
return from_json(raw)
|
||||
end
|
||||
|
||||
-- ======== Spec Builder ========
|
||||
|
||||
local function create_spec()
|
||||
local S = {}
|
||||
local unique = create_set()
|
||||
@@ -64,20 +119,15 @@ local function create_spec()
|
||||
|
||||
for i = 1, last_i do
|
||||
local group = groups[i]
|
||||
|
||||
if i == last_i then
|
||||
for _, item in ipairs(wrap(list)) do
|
||||
if unique(ref, item) then
|
||||
if not pointer[group] then
|
||||
pointer[group] = {}
|
||||
end
|
||||
pointer[group] = pointer[group] or {}
|
||||
table.insert(pointer[group], item)
|
||||
end
|
||||
end
|
||||
else
|
||||
if not pointer[group] then
|
||||
pointer[group] = {}
|
||||
end
|
||||
pointer[group] = pointer[group] or {}
|
||||
pointer = pointer[group]
|
||||
end
|
||||
end
|
||||
@@ -86,47 +136,189 @@ local function create_spec()
|
||||
return S
|
||||
end
|
||||
|
||||
-- ======== Spec Generation ========
|
||||
|
||||
function M.generate_specs(specs_raw)
|
||||
local install_spec = create_spec()
|
||||
local specs = create_spec()
|
||||
|
||||
-- ensure Mason is available
|
||||
vim.cmd.packadd('mason.nvim')
|
||||
require('mason').setup()
|
||||
local registry = require('mason-registry')
|
||||
|
||||
local lsp_map = {}
|
||||
|
||||
for _, spec in ipairs(specs_raw) do
|
||||
-- <filetype> -> { ft = <filetype> }
|
||||
if type(spec) == 'string' then
|
||||
spec = { ft = spec }
|
||||
end
|
||||
|
||||
-- Filetype = TS Parser
|
||||
if not spec.ts then
|
||||
spec.ts = spec.ft
|
||||
end
|
||||
|
||||
spec.ts = spec.ts or spec.ft
|
||||
specs.add(spec.ts, 'ts_parsers')
|
||||
specs.add(spec.lsp, 'language_servers')
|
||||
|
||||
for _, filetype in ipairs(wrap(spec.ft)) do
|
||||
specs.add(spec.lint, 'linters_by_ft', filetype)
|
||||
specs.add(spec.format, 'formatters_by_ft', filetype)
|
||||
-- resolve LSP name using Mason registry
|
||||
install_spec.add(spec.lsp, 'language_servers')
|
||||
local resolved_lsps = {}
|
||||
for _, lsp in ipairs(wrap(spec.lsp)) do
|
||||
if registry.has_package(lsp) then
|
||||
local pkg = registry.get_package(lsp)
|
||||
local lspconfig = pkg.spec and pkg.spec.neovim and pkg.spec.neovim.lspconfig or lsp
|
||||
table.insert(resolved_lsps, lspconfig)
|
||||
lsp_map[lspconfig] = lsp
|
||||
else
|
||||
vim.notify('Unknown LSP: ' .. lsp, vim.log.levels.WARN)
|
||||
end
|
||||
end
|
||||
specs.add(resolved_lsps, 'language_servers')
|
||||
|
||||
install_spec.add(spec.lint, 'code_tools')
|
||||
install_spec.add(spec.format, 'code_tools')
|
||||
for _, ft in ipairs(wrap(spec.ft)) do
|
||||
specs.add(spec.lint, 'linters_by_ft', ft)
|
||||
specs.add(spec.format, 'formatters_by_ft', ft)
|
||||
end
|
||||
end
|
||||
|
||||
M.general = specs.get()
|
||||
return M.general
|
||||
local result = specs.get()
|
||||
result.lsp_map = lsp_map
|
||||
return result, install_spec.get()
|
||||
end
|
||||
|
||||
-- ======== Cache Interface ========
|
||||
|
||||
function M.load_or_generate(specs_raw)
|
||||
local hash = hash_spec(specs_raw)
|
||||
local cache = load_cache()
|
||||
if cache and cache.hash == hash then
|
||||
M.general = cache.spec
|
||||
else
|
||||
M.general, M.mason = M.generate_specs(specs_raw)
|
||||
save_cache({ hash = hash, spec = M.general })
|
||||
end
|
||||
return M.general, M.mason
|
||||
end
|
||||
|
||||
function M.load_specs()
|
||||
local cache = load_cache()
|
||||
if cache then
|
||||
M.general = cache.spec
|
||||
else
|
||||
local specs_raw = require('modules.language-specs').get()
|
||||
local hash = hash_spec(specs_raw)
|
||||
M.general, M.mason = M.generate_specs(specs_raw)
|
||||
save_cache({ hash = hash, spec = M.general })
|
||||
end
|
||||
return M.general, M.mason
|
||||
end
|
||||
|
||||
function M.invalidate_cache()
|
||||
local ok = os.remove(cache_path)
|
||||
if ok then
|
||||
vim.notify('Language manager cache invalidated', vim.log.levels.INFO)
|
||||
else
|
||||
vim.notify('No cache to invalidate or failed to delete', vim.log.levels.WARN)
|
||||
end
|
||||
M.general = nil
|
||||
M.mason = nil
|
||||
end
|
||||
|
||||
-- ======== Setup Functions ========
|
||||
|
||||
local function on_ts_installed(parsers, cb)
|
||||
local info = require('nvim-treesitter.info')
|
||||
local timer = vim.loop.new_timer()
|
||||
timer:start(0, 500, vim.schedule_wrap(function()
|
||||
for _, lang in ipairs(parsers) do
|
||||
if not vim.tbl_contains(info.installed_parsers(), lang) then
|
||||
return
|
||||
end
|
||||
end
|
||||
timer:stop()
|
||||
timer:close()
|
||||
cb()
|
||||
end))
|
||||
end
|
||||
|
||||
function M.ts.install()
|
||||
local install = require('nvim-treesitter.install')
|
||||
local parsers = M.general.ts_parsers or {}
|
||||
install.ensure_installed(parsers) -- async
|
||||
return parsers
|
||||
end
|
||||
|
||||
-- ======== Orchestration ========
|
||||
|
||||
function M.install()
|
||||
local parsers = M.ts.install()
|
||||
on_ts_installed(parsers, function()
|
||||
M.mason_install()
|
||||
end)
|
||||
end
|
||||
|
||||
local function ensure_registry_ready()
|
||||
local registry = require('mason-registry')
|
||||
if not registry.is_installed() then
|
||||
registry.update()
|
||||
vim.wait(10000, function()
|
||||
return registry.is_installed()
|
||||
end, 200)
|
||||
end
|
||||
return registry
|
||||
end
|
||||
|
||||
function M.mason_install()
|
||||
vim.cmd.packadd('mason.nvim')
|
||||
require('mason').setup()
|
||||
local registry = ensure_registry_ready()
|
||||
local list = vim.list_extend(M.mason.language_servers, M.mason.code_tools)
|
||||
print(vim.inspect(list))
|
||||
|
||||
local function install_and_wait(name)
|
||||
local pkg = registry.get_package(name)
|
||||
if pkg:is_installed() then
|
||||
vim.notify('Already installed ' .. name, vim.log.levels.INFO)
|
||||
return
|
||||
end
|
||||
|
||||
vim.notify('Installing ' .. name, vim.log.levels.INFO)
|
||||
local done = false
|
||||
pkg:install():once('closed', function()
|
||||
done = true
|
||||
end)
|
||||
|
||||
local ok = vim.wait(60 * 60 * 1000, function()
|
||||
return done or pkg:is_installed()
|
||||
end, 200)
|
||||
|
||||
if not ok or not pkg:is_installed() then
|
||||
vim.notify('Install failed: ' .. name, vim.log.levels.ERROR)
|
||||
else
|
||||
vim.notify('Installed ' .. name, vim.log.levels.INFO)
|
||||
end
|
||||
end
|
||||
|
||||
for _, name in ipairs(list) do
|
||||
if registry.has_package(name) then
|
||||
install_and_wait(name)
|
||||
else
|
||||
vim.notify('Package not found in registry: ' .. name, vim.log.levels.WARN)
|
||||
end
|
||||
end
|
||||
|
||||
-- force event loop to process any pending Mason async teardown
|
||||
local settled = false
|
||||
vim.defer_fn(function()
|
||||
settled = true
|
||||
end, 3000)
|
||||
vim.wait(10 * 1000, function()
|
||||
return settled
|
||||
end, 100)
|
||||
end
|
||||
|
||||
function M.lsp.setup()
|
||||
require('mason').setup()
|
||||
local registry = require('mason-registry')
|
||||
|
||||
for _, lsp in ipairs(M.general.language_servers) do
|
||||
if registry.has_package(lsp) then
|
||||
local pkg = registry.get_package(lsp)
|
||||
local spec = pkg.spec and pkg.spec.neovim
|
||||
local lsp_name = (spec and spec.lspconfig) or lsp
|
||||
|
||||
vim.lsp.enable(lsp_name)
|
||||
else
|
||||
vim.notify('Unknown LSP: ' .. lsp, vim.log.levels.WARN)
|
||||
end
|
||||
for _, lsp_name in ipairs(M.general.language_servers or {}) do
|
||||
vim.lsp.enable(lsp_name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -142,7 +334,7 @@ function M.lint.setup()
|
||||
group = M.group,
|
||||
callback = function()
|
||||
local lint = require('lint')
|
||||
lint.linters_by_ft = M.general.linters_by_ft
|
||||
lint.linters_by_ft = M.general.linters_by_ft or {}
|
||||
vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost', 'InsertLeave' }, {
|
||||
group = vim.api.nvim_create_augroup('language-manager.lint', { clear = true }),
|
||||
callback = function()
|
||||
@@ -161,10 +353,18 @@ function M.format.setup()
|
||||
require('conform').setup({
|
||||
format_on_save = { timeout_ms = 500, lsp_format = 'fallback' },
|
||||
default_format_opts = { stop_after_first = true },
|
||||
formatters_by_ft = M.general.formatters_by_ft,
|
||||
formatters_by_ft = M.general.formatters_by_ft or {},
|
||||
})
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
function M.setup()
|
||||
M.load_specs()
|
||||
M.ts.setup()
|
||||
M.lsp.setup()
|
||||
M.lint.setup()
|
||||
M.format.setup()
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -76,8 +76,8 @@ function M.tabline()
|
||||
end
|
||||
|
||||
function M.setup()
|
||||
vim.o.showtabline = 1
|
||||
vim.o.tabline = "%!v:lua.require'plugins.tabline'.tabline()"
|
||||
vim.opt.showtabline = 1
|
||||
vim.opt.tabline = "%!v:lua.require'plugins.tabline'.tabline()"
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
Reference in New Issue
Block a user