diff --git a/config/nvim/lua/config/canola.lua b/config/nvim/lua/config/canola.lua new file mode 100644 index 0000000..39fad1f --- /dev/null +++ b/config/nvim/lua/config/canola.lua @@ -0,0 +1,145 @@ +local M = {} + +local globals_configured = false +local integrations_configured = false + +local ns = vim.api.nvim_create_namespace("canola_git_trailing") +local symbols = { + M = { "M", "DiagnosticWarn" }, + A = { "A", "DiagnosticOk" }, + D = { "D", "DiagnosticError" }, + R = { "R", "DiagnosticWarn" }, + ["?"] = { "?", "DiagnosticInfo" }, + ["!"] = { "!", "Comment" }, +} + +local function apply_git_status(buf) + if not vim.api.nvim_buf_is_valid(buf) then return end + vim.api.nvim_buf_clear_namespace(buf, ns, 0, -1) + + local ok, canola = pcall(require, "canola") + if not ok then return end + + local dir = canola.get_current_dir(buf) + if not dir then return end + + local git_ok, git = pcall(require, "canola-git") + if not git_ok then return end + + local dir_cache = git._cache[dir] + if not dir_cache or not dir_cache.status then return end + + local lines = vim.api.nvim_buf_line_count(buf) + for lnum = 0, lines - 1 do + local entry = canola.get_entry_on_line(buf, lnum + 1) + if entry then + local status = dir_cache.status[entry.name] + if status then + local ch = status:sub(1, 1) + if ch == " " then ch = status:sub(2, 2) end + local sym = symbols[ch] + if sym then + vim.api.nvim_buf_set_extmark(buf, ns, lnum, 0, { + virt_text = { { " " .. sym[1], sym[2] } }, + virt_text_pos = "eol", + invalidate = true, + }) + end + end + end + end +end + +function M.setup_globals() + if globals_configured then return end + globals_configured = true + + pcall(vim.cmd.packadd, "nvim-web-devicons") + pcall(vim.cmd.packadd, "nonicons.nvim") + + vim.g.canola = { + columns = { "icon" }, + hidden = { enabled = false }, + highlights = { filename = {}, columns = true }, + save = "auto", + extglob = true, + delete = { wipe = false, recursive = true }, + float = { border = "single" }, + keymaps = { + ["g?"] = { callback = "actions.show_help", mode = "n" }, + [""] = "actions.select", + [""] = { callback = "actions.select", opts = { vertical = true } }, + [""] = { callback = "actions.select", opts = { horizontal = true } }, + [""] = "actions.preview", + [""] = { callback = "actions.close", mode = "n" }, + ["-"] = { callback = "actions.parent", mode = "n" }, + ["g."] = { callback = "actions.toggle_hidden", mode = "n" }, + [""] = false, + }, + } +end + +function M.setup_integrations() + if integrations_configured then return end + integrations_configured = true + + vim.cmd.packadd("canola-collection") + + local augroup = vim.api.nvim_create_augroup("UserCanolaConfig", { clear = true }) + local detail_columns = { "git_status", "permissions", "owner", "size", "mtime" } + local base_columns = vim.deepcopy((vim.g.canola or {}).columns or {}) + local show_all = false + + vim.api.nvim_create_autocmd("FileType", { + group = augroup, + pattern = "canola", + callback = function(args) + local bufnr = args.buf + + vim.keymap.set("n", "gC", function() + show_all = not show_all + require("canola").set_columns(show_all and detail_columns or base_columns) + end, { + buffer = bufnr, + desc = "toggle canola columns", + }) + + vim.keymap.set("n", "gX", function() + local canola = require("canola") + local entry = canola.get_cursor_entry() + local dir = canola.get_current_dir() + if not entry or not dir then return end + + vim.ui.input({ prompt = "chmod: ", default = "755" }, function(mode) + if not mode then return end + + vim.uv.fs_chmod(dir .. entry.name, tonumber(mode, 8), function(err) + if err then + vim.schedule(function() vim.notify(err, vim.log.levels.ERROR) end) + return + end + + vim.schedule(function() require("canola.actions").refresh.callback() end) + end) + end) + end, { + buffer = bufnr, + desc = "chmod entry", + }) + end, + }) + + vim.api.nvim_create_autocmd("User", { + group = augroup, + pattern = "CanolaReadPost", + callback = function(args) + local buf = args.data and args.data.buf or args.buf + if not buf then return end + + apply_git_status(buf) + vim.defer_fn(function() apply_git_status(buf) end, 500) + end, + }) +end + +return M diff --git a/config/nvim/lua/plugins/oil.lua b/config/nvim/lua/plugins/oil.lua index 0e03e08..6bc972a 100644 --- a/config/nvim/lua/plugins/oil.lua +++ b/config/nvim/lua/plugins/oil.lua @@ -3,139 +3,14 @@ vim.pack.add({ "https://github.com/barrettruth/canola-collection", }, { load = function() end }) -local ns = vim.api.nvim_create_namespace("canola_git_trailing") -local symbols = { - M = { "M", "DiagnosticWarn" }, - A = { "A", "DiagnosticOk" }, - D = { "D", "DiagnosticError" }, - R = { "R", "DiagnosticWarn" }, - ["?"] = { "?", "DiagnosticInfo" }, - ["!"] = { "!", "Comment" }, -} - -local function apply_git_status(buf) - if not vim.api.nvim_buf_is_valid(buf) then return end - vim.api.nvim_buf_clear_namespace(buf, ns, 0, -1) - - local ok, canola = pcall(require, "canola") - if not ok then return end - - local dir = canola.get_current_dir(buf) - if not dir then return end - - local git_ok, git = pcall(require, "canola-git") - if not git_ok then return end - - local dir_cache = git._cache[dir] - if not dir_cache or not dir_cache.status then return end - - local lines = vim.api.nvim_buf_line_count(buf) - for lnum = 0, lines - 1 do - local entry = canola.get_entry_on_line(buf, lnum + 1) - if entry then - local status = dir_cache.status[entry.name] - if status then - local ch = status:sub(1, 1) - if ch == " " then ch = status:sub(2, 2) end - local sym = symbols[ch] - if sym then - vim.api.nvim_buf_set_extmark(buf, ns, lnum, 0, { - virt_text = { { " " .. sym[1], sym[2] } }, - virt_text_pos = "eol", - invalidate = true, - }) - end - end - end - end -end +local canola_config = require("config.canola") return { { "barrettruth/canola.nvim", cmd = "Canola", - before = function() - pcall(vim.cmd.packadd, "nvim-web-devicons") - pcall(vim.cmd.packadd, "nonicons.nvim") - - vim.g.canola = { - columns = { "icon" }, - hidden = { enabled = false }, - highlights = { filename = {}, columns = true }, - save = "auto", - extglob = true, - delete = { wipe = false, recursive = true }, - float = { border = "single" }, - keymaps = { - ["g?"] = { callback = "actions.show_help", mode = "n" }, - [""] = "actions.select", - [""] = { callback = "actions.select", opts = { vertical = true } }, - [""] = { callback = "actions.select", opts = { horizontal = true } }, - [""] = "actions.preview", - [""] = { callback = "actions.close", mode = "n" }, - ["-"] = { callback = "actions.parent", mode = "n" }, - ["g."] = { callback = "actions.toggle_hidden", mode = "n" }, - [""] = false, - }, - } - end, - after = function() - vim.cmd.packadd("canola-collection") - - local augroup = vim.api.nvim_create_augroup("UserCanolaConfig", { clear = true }) - local detail_columns = { "git_status", "permissions", "owner", "size", "mtime" } - local base_columns = vim.deepcopy(vim.g.canola.columns or {}) - local show_all = false - - vim.api.nvim_create_autocmd("FileType", { - group = augroup, - pattern = "canola", - callback = function(args) - local bufnr = args.buf - - vim.keymap.set("n", "gC", function() - show_all = not show_all - require("canola").set_columns(show_all and detail_columns or base_columns) - end, { - buffer = bufnr, - desc = "toggle canola columns", - }) - - vim.keymap.set("n", "gX", function() - local canola = require("canola") - local entry = canola.get_cursor_entry() - local dir = canola.get_current_dir() - if not entry or not dir then return end - - vim.ui.input({ prompt = "chmod: ", default = "755" }, function(mode) - if not mode then return end - - vim.uv.fs_chmod(dir .. entry.name, tonumber(mode, 8), function(err) - if err then - vim.schedule(function() vim.notify(err, vim.log.levels.ERROR) end) - return - end - - vim.schedule(function() require("canola.actions").refresh.callback() end) - end) - end) - end, { - buffer = bufnr, - desc = "chmod entry", - }) - end, - }) - - vim.api.nvim_create_autocmd("User", { - group = augroup, - pattern = "CanolaReadPost", - callback = function(args) - local buf = args.buf - apply_git_status(buf) - vim.defer_fn(function() apply_git_status(buf) end, 500) - end, - }) - end, + before = canola_config.setup_globals, + after = canola_config.setup_integrations, keys = { { "-", "Canola" }, { "e", "Canola" }, diff --git a/config/nvim/plugin/autocmds.lua b/config/nvim/plugin/autocmds.lua index a5b0110..be0315a 100644 --- a/config/nvim/plugin/autocmds.lua +++ b/config/nvim/plugin/autocmds.lua @@ -1,11 +1,29 @@ local api = vim.api local augroup = api.nvim_create_augroup("UserAutocmds", { clear = true }) +local function ensure_canola_loaded() + local canola_config = require("config.canola") + canola_config.setup_globals() + + local ok_lz, lz = pcall(require, "lz.n") + if ok_lz then + -- Loading the raw package skips the lz.n hooks that apply the user's + -- canola config and packadd canola-collection. + pcall(lz.trigger_load, "barrettruth/canola.nvim") + end + + if vim.fn.exists(":Canola") ~= 2 then + pcall(vim.cmd.packadd, "canola.nvim") + end + + canola_config.setup_integrations() +end + local function maybe_load_canola(bufnr) local name = api.nvim_buf_get_name(bufnr) if name == "" or vim.bo[bufnr].filetype == "canola" or vim.fn.isdirectory(name) == 0 then return end - pcall(vim.cmd.packadd, "canola.nvim") + ensure_canola_loaded() pcall(vim.cmd, "silent keepalt Canola " .. vim.fn.fnameescape(name)) end