Merge branch 'master' of ssh://git@git.john.me.tz:223/jpm/.dotfiles.git
Conflicts: bash/bashrc.host sway/autostart
This commit is contained in:
commit
914a95d622
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
## Configure static SSH Agent
|
## Configure static SSH Agent
|
||||||
export SSH_AUTH_SOCK="$HOME/.spool/ssh-agent.sock"
|
export SSH_AUTH_SOCK="$HOME/.spool/ssh-agent.sock"
|
||||||
if [ -e $SSH_AUTH_SOCK ]; then
|
if [ -e "$SSH_AUTH_SOCK" ]; then
|
||||||
rm $SSH_AUTH_SOCK
|
rm "$SSH_AUTH_SOCK"
|
||||||
fi
|
fi
|
||||||
if [ -e "$HOME/.spool/ssh-agent.env" ]; then
|
if [ -e "$HOME/.spool/ssh-agent.env" ]; then
|
||||||
rm "$HOME/.spool/ssh-agent.env"
|
rm "$HOME/.spool/ssh-agent.env"
|
||||||
|
@ -11,7 +11,7 @@ fi
|
||||||
if [[ "$(pgrep ssh-agent)" ]]; then
|
if [[ "$(pgrep ssh-agent)" ]]; then
|
||||||
pkill ssh-agent
|
pkill ssh-agent
|
||||||
fi
|
fi
|
||||||
. "$HOME/scripts/ssh-agent.sh"
|
. ${HOME}/scripts/ssh-agent.sh
|
||||||
|
|
||||||
# Static/predictable Sway socket
|
# Static/predictable Sway socket
|
||||||
export SWAYSOCK="$HOME/.spool/sway-ipc.sock"
|
export SWAYSOCK="$HOME/.spool/sway-ipc.sock"
|
||||||
|
|
|
@ -1,18 +1,8 @@
|
||||||
# vim: ft=sh
|
# vim: ft=sh
|
||||||
|
|
||||||
export TERMINAL="alacritty"
|
# Setup editor
|
||||||
export EDITOR="flatpak run io.neovim.nvim"
|
export EDITOR="flatpak run io.neovim.nvim"
|
||||||
|
|
||||||
export SSH_AUTH_SOCK="$HOME/.spool/ssh-agent.sock"
|
export SSH_AUTH_SOCK="$HOME/.spool/ssh-agent.sock"
|
||||||
if [ -z "$SSH_AGENT_PID" ]; then
|
|
||||||
if [ -f "$HOME/.spool/ssh-agent.env" ]; then
|
|
||||||
source "$HOME/.spool/ssh-agent.env" >/dev/null
|
|
||||||
else
|
|
||||||
if [ ! -f "$SSH_AUTH_SOCK" ]; then
|
|
||||||
touch "$SSH_AUTH_SOCK"
|
|
||||||
fi
|
|
||||||
$HOME/scripts/ssh-agent.sh
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "This is the host OS. You probably want to open a Distrobox."
|
echo "This is the host OS. You probably want to open a Distrobox."
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
local impatient_ok, impatient = pcall(require, "impatient")
|
||||||
|
if impatient_ok then impatient.enable_profile() end
|
||||||
|
|
||||||
|
for _, source in ipairs {
|
||||||
|
"core.utils",
|
||||||
|
"core.options",
|
||||||
|
"core.bootstrap",
|
||||||
|
"core.diagnostics",
|
||||||
|
"core.autocmds",
|
||||||
|
"core.mappings",
|
||||||
|
"configs.which-key-register",
|
||||||
|
} do
|
||||||
|
local status_ok, fault = pcall(require, source)
|
||||||
|
if not status_ok then vim.api.nvim_err_writeln("Failed to load " .. source .. "\n\n" .. fault) end
|
||||||
|
end
|
||||||
|
|
||||||
|
astronvim.conditional_func(astronvim.user_plugin_opts("polish", nil, false))
|
||||||
|
|
||||||
|
if vim.fn.has "nvim-0.8" ~= 1 or vim.version().prerelease then
|
||||||
|
vim.schedule(function() astronvim.notify("Unsupported Neovim Version! Please check the requirements", "error") end)
|
||||||
|
end
|
|
@ -0,0 +1,194 @@
|
||||||
|
let plug_install = 0
|
||||||
|
let autoload_plug_path = stdpath('config') . '/autoload/plug.vim'
|
||||||
|
if !filereadable(autoload_plug_path)
|
||||||
|
silent exe '!curl -fL --create-dirs -o ' . autoload_plug_path .
|
||||||
|
\ ' https://raw.github.com/junegunn/vim-plug/master/plug.vim'
|
||||||
|
execute 'source ' . fnameescape(autoload_plug_path)
|
||||||
|
let plug_install = 1
|
||||||
|
endif
|
||||||
|
unlet autoload_plug_path
|
||||||
|
|
||||||
|
call plug#begin('~/.dotfiles/nvim/plugins')
|
||||||
|
" Plugins here
|
||||||
|
|
||||||
|
" LSP - Language Server Protocol
|
||||||
|
" Plug 'neovim/nvim-lspconfig'
|
||||||
|
Plug 'hrsh7th/cmp-nvim-lsp'
|
||||||
|
Plug 'hrsh7th/cmp-buffer'
|
||||||
|
Plug 'hrsh7th/cmp-path'
|
||||||
|
Plug 'hrsh7th/cmp-cmdline'
|
||||||
|
Plug 'hrsh7th/nvim-cmp'
|
||||||
|
" TreeSitter - Syntax highlighting
|
||||||
|
Plug 'nvim-treesitter/nvim-treesitter', {'do': ':TSUpdate'}
|
||||||
|
" Fold-Cycle - Better management of foldable blocks
|
||||||
|
Plug 'jghauser/fold-cycle.nvim'
|
||||||
|
" Git Gutter - Git diff markers
|
||||||
|
Plug 'airblade/vim-gitgutter'
|
||||||
|
" Lightline - lightweight status/tabline beautification
|
||||||
|
Plug 'itchyny/lightline.vim'
|
||||||
|
" Nerdtree - Tree explorer
|
||||||
|
Plug 'preservim/nerdtree'
|
||||||
|
" Conqueror of Completion
|
||||||
|
Plug 'neoclide/coc.nvim', {'branch': 'release'}
|
||||||
|
Plug 'bmeneg/coc-perl', {'do': 'yarn install && yarn build'}
|
||||||
|
" Dart lsp
|
||||||
|
Plug 'dart-lang/dart-vim-plugin'
|
||||||
|
|
||||||
|
call plug#end()
|
||||||
|
|
||||||
|
let g:coc_global_extensions = ['coc-json', 'coc-html', 'coc-python', 'coc-php', 'coc-perl', 'coc-flutter', 'coc-git']
|
||||||
|
if plug_install
|
||||||
|
PlugInstall --sync
|
||||||
|
endif
|
||||||
|
unlet plug_install
|
||||||
|
|
||||||
|
source $HOME/.dotfiles/vim/generic
|
||||||
|
|
||||||
|
lua <<EOF
|
||||||
|
require'nvim-treesitter.configs'.setup {
|
||||||
|
ensure_installed = {
|
||||||
|
"bash",
|
||||||
|
"c",
|
||||||
|
"cmake",
|
||||||
|
"cpp",
|
||||||
|
"css",
|
||||||
|
"dart",
|
||||||
|
"html",
|
||||||
|
"javascript",
|
||||||
|
"json",
|
||||||
|
"lua",
|
||||||
|
"make",
|
||||||
|
"markdown",
|
||||||
|
"perl",
|
||||||
|
"php",
|
||||||
|
"rasi",
|
||||||
|
"vim",
|
||||||
|
"yaml",
|
||||||
|
},
|
||||||
|
-- Install languages synchronously (only applied to `ensure_installed`)
|
||||||
|
sync_install = true,
|
||||||
|
-- List of parsers to ignore installing
|
||||||
|
ignore_install = { },
|
||||||
|
highlight = {
|
||||||
|
-- `false` will disable the whole extension
|
||||||
|
enable = true,
|
||||||
|
-- list of language that will be disabled
|
||||||
|
disable = { "" },
|
||||||
|
-- Setting this to true will run `:h syntax` and tree-sitter at the same time.
|
||||||
|
-- Set this to `true` if you depend on 'syntax' being enabled (like for indentation).
|
||||||
|
-- Using this option may slow down your editor, and you may see some duplicate highlights.
|
||||||
|
-- Instead of true it can also be a list of languages
|
||||||
|
additional_vim_regex_highlighting = false,
|
||||||
|
},
|
||||||
|
indent = {
|
||||||
|
-- dont enable this, messes up python indentation
|
||||||
|
enable = false,
|
||||||
|
disable = {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
-- local nvim_lsp = require('lspconfig')
|
||||||
|
local on_attach = function(client, bufnr)
|
||||||
|
local function buf_set_keymap(...)
|
||||||
|
vim.api.nvim_buf_set_keymap(bufnr, ...)
|
||||||
|
end
|
||||||
|
local function buf_set_option(...)
|
||||||
|
vim.api.nvim_buf_set_option(bufnr, ...)
|
||||||
|
end
|
||||||
|
buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')
|
||||||
|
-- Mappings
|
||||||
|
local opts = { noremap=true, silent=false }
|
||||||
|
local opts2 = { focusable = false,
|
||||||
|
close_events = { "BufLeave", "CursorMoved", "InsertEnter", "FocusLost" },
|
||||||
|
border = 'rounded',
|
||||||
|
source = 'always', -- show source in diagnostic popup window
|
||||||
|
prefix = ' '}
|
||||||
|
buf_set_keymap('n', 'gD', '<Cmd>lua vim.lsp.buf.declaration()<CR>', opts)
|
||||||
|
buf_set_keymap('n', 'gd', '<Cmd>tab split | lua vim.lsp.buf.definition()<CR>', opts)
|
||||||
|
buf_set_keymap('n', 'K', '<Cmd>lua vim.lsp.buf.hover()<CR>', opts)
|
||||||
|
buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
|
||||||
|
buf_set_keymap('n', '<leader>t', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
|
||||||
|
buf_set_keymap('n', '<leader>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
|
||||||
|
buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
|
||||||
|
buf_set_keymap('n', '<leader>e', '<cmd>lua vim.diagnostic.open_float(0, {{opts2}, scope="line", border="rounded"})<CR>', opts)
|
||||||
|
buf_set_keymap('n', '[d', '<cmd>lua vim.diagnostic.goto_prev({ float = { border = "rounded" }})<CR>', opts)
|
||||||
|
buf_set_keymap('n', ']d', '<cmd>lua vim.diagnostic.goto_next({ float = { border = "rounded" }})<CR>', opts)
|
||||||
|
buf_set_keymap("n", "<leader>q", "<cmd>lua vim.diagnostic.setloclist({open = true})<CR>", opts)
|
||||||
|
-- Set some keybinds conditional on server capabilities
|
||||||
|
if client.resolved_capabilities.document_formatting then
|
||||||
|
buf_set_keymap("n", "<leader>lf", "<cmd>lua vim.lsp.buf.formatting()<CR>", opts)
|
||||||
|
end
|
||||||
|
if client.resolved_capabilities.document_range_formatting then
|
||||||
|
buf_set_keymap("n", "<leader>lf", "<cmd>lua vim.lsp.buf.formatting()<CR>", opts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- NOTE: Don't use more than 1 servers otherwise nvim is unstable
|
||||||
|
local capabilities = vim.lsp.protocol.make_client_capabilities()
|
||||||
|
capabilities = require('cmp_nvim_lsp').update_capabilities(capabilities)
|
||||||
|
capabilities.textDocument.completion.completionItem.snippetSupport = true
|
||||||
|
-- Use pylsp
|
||||||
|
-- nvim_lsp.pylsp.setup({
|
||||||
|
-- on_attach = on_attach,
|
||||||
|
-- settings = {
|
||||||
|
-- pylsp = {
|
||||||
|
-- plugins = {
|
||||||
|
-- pylint = { enabled = true, executable = "pylint" },
|
||||||
|
-- pyflakes = { enabled = true },
|
||||||
|
-- pycodestyle = { enabled = false },
|
||||||
|
-- jedi_completion = { fuzzy = true },
|
||||||
|
-- pyls_isort = { enabled = true },
|
||||||
|
-- pylsp_mypy = { enabled = true },
|
||||||
|
-- },
|
||||||
|
-- }, },
|
||||||
|
-- flags = {
|
||||||
|
-- debounce_text_changes = 200,
|
||||||
|
-- },
|
||||||
|
-- capabilities = capabilities,
|
||||||
|
-- })
|
||||||
|
-- Use pyright or jedi_language_server
|
||||||
|
--local servers = {'jedi_language_server'}
|
||||||
|
--local servers = {'pyright'}
|
||||||
|
--for _, lsp in ipairs(servers) do
|
||||||
|
-- nvim_lsp[lsp].setup({
|
||||||
|
-- on_attach = on_attach,
|
||||||
|
-- capabilities = capabilities
|
||||||
|
--})
|
||||||
|
--end
|
||||||
|
-- Change diagnostic signs.
|
||||||
|
vim.fn.sign_define("DiagnosticSignError", { text = "✗", texthl = "DiagnosticSignError" })
|
||||||
|
vim.fn.sign_define("DiagnosticSignWarn", { text = "!", texthl = "DiagnosticSignWarn" })
|
||||||
|
vim.fn.sign_define("DiagnosticSignInformation", { text = "", texthl = "DiagnosticSignInfo" })
|
||||||
|
vim.fn.sign_define("DiagnosticSignHint", { text = "", texthl = "DiagnosticSignHint" })
|
||||||
|
-- global config for diagnostic
|
||||||
|
vim.diagnostic.config({
|
||||||
|
underline = false,
|
||||||
|
virtual_text = true,
|
||||||
|
signs = true,
|
||||||
|
severity_sort = true,
|
||||||
|
})
|
||||||
|
-- Change border of documentation hover window, See https://github.com/neovim/neovim/pull/13998.
|
||||||
|
vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, {
|
||||||
|
border = "rounded",
|
||||||
|
})
|
||||||
|
|
||||||
|
-- require'lspconfig'.perlpls.setup()
|
||||||
|
|
||||||
|
require('fold-cycle').setup({
|
||||||
|
open_if_closed = true,
|
||||||
|
close_if_opened = true,
|
||||||
|
softwrap_movement_fix = true,
|
||||||
|
})
|
||||||
|
vim.keymap.set('n', '<tab>',
|
||||||
|
function() return require('fold-cycle').open() end,
|
||||||
|
{silent = true, desc = 'Fold-cycle: open folds'})
|
||||||
|
vim.keymap.set('n', '<s-tab>',
|
||||||
|
function() return require('fold-cycle').close() end,
|
||||||
|
{silent = true, desc = 'Fold-cycle: close folds'})
|
||||||
|
vim.keymap.set('n', 'zC',
|
||||||
|
function() return require('fold-cycle').close_all() end,
|
||||||
|
{remap = true, silent = true, desc = 'Fold-cycle: close all folds'})
|
||||||
|
EOF
|
||||||
|
|
||||||
|
set foldmethod=expr
|
||||||
|
set cursorline
|
||||||
|
set foldexpr=nvim_treesitter#foldexpr()
|
|
@ -0,0 +1,16 @@
|
||||||
|
local utils = require "Comment.utils"
|
||||||
|
require("Comment").setup(astronvim.user_plugin_opts("plugins.Comment", {
|
||||||
|
pre_hook = function(ctx)
|
||||||
|
local location = nil
|
||||||
|
if ctx.ctype == utils.ctype.blockwise then
|
||||||
|
location = require("ts_context_commentstring.utils").get_cursor_location()
|
||||||
|
elseif ctx.cmotion == utils.cmotion.v or ctx.cmotion == utils.cmotion.V then
|
||||||
|
location = require("ts_context_commentstring.utils").get_visual_start_location()
|
||||||
|
end
|
||||||
|
|
||||||
|
return require("ts_context_commentstring.internal").calculate_commentstring {
|
||||||
|
key = ctx.ctype == utils.ctype.linewise and "__default" or "__multiline",
|
||||||
|
location = location,
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
}))
|
|
@ -0,0 +1,25 @@
|
||||||
|
require("aerial").setup(astronvim.user_plugin_opts("plugins.aerial", {
|
||||||
|
attach_mode = "global",
|
||||||
|
backends = { "lsp", "treesitter", "markdown", "man" },
|
||||||
|
layout = {
|
||||||
|
min_width = 28,
|
||||||
|
},
|
||||||
|
show_guides = true,
|
||||||
|
filter_kind = false,
|
||||||
|
guides = {
|
||||||
|
mid_item = "├ ",
|
||||||
|
last_item = "└ ",
|
||||||
|
nested_top = "│ ",
|
||||||
|
whitespace = " ",
|
||||||
|
},
|
||||||
|
keymaps = {
|
||||||
|
["[y"] = "actions.prev",
|
||||||
|
["]y"] = "actions.next",
|
||||||
|
["[Y"] = "actions.prev_up",
|
||||||
|
["]Y"] = "actions.next_up",
|
||||||
|
["{"] = false,
|
||||||
|
["}"] = false,
|
||||||
|
["[["] = false,
|
||||||
|
["]]"] = false,
|
||||||
|
},
|
||||||
|
}))
|
|
@ -0,0 +1,36 @@
|
||||||
|
require("alpha").setup(astronvim.user_plugin_opts("plugins.alpha", {
|
||||||
|
layout = {
|
||||||
|
{ type = "padding", val = vim.fn.max { 2, vim.fn.floor(vim.fn.winheight(0) * 0.2) } },
|
||||||
|
{
|
||||||
|
type = "text",
|
||||||
|
val = astronvim.user_plugin_opts("header", {
|
||||||
|
" █████ ███████ ████████ ██████ ██████",
|
||||||
|
"██ ██ ██ ██ ██ ██ ██ ██",
|
||||||
|
"███████ ███████ ██ ██████ ██ ██",
|
||||||
|
"██ ██ ██ ██ ██ ██ ██ ██",
|
||||||
|
"██ ██ ███████ ██ ██ ██ ██████",
|
||||||
|
" ",
|
||||||
|
" ███ ██ ██ ██ ██ ███ ███",
|
||||||
|
" ████ ██ ██ ██ ██ ████ ████",
|
||||||
|
" ██ ██ ██ ██ ██ ██ ██ ████ ██",
|
||||||
|
" ██ ██ ██ ██ ██ ██ ██ ██ ██",
|
||||||
|
" ██ ████ ████ ██ ██ ██",
|
||||||
|
}, false),
|
||||||
|
opts = { position = "center", hl = "DashboardHeader" },
|
||||||
|
},
|
||||||
|
{ type = "padding", val = 5 },
|
||||||
|
{
|
||||||
|
type = "group",
|
||||||
|
val = {
|
||||||
|
astronvim.alpha_button("LDR f F", " Find File "),
|
||||||
|
astronvim.alpha_button("LDR f o", " Recents "),
|
||||||
|
astronvim.alpha_button("LDR f w", " Find Word "),
|
||||||
|
astronvim.alpha_button("LDR f n", " New File "),
|
||||||
|
astronvim.alpha_button("LDR f m", " Bookmarks "),
|
||||||
|
astronvim.alpha_button("LDR S l", " Last Session "),
|
||||||
|
},
|
||||||
|
opts = { spacing = 1 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
opts = { noautocmd = true },
|
||||||
|
}))
|
|
@ -0,0 +1,28 @@
|
||||||
|
local npairs = require "nvim-autopairs"
|
||||||
|
npairs.setup(astronvim.user_plugin_opts("plugins.nvim-autopairs", {
|
||||||
|
check_ts = true,
|
||||||
|
ts_config = { java = false },
|
||||||
|
fast_wrap = {
|
||||||
|
map = "<M-e>",
|
||||||
|
chars = { "{", "[", "(", '"', "'" },
|
||||||
|
pattern = string.gsub([[ [%'%"%)%>%]%)%}%,] ]], "%s+", ""),
|
||||||
|
offset = 0,
|
||||||
|
end_key = "$",
|
||||||
|
keys = "qwertyuiopzxcvbnmasdfghjkl",
|
||||||
|
check_comma = true,
|
||||||
|
highlight = "PmenuSel",
|
||||||
|
highlight_grey = "LineNr",
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
if not vim.g.autopairs_enabled then npairs.disable() end
|
||||||
|
|
||||||
|
local rules = astronvim.user_plugin_opts("nvim-autopairs").add_rules
|
||||||
|
if vim.tbl_contains({ "function", "table" }, type(rules)) then
|
||||||
|
npairs.add_rules(type(rules) == "function" and rules(npairs) or rules)
|
||||||
|
end
|
||||||
|
|
||||||
|
local cmp_status_ok, cmp = pcall(require, "cmp")
|
||||||
|
if cmp_status_ok then
|
||||||
|
cmp.event:on("confirm_done", require("nvim-autopairs.completion.cmp").on_confirm_done { tex = false })
|
||||||
|
end
|
|
@ -0,0 +1 @@
|
||||||
|
require("better_escape").setup(astronvim.user_plugin_opts "plugins.better_escape")
|
|
@ -0,0 +1,36 @@
|
||||||
|
local close_func = function(bufnum)
|
||||||
|
local bufdelete_avail, bufdelete = pcall(require, "bufdelete")
|
||||||
|
if bufdelete_avail then
|
||||||
|
bufdelete.bufdelete(bufnum, true)
|
||||||
|
else
|
||||||
|
vim.cmd.bdelete { args = { bufnum }, bang = true }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
require("bufferline").setup(astronvim.user_plugin_opts("plugins.bufferline", {
|
||||||
|
options = {
|
||||||
|
offsets = {
|
||||||
|
{ filetype = "NvimTree", text = "", padding = 1 },
|
||||||
|
{ filetype = "neo-tree", text = "", padding = 1 },
|
||||||
|
{ filetype = "Outline", text = "", padding = 1 },
|
||||||
|
},
|
||||||
|
buffer_close_icon = astronvim.get_icon "BufferClose",
|
||||||
|
modified_icon = astronvim.get_icon "FileModified",
|
||||||
|
close_icon = astronvim.get_icon "NeovimClose",
|
||||||
|
close_command = close_func,
|
||||||
|
right_mouse_command = close_func,
|
||||||
|
max_name_length = 14,
|
||||||
|
max_prefix_length = 13,
|
||||||
|
tab_size = 20,
|
||||||
|
separator_style = "thin",
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
local highlights = require "bufferline.highlights"
|
||||||
|
vim.api.nvim_create_autocmd("User", {
|
||||||
|
pattern = "AstroColorScheme",
|
||||||
|
group = "BufferlineCmds",
|
||||||
|
desc = "Bufferline apply colors after astronvim colorscheme change",
|
||||||
|
callback = function()
|
||||||
|
highlights.reset_icon_hl_cache()
|
||||||
|
highlights.set_all(require("bufferline.config").update_highlights())
|
||||||
|
end,
|
||||||
|
})
|
|
@ -0,0 +1,92 @@
|
||||||
|
local cmp = require "cmp"
|
||||||
|
local snip_status_ok, luasnip = pcall(require, "luasnip")
|
||||||
|
local lspkind_status_ok, lspkind = pcall(require, "lspkind")
|
||||||
|
if not snip_status_ok then return end
|
||||||
|
local setup = cmp.setup
|
||||||
|
local border_opts =
|
||||||
|
{ border = "single", winhighlight = "Normal:Normal,FloatBorder:FloatBorder,CursorLine:Visual,Search:None" }
|
||||||
|
|
||||||
|
local function has_words_before()
|
||||||
|
local line, col = unpack(vim.api.nvim_win_get_cursor(0))
|
||||||
|
return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match "%s" == nil
|
||||||
|
end
|
||||||
|
|
||||||
|
setup(astronvim.user_plugin_opts("plugins.cmp", {
|
||||||
|
enabled = function()
|
||||||
|
if vim.api.nvim_buf_get_option(0, "buftype") == "prompt" then return false end
|
||||||
|
return vim.g.cmp_enabled
|
||||||
|
end,
|
||||||
|
preselect = cmp.PreselectMode.None,
|
||||||
|
formatting = {
|
||||||
|
fields = { "kind", "abbr", "menu" },
|
||||||
|
format = lspkind_status_ok and lspkind.cmp_format(astronvim.lspkind) or nil,
|
||||||
|
},
|
||||||
|
snippet = {
|
||||||
|
expand = function(args) luasnip.lsp_expand(args.body) end,
|
||||||
|
},
|
||||||
|
duplicates = {
|
||||||
|
nvim_lsp = 1,
|
||||||
|
luasnip = 1,
|
||||||
|
cmp_tabnine = 1,
|
||||||
|
buffer = 1,
|
||||||
|
path = 1,
|
||||||
|
},
|
||||||
|
confirm_opts = {
|
||||||
|
behavior = cmp.ConfirmBehavior.Replace,
|
||||||
|
select = false,
|
||||||
|
},
|
||||||
|
window = {
|
||||||
|
completion = cmp.config.window.bordered(border_opts),
|
||||||
|
documentation = cmp.config.window.bordered(border_opts),
|
||||||
|
},
|
||||||
|
mapping = {
|
||||||
|
["<Up>"] = cmp.mapping.select_prev_item { behavior = cmp.SelectBehavior.Select },
|
||||||
|
["<Down>"] = cmp.mapping.select_next_item { behavior = cmp.SelectBehavior.Select },
|
||||||
|
["<C-p>"] = cmp.mapping.select_prev_item { behavior = cmp.SelectBehavior.Insert },
|
||||||
|
["<C-n>"] = cmp.mapping.select_next_item { behavior = cmp.SelectBehavior.Insert },
|
||||||
|
["<C-k>"] = cmp.mapping.select_prev_item { behavior = cmp.SelectBehavior.Insert },
|
||||||
|
["<C-j>"] = cmp.mapping.select_next_item { behavior = cmp.SelectBehavior.Insert },
|
||||||
|
["<C-d>"] = cmp.mapping(cmp.mapping.scroll_docs(-1), { "i", "c" }),
|
||||||
|
["<C-f>"] = cmp.mapping(cmp.mapping.scroll_docs(1), { "i", "c" }),
|
||||||
|
["<C-Space>"] = cmp.mapping(cmp.mapping.complete(), { "i", "c" }),
|
||||||
|
["<C-y>"] = cmp.config.disable,
|
||||||
|
["<C-e>"] = cmp.mapping {
|
||||||
|
i = cmp.mapping.abort(),
|
||||||
|
c = cmp.mapping.close(),
|
||||||
|
},
|
||||||
|
["<CR>"] = cmp.mapping.confirm { select = false },
|
||||||
|
["<Tab>"] = cmp.mapping(function(fallback)
|
||||||
|
if cmp.visible() then
|
||||||
|
cmp.select_next_item()
|
||||||
|
elseif luasnip.expandable() then
|
||||||
|
luasnip.expand()
|
||||||
|
elseif luasnip.expand_or_jumpable() then
|
||||||
|
luasnip.expand_or_jump()
|
||||||
|
elseif has_words_before() then
|
||||||
|
cmp.complete()
|
||||||
|
else
|
||||||
|
fallback()
|
||||||
|
end
|
||||||
|
end, {
|
||||||
|
"i",
|
||||||
|
"s",
|
||||||
|
}),
|
||||||
|
["<S-Tab>"] = cmp.mapping(function(fallback)
|
||||||
|
if cmp.visible() then
|
||||||
|
cmp.select_prev_item()
|
||||||
|
elseif luasnip.jumpable(-1) then
|
||||||
|
luasnip.jump(-1)
|
||||||
|
else
|
||||||
|
fallback()
|
||||||
|
end
|
||||||
|
end, {
|
||||||
|
"i",
|
||||||
|
"s",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
for setup_opt, setup_table in pairs(astronvim.user_plugin_opts("cmp.setup", {})) do
|
||||||
|
for pattern, options in pairs(setup_table) do
|
||||||
|
setup[setup_opt](pattern, options)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,3 @@
|
||||||
|
require("colorizer").setup(
|
||||||
|
astronvim.user_plugin_opts("plugins.colorizer", { user_default_options = { names = false } })
|
||||||
|
)
|
|
@ -0,0 +1,3 @@
|
||||||
|
local dap = require "dap"
|
||||||
|
dap.adapters = astronvim.user_plugin_opts("dap.adapters", dap.adapters)
|
||||||
|
dap.configurations = astronvim.user_plugin_opts("dap.configurations", dap.configurations)
|
|
@ -0,0 +1,5 @@
|
||||||
|
local dap, dapui = require "dap", require "dapui"
|
||||||
|
dap.listeners.after.event_initialized["dapui_config"] = function() dapui.open() end
|
||||||
|
dap.listeners.before.event_terminated["dapui_config"] = function() dapui.close() end
|
||||||
|
dap.listeners.before.event_exited["dapui_config"] = function() dapui.close() end
|
||||||
|
dapui.setup(astronvim.user_plugin_opts("plugins.dapui", { floating = { border = "rounded" } }))
|
|
@ -0,0 +1,10 @@
|
||||||
|
require("dressing").setup(astronvim.user_plugin_opts("plugins.dressing", {
|
||||||
|
input = {
|
||||||
|
default_prompt = "➤ ",
|
||||||
|
win_options = { winhighlight = "Normal:Normal,NormalNC:Normal" },
|
||||||
|
},
|
||||||
|
select = {
|
||||||
|
backend = { "telescope", "builtin" },
|
||||||
|
builtin = { win_options = { winhighlight = "Normal:Normal,NormalNC:Normal" } },
|
||||||
|
},
|
||||||
|
}))
|
|
@ -0,0 +1,10 @@
|
||||||
|
require("gitsigns").setup(astronvim.user_plugin_opts("plugins.gitsigns", {
|
||||||
|
signs = {
|
||||||
|
add = { text = "▎" },
|
||||||
|
change = { text = "▎" },
|
||||||
|
delete = { text = "▎" },
|
||||||
|
topdelete = { text = "契" },
|
||||||
|
changedelete = { text = "▎" },
|
||||||
|
untracked = { text = "▎" },
|
||||||
|
},
|
||||||
|
}))
|
|
@ -0,0 +1,309 @@
|
||||||
|
local heirline = require "heirline"
|
||||||
|
if not astronvim.status then return end
|
||||||
|
local C = require "default_theme.colors"
|
||||||
|
|
||||||
|
local function setup_colors()
|
||||||
|
local Normal = astronvim.get_hlgroup("Normal", { fg = C.fg, bg = C.bg })
|
||||||
|
local Comment = astronvim.get_hlgroup("Comment", { fg = C.grey_2, bg = C.bg })
|
||||||
|
local Error = astronvim.get_hlgroup("Error", { fg = C.red, bg = C.bg })
|
||||||
|
local StatusLine = astronvim.get_hlgroup("StatusLine", { fg = C.fg, bg = C.grey_4 })
|
||||||
|
local TabLine = astronvim.get_hlgroup("TabLine", { fg = C.grey, bg = C.none })
|
||||||
|
local TabLineSel = astronvim.get_hlgroup("TabLineSel", { fg = C.fg, bg = C.none })
|
||||||
|
local WinBar = astronvim.get_hlgroup("WinBar", { fg = C.grey_2, bg = C.bg })
|
||||||
|
local WinBarNC = astronvim.get_hlgroup("WinBarNC", { fg = C.grey, bg = C.bg })
|
||||||
|
local Conditional = astronvim.get_hlgroup("Conditional", { fg = C.purple_1, bg = C.grey_4 })
|
||||||
|
local String = astronvim.get_hlgroup("String", { fg = C.green, bg = C.grey_4 })
|
||||||
|
local TypeDef = astronvim.get_hlgroup("TypeDef", { fg = C.yellow, bg = C.grey_4 })
|
||||||
|
local GitSignsAdd = astronvim.get_hlgroup("GitSignsAdd", { fg = C.green, bg = C.grey_4 })
|
||||||
|
local GitSignsChange = astronvim.get_hlgroup("GitSignsChange", { fg = C.orange_1, bg = C.grey_4 })
|
||||||
|
local GitSignsDelete = astronvim.get_hlgroup("GitSignsDelete", { fg = C.red_1, bg = C.grey_4 })
|
||||||
|
local DiagnosticError = astronvim.get_hlgroup("DiagnosticError", { fg = C.red_1, bg = C.grey_4 })
|
||||||
|
local DiagnosticWarn = astronvim.get_hlgroup("DiagnosticWarn", { fg = C.orange_1, bg = C.grey_4 })
|
||||||
|
local DiagnosticInfo = astronvim.get_hlgroup("DiagnosticInfo", { fg = C.white_2, bg = C.grey_4 })
|
||||||
|
local DiagnosticHint = astronvim.get_hlgroup("DiagnosticHint", { fg = C.yellow_1, bg = C.grey_4 })
|
||||||
|
local HeirlineInactive = astronvim.get_hlgroup("HeirlineInactive", { fg = nil }).fg
|
||||||
|
or astronvim.status.hl.lualine_mode("inactive", C.grey_7)
|
||||||
|
local HeirlineNormal = astronvim.get_hlgroup("HeirlineNormal", { fg = nil }).fg
|
||||||
|
or astronvim.status.hl.lualine_mode("normal", C.blue)
|
||||||
|
local HeirlineInsert = astronvim.get_hlgroup("HeirlineInsert", { fg = nil }).fg
|
||||||
|
or astronvim.status.hl.lualine_mode("insert", C.green)
|
||||||
|
local HeirlineVisual = astronvim.get_hlgroup("HeirlineVisual", { fg = nil }).fg
|
||||||
|
or astronvim.status.hl.lualine_mode("visual", C.purple)
|
||||||
|
local HeirlineReplace = astronvim.get_hlgroup("HeirlineReplace", { fg = nil }).fg
|
||||||
|
or astronvim.status.hl.lualine_mode("replace", C.red_1)
|
||||||
|
local HeirlineCommand = astronvim.get_hlgroup("HeirlineCommand", { fg = nil }).fg
|
||||||
|
or astronvim.status.hl.lualine_mode("command", C.yellow_1)
|
||||||
|
local HeirlineTerminal = astronvim.get_hlgroup("HeirlineTerminal", { fg = nil }).fg
|
||||||
|
or astronvim.status.hl.lualine_mode("inactive", HeirlineInsert)
|
||||||
|
|
||||||
|
local colors = astronvim.user_plugin_opts("heirline.colors", {
|
||||||
|
close_fg = Error.fg,
|
||||||
|
fg = StatusLine.fg,
|
||||||
|
bg = StatusLine.bg,
|
||||||
|
section_fg = StatusLine.fg,
|
||||||
|
section_bg = StatusLine.bg,
|
||||||
|
git_branch_fg = Conditional.fg,
|
||||||
|
mode_fg = StatusLine.bg,
|
||||||
|
treesitter_fg = String.fg,
|
||||||
|
scrollbar = TypeDef.fg,
|
||||||
|
git_added = GitSignsAdd.fg,
|
||||||
|
git_changed = GitSignsChange.fg,
|
||||||
|
git_removed = GitSignsDelete.fg,
|
||||||
|
diag_ERROR = DiagnosticError.fg,
|
||||||
|
diag_WARN = DiagnosticWarn.fg,
|
||||||
|
diag_INFO = DiagnosticInfo.fg,
|
||||||
|
diag_HINT = DiagnosticHint.fg,
|
||||||
|
winbar_fg = WinBar.fg,
|
||||||
|
winbar_bg = WinBar.bg,
|
||||||
|
winbarnc_fg = WinBarNC.fg,
|
||||||
|
winbarnc_bg = WinBarNC.bg,
|
||||||
|
tabline_bg = StatusLine.bg,
|
||||||
|
tabline_fg = StatusLine.bg,
|
||||||
|
buffer_fg = Comment.fg,
|
||||||
|
buffer_path_fg = WinBarNC.fg,
|
||||||
|
buffer_close_fg = Comment.fg,
|
||||||
|
buffer_bg = StatusLine.bg,
|
||||||
|
buffer_active_fg = Normal.fg,
|
||||||
|
buffer_active_path_fg = WinBarNC.fg,
|
||||||
|
buffer_active_close_fg = Error.fg,
|
||||||
|
buffer_active_bg = Normal.bg,
|
||||||
|
buffer_visible_fg = Normal.fg,
|
||||||
|
buffer_visible_path_fg = WinBarNC.fg,
|
||||||
|
buffer_visible_close_fg = Error.fg,
|
||||||
|
buffer_visible_bg = Normal.bg,
|
||||||
|
buffer_overflow_fg = Comment.fg,
|
||||||
|
buffer_overflow_bg = StatusLine.bg,
|
||||||
|
buffer_picker_fg = Error.fg,
|
||||||
|
tab_close_fg = Error.fg,
|
||||||
|
tab_close_bg = StatusLine.bg,
|
||||||
|
tab_fg = TabLine.fg,
|
||||||
|
tab_bg = TabLine.bg,
|
||||||
|
tab_active_fg = TabLineSel.fg,
|
||||||
|
tab_active_bg = TabLineSel.bg,
|
||||||
|
inactive = HeirlineInactive,
|
||||||
|
normal = HeirlineNormal,
|
||||||
|
insert = HeirlineInsert,
|
||||||
|
visual = HeirlineVisual,
|
||||||
|
replace = HeirlineReplace,
|
||||||
|
command = HeirlineCommand,
|
||||||
|
terminal = HeirlineTerminal,
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, section in ipairs {
|
||||||
|
"git_branch",
|
||||||
|
"file_info",
|
||||||
|
"git_diff",
|
||||||
|
"diagnostics",
|
||||||
|
"lsp",
|
||||||
|
"macro_recording",
|
||||||
|
"mode",
|
||||||
|
"cmd_info",
|
||||||
|
"treesitter",
|
||||||
|
"nav",
|
||||||
|
} do
|
||||||
|
if not colors[section .. "_bg"] then colors[section .. "_bg"] = colors["section_bg"] end
|
||||||
|
if not colors[section .. "_fg"] then colors[section .. "_fg"] = colors["section_fg"] end
|
||||||
|
end
|
||||||
|
return colors
|
||||||
|
end
|
||||||
|
|
||||||
|
--- a submodule of heirline specific functions and aliases
|
||||||
|
astronvim.status.heirline = {}
|
||||||
|
|
||||||
|
--- A helper function to get the type a tab or buffer is
|
||||||
|
-- @param self the self table from a heirline component function
|
||||||
|
-- @param prefix the prefix of the type, either "tab" or "buffer" (Default: "buffer")
|
||||||
|
-- @return the string of prefix with the type (i.e. "_active" or "_visible")
|
||||||
|
function astronvim.status.heirline.tab_type(self, prefix)
|
||||||
|
local tab_type = ""
|
||||||
|
if self.is_active then
|
||||||
|
tab_type = "_active"
|
||||||
|
elseif self.is_visible then
|
||||||
|
tab_type = "_visible"
|
||||||
|
end
|
||||||
|
return (prefix or "buffer") .. tab_type
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Make a list of buffers, rendering each buffer with the provided component
|
||||||
|
---@param component table
|
||||||
|
---@return table
|
||||||
|
astronvim.status.heirline.make_buflist = function(component)
|
||||||
|
local overflow_hl = astronvim.status.hl.get_attributes("buffer_overflow", true)
|
||||||
|
return require("heirline.utils").make_buflist(
|
||||||
|
astronvim.status.utils.surround(
|
||||||
|
"tab",
|
||||||
|
function(self)
|
||||||
|
return {
|
||||||
|
main = astronvim.status.heirline.tab_type(self) .. "_bg",
|
||||||
|
left = "tabline_bg",
|
||||||
|
right = "tabline_bg",
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
{ -- bufferlist
|
||||||
|
init = function(self) self.tab_type = astronvim.status.heirline.tab_type(self) end,
|
||||||
|
on_click = { -- add clickable component to each buffer
|
||||||
|
callback = function(_, minwid) vim.api.nvim_win_set_buf(0, minwid) end,
|
||||||
|
minwid = function(self) return self.bufnr end,
|
||||||
|
name = "heirline_tabline_buffer_callback",
|
||||||
|
},
|
||||||
|
{ -- add buffer picker functionality to each buffer
|
||||||
|
condition = function(self) return self._show_picker end,
|
||||||
|
update = false,
|
||||||
|
init = function(self)
|
||||||
|
local bufname = astronvim.status.provider.filename { fallback = "empty_file" }(self)
|
||||||
|
local label = bufname:sub(1, 1)
|
||||||
|
local i = 2
|
||||||
|
while label ~= " " and self._picker_labels[label] do
|
||||||
|
if i > #bufname then break end
|
||||||
|
label = bufname:sub(i, i)
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
self._picker_labels[label] = self.bufnr
|
||||||
|
self.label = label
|
||||||
|
end,
|
||||||
|
provider = function(self)
|
||||||
|
return astronvim.status.provider.str { str = self.label, padding = { left = 1, right = 1 } }
|
||||||
|
end,
|
||||||
|
hl = astronvim.status.hl.get_attributes "buffer_picker",
|
||||||
|
},
|
||||||
|
component, -- create buffer component
|
||||||
|
},
|
||||||
|
false -- disable surrounding
|
||||||
|
),
|
||||||
|
{ provider = astronvim.get_icon "ArrowLeft" .. " ", hl = overflow_hl },
|
||||||
|
{ provider = astronvim.get_icon "ArrowRight" .. " ", hl = overflow_hl },
|
||||||
|
function() return vim.t.bufs end, -- use astronvim bufs variable
|
||||||
|
false -- disable internal caching
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Alias to require("heirline.utils").make_tablist
|
||||||
|
astronvim.status.heirline.make_tablist = require("heirline.utils").make_tablist
|
||||||
|
|
||||||
|
--- Run the buffer picker and execute the callback function on the selected buffer
|
||||||
|
-- @param callback function with a single parameter of the buffer number
|
||||||
|
function astronvim.status.heirline.buffer_picker(callback)
|
||||||
|
local tabline = require("heirline").tabline
|
||||||
|
local buflist = tabline and tabline._buflist[1]
|
||||||
|
if buflist then
|
||||||
|
local prev_showtabline = vim.opt.showtabline
|
||||||
|
buflist._picker_labels = {}
|
||||||
|
buflist._show_picker = true
|
||||||
|
vim.opt.showtabline = 2
|
||||||
|
vim.cmd.redrawtabline()
|
||||||
|
local char = vim.fn.getcharstr()
|
||||||
|
local bufnr = buflist._picker_labels[char]
|
||||||
|
if bufnr then callback(bufnr) end
|
||||||
|
buflist._show_picker = false
|
||||||
|
vim.opt.showtabline = prev_showtabline
|
||||||
|
vim.cmd.redrawtabline()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
heirline.load_colors(setup_colors())
|
||||||
|
local heirline_opts = astronvim.user_plugin_opts("plugins.heirline", {
|
||||||
|
{ -- statusline
|
||||||
|
hl = { fg = "fg", bg = "bg" },
|
||||||
|
astronvim.status.component.mode(),
|
||||||
|
astronvim.status.component.git_branch(),
|
||||||
|
-- TODO: REMOVE THIS WITH v3
|
||||||
|
astronvim.status.component.file_info(
|
||||||
|
(astronvim.is_available "bufferline.nvim" or vim.g.heirline_bufferline)
|
||||||
|
and { filetype = {}, filename = false, file_modified = false }
|
||||||
|
or nil
|
||||||
|
),
|
||||||
|
-- astronvim.status.component.file_info { filetype = {}, filename = false, file_modified = false },
|
||||||
|
astronvim.status.component.git_diff(),
|
||||||
|
astronvim.status.component.diagnostics(),
|
||||||
|
astronvim.status.component.fill(),
|
||||||
|
astronvim.status.component.cmd_info(),
|
||||||
|
astronvim.status.component.fill(),
|
||||||
|
astronvim.status.component.lsp(),
|
||||||
|
astronvim.status.component.treesitter(),
|
||||||
|
astronvim.status.component.nav(),
|
||||||
|
astronvim.status.component.mode { surround = { separator = "right" } },
|
||||||
|
},
|
||||||
|
{ -- winbar
|
||||||
|
static = {
|
||||||
|
disabled = {
|
||||||
|
buftype = { "terminal", "prompt", "nofile", "help", "quickfix" },
|
||||||
|
filetype = { "NvimTree", "neo%-tree", "dashboard", "Outline", "aerial" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
init = function(self) self.bufnr = vim.api.nvim_get_current_buf() end,
|
||||||
|
fallthrough = false,
|
||||||
|
{
|
||||||
|
condition = function(self)
|
||||||
|
return vim.opt.diff:get() or astronvim.status.condition.buffer_matches(self.disabled or {})
|
||||||
|
end,
|
||||||
|
init = function() vim.opt_local.winbar = nil end,
|
||||||
|
},
|
||||||
|
astronvim.status.component.file_info {
|
||||||
|
condition = function() return not astronvim.status.condition.is_active() end,
|
||||||
|
unique_path = {},
|
||||||
|
file_icon = { hl = astronvim.status.hl.file_icon "winbar" },
|
||||||
|
file_modified = false,
|
||||||
|
file_read_only = false,
|
||||||
|
hl = astronvim.status.hl.get_attributes("winbarnc", true),
|
||||||
|
surround = false,
|
||||||
|
update = "BufEnter",
|
||||||
|
},
|
||||||
|
astronvim.status.component.breadcrumbs { hl = astronvim.status.hl.get_attributes("winbar", true) },
|
||||||
|
},
|
||||||
|
vim.g.heirline_bufferline -- TODO v3: remove this option and make bufferline default
|
||||||
|
and { -- bufferline
|
||||||
|
{ -- file tree padding
|
||||||
|
condition = function(self)
|
||||||
|
self.winid = vim.api.nvim_tabpage_list_wins(0)[1]
|
||||||
|
return astronvim.status.condition.buffer_matches(
|
||||||
|
{ filetype = { "neo%-tree", "NvimTree" } },
|
||||||
|
vim.api.nvim_win_get_buf(self.winid)
|
||||||
|
)
|
||||||
|
end,
|
||||||
|
provider = function(self) return string.rep(" ", vim.api.nvim_win_get_width(self.winid)) end,
|
||||||
|
hl = { bg = "tabline_bg" },
|
||||||
|
},
|
||||||
|
astronvim.status.heirline.make_buflist(astronvim.status.component.tabline_file_info()), -- component for each buffer tab
|
||||||
|
astronvim.status.component.fill { hl = { bg = "tabline_bg" } }, -- fill the rest of the tabline with background color
|
||||||
|
{ -- tab list
|
||||||
|
condition = function() return #vim.api.nvim_list_tabpages() >= 2 end, -- only show tabs if there are more than one
|
||||||
|
astronvim.status.heirline.make_tablist { -- component for each tab
|
||||||
|
provider = astronvim.status.provider.tabnr(),
|
||||||
|
hl = function(self)
|
||||||
|
return astronvim.status.hl.get_attributes(astronvim.status.heirline.tab_type(self, "tab"), true)
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
{ -- close button for current tab
|
||||||
|
provider = astronvim.status.provider.close_button { kind = "TabClose", padding = { left = 1, right = 1 } },
|
||||||
|
hl = astronvim.status.hl.get_attributes("tab_close", true),
|
||||||
|
on_click = { callback = astronvim.close_tab, name = "heirline_tabline_close_tab_callback" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
or nil,
|
||||||
|
})
|
||||||
|
heirline.setup(heirline_opts[1], heirline_opts[2], heirline_opts[3])
|
||||||
|
|
||||||
|
local augroup = vim.api.nvim_create_augroup("Heirline", { clear = true })
|
||||||
|
vim.api.nvim_create_autocmd("User", {
|
||||||
|
pattern = "AstroColorScheme",
|
||||||
|
group = augroup,
|
||||||
|
desc = "Refresh heirline colors",
|
||||||
|
callback = function() require("heirline.utils").on_colorscheme(setup_colors()) end,
|
||||||
|
})
|
||||||
|
vim.api.nvim_create_autocmd("User", {
|
||||||
|
pattern = "HeirlineInitWinbar",
|
||||||
|
group = augroup,
|
||||||
|
desc = "Disable winbar for some filetypes",
|
||||||
|
callback = function()
|
||||||
|
if
|
||||||
|
vim.opt.diff:get()
|
||||||
|
or astronvim.status.condition.buffer_matches(require("heirline").winbar.disabled or {
|
||||||
|
buftype = { "terminal", "prompt", "nofile", "help", "quickfix" },
|
||||||
|
filetype = { "NvimTree", "neo%-tree", "dashboard", "Outline", "aerial" },
|
||||||
|
}) -- TODO v3: remove the default fallback here
|
||||||
|
then
|
||||||
|
vim.opt_local.winbar = nil
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
|
@ -0,0 +1,45 @@
|
||||||
|
require("indent_blankline").setup(astronvim.user_plugin_opts("plugins.indent_blankline", {
|
||||||
|
buftype_exclude = {
|
||||||
|
"nofile",
|
||||||
|
"terminal",
|
||||||
|
},
|
||||||
|
filetype_exclude = {
|
||||||
|
"help",
|
||||||
|
"startify",
|
||||||
|
"aerial",
|
||||||
|
"alpha",
|
||||||
|
"dashboard",
|
||||||
|
"packer",
|
||||||
|
"neogitstatus",
|
||||||
|
"NvimTree",
|
||||||
|
"neo-tree",
|
||||||
|
"Trouble",
|
||||||
|
},
|
||||||
|
context_patterns = {
|
||||||
|
"class",
|
||||||
|
"return",
|
||||||
|
"function",
|
||||||
|
"method",
|
||||||
|
"^if",
|
||||||
|
"^while",
|
||||||
|
"jsx_element",
|
||||||
|
"^for",
|
||||||
|
"^object",
|
||||||
|
"^table",
|
||||||
|
"block",
|
||||||
|
"arguments",
|
||||||
|
"if_statement",
|
||||||
|
"else_clause",
|
||||||
|
"jsx_element",
|
||||||
|
"jsx_self_closing_element",
|
||||||
|
"try_statement",
|
||||||
|
"catch_clause",
|
||||||
|
"import_statement",
|
||||||
|
"operation_type",
|
||||||
|
},
|
||||||
|
show_trailing_blankline_indent = false,
|
||||||
|
use_treesitter = true,
|
||||||
|
char = "▏",
|
||||||
|
context_char = "▏",
|
||||||
|
show_current_context = true,
|
||||||
|
}))
|
|
@ -0,0 +1,3 @@
|
||||||
|
local indent_o_matic = require "indent-o-matic"
|
||||||
|
indent_o_matic.setup(astronvim.user_plugin_opts "plugins.indent-o-matic")
|
||||||
|
indent_o_matic.detect()
|
|
@ -0,0 +1,13 @@
|
||||||
|
if vim.g.lsp_handlers_enabled then
|
||||||
|
vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { border = "rounded" })
|
||||||
|
vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, { border = "rounded" })
|
||||||
|
end
|
||||||
|
local setup_servers = function()
|
||||||
|
vim.tbl_map(astronvim.lsp.setup, astronvim.user_plugin_opts "lsp.servers")
|
||||||
|
vim.cmd "silent! do FileType"
|
||||||
|
end
|
||||||
|
if astronvim.is_available "mason-lspconfig.nvim" then
|
||||||
|
vim.api.nvim_create_autocmd("User", { pattern = "AstroLspSetup", once = true, callback = setup_servers })
|
||||||
|
else
|
||||||
|
setup_servers()
|
||||||
|
end
|
|
@ -0,0 +1,23 @@
|
||||||
|
astronvim.lspkind = astronvim.user_plugin_opts("plugins.lspkind", {
|
||||||
|
mode = "symbol",
|
||||||
|
symbol_map = {
|
||||||
|
NONE = "",
|
||||||
|
Array = "",
|
||||||
|
Boolean = "⊨",
|
||||||
|
Class = "",
|
||||||
|
Constructor = "",
|
||||||
|
Key = "",
|
||||||
|
Namespace = "",
|
||||||
|
Null = "NULL",
|
||||||
|
Number = "#",
|
||||||
|
Object = "⦿",
|
||||||
|
Package = "",
|
||||||
|
Property = "",
|
||||||
|
Reference = "",
|
||||||
|
Snippet = "",
|
||||||
|
String = "𝓐",
|
||||||
|
TypeParameter = "",
|
||||||
|
Unit = "",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require("lspkind").init(astronvim.lspkind)
|
|
@ -0,0 +1,17 @@
|
||||||
|
local user_settings = astronvim.user_plugin_opts "luasnip"
|
||||||
|
local luasnip = require "luasnip"
|
||||||
|
if user_settings.config then luasnip.config.setup(user_settings.config) end
|
||||||
|
for _, load_type in ipairs { "vscode", "snipmate", "lua" } do
|
||||||
|
local loader = require("luasnip.loaders.from_" .. load_type)
|
||||||
|
loader.lazy_load()
|
||||||
|
-- TODO: DEPRECATE _snippet_paths option in next major version release
|
||||||
|
local paths = user_settings[load_type .. "_snippet_paths"]
|
||||||
|
if paths then loader.lazy_load { paths = paths } end
|
||||||
|
local loader_settings = user_settings[load_type]
|
||||||
|
if loader_settings then loader.lazy_load(loader_settings) end
|
||||||
|
end
|
||||||
|
if type(user_settings.filetype_extend) == "table" then
|
||||||
|
for filetype, snippets in pairs(user_settings.filetype_extend) do
|
||||||
|
luasnip.filetype_extend(filetype, snippets)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,6 @@
|
||||||
|
local mason_lspconfig = require "mason-lspconfig"
|
||||||
|
mason_lspconfig.setup(astronvim.user_plugin_opts "plugins.mason-lspconfig")
|
||||||
|
mason_lspconfig.setup_handlers(
|
||||||
|
astronvim.user_plugin_opts("mason-lspconfig.setup_handlers", { function(server) astronvim.lsp.setup(server) end })
|
||||||
|
)
|
||||||
|
astronvim.event "LspSetup"
|
|
@ -0,0 +1,3 @@
|
||||||
|
local mason_null_ls = require "mason-null-ls"
|
||||||
|
mason_null_ls.setup(astronvim.user_plugin_opts("plugins.mason-null-ls", { automatic_setup = true }))
|
||||||
|
mason_null_ls.setup_handlers(astronvim.user_plugin_opts("mason-null-ls.setup_handlers", {}))
|
|
@ -0,0 +1,3 @@
|
||||||
|
local mason_nvim_dap = require "mason-nvim-dap"
|
||||||
|
mason_nvim_dap.setup(astronvim.user_plugin_opts("plugins.mason-nvim-dap", { automatic_setup = true }))
|
||||||
|
mason_nvim_dap.setup_handlers(astronvim.user_plugin_opts("mason-nvim-dap.setup_handlers", {}))
|
|
@ -0,0 +1,13 @@
|
||||||
|
require("mason").setup(astronvim.user_plugin_opts("plugins.mason", {
|
||||||
|
ui = {
|
||||||
|
icons = {
|
||||||
|
package_installed = "✓",
|
||||||
|
package_uninstalled = "✗",
|
||||||
|
package_pending = "⟳",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
local cmd = vim.api.nvim_create_user_command
|
||||||
|
cmd("MasonUpdateAll", function() astronvim.mason.update_all() end, { desc = "Update Mason Packages" })
|
||||||
|
cmd("MasonUpdate", function(opts) astronvim.mason.update(opts.args) end, { nargs = 1, desc = "Update Mason Package" })
|
|
@ -0,0 +1,62 @@
|
||||||
|
require("neo-tree").setup(astronvim.user_plugin_opts("plugins.neo-tree", {
|
||||||
|
close_if_last_window = true,
|
||||||
|
enable_diagnostics = false,
|
||||||
|
source_selector = {
|
||||||
|
winbar = true,
|
||||||
|
content_layout = "center",
|
||||||
|
tab_labels = {
|
||||||
|
filesystem = astronvim.get_icon "FolderClosed" .. " File",
|
||||||
|
buffers = astronvim.get_icon "DefaultFile" .. " Bufs",
|
||||||
|
git_status = astronvim.get_icon "Git" .. " Git",
|
||||||
|
diagnostics = astronvim.get_icon "Diagnostic" .. " Diagnostic",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default_component_configs = {
|
||||||
|
indent = { padding = 0 },
|
||||||
|
icon = {
|
||||||
|
folder_closed = astronvim.get_icon "FolderClosed",
|
||||||
|
folder_open = astronvim.get_icon "FolderOpen",
|
||||||
|
folder_empty = astronvim.get_icon "FolderEmpty",
|
||||||
|
default = astronvim.get_icon "DefaultFile",
|
||||||
|
},
|
||||||
|
git_status = {
|
||||||
|
symbols = {
|
||||||
|
added = astronvim.get_icon "GitAdd",
|
||||||
|
deleted = astronvim.get_icon "GitDelete",
|
||||||
|
modified = astronvim.get_icon "GitChange",
|
||||||
|
renamed = astronvim.get_icon "GitRenamed",
|
||||||
|
untracked = astronvim.get_icon "GitUntracked",
|
||||||
|
ignored = astronvim.get_icon "GitIgnored",
|
||||||
|
unstaged = astronvim.get_icon "GitUnstaged",
|
||||||
|
staged = astronvim.get_icon "GitStaged",
|
||||||
|
conflict = astronvim.get_icon "GitConflict",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
window = {
|
||||||
|
width = 30,
|
||||||
|
mappings = {
|
||||||
|
["<space>"] = false, -- disable space until we figure out which-key disabling
|
||||||
|
o = "open",
|
||||||
|
H = "prev_source",
|
||||||
|
L = "next_source",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
filesystem = {
|
||||||
|
follow_current_file = true,
|
||||||
|
hijack_netrw_behavior = "open_current",
|
||||||
|
use_libuv_file_watcher = true,
|
||||||
|
window = {
|
||||||
|
mappings = {
|
||||||
|
O = "system_open",
|
||||||
|
h = "toggle_hidden",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
commands = {
|
||||||
|
system_open = function(state) astronvim.system_open(state.tree:get_node():get_id()) end,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
event_handlers = {
|
||||||
|
{ event = "neo_tree_buffer_enter", handler = function(_) vim.opt_local.signcolumn = "auto" end },
|
||||||
|
},
|
||||||
|
}))
|
|
@ -0,0 +1,3 @@
|
||||||
|
local notify = require "notify"
|
||||||
|
notify.setup(astronvim.user_plugin_opts("plugins.notify", { stages = "fade" }))
|
||||||
|
vim.notify = notify
|
|
@ -0,0 +1 @@
|
||||||
|
require("null-ls").setup(astronvim.user_plugin_opts("plugins.null-ls", { on_attach = astronvim.lsp.on_attach }))
|
|
@ -0,0 +1,15 @@
|
||||||
|
require("nvim-web-devicons").set_default_icon(astronvim.get_icon "DefaultFile", "#6d8086", "66")
|
||||||
|
require("nvim-web-devicons").set_icon(astronvim.user_plugin_opts("plugins.nvim-web-devicons", {
|
||||||
|
deb = { icon = "", name = "Deb" },
|
||||||
|
lock = { icon = "", name = "Lock" },
|
||||||
|
mp3 = { icon = "", name = "Mp3" },
|
||||||
|
mp4 = { icon = "", name = "Mp4" },
|
||||||
|
out = { icon = "", name = "Out" },
|
||||||
|
["robots.txt"] = { icon = "ﮧ", name = "Robots" },
|
||||||
|
ttf = { icon = "", name = "TrueTypeFont" },
|
||||||
|
rpm = { icon = "", name = "Rpm" },
|
||||||
|
woff = { icon = "", name = "WebOpenFontFormat" },
|
||||||
|
woff2 = { icon = "", name = "WebOpenFontFormat2" },
|
||||||
|
xz = { icon = "", name = "Xz" },
|
||||||
|
zip = { icon = "", name = "Zip" },
|
||||||
|
}))
|
|
@ -0,0 +1,8 @@
|
||||||
|
return {
|
||||||
|
settings = {
|
||||||
|
json = {
|
||||||
|
schemas = require("schemastore").json.schemas(),
|
||||||
|
validate = { enable = true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
return {
|
||||||
|
settings = {
|
||||||
|
Lua = {
|
||||||
|
telemetry = { enable = false },
|
||||||
|
runtime = { version = "LuaJIT" },
|
||||||
|
diagnostics = { globals = { "vim", "astronvim", "astronvim_installation", "packer_plugins", "bit" } },
|
||||||
|
workspace = {
|
||||||
|
library = {
|
||||||
|
vim.fn.expand "$VIMRUNTIME/lua",
|
||||||
|
astronvim.install.home .. "/lua",
|
||||||
|
astronvim.install.config .. "/lua",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
require("session_manager").setup(astronvim.user_plugin_opts "plugins.session_manager")
|
|
@ -0,0 +1,9 @@
|
||||||
|
require("smart-splits").setup(astronvim.user_plugin_opts("plugins.smart-splits", {
|
||||||
|
ignored_filetypes = {
|
||||||
|
"nofile",
|
||||||
|
"quickfix",
|
||||||
|
"qf",
|
||||||
|
"prompt",
|
||||||
|
},
|
||||||
|
ignored_buftypes = { "nofile" },
|
||||||
|
}))
|
|
@ -0,0 +1,38 @@
|
||||||
|
local telescope = require "telescope"
|
||||||
|
local actions = require "telescope.actions"
|
||||||
|
|
||||||
|
telescope.setup(astronvim.user_plugin_opts("plugins.telescope", {
|
||||||
|
defaults = {
|
||||||
|
|
||||||
|
prompt_prefix = string.format("%s ", astronvim.get_icon "Search"),
|
||||||
|
selection_caret = string.format("%s ", astronvim.get_icon "Selected"),
|
||||||
|
path_display = { "truncate" },
|
||||||
|
sorting_strategy = "ascending",
|
||||||
|
layout_config = {
|
||||||
|
horizontal = {
|
||||||
|
prompt_position = "top",
|
||||||
|
preview_width = 0.55,
|
||||||
|
results_width = 0.8,
|
||||||
|
},
|
||||||
|
vertical = {
|
||||||
|
mirror = false,
|
||||||
|
},
|
||||||
|
width = 0.87,
|
||||||
|
height = 0.80,
|
||||||
|
preview_cutoff = 120,
|
||||||
|
},
|
||||||
|
|
||||||
|
mappings = {
|
||||||
|
i = {
|
||||||
|
["<C-n>"] = actions.cycle_history_next,
|
||||||
|
["<C-p>"] = actions.cycle_history_prev,
|
||||||
|
["<C-j>"] = actions.move_selection_next,
|
||||||
|
["<C-k>"] = actions.move_selection_previous,
|
||||||
|
},
|
||||||
|
n = { ["q"] = actions.close },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
astronvim.conditional_func(telescope.load_extension, pcall(require, "notify"), "notify")
|
||||||
|
astronvim.conditional_func(telescope.load_extension, pcall(require, "aerial"), "aerial")
|
|
@ -0,0 +1,13 @@
|
||||||
|
require("toggleterm").setup(astronvim.user_plugin_opts("plugins.toggleterm", {
|
||||||
|
size = 10,
|
||||||
|
open_mapping = [[<F7>]],
|
||||||
|
shading_factor = 2,
|
||||||
|
direction = "float",
|
||||||
|
float_opts = {
|
||||||
|
border = "curved",
|
||||||
|
highlights = {
|
||||||
|
border = "Normal",
|
||||||
|
background = "Normal",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}))
|
|
@ -0,0 +1,19 @@
|
||||||
|
require("nvim-treesitter.configs").setup(astronvim.user_plugin_opts("plugins.treesitter", {
|
||||||
|
highlight = {
|
||||||
|
enable = true,
|
||||||
|
additional_vim_regex_highlighting = false,
|
||||||
|
},
|
||||||
|
context_commentstring = {
|
||||||
|
enable = true,
|
||||||
|
enable_autocmd = false,
|
||||||
|
},
|
||||||
|
rainbow = {
|
||||||
|
enable = true,
|
||||||
|
disable = { "html" },
|
||||||
|
extended_mode = false,
|
||||||
|
max_file_lines = nil,
|
||||||
|
},
|
||||||
|
autotag = { enable = true },
|
||||||
|
incremental_selection = { enable = true },
|
||||||
|
indent = { enable = false },
|
||||||
|
}))
|
|
@ -0,0 +1,55 @@
|
||||||
|
local is_available = astronvim.is_available
|
||||||
|
local user_plugin_opts = astronvim.user_plugin_opts
|
||||||
|
local mappings = {
|
||||||
|
n = {
|
||||||
|
["<leader>"] = {
|
||||||
|
f = { name = "File" },
|
||||||
|
p = { name = "Packages" },
|
||||||
|
l = { name = "LSP" },
|
||||||
|
u = { name = "UI" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local extra_sections = {
|
||||||
|
b = "Buffers",
|
||||||
|
D = "Debugger",
|
||||||
|
g = "Git",
|
||||||
|
s = "Search",
|
||||||
|
S = "Session",
|
||||||
|
t = "Terminal",
|
||||||
|
}
|
||||||
|
|
||||||
|
local function init_table(mode, prefix, idx)
|
||||||
|
if not mappings[mode][prefix][idx] then mappings[mode][prefix][idx] = { name = extra_sections[idx] } end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- TODO v3: remove vim.g.heirline_bufferline check
|
||||||
|
if is_available "heirline.nvim" and vim.g.heirline_bufferline then init_table("n", "<leader>", "b") end
|
||||||
|
|
||||||
|
if is_available "neovim-session-manager" then init_table("n", "<leader>", "S") end
|
||||||
|
|
||||||
|
if is_available "gitsigns.nvim" then init_table("n", "<leader>", "g") end
|
||||||
|
|
||||||
|
if is_available "toggleterm.nvim" then
|
||||||
|
init_table("n", "<leader>", "g")
|
||||||
|
init_table("n", "<leader>", "t")
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_available "telescope.nvim" then
|
||||||
|
init_table("n", "<leader>", "s")
|
||||||
|
init_table("n", "<leader>", "g")
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_available "nvim-dap" then init_table("n", "<leader>", "D") end
|
||||||
|
|
||||||
|
if is_available "Comment.nvim" then
|
||||||
|
for _, mode in ipairs { "n", "v" } do
|
||||||
|
if not mappings[mode] then mappings[mode] = {} end
|
||||||
|
if not mappings[mode].g then mappings[mode].g = {} end
|
||||||
|
mappings[mode].g.c = "Comment toggle linewise"
|
||||||
|
mappings[mode].g.b = "Comment toggle blockwise"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
astronvim.which_key_register(user_plugin_opts("which-key.register", mappings))
|
|
@ -0,0 +1,11 @@
|
||||||
|
require("which-key").setup(astronvim.user_plugin_opts("plugins.which-key", {
|
||||||
|
plugins = {
|
||||||
|
spelling = { enabled = true },
|
||||||
|
presets = { operators = false },
|
||||||
|
},
|
||||||
|
window = {
|
||||||
|
border = "rounded",
|
||||||
|
padding = { 2, 2, 2, 2 },
|
||||||
|
},
|
||||||
|
disable = { filetypes = { "TelescopePrompt" } },
|
||||||
|
}))
|
|
@ -0,0 +1,4 @@
|
||||||
|
local colors = require "default_theme.colors"
|
||||||
|
require("window-picker").setup(
|
||||||
|
astronvim.user_plugin_opts("plugins.window-picker", { use_winbar = "smart", other_win_hl_color = colors.grey_4 })
|
||||||
|
)
|
|
@ -0,0 +1,213 @@
|
||||||
|
local is_available = astronvim.is_available
|
||||||
|
local user_plugin_opts = astronvim.user_plugin_opts
|
||||||
|
local namespace = vim.api.nvim_create_namespace
|
||||||
|
local cmd = vim.api.nvim_create_autocmd
|
||||||
|
local augroup = vim.api.nvim_create_augroup
|
||||||
|
local create_command = vim.api.nvim_create_user_command
|
||||||
|
|
||||||
|
vim.on_key(function(char)
|
||||||
|
if vim.fn.mode() == "n" then
|
||||||
|
local new_hlsearch = vim.tbl_contains({ "<CR>", "n", "N", "*", "#", "?", "/" }, vim.fn.keytrans(char))
|
||||||
|
if vim.opt.hlsearch:get() ~= new_hlsearch then vim.opt.hlsearch = new_hlsearch end
|
||||||
|
end
|
||||||
|
end, namespace "auto_hlsearch")
|
||||||
|
|
||||||
|
if vim.g.heirline_bufferline then
|
||||||
|
local bufferline_group = augroup("bufferline", { clear = true })
|
||||||
|
cmd({ "BufAdd", "BufEnter" }, {
|
||||||
|
desc = "Update buffers when adding new buffers",
|
||||||
|
group = bufferline_group,
|
||||||
|
callback = function(args)
|
||||||
|
if not vim.t.bufs then vim.t.bufs = {} end
|
||||||
|
local bufs = vim.t.bufs
|
||||||
|
if not vim.tbl_contains(bufs, args.buf) then
|
||||||
|
table.insert(bufs, args.buf)
|
||||||
|
vim.t.bufs = bufs
|
||||||
|
end
|
||||||
|
vim.t.bufs = vim.tbl_filter(astronvim.is_valid_buffer, vim.t.bufs)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
cmd("BufDelete", {
|
||||||
|
desc = "Update buffers when deleting buffers",
|
||||||
|
group = bufferline_group,
|
||||||
|
callback = function(args)
|
||||||
|
for _, tab in ipairs(vim.api.nvim_list_tabpages()) do
|
||||||
|
local bufs = vim.t[tab].bufs
|
||||||
|
if bufs then
|
||||||
|
for i, bufnr in ipairs(bufs) do
|
||||||
|
if bufnr == args.buf then
|
||||||
|
table.remove(bufs, i)
|
||||||
|
vim.t[tab].bufs = bufs
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
vim.t.bufs = vim.tbl_filter(astronvim.is_valid_buffer, vim.t.bufs)
|
||||||
|
vim.cmd.redrawtabline()
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
cmd({ "VimEnter", "FileType", "BufEnter", "WinEnter" }, {
|
||||||
|
desc = "URL Highlighting",
|
||||||
|
group = augroup("highlighturl", { clear = true }),
|
||||||
|
pattern = "*",
|
||||||
|
callback = function() astronvim.set_url_match() end,
|
||||||
|
})
|
||||||
|
|
||||||
|
cmd("TextYankPost", {
|
||||||
|
desc = "Highlight yanked text",
|
||||||
|
group = augroup("highlightyank", { clear = true }),
|
||||||
|
pattern = "*",
|
||||||
|
callback = function() vim.highlight.on_yank() end,
|
||||||
|
})
|
||||||
|
|
||||||
|
cmd("FileType", {
|
||||||
|
desc = "Unlist quickfist buffers",
|
||||||
|
group = augroup("unlist_quickfist", { clear = true }),
|
||||||
|
pattern = "qf",
|
||||||
|
callback = function() vim.opt_local.buflisted = false end,
|
||||||
|
})
|
||||||
|
|
||||||
|
cmd("BufEnter", {
|
||||||
|
desc = "Quit AstroNvim if more than one window is open and only sidebar windows are list",
|
||||||
|
group = augroup("auto_quit", { clear = true }),
|
||||||
|
callback = function()
|
||||||
|
local wins = vim.api.nvim_tabpage_list_wins(0)
|
||||||
|
-- Both neo-tree and aerial will auto-quit if there is only a single window left
|
||||||
|
if #wins <= 1 then return end
|
||||||
|
local sidebar_fts = { aerial = true, ["neo-tree"] = true }
|
||||||
|
for _, winid in ipairs(wins) do
|
||||||
|
if vim.api.nvim_win_is_valid(winid) then
|
||||||
|
local bufnr = vim.api.nvim_win_get_buf(winid)
|
||||||
|
local filetype = vim.api.nvim_buf_get_option(bufnr, "filetype")
|
||||||
|
-- If any visible windows are not sidebars, early return
|
||||||
|
if not sidebar_fts[filetype] then
|
||||||
|
return
|
||||||
|
-- If the visible window is a sidebar
|
||||||
|
else
|
||||||
|
-- only count filetypes once, so remove a found sidebar from the detection
|
||||||
|
sidebar_fts[filetype] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #vim.api.nvim_list_tabpages() > 1 then
|
||||||
|
vim.cmd.tabclose()
|
||||||
|
else
|
||||||
|
vim.cmd.qall()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
if is_available "alpha-nvim" then
|
||||||
|
local group_name = augroup("alpha_settings", { clear = true })
|
||||||
|
cmd("User", {
|
||||||
|
desc = "Disable status and tablines for alpha",
|
||||||
|
group = group_name,
|
||||||
|
pattern = "AlphaReady",
|
||||||
|
callback = function()
|
||||||
|
local prev_showtabline = vim.opt.showtabline
|
||||||
|
local prev_status = vim.opt.laststatus
|
||||||
|
vim.opt.laststatus = 0
|
||||||
|
vim.opt.showtabline = 0
|
||||||
|
vim.opt_local.winbar = nil
|
||||||
|
cmd("BufUnload", {
|
||||||
|
pattern = "<buffer>",
|
||||||
|
callback = function()
|
||||||
|
vim.opt.laststatus = prev_status
|
||||||
|
vim.opt.showtabline = prev_showtabline
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
cmd("VimEnter", {
|
||||||
|
desc = "Start Alpha when vim is opened with no arguments",
|
||||||
|
group = group_name,
|
||||||
|
callback = function()
|
||||||
|
local should_skip = false
|
||||||
|
if vim.fn.argc() > 0 or vim.fn.line2byte "$" ~= -1 or not vim.o.modifiable then
|
||||||
|
should_skip = true
|
||||||
|
else
|
||||||
|
for _, arg in pairs(vim.v.argv) do
|
||||||
|
if arg == "-b" or arg == "-c" or vim.startswith(arg, "+") or arg == "-S" then
|
||||||
|
should_skip = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not should_skip then
|
||||||
|
if is_available "bufferline.nvim" then pcall(require, "bufferline") end -- TODO v3: remove this line
|
||||||
|
require("alpha").start(true)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_available "neo-tree.nvim" then
|
||||||
|
cmd("BufEnter", {
|
||||||
|
desc = "Open Neo-Tree on startup with directory",
|
||||||
|
group = augroup("neotree_start", { clear = true }),
|
||||||
|
callback = function()
|
||||||
|
local stats = vim.loop.fs_stat(vim.api.nvim_buf_get_name(0))
|
||||||
|
if stats and stats.type == "directory" then require("neo-tree.setup.netrw").hijack() end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_available "nvim-dap-ui" then
|
||||||
|
vim.api.nvim_create_autocmd("FileType", {
|
||||||
|
desc = "Make q close dap floating windows",
|
||||||
|
group = vim.api.nvim_create_augroup("dapui", { clear = true }),
|
||||||
|
pattern = "dap-float",
|
||||||
|
callback = function() vim.keymap.set("n", "q", "<cmd>close!<cr>") end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
cmd({ "VimEnter", "ColorScheme" }, {
|
||||||
|
desc = "Load custom highlights from user configuration",
|
||||||
|
group = augroup("astronvim_highlights", { clear = true }),
|
||||||
|
callback = function()
|
||||||
|
if vim.g.colors_name then
|
||||||
|
for _, module in ipairs { "init", vim.g.colors_name } do
|
||||||
|
for group, spec in pairs(user_plugin_opts("highlights." .. module)) do
|
||||||
|
vim.api.nvim_set_hl(0, group, spec)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
astronvim.event "ColorScheme"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
vim.api.nvim_create_autocmd("BufRead", {
|
||||||
|
group = vim.api.nvim_create_augroup("git_plugin_lazy_load", { clear = true }),
|
||||||
|
callback = function()
|
||||||
|
vim.fn.system("git -C " .. vim.fn.expand "%:p:h" .. " rev-parse")
|
||||||
|
if vim.v.shell_error == 0 then
|
||||||
|
vim.api.nvim_del_augroup_by_name "git_plugin_lazy_load"
|
||||||
|
local packer = require "packer"
|
||||||
|
vim.tbl_map(function(plugin) packer.loader(plugin) end, astronvim.git_plugins)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
vim.api.nvim_create_autocmd({ "BufRead", "BufWinEnter", "BufNewFile" }, {
|
||||||
|
group = vim.api.nvim_create_augroup("file_plugin_lazy_load", { clear = true }),
|
||||||
|
callback = function(args)
|
||||||
|
if not (vim.fn.expand "%" == "" or vim.api.nvim_buf_get_option(args.buf, "buftype") == "nofile") then
|
||||||
|
vim.api.nvim_del_augroup_by_name "file_plugin_lazy_load"
|
||||||
|
local packer = require "packer"
|
||||||
|
vim.tbl_map(function(plugin) packer.loader(plugin) end, astronvim.file_plugins)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
create_command(
|
||||||
|
"AstroUpdatePackages",
|
||||||
|
function() astronvim.updater.update_packages() end,
|
||||||
|
{ desc = "Update Packer and Mason" }
|
||||||
|
)
|
||||||
|
create_command("AstroUpdate", function() astronvim.updater.update() end, { desc = "Update AstroNvim" })
|
||||||
|
create_command("AstroReload", function() astronvim.updater.reload() end, { desc = "Reload AstroNvim" })
|
||||||
|
create_command("AstroVersion", function() astronvim.updater.version() end, { desc = "Check AstroNvim Version" })
|
||||||
|
create_command("AstroChangelog", function() astronvim.updater.changelog() end, { desc = "Check AstroNvim Changelog" })
|
||||||
|
create_command("ToggleHighlightURL", function() astronvim.ui.toggle_url_match() end, { desc = "Toggle URL Highlights" })
|
|
@ -0,0 +1,4 @@
|
||||||
|
astronvim.initialize_packer()
|
||||||
|
|
||||||
|
local colorscheme = astronvim.user_plugin_opts("colorscheme", nil, false)
|
||||||
|
vim.cmd.colorscheme(vim.tbl_contains(vim.fn.getcompletion("", "color"), colorscheme) and colorscheme or "default_theme")
|
|
@ -0,0 +1,43 @@
|
||||||
|
local signs = {
|
||||||
|
{ name = "DiagnosticSignError", text = astronvim.get_icon "DiagnosticError" },
|
||||||
|
{ name = "DiagnosticSignWarn", text = astronvim.get_icon "DiagnosticWarn" },
|
||||||
|
{ name = "DiagnosticSignHint", text = astronvim.get_icon "DiagnosticHint" },
|
||||||
|
{ name = "DiagnosticSignInfo", text = astronvim.get_icon "DiagnosticInfo" },
|
||||||
|
{ name = "DiagnosticSignError", text = astronvim.get_icon "DiagnosticError" },
|
||||||
|
{ name = "DapStopped", text = astronvim.get_icon "DapStopped", texthl = "DiagnosticWarn" },
|
||||||
|
{ name = "DapBreakpoint", text = astronvim.get_icon "DapBreakpoint", texthl = "DiagnosticInfo" },
|
||||||
|
{ name = "DapBreakpointRejected", text = astronvim.get_icon "DapBreakpointRejected", texthl = "DiagnosticError" },
|
||||||
|
{ name = "DapBreakpointCondition", text = astronvim.get_icon "DapBreakpointCondition", texthl = "DiagnosticInfo" },
|
||||||
|
{ name = "DapLogPoint", text = astronvim.get_icon "DapLogPoint", texthl = "DiagnosticInfo" },
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sign in ipairs(signs) do
|
||||||
|
if not sign.texthl then sign.texthl = sign.name end
|
||||||
|
vim.fn.sign_define(sign.name, sign)
|
||||||
|
end
|
||||||
|
|
||||||
|
astronvim.lsp.diagnostics = {
|
||||||
|
off = {
|
||||||
|
underline = false,
|
||||||
|
virtual_text = false,
|
||||||
|
signs = false,
|
||||||
|
update_in_insert = false,
|
||||||
|
},
|
||||||
|
on = astronvim.user_plugin_opts("diagnostics", {
|
||||||
|
virtual_text = true,
|
||||||
|
signs = { active = signs },
|
||||||
|
update_in_insert = true,
|
||||||
|
underline = true,
|
||||||
|
severity_sort = true,
|
||||||
|
float = {
|
||||||
|
focused = false,
|
||||||
|
style = "minimal",
|
||||||
|
border = "rounded",
|
||||||
|
source = "always",
|
||||||
|
header = "",
|
||||||
|
prefix = "",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
vim.diagnostic.config(astronvim.lsp.diagnostics[vim.g.diagnostics_enabled and "on" or "off"])
|
|
@ -0,0 +1,46 @@
|
||||||
|
return {
|
||||||
|
ActiveLSP = "",
|
||||||
|
ActiveTS = "綠",
|
||||||
|
ArrowLeft = "",
|
||||||
|
ArrowRight = "",
|
||||||
|
BufferClose = "",
|
||||||
|
DapBreakpoint = "",
|
||||||
|
DapBreakpointCondition = "",
|
||||||
|
DapBreakpointRejected = "",
|
||||||
|
DapLogPoint = ".>",
|
||||||
|
DapStopped = "",
|
||||||
|
DefaultFile = "",
|
||||||
|
Diagnostic = "裂",
|
||||||
|
DiagnosticError = "",
|
||||||
|
DiagnosticHint = "",
|
||||||
|
DiagnosticInfo = "",
|
||||||
|
DiagnosticWarn = "",
|
||||||
|
Ellipsis = "…",
|
||||||
|
FileModified = "",
|
||||||
|
FileReadOnly = "",
|
||||||
|
FolderClosed = "",
|
||||||
|
FolderEmpty = "",
|
||||||
|
FolderOpen = "",
|
||||||
|
Git = "",
|
||||||
|
GitAdd = "",
|
||||||
|
GitBranch = "",
|
||||||
|
GitChange = "",
|
||||||
|
GitConflict = "",
|
||||||
|
GitDelete = "",
|
||||||
|
GitIgnored = "◌",
|
||||||
|
GitRenamed = "➜",
|
||||||
|
GitStaged = "✓",
|
||||||
|
GitUnstaged = "✗",
|
||||||
|
GitUntracked = "★",
|
||||||
|
LSPLoaded = "",
|
||||||
|
LSPLoading1 = "",
|
||||||
|
LSPLoading2 = "",
|
||||||
|
LSPLoading3 = "",
|
||||||
|
MacroRecording = "",
|
||||||
|
NeovimClose = "", -- TODO v3: remove this icon
|
||||||
|
Paste = "",
|
||||||
|
Search = "",
|
||||||
|
Selected = "❯",
|
||||||
|
Spellcheck = "暈",
|
||||||
|
TabClose = "",
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
return {
|
||||||
|
ActiveLSP = "LSP:",
|
||||||
|
ArrowLeft = "<",
|
||||||
|
ArrowRight = ">",
|
||||||
|
BufferClose = "x",
|
||||||
|
DapBreakpoint = "B",
|
||||||
|
DapBreakpointCondition = "C",
|
||||||
|
DapBreakpointRejected = "R",
|
||||||
|
DapLogPoint = "L",
|
||||||
|
DapStopped = ">",
|
||||||
|
DefaultFile = "[F]",
|
||||||
|
DiagnosticError = "X",
|
||||||
|
DiagnosticHint = "?",
|
||||||
|
DiagnosticInfo = "i",
|
||||||
|
DiagnosticWarn = "!",
|
||||||
|
Ellipsis = "...",
|
||||||
|
FileModified = "*",
|
||||||
|
FileReadOnly = "[lock]",
|
||||||
|
FolderClosed = "[D]",
|
||||||
|
FolderEmpty = "[E]",
|
||||||
|
FolderOpen = "[O]",
|
||||||
|
GitAdd = "[+]",
|
||||||
|
GitChange = "[/]",
|
||||||
|
GitConflict = "[!]",
|
||||||
|
GitDelete = "[-]",
|
||||||
|
GitIgnored = "[I]",
|
||||||
|
GitRenamed = "[R]",
|
||||||
|
GitStaged = "[S]",
|
||||||
|
GitUnstaged = "[U]",
|
||||||
|
GitUntracked = "[?]",
|
||||||
|
MacroRecording = "Recording:",
|
||||||
|
NeovimClose = "X", -- TODO v3: remove this icon
|
||||||
|
Paste = "[PASTE]",
|
||||||
|
Search = "?",
|
||||||
|
Selected = "*",
|
||||||
|
Spellcheck = "[SPELL]",
|
||||||
|
TabClose = "X",
|
||||||
|
}
|
|
@ -0,0 +1,317 @@
|
||||||
|
local is_available = astronvim.is_available
|
||||||
|
|
||||||
|
local maps = { i = {}, n = {}, v = {}, t = {} }
|
||||||
|
|
||||||
|
-- Normal --
|
||||||
|
-- Standard Operations
|
||||||
|
maps.n["<leader>w"] = { "<cmd>w<cr>", desc = "Save" }
|
||||||
|
maps.n["<leader>q"] = { "<cmd>q<cr>", desc = "Quit" }
|
||||||
|
maps.n["<leader>h"] = { "<cmd>nohlsearch<cr>", desc = "No Highlight" } -- TODO: REMOVE IN v3
|
||||||
|
maps.n["<leader>fn"] = { "<cmd>enew<cr>", desc = "New File" }
|
||||||
|
maps.n["gx"] = { function() astronvim.system_open() end, desc = "Open the file under cursor with system app" }
|
||||||
|
maps.n["<C-s>"] = { "<cmd>w!<cr>", desc = "Force write" }
|
||||||
|
maps.n["<C-q>"] = { "<cmd>q!<cr>", desc = "Force quit" }
|
||||||
|
maps.n["Q"] = "<Nop>"
|
||||||
|
maps.n["|"] = { "<cmd>vsplit<cr>", desc = "Vertical Split" }
|
||||||
|
maps.n["\\"] = { "<cmd>split<cr>", desc = "Horizontal Split" }
|
||||||
|
|
||||||
|
-- Packer
|
||||||
|
maps.n["<leader>pc"] = { "<cmd>PackerCompile<cr>", desc = "Packer Compile" }
|
||||||
|
maps.n["<leader>pi"] = { "<cmd>PackerInstall<cr>", desc = "Packer Install" }
|
||||||
|
maps.n["<leader>ps"] = { "<cmd>PackerSync<cr>", desc = "Packer Sync" }
|
||||||
|
maps.n["<leader>pS"] = { "<cmd>PackerStatus<cr>", desc = "Packer Status" }
|
||||||
|
maps.n["<leader>pu"] = { "<cmd>PackerUpdate<cr>", desc = "Packer Update" }
|
||||||
|
|
||||||
|
-- AstroNvim
|
||||||
|
maps.n["<leader>pa"] = { "<cmd>AstroUpdatePackages<cr>", desc = "Update Packer and Mason" }
|
||||||
|
maps.n["<leader>pA"] = { "<cmd>AstroUpdate<cr>", desc = "AstroNvim Update" }
|
||||||
|
maps.n["<leader>pv"] = { "<cmd>AstroVersion<cr>", desc = "AstroNvim Version" }
|
||||||
|
maps.n["<leader>pl"] = { "<cmd>AstroChangelog<cr>", desc = "AstroNvim Changelog" }
|
||||||
|
|
||||||
|
-- Alpha
|
||||||
|
if is_available "alpha-nvim" then
|
||||||
|
maps.n["<leader>d"] = { function() require("alpha").start() end, desc = "Alpha Dashboard" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if vim.g.heirline_bufferline then
|
||||||
|
-- Manage Buffers
|
||||||
|
maps.n["<leader>c"] = { function() astronvim.close_buf(0) end, desc = "Close buffer" }
|
||||||
|
maps.n["<leader>C"] = { function() astronvim.close_buf(0, true) end, desc = "Force close buffer" }
|
||||||
|
maps.n["<S-l>"] = { function() astronvim.nav_buf(vim.v.count > 0 and vim.v.count or 1) end, desc = "Next buffer" }
|
||||||
|
maps.n["<S-h>"] =
|
||||||
|
{ function() astronvim.nav_buf(-(vim.v.count > 0 and vim.v.count or 1)) end, desc = "Previous buffer" }
|
||||||
|
maps.n[">b"] =
|
||||||
|
{ function() astronvim.move_buf(vim.v.count > 0 and vim.v.count or 1) end, desc = "Move buffer tab right" }
|
||||||
|
maps.n["<b"] =
|
||||||
|
{ function() astronvim.move_buf(-(vim.v.count > 0 and vim.v.count or 1)) end, desc = "Move buffer tab left" }
|
||||||
|
|
||||||
|
maps.n["<leader>bb"] = {
|
||||||
|
function()
|
||||||
|
astronvim.status.heirline.buffer_picker(function(bufnr) vim.api.nvim_win_set_buf(0, bufnr) end)
|
||||||
|
end,
|
||||||
|
desc = "Select buffer from tabline",
|
||||||
|
}
|
||||||
|
maps.n["<leader>bd"] = {
|
||||||
|
function()
|
||||||
|
astronvim.status.heirline.buffer_picker(function(bufnr) astronvim.close_buf(bufnr) end)
|
||||||
|
end,
|
||||||
|
desc = "Delete buffer from tabline",
|
||||||
|
}
|
||||||
|
maps.n["<leader>b\\"] = {
|
||||||
|
function()
|
||||||
|
astronvim.status.heirline.buffer_picker(function(bufnr)
|
||||||
|
vim.cmd.split()
|
||||||
|
vim.api.nvim_win_set_buf(0, bufnr)
|
||||||
|
end)
|
||||||
|
end,
|
||||||
|
desc = "Horizontal split buffer from tabline",
|
||||||
|
}
|
||||||
|
maps.n["<leader>b|"] = {
|
||||||
|
function()
|
||||||
|
astronvim.status.heirline.buffer_picker(function(bufnr)
|
||||||
|
vim.cmd.vsplit()
|
||||||
|
vim.api.nvim_win_set_buf(0, bufnr)
|
||||||
|
end)
|
||||||
|
end,
|
||||||
|
desc = "Vertical split buffer from tabline",
|
||||||
|
}
|
||||||
|
else -- TODO v3: remove this else block
|
||||||
|
-- Bufdelete
|
||||||
|
if is_available "bufdelete.nvim" then
|
||||||
|
maps.n["<leader>c"] = { function() require("bufdelete").bufdelete(0, false) end, desc = "Close buffer" }
|
||||||
|
maps.n["<leader>C"] = { function() require("bufdelete").bufdelete(0, true) end, desc = "Force close buffer" }
|
||||||
|
else
|
||||||
|
maps.n["<leader>c"] = { "<cmd>bdelete<cr>", desc = "Close buffer" }
|
||||||
|
maps.n["<leader>C"] = { "<cmd>bdelete!<cr>", desc = "Force close buffer" }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Navigate buffers
|
||||||
|
if is_available "bufferline.nvim" then
|
||||||
|
maps.n["<S-l>"] = { "<cmd>BufferLineCycleNext<cr>", desc = "Next buffer tab" }
|
||||||
|
maps.n["<S-h>"] = { "<cmd>BufferLineCyclePrev<cr>", desc = "Previous buffer tab" }
|
||||||
|
maps.n[">b"] = { "<cmd>BufferLineMoveNext<cr>", desc = "Move buffer tab right" }
|
||||||
|
maps.n["<b"] = { "<cmd>BufferLineMovePrev<cr>", desc = "Move buffer tab left" }
|
||||||
|
else
|
||||||
|
maps.n["<S-l>"] = { "<cmd>bnext<cr>", desc = "Next buffer" }
|
||||||
|
maps.n["<S-h>"] = { "<cmd>bprevious<cr>", desc = "Previous buffer" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Navigate tabs
|
||||||
|
maps.n["]t"] = { function() vim.cmd.tabnext() end, desc = "Next tab" }
|
||||||
|
maps.n["[t"] = { function() vim.cmd.tabprevious() end, desc = "Previous tab" }
|
||||||
|
|
||||||
|
-- Comment
|
||||||
|
if is_available "Comment.nvim" then
|
||||||
|
maps.n["<leader>/"] = { function() require("Comment.api").toggle.linewise.current() end, desc = "Comment line" }
|
||||||
|
maps.v["<leader>/"] = {
|
||||||
|
"<esc><cmd>lua require('Comment.api').toggle.linewise(vim.fn.visualmode())<cr>",
|
||||||
|
desc = "Toggle comment line",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- GitSigns
|
||||||
|
if is_available "gitsigns.nvim" then
|
||||||
|
maps.n["<leader>gj"] = { function() require("gitsigns").next_hunk() end, desc = "Next Git hunk" }
|
||||||
|
maps.n["<leader>gk"] = { function() require("gitsigns").prev_hunk() end, desc = "Previous Git hunk" }
|
||||||
|
maps.n["<leader>gl"] = { function() require("gitsigns").blame_line() end, desc = "View Git blame" }
|
||||||
|
maps.n["<leader>gp"] = { function() require("gitsigns").preview_hunk() end, desc = "Preview Git hunk" }
|
||||||
|
maps.n["<leader>gh"] = { function() require("gitsigns").reset_hunk() end, desc = "Reset Git hunk" }
|
||||||
|
maps.n["<leader>gr"] = { function() require("gitsigns").reset_buffer() end, desc = "Reset Git buffer" }
|
||||||
|
maps.n["<leader>gs"] = { function() require("gitsigns").stage_hunk() end, desc = "Stage Git hunk" }
|
||||||
|
maps.n["<leader>gu"] = { function() require("gitsigns").undo_stage_hunk() end, desc = "Unstage Git hunk" }
|
||||||
|
maps.n["<leader>gd"] = { function() require("gitsigns").diffthis() end, desc = "View Git diff" }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- NeoTree
|
||||||
|
if is_available "neo-tree.nvim" then
|
||||||
|
maps.n["<leader>e"] = { "<cmd>Neotree toggle<cr>", desc = "Toggle Explorer" }
|
||||||
|
maps.n["<leader>o"] = { "<cmd>Neotree focus<cr>", desc = "Focus Explorer" }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Session Manager
|
||||||
|
if is_available "neovim-session-manager" then
|
||||||
|
maps.n["<leader>Sl"] = { "<cmd>SessionManager! load_last_session<cr>", desc = "Load last session" }
|
||||||
|
maps.n["<leader>Ss"] = { "<cmd>SessionManager! save_current_session<cr>", desc = "Save this session" }
|
||||||
|
maps.n["<leader>Sd"] = { "<cmd>SessionManager! delete_session<cr>", desc = "Delete session" }
|
||||||
|
maps.n["<leader>Sf"] = { "<cmd>SessionManager! load_session<cr>", desc = "Search sessions" }
|
||||||
|
maps.n["<leader>S."] =
|
||||||
|
{ "<cmd>SessionManager! load_current_dir_session<cr>", desc = "Load current directory session" }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Package Manager
|
||||||
|
if is_available "mason.nvim" then
|
||||||
|
maps.n["<leader>pI"] = { "<cmd>Mason<cr>", desc = "Mason Installer" }
|
||||||
|
maps.n["<leader>pU"] = { "<cmd>MasonUpdateAll<cr>", desc = "Mason Update" }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Smart Splits
|
||||||
|
if is_available "smart-splits.nvim" then
|
||||||
|
-- Better window navigation
|
||||||
|
maps.n["<C-h>"] = { function() require("smart-splits").move_cursor_left() end, desc = "Move to left split" }
|
||||||
|
maps.n["<C-j>"] = { function() require("smart-splits").move_cursor_down() end, desc = "Move to below split" }
|
||||||
|
maps.n["<C-k>"] = { function() require("smart-splits").move_cursor_up() end, desc = "Move to above split" }
|
||||||
|
maps.n["<C-l>"] = { function() require("smart-splits").move_cursor_right() end, desc = "Move to right split" }
|
||||||
|
|
||||||
|
-- Resize with arrows
|
||||||
|
maps.n["<C-Up>"] = { function() require("smart-splits").resize_up() end, desc = "Resize split up" }
|
||||||
|
maps.n["<C-Down>"] = { function() require("smart-splits").resize_down() end, desc = "Resize split down" }
|
||||||
|
maps.n["<C-Left>"] = { function() require("smart-splits").resize_left() end, desc = "Resize split left" }
|
||||||
|
maps.n["<C-Right>"] = { function() require("smart-splits").resize_right() end, desc = "Resize split right" }
|
||||||
|
else
|
||||||
|
maps.n["<C-h>"] = { "<C-w>h", desc = "Move to left split" }
|
||||||
|
maps.n["<C-j>"] = { "<C-w>j", desc = "Move to below split" }
|
||||||
|
maps.n["<C-k>"] = { "<C-w>k", desc = "Move to above split" }
|
||||||
|
maps.n["<C-l>"] = { "<C-w>l", desc = "Move to right split" }
|
||||||
|
maps.n["<C-Up>"] = { "<cmd>resize -2<CR>", desc = "Resize split up" }
|
||||||
|
maps.n["<C-Down>"] = { "<cmd>resize +2<CR>", desc = "Resize split down" }
|
||||||
|
maps.n["<C-Left>"] = { "<cmd>vertical resize -2<CR>", desc = "Resize split left" }
|
||||||
|
maps.n["<C-Right>"] = { "<cmd>vertical resize +2<CR>", desc = "Resize split right" }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- SymbolsOutline
|
||||||
|
if is_available "aerial.nvim" then
|
||||||
|
maps.n["<leader>lS"] = { function() require("aerial").toggle() end, desc = "Symbols outline" }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Telescope
|
||||||
|
if is_available "telescope.nvim" then
|
||||||
|
maps.n["<leader>fw"] = { function() require("telescope.builtin").live_grep() end, desc = "Search words" }
|
||||||
|
maps.n["<leader>fW"] = {
|
||||||
|
function()
|
||||||
|
require("telescope.builtin").live_grep {
|
||||||
|
additional_args = function(args) return vim.list_extend(args, { "--hidden", "--no-ignore" }) end,
|
||||||
|
}
|
||||||
|
end,
|
||||||
|
desc = "Search words in all files",
|
||||||
|
}
|
||||||
|
maps.n["<leader>gt"] = { function() require("telescope.builtin").git_status() end, desc = "Git status" }
|
||||||
|
maps.n["<leader>gb"] = { function() require("telescope.builtin").git_branches() end, desc = "Git branches" }
|
||||||
|
maps.n["<leader>gc"] = { function() require("telescope.builtin").git_commits() end, desc = "Git commits" }
|
||||||
|
maps.n["<leader>ff"] = { function() require("telescope.builtin").find_files( { hidden = true } ) end, desc = "Search files" }
|
||||||
|
maps.n["<leader>fF"] = {
|
||||||
|
function() require("telescope.builtin").find_files { hidden = true, no_ignore = true } end,
|
||||||
|
desc = "Search all files",
|
||||||
|
}
|
||||||
|
maps.n["<leader>fb"] = { function() require("telescope.builtin").buffers() end, desc = "Search buffers" }
|
||||||
|
maps.n["<leader>fh"] = { function() require("telescope.builtin").help_tags() end, desc = "Search help" }
|
||||||
|
maps.n["<leader>fm"] = { function() require("telescope.builtin").marks() end, desc = "Search marks" }
|
||||||
|
maps.n["<leader>fo"] = { function() require("telescope.builtin").oldfiles() end, desc = "Search history" }
|
||||||
|
maps.n["<leader>fc"] =
|
||||||
|
{ function() require("telescope.builtin").grep_string() end, desc = "Search for word under cursor" }
|
||||||
|
maps.n["<leader>sb"] = { function() require("telescope.builtin").git_branches() end, desc = "Git branches" }
|
||||||
|
maps.n["<leader>sh"] = { function() require("telescope.builtin").help_tags() end, desc = "Search help" }
|
||||||
|
maps.n["<leader>sm"] = { function() require("telescope.builtin").man_pages() end, desc = "Search man" }
|
||||||
|
maps.n["<leader>sr"] = { function() require("telescope.builtin").registers() end, desc = "Search registers" }
|
||||||
|
maps.n["<leader>sk"] = { function() require("telescope.builtin").keymaps() end, desc = "Search keymaps" }
|
||||||
|
maps.n["<leader>sc"] = { function() require("telescope.builtin").commands() end, desc = "Search commands" }
|
||||||
|
if astronvim.is_available "nvim-notify" then
|
||||||
|
maps.n["<leader>sn"] =
|
||||||
|
{ function() require("telescope").extensions.notify.notify() end, desc = "Search notifications" }
|
||||||
|
end
|
||||||
|
maps.n["<leader>ls"] = {
|
||||||
|
function()
|
||||||
|
local aerial_avail, _ = pcall(require, "aerial")
|
||||||
|
if aerial_avail then
|
||||||
|
require("telescope").extensions.aerial.aerial()
|
||||||
|
else
|
||||||
|
require("telescope.builtin").lsp_document_symbols()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
desc = "Search symbols",
|
||||||
|
}
|
||||||
|
maps.n["<leader>lD"] = { function() require("telescope.builtin").diagnostics() end, desc = "Search diagnostics" }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Terminal
|
||||||
|
if is_available "toggleterm.nvim" then
|
||||||
|
local toggle_term_cmd = astronvim.toggle_term_cmd
|
||||||
|
if vim.fn.executable "lazygit" == 1 then
|
||||||
|
maps.n["<leader>gg"] = { function() toggle_term_cmd "lazygit" end, desc = "ToggleTerm lazygit" }
|
||||||
|
maps.n["<leader>tl"] = { function() toggle_term_cmd "lazygit" end, desc = "ToggleTerm lazygit" }
|
||||||
|
end
|
||||||
|
if vim.fn.executable "node" == 1 then
|
||||||
|
maps.n["<leader>tn"] = { function() toggle_term_cmd "node" end, desc = "ToggleTerm node" }
|
||||||
|
end
|
||||||
|
if vim.fn.executable "gdu" == 1 then
|
||||||
|
maps.n["<leader>tu"] = { function() toggle_term_cmd "gdu" end, desc = "ToggleTerm gdu" }
|
||||||
|
end
|
||||||
|
if vim.fn.executable "btm" == 1 then
|
||||||
|
maps.n["<leader>tt"] = { function() toggle_term_cmd "btm" end, desc = "ToggleTerm btm" }
|
||||||
|
end
|
||||||
|
if vim.fn.executable "python" == 1 then
|
||||||
|
maps.n["<leader>tp"] = { function() toggle_term_cmd "python" end, desc = "ToggleTerm python" }
|
||||||
|
end
|
||||||
|
maps.n["<leader>tf"] = { "<cmd>ToggleTerm direction=float<cr>", desc = "ToggleTerm float" }
|
||||||
|
maps.n["<leader>th"] = { "<cmd>ToggleTerm size=10 direction=horizontal<cr>", desc = "ToggleTerm horizontal split" }
|
||||||
|
maps.n["<leader>tv"] = { "<cmd>ToggleTerm size=80 direction=vertical<cr>", desc = "ToggleTerm vertical split" }
|
||||||
|
maps.n["<F7>"] = { "<cmd>ToggleTerm<cr>", desc = "Toggle terminal" }
|
||||||
|
maps.t["<F7>"] = maps.n["<F7>"]
|
||||||
|
maps.n["<C-'>"] = maps.n["<F7>"]
|
||||||
|
maps.t["<C-'>"] = maps.n["<F7>"]
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_available "nvim-dap" then
|
||||||
|
-- modified function keys found with `showkey -a` in the terminal to get key code
|
||||||
|
-- run `nvim -V3log +quit` and search through the "Terminal info" in the `log` file for the correct keyname
|
||||||
|
maps.n["<F5>"] = { function() require("dap").continue() end, desc = "Debugger: Start" }
|
||||||
|
maps.n["<F17>"] = { function() require("dap").terminate() end, desc = "Debugger: Stop" } -- Shift+F5
|
||||||
|
maps.n["<F29>"] = { function() require("dap").restart_frame() end, desc = "Debugger: Restart" } -- Control+F5
|
||||||
|
maps.n["<F6>"] = { function() require("dap").pause() end, desc = "Debugger: Pause" }
|
||||||
|
maps.n["<F9>"] = { function() require("dap").toggle_breakpoint() end, desc = "Debugger: Toggle Breakpoint" }
|
||||||
|
maps.n["<F10>"] = { function() require("dap").step_over() end, desc = "Debugger: Step Over" }
|
||||||
|
maps.n["<F11>"] = { function() require("dap").step_into() end, desc = "Debugger: Step Into" }
|
||||||
|
maps.n["<F23>"] = { function() require("dap").step_out() end, desc = "Debugger: Step Out" } -- Shift+F11
|
||||||
|
maps.n["<leader>Db"] = { function() require("dap").toggle_breakpoint() end, desc = "Toggle Breakpoint (F9)" }
|
||||||
|
maps.n["<leader>DB"] = { function() require("dap").clear_breakpoints() end, desc = "Clear Breakpoints" }
|
||||||
|
maps.n["<leader>Dc"] = { function() require("dap").continue() end, desc = "Start/Continue (F5)" }
|
||||||
|
maps.n["<leader>Di"] = { function() require("dap").step_into() end, desc = "Step Into (F11)" }
|
||||||
|
maps.n["<leader>Do"] = { function() require("dap").step_over() end, desc = "Step Over (F10)" }
|
||||||
|
maps.n["<leader>DO"] = { function() require("dap").step_out() end, desc = "Step Out (S-F11)" }
|
||||||
|
maps.n["<leader>Dq"] = { function() require("dap").close() end, desc = "Close Session" }
|
||||||
|
maps.n["<leader>DQ"] = { function() require("dap").terminate() end, desc = "Terminate Session (S-F5)" }
|
||||||
|
maps.n["<leader>Dp"] = { function() require("dap").pause() end, desc = "Pause (F6)" }
|
||||||
|
maps.n["<leader>Dr"] = { function() require("dap").restart_frame() end, desc = "Restart (C-F5)" }
|
||||||
|
maps.n["<leader>DR"] = { function() require("dap").repl.toggle() end, desc = "Toggle REPL" }
|
||||||
|
if is_available "nvim-dap-ui" then
|
||||||
|
maps.n["<leader>Du"] = { function() require("dapui").toggle() end, desc = "Toggle Debugger UI" }
|
||||||
|
maps.n["<leader>Dh"] = { function() require("dap.ui.widgets").hover() end, desc = "Debugger Hover" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Stay in indent mode
|
||||||
|
maps.v["<"] = { "<gv", desc = "unindent line" }
|
||||||
|
maps.v[">"] = { ">gv", desc = "indent line" }
|
||||||
|
|
||||||
|
-- Improved Terminal Navigation
|
||||||
|
maps.t["<C-h>"] = { "<c-\\><c-n><c-w>h", desc = "Terminal left window navigation" }
|
||||||
|
maps.t["<C-j>"] = { "<c-\\><c-n><c-w>j", desc = "Terminal down window navigation" }
|
||||||
|
maps.t["<C-k>"] = { "<c-\\><c-n><c-w>k", desc = "Terminal up window navigation" }
|
||||||
|
maps.t["<C-l>"] = { "<c-\\><c-n><c-w>l", desc = "Terminal right window navigation" }
|
||||||
|
|
||||||
|
-- Custom menu for modification of the user experience
|
||||||
|
if is_available "nvim-autopairs" then
|
||||||
|
maps.n["<leader>ua"] = { function() astronvim.ui.toggle_autopairs() end, desc = "Toggle autopairs" }
|
||||||
|
end
|
||||||
|
maps.n["<leader>ub"] = { function() astronvim.ui.toggle_background() end, desc = "Toggle background" }
|
||||||
|
if is_available "nvim-cmp" then
|
||||||
|
maps.n["<leader>uc"] = { function() astronvim.ui.toggle_cmp() end, desc = "Toggle autocompletion" }
|
||||||
|
end
|
||||||
|
if is_available "nvim-colorizer.lua" then
|
||||||
|
maps.n["<leader>uC"] = { "<cmd>ColorizerToggle<cr>", desc = "Toggle color highlight" }
|
||||||
|
end
|
||||||
|
maps.n["<leader>uS"] = { function() astronvim.ui.toggle_conceal() end, desc = "Toggle conceal" }
|
||||||
|
maps.n["<leader>ud"] = { function() astronvim.ui.toggle_diagnostics() end, desc = "Toggle diagnostics" }
|
||||||
|
maps.n["<leader>ug"] = { function() astronvim.ui.toggle_signcolumn() end, desc = "Toggle signcolumn" }
|
||||||
|
maps.n["<leader>ui"] = { function() astronvim.ui.set_indent() end, desc = "Change indent setting" }
|
||||||
|
maps.n["<leader>ul"] = { function() astronvim.ui.toggle_statusline() end, desc = "Toggle statusline" }
|
||||||
|
maps.n["<leader>un"] = { function() astronvim.ui.change_number() end, desc = "Change line numbering" }
|
||||||
|
maps.n["<leader>us"] = { function() astronvim.ui.toggle_spell() end, desc = "Toggle spellcheck" }
|
||||||
|
maps.n["<leader>up"] = { function() astronvim.ui.toggle_paste() end, desc = "Toggle paste mode" }
|
||||||
|
maps.n["<leader>ut"] = { function() astronvim.ui.toggle_tabline() end, desc = "Toggle tabline" }
|
||||||
|
maps.n["<leader>uu"] = { function() astronvim.ui.toggle_url_match() end, desc = "Toggle URL highlight" }
|
||||||
|
maps.n["<leader>uw"] = { function() astronvim.ui.toggle_wrap() end, desc = "Toggle wrap" }
|
||||||
|
maps.n["<leader>uy"] = { function() astronvim.ui.toggle_syntax() end, desc = "Toggle syntax highlight" }
|
||||||
|
maps.n["<leader>uN"] = { function() astronvim.ui.toggle_ui_notifications() end, desc = "Toggle UI notifications" }
|
||||||
|
|
||||||
|
astronvim.set_mappings(astronvim.user_plugin_opts("mappings", maps))
|
|
@ -0,0 +1,72 @@
|
||||||
|
vim.opt.shortmess:append { s = true, I = true } -- disable startup message
|
||||||
|
astronvim.vim_opts(astronvim.user_plugin_opts("options", {
|
||||||
|
opt = {
|
||||||
|
backspace = vim.opt.backspace + { "nostop" }, -- Don't stop backspace at insert
|
||||||
|
clipboard = "unnamedplus", -- Connection to the system clipboard
|
||||||
|
cmdheight = 0, -- hide command line unless needed
|
||||||
|
completeopt = { "menuone", "noselect" }, -- Options for insert mode completion
|
||||||
|
copyindent = true, -- Copy the previous indentation on autoindenting
|
||||||
|
cursorline = true, -- Highlight the text line of the cursor
|
||||||
|
expandtab = true, -- Enable the use of space in tab
|
||||||
|
fileencoding = "utf-8", -- File content encoding for the buffer
|
||||||
|
fillchars = { eob = " " }, -- Disable `~` on nonexistent lines
|
||||||
|
history = 100, -- Number of commands to remember in a history table
|
||||||
|
ignorecase = true, -- Case insensitive searching
|
||||||
|
laststatus = 3, -- globalstatus
|
||||||
|
mouse = "a", -- Enable mouse support
|
||||||
|
number = true, -- Show numberline
|
||||||
|
preserveindent = true, -- Preserve indent structure as much as possible
|
||||||
|
pumheight = 10, -- Height of the pop up menu
|
||||||
|
relativenumber = true, -- Show relative numberline
|
||||||
|
scrolloff = 8, -- Number of lines to keep above and below the cursor
|
||||||
|
shiftwidth = 2, -- Number of space inserted for indentation
|
||||||
|
showmode = false, -- Disable showing modes in command line
|
||||||
|
showtabline = 2, -- always display tabline
|
||||||
|
sidescrolloff = 8, -- Number of columns to keep at the sides of the cursor
|
||||||
|
signcolumn = "yes", -- Always show the sign column
|
||||||
|
smartcase = true, -- Case sensitivie searching
|
||||||
|
splitbelow = true, -- Splitting a new window below the current one
|
||||||
|
splitright = true, -- Splitting a new window at the right of the current one
|
||||||
|
tabstop = 2, -- Number of space in a tab
|
||||||
|
termguicolors = true, -- Enable 24-bit RGB color in the TUI
|
||||||
|
timeoutlen = 300, -- Length of time to wait for a mapped sequence
|
||||||
|
undofile = true, -- Enable persistent undo
|
||||||
|
updatetime = 300, -- Length of time to wait before triggering the plugin
|
||||||
|
wrap = false, -- Disable wrapping of lines longer than the width of window
|
||||||
|
writebackup = false, -- Disable making a backup before overwriting a file
|
||||||
|
},
|
||||||
|
g = {
|
||||||
|
highlighturl_enabled = true, -- highlight URLs by default
|
||||||
|
mapleader = " ", -- set leader key
|
||||||
|
zipPlugin = false, -- disable zip
|
||||||
|
load_black = false, -- disable black
|
||||||
|
loaded_2html_plugin = true, -- disable 2html
|
||||||
|
loaded_getscript = true, -- disable getscript
|
||||||
|
loaded_getscriptPlugin = true, -- disable getscript
|
||||||
|
loaded_gzip = true, -- disable gzip
|
||||||
|
loaded_logipat = true, -- disable logipat
|
||||||
|
loaded_matchit = true, -- disable matchit
|
||||||
|
loaded_netrwFileHandlers = true, -- disable netrw
|
||||||
|
loaded_netrwPlugin = true, -- disable netrw
|
||||||
|
loaded_netrwSettngs = true, -- disable netrw
|
||||||
|
loaded_remote_plugins = true, -- disable remote plugins
|
||||||
|
loaded_tar = true, -- disable tar
|
||||||
|
loaded_tarPlugin = true, -- disable tar
|
||||||
|
loaded_zip = true, -- disable zip
|
||||||
|
loaded_zipPlugin = true, -- disable zip
|
||||||
|
loaded_vimball = true, -- disable vimball
|
||||||
|
loaded_vimballPlugin = true, -- disable vimball
|
||||||
|
autoformat_enabled = true, -- enable or disable auto formatting at start (lsp.formatting.format_on_save must be enabled)
|
||||||
|
lsp_handlers_enabled = true, -- enable or disable default vim.lsp.handlers (hover and signatureHelp)
|
||||||
|
cmp_enabled = true, -- enable completion at start
|
||||||
|
autopairs_enabled = true, -- enable autopairs at start
|
||||||
|
diagnostics_enabled = true, -- enable diagnostics at start
|
||||||
|
status_diagnostics_enabled = true, -- enable diagnostics in statusline
|
||||||
|
icons_enabled = true, -- disable icons in the UI (disable if no nerd font is available)
|
||||||
|
ui_notifications_enabled = true, -- disable notifications when toggling UI elements
|
||||||
|
heirline_bufferline = false, -- enable heirline bufferline (TODO v3: remove this option and make it default)
|
||||||
|
},
|
||||||
|
t = {
|
||||||
|
bufs = vim.tbl_filter(astronvim.is_valid_buffer, vim.api.nvim_list_bufs()), -- buffers in tab
|
||||||
|
},
|
||||||
|
}))
|
|
@ -0,0 +1,375 @@
|
||||||
|
local astro_plugins = {
|
||||||
|
-- Plugin manager
|
||||||
|
["wbthomason/packer.nvim"] = {
|
||||||
|
setup = function()
|
||||||
|
astronvim.lazy_load_commands("packer.nvim", {
|
||||||
|
"PackerSnapshot",
|
||||||
|
"PackerSnapshotRollback",
|
||||||
|
"PackerSnapshotDelete",
|
||||||
|
"PackerInstall",
|
||||||
|
"PackerUpdate",
|
||||||
|
"PackerSync",
|
||||||
|
"PackerClean",
|
||||||
|
"PackerCompile",
|
||||||
|
"PackerStatus",
|
||||||
|
"PackerProfile",
|
||||||
|
"PackerLoad",
|
||||||
|
})
|
||||||
|
end,
|
||||||
|
config = function() require "core.plugins" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Optimiser
|
||||||
|
["lewis6991/impatient.nvim"] = {},
|
||||||
|
|
||||||
|
-- Lua functions
|
||||||
|
["nvim-lua/plenary.nvim"] = { module = "plenary" },
|
||||||
|
|
||||||
|
-- Indent detection
|
||||||
|
["Darazaki/indent-o-matic"] = {
|
||||||
|
opt = true,
|
||||||
|
setup = function() table.insert(astronvim.file_plugins, "indent-o-matic") end,
|
||||||
|
config = function() require "configs.indent-o-matic" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Notification Enhancer
|
||||||
|
["rcarriga/nvim-notify"] = {
|
||||||
|
module = "notify",
|
||||||
|
setup = function() astronvim.load_plugin_with_func("nvim-notify", vim, "notify") end,
|
||||||
|
config = function() require "configs.notify" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Neovim UI Enhancer
|
||||||
|
["stevearc/dressing.nvim"] = {
|
||||||
|
opt = true,
|
||||||
|
setup = function() astronvim.load_plugin_with_func("dressing.nvim", vim.ui, { "input", "select" }) end,
|
||||||
|
config = function() require "configs.dressing" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Smarter Splits
|
||||||
|
["mrjones2014/smart-splits.nvim"] = {
|
||||||
|
module = "smart-splits",
|
||||||
|
config = function() require "configs.smart-splits" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Icons
|
||||||
|
["nvim-tree/nvim-web-devicons"] = {
|
||||||
|
disable = not vim.g.icons_enabled,
|
||||||
|
module = "nvim-web-devicons",
|
||||||
|
config = function() require "configs.nvim-web-devicons" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- LSP Icons
|
||||||
|
["onsails/lspkind.nvim"] = {
|
||||||
|
disable = not vim.g.icons_enabled,
|
||||||
|
module = "lspkind",
|
||||||
|
config = function() require "configs.lspkind" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Bufferline
|
||||||
|
["akinsho/bufferline.nvim"] = { -- TODO v3: remove this plugin
|
||||||
|
disable = vim.g.heirline_bufferline,
|
||||||
|
module = "bufferline",
|
||||||
|
event = "UIEnter",
|
||||||
|
config = function() require "configs.bufferline" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Better buffer closing
|
||||||
|
["famiu/bufdelete.nvim"] = {
|
||||||
|
module = "bufdelete",
|
||||||
|
setup = function() astronvim.lazy_load_commands("bufdelete.nvim", { "Bdelete", "Bwipeout" }) end,
|
||||||
|
},
|
||||||
|
|
||||||
|
["s1n7ax/nvim-window-picker"] = {
|
||||||
|
tag = "v1.*",
|
||||||
|
module = "window-picker",
|
||||||
|
config = function() require "configs.window-picker" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- File explorer
|
||||||
|
["nvim-neo-tree/neo-tree.nvim"] = {
|
||||||
|
branch = "v2.x",
|
||||||
|
module = "neo-tree",
|
||||||
|
requires = { { "MunifTanjim/nui.nvim", module = "nui" } },
|
||||||
|
setup = function()
|
||||||
|
astronvim.lazy_load_commands("neo-tree.nvim", "Neotree")
|
||||||
|
vim.g.neo_tree_remove_legacy_commands = true
|
||||||
|
end,
|
||||||
|
config = function() require "configs.neo-tree" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Statusline
|
||||||
|
["rebelot/heirline.nvim"] = { event = "VimEnter", config = function() require "configs.heirline" end },
|
||||||
|
|
||||||
|
-- Syntax highlighting
|
||||||
|
["nvim-treesitter/nvim-treesitter"] = {
|
||||||
|
module = "nvim-treesitter",
|
||||||
|
setup = function()
|
||||||
|
table.insert(astronvim.file_plugins, "nvim-treesitter")
|
||||||
|
astronvim.lazy_load_commands("nvim-treesitter", {
|
||||||
|
"TSBufDisable",
|
||||||
|
"TSBufEnable",
|
||||||
|
"TSBufToggle",
|
||||||
|
"TSDisable",
|
||||||
|
"TSEnable",
|
||||||
|
"TSToggle",
|
||||||
|
"TSInstall",
|
||||||
|
"TSInstallInfo",
|
||||||
|
"TSInstallSync",
|
||||||
|
"TSModuleInfo",
|
||||||
|
"TSUninstall",
|
||||||
|
"TSUpdate",
|
||||||
|
"TSUpdateSync",
|
||||||
|
})
|
||||||
|
end,
|
||||||
|
run = function() require("nvim-treesitter.install").update { with_sync = true }() end,
|
||||||
|
config = function() require "configs.treesitter" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Parenthesis highlighting
|
||||||
|
["p00f/nvim-ts-rainbow"] = { after = "nvim-treesitter" },
|
||||||
|
|
||||||
|
-- Autoclose tags
|
||||||
|
["windwp/nvim-ts-autotag"] = { after = "nvim-treesitter" },
|
||||||
|
|
||||||
|
-- Context based commenting
|
||||||
|
["JoosepAlviste/nvim-ts-context-commentstring"] = { after = "nvim-treesitter" },
|
||||||
|
|
||||||
|
-- Snippet collection
|
||||||
|
["rafamadriz/friendly-snippets"] = { opt = true },
|
||||||
|
|
||||||
|
-- Snippet engine
|
||||||
|
["L3MON4D3/LuaSnip"] = {
|
||||||
|
module = "luasnip",
|
||||||
|
wants = "friendly-snippets",
|
||||||
|
config = function() require "configs.luasnip" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Completion engine
|
||||||
|
["hrsh7th/nvim-cmp"] = { event = "InsertEnter", config = function() require "configs.cmp" end },
|
||||||
|
|
||||||
|
-- Snippet completion source
|
||||||
|
["saadparwaiz1/cmp_luasnip"] = {
|
||||||
|
after = "nvim-cmp",
|
||||||
|
config = function() astronvim.add_user_cmp_source "luasnip" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Buffer completion source
|
||||||
|
["hrsh7th/cmp-buffer"] = { after = "nvim-cmp", config = function() astronvim.add_user_cmp_source "buffer" end },
|
||||||
|
|
||||||
|
-- Path completion source
|
||||||
|
["hrsh7th/cmp-path"] = { after = "nvim-cmp", config = function() astronvim.add_user_cmp_source "path" end },
|
||||||
|
|
||||||
|
-- LSP completion source
|
||||||
|
["hrsh7th/cmp-nvim-lsp"] = { after = "nvim-cmp", config = function() astronvim.add_user_cmp_source "nvim_lsp" end },
|
||||||
|
|
||||||
|
-- Built-in LSP
|
||||||
|
["neovim/nvim-lspconfig"] = {
|
||||||
|
module = "lspconfig",
|
||||||
|
setup = function() table.insert(astronvim.file_plugins, "nvim-lspconfig") end,
|
||||||
|
config = function() require "configs.lspconfig" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Formatting and linting
|
||||||
|
["jose-elias-alvarez/null-ls.nvim"] = {
|
||||||
|
module = "null-ls",
|
||||||
|
setup = function() table.insert(astronvim.file_plugins, "null-ls.nvim") end,
|
||||||
|
config = function() require "configs.null-ls" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Debugger
|
||||||
|
["mfussenegger/nvim-dap"] = {
|
||||||
|
disable = vim.fn.has "win32" == 1,
|
||||||
|
module = "dap",
|
||||||
|
config = function() require "configs.dap" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Debugger UI
|
||||||
|
["rcarriga/nvim-dap-ui"] = {
|
||||||
|
disable = vim.fn.has "win32" == 1,
|
||||||
|
after = "nvim-dap",
|
||||||
|
config = function() require "configs.dapui" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Package Manager
|
||||||
|
["williamboman/mason.nvim"] = {
|
||||||
|
module = "mason",
|
||||||
|
cmd = {
|
||||||
|
"Mason",
|
||||||
|
"MasonInstall",
|
||||||
|
"MasonUninstall",
|
||||||
|
"MasonUninstallAll",
|
||||||
|
"MasonLog",
|
||||||
|
"MasonUpdate", -- astronvim command
|
||||||
|
"MasonUpdateAll", -- astronvim command
|
||||||
|
},
|
||||||
|
config = function()
|
||||||
|
require "configs.mason"
|
||||||
|
vim.tbl_map(function(plugin) pcall(require, plugin) end, { "lspconfig", "null-ls", "dap" })
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- LSP manager
|
||||||
|
["williamboman/mason-lspconfig.nvim"] = {
|
||||||
|
after = "nvim-lspconfig",
|
||||||
|
config = function() require "configs.mason-lspconfig" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- null-ls manager
|
||||||
|
["jayp0521/mason-null-ls.nvim"] = { after = "null-ls.nvim", config = function() require "configs.mason-null-ls" end },
|
||||||
|
|
||||||
|
-- dap manager
|
||||||
|
["jayp0521/mason-nvim-dap.nvim"] = {
|
||||||
|
disable = vim.fn.has "win32" == 1,
|
||||||
|
after = "nvim-dap",
|
||||||
|
config = function() require "configs.mason-nvim-dap" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- LSP symbols
|
||||||
|
["stevearc/aerial.nvim"] = {
|
||||||
|
module = "aerial",
|
||||||
|
after = { "nvim-treesitter", "nvim-lspconfig" },
|
||||||
|
ft = { "man", "markdown" },
|
||||||
|
config = function() require "configs.aerial" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Fuzzy finder
|
||||||
|
["nvim-telescope/telescope.nvim"] = {
|
||||||
|
module = "telescope",
|
||||||
|
setup = function() astronvim.lazy_load_commands("telescope.nvim", "Telescope") end,
|
||||||
|
config = function() require "configs.telescope" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Fuzzy finder syntax support
|
||||||
|
["nvim-telescope/telescope-fzf-native.nvim"] = {
|
||||||
|
after = "telescope.nvim",
|
||||||
|
disable = vim.fn.executable "make" == 0,
|
||||||
|
run = "make",
|
||||||
|
config = function() require("telescope").load_extension "fzf" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Git integration
|
||||||
|
["lewis6991/gitsigns.nvim"] = {
|
||||||
|
disable = vim.fn.executable "git" == 0,
|
||||||
|
ft = "gitcommit",
|
||||||
|
setup = function() table.insert(astronvim.git_plugins, "gitsigns.nvim") end,
|
||||||
|
config = function() require "configs.gitsigns" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Start screen
|
||||||
|
["goolord/alpha-nvim"] = {
|
||||||
|
module = "alpha",
|
||||||
|
setup = function() astronvim.lazy_load_commands("alpha-nvim", "Alpha") end,
|
||||||
|
config = function() require "configs.alpha" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Color highlighting
|
||||||
|
["NvChad/nvim-colorizer.lua"] = {
|
||||||
|
opt = true,
|
||||||
|
setup = function()
|
||||||
|
astronvim.lazy_load_commands(
|
||||||
|
"nvim-colorizer.lua",
|
||||||
|
{ "ColorizerToggle", "ColorizerAttachToBuffer", "ColorizerDetachFromBuffer", "ColorizerReloadAllBuffers" }
|
||||||
|
)
|
||||||
|
table.insert(astronvim.file_plugins, "nvim-colorizer.lua")
|
||||||
|
end,
|
||||||
|
config = function() require "configs.colorizer" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Autopairs
|
||||||
|
["windwp/nvim-autopairs"] = { event = "InsertEnter", config = function() require "configs.autopairs" end },
|
||||||
|
|
||||||
|
-- Terminal
|
||||||
|
["akinsho/toggleterm.nvim"] = {
|
||||||
|
module = "toggleterm",
|
||||||
|
setup = function() astronvim.lazy_load_commands("toggleterm.nvim", { "ToggleTerm", "TermExec" }) end,
|
||||||
|
config = function() require "configs.toggleterm" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Commenting
|
||||||
|
["numToStr/Comment.nvim"] = {
|
||||||
|
module = "Comment",
|
||||||
|
keys = { "gc", "gb" },
|
||||||
|
config = function() require "configs.Comment" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Indentation
|
||||||
|
["lukas-reineke/indent-blankline.nvim"] = {
|
||||||
|
opt = true,
|
||||||
|
setup = function() table.insert(astronvim.file_plugins, "indent-blankline.nvim") end,
|
||||||
|
config = function() require "configs.indent-line" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Keymaps popup
|
||||||
|
["folke/which-key.nvim"] = { module = "which-key", config = function() require "configs.which-key" end },
|
||||||
|
|
||||||
|
-- Smooth escaping
|
||||||
|
["max397574/better-escape.nvim"] = {
|
||||||
|
event = "InsertCharPre",
|
||||||
|
config = function() require "configs.better_escape" end,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Get extra JSON schemas
|
||||||
|
["b0o/SchemaStore.nvim"] = { module = "schemastore" },
|
||||||
|
|
||||||
|
-- Session manager
|
||||||
|
["Shatur/neovim-session-manager"] = {
|
||||||
|
module = "session_manager",
|
||||||
|
event = "BufWritePost",
|
||||||
|
setup = function() astronvim.lazy_load_commands("neovim-session-manager", "SessionManager") end,
|
||||||
|
config = function() require "configs.session_manager" end,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if astronvim.updater.snapshot then
|
||||||
|
for plugin, options in pairs(astro_plugins) do
|
||||||
|
local pin = astronvim.updater.snapshot[plugin:match "/([^/]*)$"]
|
||||||
|
if pin and pin.commit then
|
||||||
|
options.commit = pin.commit
|
||||||
|
options.tag = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local user_plugin_opts = astronvim.user_plugin_opts
|
||||||
|
local status_ok, packer = pcall(require, "packer")
|
||||||
|
if status_ok then
|
||||||
|
packer.startup {
|
||||||
|
function(use)
|
||||||
|
local plugins = user_plugin_opts("plugins.init", astro_plugins)
|
||||||
|
for key, plugin in pairs(plugins) do
|
||||||
|
if type(key) == "string" and not plugin[1] then plugin[1] = key end
|
||||||
|
if key == "williamboman/mason.nvim" and plugin.cmd then
|
||||||
|
for mason_plugin, commands in pairs { -- lazy load mason plugin commands with Mason
|
||||||
|
["jayp0521/mason-null-ls.nvim"] = { "NullLsInstall", "NullLsUninstall" },
|
||||||
|
["williamboman/mason-lspconfig.nvim"] = { "LspInstall", "LspUninstall" },
|
||||||
|
["jayp0521/mason-nvim-dap.nvim"] = { "DapInstall", "DapUninstall" },
|
||||||
|
} do
|
||||||
|
if plugins[mason_plugin] and not plugins[mason_plugin].disable then
|
||||||
|
vim.list_extend(plugin.cmd, commands)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
use(plugin)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
config = user_plugin_opts("plugins.packer", {
|
||||||
|
compile_path = astronvim.default_compile_path,
|
||||||
|
display = {
|
||||||
|
open_fn = function() return require("packer.util").float { border = "rounded" } end,
|
||||||
|
},
|
||||||
|
profile = {
|
||||||
|
enable = true,
|
||||||
|
threshold = 0.0001,
|
||||||
|
},
|
||||||
|
git = {
|
||||||
|
clone_timeout = 300,
|
||||||
|
subcommands = {
|
||||||
|
update = "pull --rebase",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
auto_clean = true,
|
||||||
|
compile_on_sync = true,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
end
|
|
@ -0,0 +1,157 @@
|
||||||
|
--- ### Git LUA API
|
||||||
|
--
|
||||||
|
-- This module can be loaded with `local git = require "core.utils.git"`
|
||||||
|
--
|
||||||
|
-- @module core.utils.git
|
||||||
|
-- @copyright 2022
|
||||||
|
-- @license GNU General Public License v3.0
|
||||||
|
|
||||||
|
local git = { url = "https://github.com/" }
|
||||||
|
|
||||||
|
--- Run a git command from the AstroNvim installation directory
|
||||||
|
-- @param args the git arguments
|
||||||
|
-- @return the result of the command or nil if unsuccessful
|
||||||
|
function git.cmd(args, ...) return astronvim.cmd("git -C " .. astronvim.install.home .. " " .. args, ...) end
|
||||||
|
|
||||||
|
--- Check if the AstroNvim is able to reach the `git` command
|
||||||
|
-- @return the result of running `git --help`
|
||||||
|
function git.available() return vim.fn.executable "git" == 1 end
|
||||||
|
|
||||||
|
--- Check if the AstroNvim home is a git repo
|
||||||
|
-- @return the result of the command
|
||||||
|
function git.is_repo() return git.cmd("rev-parse --is-inside-work-tree", false) end
|
||||||
|
|
||||||
|
--- Fetch git remote
|
||||||
|
-- @param remote the remote to fetch
|
||||||
|
-- @return the result of the command
|
||||||
|
function git.fetch(remote, ...) return git.cmd("fetch " .. remote, ...) end
|
||||||
|
|
||||||
|
--- Pull the git repo
|
||||||
|
-- @return the result of the command
|
||||||
|
function git.pull(...) return git.cmd("pull --rebase", ...) end
|
||||||
|
|
||||||
|
--- Checkout git target
|
||||||
|
-- @param dest the target to checkout
|
||||||
|
-- @return the result of the command
|
||||||
|
function git.checkout(dest, ...) return git.cmd("checkout " .. dest, ...) end
|
||||||
|
|
||||||
|
--- Hard reset to a git target
|
||||||
|
-- @param dest the target to hard reset to
|
||||||
|
-- @return the result of the command
|
||||||
|
function git.hard_reset(dest, ...) return git.cmd("reset --hard " .. dest, ...) end
|
||||||
|
|
||||||
|
--- Check if a branch contains a commit
|
||||||
|
-- @param remote the git remote to check
|
||||||
|
-- @param branch the git branch to check
|
||||||
|
-- @param commit the git commit to check for
|
||||||
|
-- @return the result of the command
|
||||||
|
function git.branch_contains(remote, branch, commit, ...)
|
||||||
|
return git.cmd("merge-base --is-ancestor " .. commit .. " " .. remote .. "/" .. branch, ...) ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a git remote
|
||||||
|
-- @param remote the remote to add
|
||||||
|
-- @param url the url of the remote
|
||||||
|
-- @return the result of the command
|
||||||
|
function git.remote_add(remote, url, ...) return git.cmd("remote add " .. remote .. " " .. url, ...) end
|
||||||
|
|
||||||
|
--- Update a git remote URL
|
||||||
|
-- @param remote the remote to update
|
||||||
|
-- @param url the new URL of the remote
|
||||||
|
-- @return the result of the command
|
||||||
|
function git.remote_update(remote, url, ...) return git.cmd("remote set-url " .. remote .. " " .. url, ...) end
|
||||||
|
|
||||||
|
--- Get the URL of a given git remote
|
||||||
|
-- @param remote the remote to get the URL of
|
||||||
|
-- @return the url of the remote
|
||||||
|
function git.remote_url(remote, ...) return astronvim.trim_or_nil(git.cmd("remote get-url " .. remote, ...)) end
|
||||||
|
|
||||||
|
--- Get the current version with git describe including tags
|
||||||
|
-- @return the current git describe string
|
||||||
|
function git.current_version(...) return astronvim.trim_or_nil(git.cmd("describe --tags", ...)) end
|
||||||
|
|
||||||
|
--- Get the current branch
|
||||||
|
-- @return the branch of the AstroNvim installation
|
||||||
|
function git.current_branch(...) return astronvim.trim_or_nil(git.cmd("rev-parse --abbrev-ref HEAD", ...)) end
|
||||||
|
|
||||||
|
--- Get the current head of the git repo
|
||||||
|
-- @return the head string
|
||||||
|
function git.local_head(...) return astronvim.trim_or_nil(git.cmd("rev-parse HEAD", ...)) end
|
||||||
|
|
||||||
|
--- Get the current head of a git remote
|
||||||
|
-- @param remote the remote to check
|
||||||
|
-- @param branch the branch to check
|
||||||
|
-- @return the head string of the remote branch
|
||||||
|
function git.remote_head(remote, branch, ...)
|
||||||
|
return astronvim.trim_or_nil(git.cmd("rev-list -n 1 " .. remote .. "/" .. branch, ...))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the commit hash of a given tag
|
||||||
|
-- @param tag the tag to resolve
|
||||||
|
-- @return the commit hash of a git tag
|
||||||
|
function git.tag_commit(tag, ...) return astronvim.trim_or_nil(git.cmd("rev-list -n 1 " .. tag, ...)) end
|
||||||
|
|
||||||
|
--- Get the commit log between two commit hashes
|
||||||
|
-- @param start_hash the start commit hash
|
||||||
|
-- @param end_hash the end commit hash
|
||||||
|
-- @return an array like table of commit messages
|
||||||
|
function git.get_commit_range(start_hash, end_hash, ...)
|
||||||
|
local range = ""
|
||||||
|
if start_hash and end_hash then range = start_hash .. ".." .. end_hash end
|
||||||
|
local log = git.cmd('log --no-merges --pretty="format:[%h] %s" ' .. range, ...)
|
||||||
|
return log and vim.fn.split(log, "\n") or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get a list of all tags with a regex filter
|
||||||
|
-- @param search a regex to search the tags with (defaults to "v*" for version tags)
|
||||||
|
-- @return an array like table of tags that match the search
|
||||||
|
function git.get_versions(search, ...)
|
||||||
|
local tags = git.cmd('tag -l --sort=version:refname "' .. (search == "latest" and "v*" or search) .. '"', ...)
|
||||||
|
return tags and vim.fn.split(tags, "\n") or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the latest version of a list of versions
|
||||||
|
-- @param versions a list of versions to search (defaults to all versions available)
|
||||||
|
-- @return the latest version from the array
|
||||||
|
function git.latest_version(versions, ...)
|
||||||
|
if not versions then versions = git.get_versions(...) end
|
||||||
|
return versions[#versions]
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Parse a remote url
|
||||||
|
-- @param str the remote to parse to a full git url
|
||||||
|
-- @return the full git url for the given remote string
|
||||||
|
function git.parse_remote_url(str)
|
||||||
|
return vim.fn.match(str, astronvim.url_matcher) == -1
|
||||||
|
and git.url .. str .. (vim.fn.match(str, "/") == -1 and "/AstroNvim.git" or ".git")
|
||||||
|
or str
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if a Conventional Commit commit message is breaking or not
|
||||||
|
-- @param commit a commit message
|
||||||
|
-- @return boolean true if the message is breaking, false if the commit message is not breaking
|
||||||
|
function git.is_breaking(commit) return vim.fn.match(commit, "\\[.*\\]\\s\\+\\w\\+\\((\\w\\+)\\)\\?!:") ~= -1 end
|
||||||
|
|
||||||
|
--- Get a list of breaking commits from commit messages using Conventional Commit standard
|
||||||
|
-- @param commits an array like table of commit messages
|
||||||
|
-- @return an array like table of commits that are breaking
|
||||||
|
function git.breaking_changes(commits) return vim.tbl_filter(git.is_breaking, commits) end
|
||||||
|
|
||||||
|
--- Generate a table of commit messages for neovim's echo API with highlighting
|
||||||
|
-- @param commits an array like table of commit messages
|
||||||
|
-- @return an array like table of echo messages to provide to nvim_echo or astronvim.echo
|
||||||
|
function git.pretty_changelog(commits)
|
||||||
|
local changelog = {}
|
||||||
|
for _, commit in ipairs(commits) do
|
||||||
|
local hash, type, msg = commit:match "(%[.*%])(.*:)(.*)"
|
||||||
|
if hash and type and msg then
|
||||||
|
vim.list_extend(
|
||||||
|
changelog,
|
||||||
|
{ { hash, "DiffText" }, { type, git.is_breaking(commit) and "DiffDelete" or "DiffChange" }, { msg }, { "\n" } }
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return changelog
|
||||||
|
end
|
||||||
|
|
||||||
|
return git
|
|
@ -0,0 +1,606 @@
|
||||||
|
--- ### AstroNvim Utilities
|
||||||
|
--
|
||||||
|
-- This module is automatically loaded by AstroNvim on during it's initialization into global variable `astronvim`
|
||||||
|
--
|
||||||
|
-- This module can also be manually loaded with `local astronvim = require "core.utils"`
|
||||||
|
--
|
||||||
|
-- @module core.utils
|
||||||
|
-- @copyright 2022
|
||||||
|
-- @license GNU General Public License v3.0
|
||||||
|
|
||||||
|
_G.astronvim = {}
|
||||||
|
local stdpath = vim.fn.stdpath
|
||||||
|
local tbl_insert = table.insert
|
||||||
|
local map = vim.keymap.set
|
||||||
|
|
||||||
|
--- installation details from external installers
|
||||||
|
astronvim.install = astronvim_installation or { home = stdpath "config" }
|
||||||
|
--- external astronvim configuration folder
|
||||||
|
astronvim.install.config = stdpath("config"):gsub("nvim$", "astronvim")
|
||||||
|
vim.opt.rtp:append(astronvim.install.config)
|
||||||
|
local supported_configs = { astronvim.install.home, astronvim.install.config }
|
||||||
|
|
||||||
|
--- Looks to see if a module path references a lua file in a configuration folder and tries to load it. If there is an error loading the file, write an error and continue
|
||||||
|
-- @param module the module path to try and load
|
||||||
|
-- @return the loaded module if successful or nil
|
||||||
|
local function load_module_file(module)
|
||||||
|
-- placeholder for final return value
|
||||||
|
local found_module = nil
|
||||||
|
-- search through each of the supported configuration locations
|
||||||
|
for _, config_path in ipairs(supported_configs) do
|
||||||
|
-- convert the module path to a file path (example user.init -> user/init.lua)
|
||||||
|
local module_path = config_path .. "/lua/" .. module:gsub("%.", "/") .. ".lua"
|
||||||
|
-- check if there is a readable file, if so, set it as found
|
||||||
|
if vim.fn.filereadable(module_path) == 1 then found_module = module_path end
|
||||||
|
end
|
||||||
|
-- if we found a readable lua file, try to load it
|
||||||
|
if found_module then
|
||||||
|
-- try to load the file
|
||||||
|
local status_ok, loaded_module = pcall(require, module)
|
||||||
|
-- if successful at loading, set the return variable
|
||||||
|
if status_ok then
|
||||||
|
found_module = loaded_module
|
||||||
|
-- if unsuccessful, throw an error
|
||||||
|
else
|
||||||
|
vim.api.nvim_err_writeln("Error loading file: " .. found_module .. "\n\n" .. loaded_module)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- return the loaded module or nil if no file found
|
||||||
|
return found_module
|
||||||
|
end
|
||||||
|
|
||||||
|
--- user settings from the base `user/init.lua` file
|
||||||
|
astronvim.user_settings = load_module_file "user.init"
|
||||||
|
--- default packer compilation location to be used in bootstrapping and packer setup call
|
||||||
|
astronvim.default_compile_path = stdpath "data" .. "/packer_compiled.lua"
|
||||||
|
--- table of user created terminals
|
||||||
|
astronvim.user_terminals = {}
|
||||||
|
--- table of plugins to load with git
|
||||||
|
astronvim.git_plugins = {}
|
||||||
|
--- table of plugins to load when file opened
|
||||||
|
astronvim.file_plugins = {}
|
||||||
|
--- regex used for matching a valid URL/URI string
|
||||||
|
astronvim.url_matcher =
|
||||||
|
"\\v\\c%(%(h?ttps?|ftp|file|ssh|git)://|[a-z]+[@][a-z]+[.][a-z]+:)%([&:#*@~%_\\-=?!+;/0-9a-z]+%(%([.;/?]|[.][.]+)[&:#*@~%_\\-=?!+/0-9a-z]+|:\\d+|,%(%(%(h?ttps?|ftp|file|ssh|git)://|[a-z]+[@][a-z]+[.][a-z]+:)@![0-9a-z]+))*|\\([&:#*@~%_\\-=?!+;/.0-9a-z]*\\)|\\[[&:#*@~%_\\-=?!+;/.0-9a-z]*\\]|\\{%([&:#*@~%_\\-=?!+;/.0-9a-z]*|\\{[&:#*@~%_\\-=?!+;/.0-9a-z]*})\\})+"
|
||||||
|
|
||||||
|
--- Main configuration engine logic for extending a default configuration table with either a function override or a table to merge into the default option
|
||||||
|
-- @function astronvim.func_or_extend
|
||||||
|
-- @param overrides the override definition, either a table or a function that takes a single parameter of the original table
|
||||||
|
-- @param default the default configuration table
|
||||||
|
-- @param extend boolean value to either extend the default or simply overwrite it if an override is provided
|
||||||
|
-- @return the new configuration table
|
||||||
|
local function func_or_extend(overrides, default, extend)
|
||||||
|
-- if we want to extend the default with the provided override
|
||||||
|
if extend then
|
||||||
|
-- if the override is a table, use vim.tbl_deep_extend
|
||||||
|
if type(overrides) == "table" then
|
||||||
|
default = astronvim.default_tbl(overrides, default)
|
||||||
|
-- if the override is a function, call it with the default and overwrite default with the return value
|
||||||
|
elseif type(overrides) == "function" then
|
||||||
|
default = overrides(default)
|
||||||
|
end
|
||||||
|
-- if extend is set to false and we have a provided override, simply override the default
|
||||||
|
elseif overrides ~= nil then
|
||||||
|
default = overrides
|
||||||
|
end
|
||||||
|
-- return the modified default table
|
||||||
|
return default
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Merge extended options with a default table of options
|
||||||
|
-- @param opts the new options that should be merged with the default table
|
||||||
|
-- @param default the default table that you want to merge into
|
||||||
|
-- @return the merged table
|
||||||
|
function astronvim.default_tbl(opts, default)
|
||||||
|
opts = opts or {}
|
||||||
|
return default and vim.tbl_deep_extend("force", default, opts) or opts
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Call function if a condition is met
|
||||||
|
-- @param func the function to run
|
||||||
|
-- @param condition a boolean value of whether to run the function or not
|
||||||
|
function astronvim.conditional_func(func, condition, ...)
|
||||||
|
-- if the condition is true or no condition is provided, evaluate the function with the rest of the parameters and return the result
|
||||||
|
if (condition == nil or condition) and type(func) == "function" then return func(...) end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get highlight properties for a given highlight name
|
||||||
|
-- @param name highlight group name
|
||||||
|
-- @return table of highlight group properties
|
||||||
|
function astronvim.get_hlgroup(name, fallback)
|
||||||
|
if vim.fn.hlexists(name) == 1 then
|
||||||
|
local hl = vim.api.nvim_get_hl_by_name(name, vim.o.termguicolors)
|
||||||
|
if not hl["foreground"] then hl["foreground"] = "NONE" end
|
||||||
|
if not hl["background"] then hl["background"] = "NONE" end
|
||||||
|
hl.fg, hl.bg, hl.sp = hl.foreground, hl.background, hl.special
|
||||||
|
hl.ctermfg, hl.ctermbg = hl.foreground, hl.background
|
||||||
|
return hl
|
||||||
|
end
|
||||||
|
return fallback
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Trim a string or return nil
|
||||||
|
-- @param str the string to trim
|
||||||
|
-- @return a trimmed version of the string or nil if the parameter isn't a string
|
||||||
|
function astronvim.trim_or_nil(str) return type(str) == "string" and vim.trim(str) or nil end
|
||||||
|
|
||||||
|
--- Add left and/or right padding to a string
|
||||||
|
-- @param str the string to add padding to
|
||||||
|
-- @param padding a table of the format `{ left = 0, right = 0}` that defines the number of spaces to include to the left and the right of the string
|
||||||
|
-- @return the padded string
|
||||||
|
function astronvim.pad_string(str, padding)
|
||||||
|
padding = padding or {}
|
||||||
|
return str and str ~= "" and string.rep(" ", padding.left or 0) .. str .. string.rep(" ", padding.right or 0) or ""
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Initialize icons used throughout the user interface
|
||||||
|
function astronvim.initialize_icons()
|
||||||
|
astronvim.icons = astronvim.user_plugin_opts("icons", require "core.icons.nerd_font")
|
||||||
|
astronvim.text_icons = astronvim.user_plugin_opts("text_icons", require "core.icons.text")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get an icon from `lspkind` if it is available and return it
|
||||||
|
-- @param kind the kind of icon in `lspkind` to retrieve
|
||||||
|
-- @return the icon
|
||||||
|
function astronvim.get_icon(kind)
|
||||||
|
local icon_pack = vim.g.icons_enabled and "icons" or "text_icons"
|
||||||
|
if not astronvim[icon_pack] then astronvim.initialize_icons() end
|
||||||
|
return astronvim[icon_pack] and astronvim[icon_pack][kind] or ""
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Serve a notification with a title of AstroNvim
|
||||||
|
-- @param msg the notification body
|
||||||
|
-- @param type the type of the notification (:help vim.log.levels)
|
||||||
|
-- @param opts table of nvim-notify options to use (:help notify-options)
|
||||||
|
function astronvim.notify(msg, type, opts)
|
||||||
|
vim.schedule(function() vim.notify(msg, type, astronvim.default_tbl(opts, { title = "AstroNvim" })) end)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Trigger an AstroNvim user event
|
||||||
|
-- @param event the event name to be appended to Astro
|
||||||
|
function astronvim.event(event)
|
||||||
|
vim.schedule(function() vim.api.nvim_exec_autocmds("User", { pattern = "Astro" .. event }) end)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Wrapper function for neovim echo API
|
||||||
|
-- @param messages an array like table where each item is an array like table of strings to echo
|
||||||
|
function astronvim.echo(messages)
|
||||||
|
-- if no parameter provided, echo a new line
|
||||||
|
messages = messages or { { "\n" } }
|
||||||
|
if type(messages) == "table" then vim.api.nvim_echo(messages, false, {}) end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Echo a message and prompt the user for yes or no response
|
||||||
|
-- @param messages the message to echo
|
||||||
|
-- @return True if the user responded y, False for any other response
|
||||||
|
function astronvim.confirm_prompt(messages)
|
||||||
|
if messages then astronvim.echo(messages) end
|
||||||
|
local confirmed = string.lower(vim.fn.input "(y/n) ") == "y"
|
||||||
|
astronvim.echo()
|
||||||
|
astronvim.echo()
|
||||||
|
return confirmed
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Search the user settings (user/init.lua table) for a table with a module like path string
|
||||||
|
-- @param module the module path like string to look up in the user settings table
|
||||||
|
-- @return the value of the table entry if exists or nil
|
||||||
|
local function user_setting_table(module)
|
||||||
|
-- get the user settings table
|
||||||
|
local settings = astronvim.user_settings or {}
|
||||||
|
-- iterate over the path string split by '.' to look up the table value
|
||||||
|
for tbl in string.gmatch(module, "([^%.]+)") do
|
||||||
|
settings = settings[tbl]
|
||||||
|
-- if key doesn't exist, keep the nil value and stop searching
|
||||||
|
if settings == nil then break end
|
||||||
|
end
|
||||||
|
-- return the found settings
|
||||||
|
return settings
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if packer is installed and loadable, if not then install it and make sure it loads
|
||||||
|
function astronvim.initialize_packer()
|
||||||
|
-- try loading packer
|
||||||
|
local packer_path = stdpath "data" .. "/site/pack/packer/opt/packer.nvim"
|
||||||
|
local packer_avail = vim.fn.empty(vim.fn.glob(packer_path)) == 0
|
||||||
|
-- if packer isn't availble, reinstall it
|
||||||
|
if not packer_avail then
|
||||||
|
-- set the location to install packer
|
||||||
|
-- delete the old packer install if one exists
|
||||||
|
vim.fn.delete(packer_path, "rf")
|
||||||
|
-- clone packer
|
||||||
|
vim.fn.system {
|
||||||
|
"git",
|
||||||
|
"clone",
|
||||||
|
"--depth",
|
||||||
|
"1",
|
||||||
|
"https://github.com/wbthomason/packer.nvim",
|
||||||
|
packer_path,
|
||||||
|
}
|
||||||
|
-- add packer and try loading it
|
||||||
|
vim.cmd.packadd "packer.nvim"
|
||||||
|
local packer_loaded, _ = pcall(require, "packer")
|
||||||
|
packer_avail = packer_loaded
|
||||||
|
-- if packer didn't load, print error
|
||||||
|
if not packer_avail then vim.api.nvim_err_writeln("Failed to load packer at:" .. packer_path) end
|
||||||
|
end
|
||||||
|
-- if packer is available, check if there is a compiled packer file
|
||||||
|
if packer_avail then
|
||||||
|
-- try to load the packer compiled file
|
||||||
|
local run_me, _ = loadfile(
|
||||||
|
astronvim.user_plugin_opts("plugins.packer", { compile_path = astronvim.default_compile_path }).compile_path
|
||||||
|
)
|
||||||
|
if run_me then
|
||||||
|
-- if the file loads, run the compiled function
|
||||||
|
run_me()
|
||||||
|
else
|
||||||
|
-- if there is no compiled file, ask user to sync packer
|
||||||
|
require "core.plugins"
|
||||||
|
vim.api.nvim_create_autocmd("User", {
|
||||||
|
once = true,
|
||||||
|
pattern = "PackerComplete",
|
||||||
|
callback = function()
|
||||||
|
vim.cmd.bw()
|
||||||
|
vim.tbl_map(require, { "nvim-treesitter", "mason" })
|
||||||
|
astronvim.notify "Mason is installing packages if configured, check status with :Mason"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
vim.opt.cmdheight = 1
|
||||||
|
vim.notify "Please wait while plugins are installed..."
|
||||||
|
vim.cmd.PackerSync()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function astronvim.lazy_load_commands(plugin, commands)
|
||||||
|
if type(commands) == "string" then commands = { commands } end
|
||||||
|
if astronvim.is_available(plugin) and not packer_plugins[plugin].loaded then
|
||||||
|
for _, command in ipairs(commands) do
|
||||||
|
pcall(
|
||||||
|
vim.cmd,
|
||||||
|
string.format(
|
||||||
|
'command -nargs=* -range -bang -complete=file %s lua require("packer.load")({"%s"}, { cmd = "%s", l1 = <line1>, l2 = <line2>, bang = <q-bang>, args = <q-args>, mods = "<mods>" }, _G.packer_plugins)',
|
||||||
|
command,
|
||||||
|
plugin,
|
||||||
|
command
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set vim options with a nested table like API with the format vim.<first_key>.<second_key>.<value>
|
||||||
|
-- @param options the nested table of vim options
|
||||||
|
function astronvim.vim_opts(options)
|
||||||
|
for scope, table in pairs(options) do
|
||||||
|
for setting, value in pairs(table) do
|
||||||
|
vim[scope][setting] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- User configuration entry point to override the default options of a configuration table with a user configuration file or table in the user/init.lua user settings
|
||||||
|
-- @param module the module path of the override setting
|
||||||
|
-- @param default the default settings that will be overridden
|
||||||
|
-- @param extend boolean value to either extend the default settings or overwrite them with the user settings entirely (default: true)
|
||||||
|
-- @param prefix a module prefix for where to search (default: user)
|
||||||
|
-- @return the new configuration settings with the user overrides applied
|
||||||
|
function astronvim.user_plugin_opts(module, default, extend, prefix)
|
||||||
|
-- default to extend = true
|
||||||
|
if extend == nil then extend = true end
|
||||||
|
-- if no default table is provided set it to an empty table
|
||||||
|
default = default or {}
|
||||||
|
-- try to load a module file if it exists
|
||||||
|
local user_settings = load_module_file((prefix or "user") .. "." .. module)
|
||||||
|
-- if no user module file is found, try to load an override from the user settings table from user/init.lua
|
||||||
|
if user_settings == nil and prefix == nil then user_settings = user_setting_table(module) end
|
||||||
|
-- if a user override was found call the configuration engine
|
||||||
|
if user_settings ~= nil then default = func_or_extend(user_settings, default, extend) end
|
||||||
|
-- return the final configuration table with any overrides applied
|
||||||
|
return default
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Open a URL under the cursor with the current operating system (Supports Mac OS X and *nix)
|
||||||
|
-- @param path the path of the file to open with the system opener
|
||||||
|
function astronvim.system_open(path)
|
||||||
|
path = path or vim.fn.expand "<cfile>"
|
||||||
|
if vim.fn.has "mac" == 1 then
|
||||||
|
-- if mac use the open command
|
||||||
|
vim.fn.jobstart({ "open", path }, { detach = true })
|
||||||
|
elseif vim.fn.has "unix" == 1 then
|
||||||
|
-- if unix then use xdg-open
|
||||||
|
vim.fn.jobstart({ "xdg-open", path }, { detach = true })
|
||||||
|
else
|
||||||
|
-- if any other operating system notify the user that there is currently no support
|
||||||
|
astronvim.notify("System open is not supported on this OS!", "error")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- term_details can be either a string for just a command or
|
||||||
|
-- a complete table to provide full access to configuration when calling Terminal:new()
|
||||||
|
|
||||||
|
--- Toggle a user terminal if it exists, if not then create a new one and save it
|
||||||
|
-- @param term_details a terminal command string or a table of options for Terminal:new() (Check toggleterm.nvim documentation for table format)
|
||||||
|
function astronvim.toggle_term_cmd(opts)
|
||||||
|
local terms = astronvim.user_terminals
|
||||||
|
-- if a command string is provided, create a basic table for Terminal:new() options
|
||||||
|
if type(opts) == "string" then opts = { cmd = opts, hidden = true } end
|
||||||
|
local num = vim.v.count > 0 and vim.v.count or 1
|
||||||
|
-- if terminal doesn't exist yet, create it
|
||||||
|
if not terms[opts.cmd] then terms[opts.cmd] = {} end
|
||||||
|
if not terms[opts.cmd][num] then
|
||||||
|
if not opts.count then opts.count = vim.tbl_count(terms) * 100 + num end
|
||||||
|
terms[opts.cmd][num] = require("toggleterm.terminal").Terminal:new(opts)
|
||||||
|
end
|
||||||
|
-- toggle the terminal
|
||||||
|
astronvim.user_terminals[opts.cmd][num]:toggle()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add a source to cmp
|
||||||
|
-- @param source the cmp source string or table to add (see cmp documentation for source table format)
|
||||||
|
function astronvim.add_cmp_source(source)
|
||||||
|
-- load cmp if available
|
||||||
|
local cmp_avail, cmp = pcall(require, "cmp")
|
||||||
|
if cmp_avail then
|
||||||
|
-- get the current cmp config
|
||||||
|
local config = cmp.get_config()
|
||||||
|
-- add the source to the list of sources
|
||||||
|
tbl_insert(config.sources, source)
|
||||||
|
-- call the setup function again
|
||||||
|
cmp.setup(config)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the priority of a cmp source
|
||||||
|
-- @param source the cmp source string or table (see cmp documentation for source table format)
|
||||||
|
-- @return a cmp source table with the priority set from the user configuration
|
||||||
|
function astronvim.get_user_cmp_source(source)
|
||||||
|
-- if the source is a string, convert it to a cmp source table
|
||||||
|
source = type(source) == "string" and { name = source } or source
|
||||||
|
-- get the priority of the source name from the user configuration
|
||||||
|
local priority = astronvim.user_plugin_opts("cmp.source_priority", {
|
||||||
|
nvim_lsp = 1000,
|
||||||
|
luasnip = 750,
|
||||||
|
buffer = 500,
|
||||||
|
path = 250,
|
||||||
|
})[source.name]
|
||||||
|
-- if a priority is found, set it in the source
|
||||||
|
if priority then source.priority = priority end
|
||||||
|
-- return the source table
|
||||||
|
return source
|
||||||
|
end
|
||||||
|
|
||||||
|
--- add a source to cmp with the user configured priority
|
||||||
|
-- @param source a cmp source string or table (see cmp documentation for source table format)
|
||||||
|
function astronvim.add_user_cmp_source(source) astronvim.add_cmp_source(astronvim.get_user_cmp_source(source)) end
|
||||||
|
|
||||||
|
--- register mappings table with which-key
|
||||||
|
-- @param mappings nested table of mappings where the first key is the mode, the second key is the prefix, and the value is the mapping table for which-key
|
||||||
|
-- @param opts table of which-key options when setting the mappings (see which-key documentation for possible values)
|
||||||
|
function astronvim.which_key_register(mappings, opts)
|
||||||
|
local status_ok, which_key = pcall(require, "which-key")
|
||||||
|
if not status_ok then return end
|
||||||
|
for mode, prefixes in pairs(mappings) do
|
||||||
|
for prefix, mapping_table in pairs(prefixes) do
|
||||||
|
which_key.register(
|
||||||
|
mapping_table,
|
||||||
|
astronvim.default_tbl(opts, {
|
||||||
|
mode = mode,
|
||||||
|
prefix = prefix,
|
||||||
|
buffer = nil,
|
||||||
|
silent = true,
|
||||||
|
noremap = true,
|
||||||
|
nowait = true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get a list of registered null-ls providers for a given filetype
|
||||||
|
-- @param filetype the filetype to search null-ls for
|
||||||
|
-- @return a list of null-ls sources
|
||||||
|
function astronvim.null_ls_providers(filetype)
|
||||||
|
local registered = {}
|
||||||
|
-- try to load null-ls
|
||||||
|
local sources_avail, sources = pcall(require, "null-ls.sources")
|
||||||
|
if sources_avail then
|
||||||
|
-- get the available sources of a given filetype
|
||||||
|
for _, source in ipairs(sources.get_available(filetype)) do
|
||||||
|
-- get each source name
|
||||||
|
for method in pairs(source.methods) do
|
||||||
|
registered[method] = registered[method] or {}
|
||||||
|
tbl_insert(registered[method], source.name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- return the found null-ls sources
|
||||||
|
return registered
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the null-ls sources for a given null-ls method
|
||||||
|
-- @param filetype the filetype to search null-ls for
|
||||||
|
-- @param method the null-ls method (check null-ls documentation for available methods)
|
||||||
|
-- @return the available sources for the given filetype and method
|
||||||
|
function astronvim.null_ls_sources(filetype, method)
|
||||||
|
local methods_avail, methods = pcall(require, "null-ls.methods")
|
||||||
|
return methods_avail and astronvim.null_ls_providers(filetype)[methods.internal[method]] or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create a button entity to use with the alpha dashboard
|
||||||
|
-- @param sc the keybinding string to convert to a button
|
||||||
|
-- @param txt the explanation text of what the keybinding does
|
||||||
|
-- @return a button entity table for an alpha configuration
|
||||||
|
function astronvim.alpha_button(sc, txt)
|
||||||
|
-- replace <leader> in shortcut text with LDR for nicer printing
|
||||||
|
local sc_ = sc:gsub("%s", ""):gsub("LDR", "<leader>")
|
||||||
|
-- if the leader is set, replace the text with the actual leader key for nicer printing
|
||||||
|
if vim.g.mapleader then sc = sc:gsub("LDR", vim.g.mapleader == " " and "SPC" or vim.g.mapleader) end
|
||||||
|
-- return the button entity to display the correct text and send the correct keybinding on press
|
||||||
|
return {
|
||||||
|
type = "button",
|
||||||
|
val = txt,
|
||||||
|
on_press = function()
|
||||||
|
local key = vim.api.nvim_replace_termcodes(sc_, true, false, true)
|
||||||
|
vim.api.nvim_feedkeys(key, "normal", false)
|
||||||
|
end,
|
||||||
|
opts = {
|
||||||
|
position = "center",
|
||||||
|
text = txt,
|
||||||
|
shortcut = sc,
|
||||||
|
cursor = 5,
|
||||||
|
width = 36,
|
||||||
|
align_shortcut = "right",
|
||||||
|
hl = "DashboardCenter",
|
||||||
|
hl_shortcut = "DashboardShortcut",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if a plugin is defined in packer. Useful with lazy loading when a plugin is not necessarily loaded yet
|
||||||
|
-- @param plugin the plugin string to search for
|
||||||
|
-- @return boolean value if the plugin is available
|
||||||
|
function astronvim.is_available(plugin) return packer_plugins ~= nil and packer_plugins[plugin] ~= nil end
|
||||||
|
|
||||||
|
--- A helper function to wrap a module function to require a plugin before running
|
||||||
|
-- @param plugin the plugin string to call `require("packer").laoder` with
|
||||||
|
-- @param module the system module where the functions live (e.g. `vim.ui`)
|
||||||
|
-- @param func_names a string or a list like table of strings for functions to wrap in the given moduel (e.g. `{ "ui", "select }`)
|
||||||
|
function astronvim.load_plugin_with_func(plugin, module, func_names)
|
||||||
|
if type(func_names) == "string" then func_names = { func_names } end
|
||||||
|
for _, func in ipairs(func_names) do
|
||||||
|
local old_func = module[func]
|
||||||
|
module[func] = function(...)
|
||||||
|
module[func] = old_func
|
||||||
|
require("packer").loader(plugin)
|
||||||
|
module[func](...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Table based API for setting keybindings
|
||||||
|
-- @param map_table A nested table where the first key is the vim mode, the second key is the key to map, and the value is the function to set the mapping to
|
||||||
|
-- @param base A base set of options to set on every keybinding
|
||||||
|
function astronvim.set_mappings(map_table, base)
|
||||||
|
-- iterate over the first keys for each mode
|
||||||
|
for mode, maps in pairs(map_table) do
|
||||||
|
-- iterate over each keybinding set in the current mode
|
||||||
|
for keymap, options in pairs(maps) do
|
||||||
|
-- build the options for the command accordingly
|
||||||
|
if options then
|
||||||
|
local cmd = options
|
||||||
|
local keymap_opts = base or {}
|
||||||
|
if type(options) == "table" then
|
||||||
|
cmd = options[1]
|
||||||
|
keymap_opts = vim.tbl_deep_extend("force", options, keymap_opts)
|
||||||
|
keymap_opts[1] = nil
|
||||||
|
end
|
||||||
|
-- extend the keybinding options with the base provided and set the mapping
|
||||||
|
map(mode, keymap, cmd, keymap_opts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Delete the syntax matching rules for URLs/URIs if set
|
||||||
|
function astronvim.delete_url_match()
|
||||||
|
for _, match in ipairs(vim.fn.getmatches()) do
|
||||||
|
if match.group == "HighlightURL" then vim.fn.matchdelete(match.id) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add syntax matching rules for highlighting URLs/URIs
|
||||||
|
function astronvim.set_url_match()
|
||||||
|
astronvim.delete_url_match()
|
||||||
|
if vim.g.highlighturl_enabled then vim.fn.matchadd("HighlightURL", astronvim.url_matcher, 15) end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Run a shell command and capture the output and if the command succeeded or failed
|
||||||
|
-- @param cmd the terminal command to execute
|
||||||
|
-- @param show_error boolean of whether or not to show an unsuccessful command as an error to the user
|
||||||
|
-- @return the result of a successfully executed command or nil
|
||||||
|
function astronvim.cmd(cmd, show_error)
|
||||||
|
if vim.fn.has "win32" == 1 then cmd = { "cmd.exe", "/C", cmd } end
|
||||||
|
local result = vim.fn.system(cmd)
|
||||||
|
local success = vim.api.nvim_get_vvar "shell_error" == 0
|
||||||
|
if not success and (show_error == nil and true or show_error) then
|
||||||
|
vim.api.nvim_err_writeln("Error running command: " .. cmd .. "\nError message:\n" .. result)
|
||||||
|
end
|
||||||
|
return success and result:gsub("[\27\155][][()#;?%d]*[A-PRZcf-ntqry=><~]", "") or nil
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Check if a buffer is valid
|
||||||
|
-- @param bufnr the buffer to check
|
||||||
|
-- @return true if the buffer is valid or false
|
||||||
|
function astronvim.is_valid_buffer(bufnr)
|
||||||
|
if not bufnr or bufnr < 1 then return false end
|
||||||
|
return vim.bo[bufnr].buflisted and vim.api.nvim_buf_is_valid(bufnr)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Move the current buffer tab n places in the bufferline
|
||||||
|
-- @param n numer of tabs to move the current buffer over by (positive = right, negative = left)
|
||||||
|
function astronvim.move_buf(n)
|
||||||
|
if n == 0 then return end -- if n = 0 then no shifts are needed
|
||||||
|
local bufs = vim.t.bufs -- make temp variable
|
||||||
|
for i, bufnr in ipairs(bufs) do -- loop to find current buffer
|
||||||
|
if bufnr == vim.api.nvim_get_current_buf() then -- found index of current buffer
|
||||||
|
for _ = 0, (n % #bufs) - 1 do -- calculate number of right shifts
|
||||||
|
local new_i = i + 1 -- get next i
|
||||||
|
if i == #bufs then -- if at end, cycle to beginning
|
||||||
|
new_i = 1 -- next i is actually 1 if at the end
|
||||||
|
local val = bufs[i] -- save value
|
||||||
|
table.remove(bufs, i) -- remove from end
|
||||||
|
table.insert(bufs, new_i, val) -- insert at beginning
|
||||||
|
else -- if not at the end,then just do an in place swap
|
||||||
|
bufs[i], bufs[new_i] = bufs[new_i], bufs[i]
|
||||||
|
end
|
||||||
|
i = new_i -- iterate i to next value
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
vim.t.bufs = bufs -- set buffers
|
||||||
|
vim.cmd.redrawtabline() -- redraw tabline
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Navigate left and right by n places in the bufferline
|
||||||
|
-- @param n the number of tabs to navigate to (positive = right, negative = left)
|
||||||
|
function astronvim.nav_buf(n)
|
||||||
|
local current = vim.api.nvim_get_current_buf()
|
||||||
|
for i, v in ipairs(vim.t.bufs) do
|
||||||
|
if current == v then
|
||||||
|
vim.cmd.b(vim.t.bufs[(i + n - 1) % #vim.t.bufs + 1])
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Close a given buffer
|
||||||
|
-- @param bufnr? the buffer number to close or the current buffer if not provided
|
||||||
|
function astronvim.close_buf(bufnr, force)
|
||||||
|
if force == nil then force = false end
|
||||||
|
local current = vim.api.nvim_get_current_buf()
|
||||||
|
if not bufnr or bufnr == 0 then bufnr = current end
|
||||||
|
if bufnr == current then astronvim.nav_buf(-1) end
|
||||||
|
|
||||||
|
if astronvim.is_available "bufdelete.nvim" then
|
||||||
|
require("bufdelete").bufdelete(bufnr, force)
|
||||||
|
else
|
||||||
|
vim.cmd((force and "bd!" or "confirm bd") .. bufnr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Close the current tab
|
||||||
|
function astronvim.close_tab()
|
||||||
|
if #vim.api.nvim_list_tabpages() > 1 then
|
||||||
|
vim.t.bufs = nil
|
||||||
|
vim.cmd.tabclose()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
require "core.utils.ui"
|
||||||
|
require "core.utils.status"
|
||||||
|
require "core.utils.updater"
|
||||||
|
require "core.utils.mason"
|
||||||
|
require "core.utils.lsp"
|
||||||
|
|
||||||
|
return astronvim
|
|
@ -0,0 +1,243 @@
|
||||||
|
--- ### AstroNvim LSP
|
||||||
|
--
|
||||||
|
-- This module is automatically loaded by AstroNvim on during it's initialization into global variable `astronvim.lsp`
|
||||||
|
--
|
||||||
|
-- This module can also be manually loaded with `local updater = require("core.utils").lsp`
|
||||||
|
--
|
||||||
|
-- @module core.utils.lsp
|
||||||
|
-- @see core.utils
|
||||||
|
-- @copyright 2022
|
||||||
|
-- @license GNU General Public License v3.0
|
||||||
|
|
||||||
|
astronvim.lsp = {}
|
||||||
|
local tbl_contains = vim.tbl_contains
|
||||||
|
local tbl_isempty = vim.tbl_isempty
|
||||||
|
local user_plugin_opts = astronvim.user_plugin_opts
|
||||||
|
local conditional_func = astronvim.conditional_func
|
||||||
|
local is_available = astronvim.is_available
|
||||||
|
local user_registration = user_plugin_opts("lsp.server_registration", nil, false)
|
||||||
|
local skip_setup = user_plugin_opts "lsp.skip_setup"
|
||||||
|
|
||||||
|
astronvim.lsp.formatting =
|
||||||
|
astronvim.user_plugin_opts("lsp.formatting", { format_on_save = { enabled = true }, disabled = {} })
|
||||||
|
if type(astronvim.lsp.formatting.format_on_save) == "boolean" then
|
||||||
|
astronvim.lsp.formatting.format_on_save = { enabled = astronvim.lsp.formatting.format_on_save }
|
||||||
|
end
|
||||||
|
|
||||||
|
astronvim.lsp.format_opts = vim.deepcopy(astronvim.lsp.formatting)
|
||||||
|
astronvim.lsp.format_opts.disabled = nil
|
||||||
|
astronvim.lsp.format_opts.format_on_save = nil
|
||||||
|
astronvim.lsp.format_opts.filter = function(client)
|
||||||
|
local filter = astronvim.lsp.formatting.filter
|
||||||
|
local disabled = astronvim.lsp.formatting.disabled or {}
|
||||||
|
-- check if client is fully disabled or filtered by function
|
||||||
|
return not (vim.tbl_contains(disabled, client.name) or (type(filter) == "function" and not filter(client)))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Helper function to set up a given server with the Neovim LSP client
|
||||||
|
-- @param server the name of the server to be setup
|
||||||
|
astronvim.lsp.setup = function(server)
|
||||||
|
if not tbl_contains(skip_setup, server) then
|
||||||
|
-- if server doesn't exist, set it up from user server definition
|
||||||
|
if not pcall(require, "lspconfig.server_configurations." .. server) then
|
||||||
|
local server_definition = user_plugin_opts("lsp.server-settings." .. server)
|
||||||
|
if server_definition.cmd then require("lspconfig.configs")[server] = { default_config = server_definition } end
|
||||||
|
end
|
||||||
|
local opts = astronvim.lsp.server_settings(server)
|
||||||
|
if type(user_registration) == "function" then
|
||||||
|
user_registration(server, opts)
|
||||||
|
else
|
||||||
|
require("lspconfig")[server].setup(opts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- The `on_attach` function used by AstroNvim
|
||||||
|
-- @param client the LSP client details when attaching
|
||||||
|
-- @param bufnr the number of the buffer that the LSP client is attaching to
|
||||||
|
astronvim.lsp.on_attach = function(client, bufnr)
|
||||||
|
local capabilities = client.server_capabilities
|
||||||
|
local lsp_mappings = {
|
||||||
|
n = {
|
||||||
|
["<leader>ld"] = { function() vim.diagnostic.open_float() end, desc = "Hover diagnostics" },
|
||||||
|
["[d"] = { function() vim.diagnostic.goto_prev() end, desc = "Previous diagnostic" },
|
||||||
|
["]d"] = { function() vim.diagnostic.goto_next() end, desc = "Next diagnostic" },
|
||||||
|
["gl"] = { function() vim.diagnostic.open_float() end, desc = "Hover diagnostics" },
|
||||||
|
},
|
||||||
|
v = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_available "mason-lspconfig.nvim" then
|
||||||
|
lsp_mappings.n["<leader>li"] = { "<cmd>LspInfo<cr>", desc = "LSP information" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_available "null-ls.nvim" then
|
||||||
|
lsp_mappings.n["<leader>lI"] = { "<cmd>NullLsInfo<cr>", desc = "Null-ls information" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if capabilities.codeActionProvider then
|
||||||
|
lsp_mappings.n["<leader>la"] = { function() vim.lsp.buf.code_action() end, desc = "LSP code action" }
|
||||||
|
lsp_mappings.v["<leader>la"] = lsp_mappings.n["<leader>la"]
|
||||||
|
end
|
||||||
|
|
||||||
|
if capabilities.codeLensProvider then
|
||||||
|
lsp_mappings.n["<leader>ll"] = { function() vim.lsp.codelens.refresh() end, desc = "LSP codelens refresh" }
|
||||||
|
lsp_mappings.n["<leader>lL"] = { function() vim.lsp.codelens.run() end, desc = "LSP codelens run" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if capabilities.declarationProvider then
|
||||||
|
lsp_mappings.n["gD"] = { function() vim.lsp.buf.declaration() end, desc = "Declaration of current symbol" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if capabilities.definitionProvider then
|
||||||
|
lsp_mappings.n["gd"] = { function() vim.lsp.buf.definition() end, desc = "Show the definition of current symbol" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if capabilities.documentFormattingProvider and not tbl_contains(astronvim.lsp.formatting.disabled, client.name) then
|
||||||
|
lsp_mappings.n["<leader>lf"] = {
|
||||||
|
function() vim.lsp.buf.format(astronvim.lsp.format_opts) end,
|
||||||
|
desc = "Format buffer",
|
||||||
|
}
|
||||||
|
lsp_mappings.v["<leader>lf"] = lsp_mappings.n["<leader>lf"]
|
||||||
|
|
||||||
|
vim.api.nvim_buf_create_user_command(
|
||||||
|
bufnr,
|
||||||
|
"Format",
|
||||||
|
function() vim.lsp.buf.format(astronvim.lsp.format_opts) end,
|
||||||
|
{ desc = "Format file with LSP" }
|
||||||
|
)
|
||||||
|
local autoformat = astronvim.lsp.formatting.format_on_save
|
||||||
|
local filetype = vim.api.nvim_buf_get_option(bufnr, "filetype")
|
||||||
|
if
|
||||||
|
autoformat.enabled
|
||||||
|
and (tbl_isempty(autoformat.allow_filetypes or {}) or tbl_contains(autoformat.allow_filetypes, filetype))
|
||||||
|
and (tbl_isempty(autoformat.ignore_filetypes or {}) or not tbl_contains(autoformat.ignore_filetypes, filetype))
|
||||||
|
then
|
||||||
|
local autocmd_group = "auto_format_" .. bufnr
|
||||||
|
vim.api.nvim_create_augroup(autocmd_group, { clear = true })
|
||||||
|
vim.api.nvim_create_autocmd("BufWritePre", {
|
||||||
|
group = autocmd_group,
|
||||||
|
buffer = bufnr,
|
||||||
|
desc = "Auto format buffer " .. bufnr .. " before save",
|
||||||
|
callback = function()
|
||||||
|
if vim.g.autoformat_enabled then
|
||||||
|
vim.lsp.buf.format(astronvim.default_tbl({ bufnr = bufnr }, astronvim.lsp.format_opts))
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
lsp_mappings.n["<leader>uf"] = {
|
||||||
|
function() astronvim.ui.toggle_autoformat() end,
|
||||||
|
desc = "Toggle autoformatting",
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if capabilities.documentHighlightProvider then
|
||||||
|
local highlight_name = vim.fn.printf("lsp_document_highlight_%d", bufnr)
|
||||||
|
vim.api.nvim_create_augroup(highlight_name, {})
|
||||||
|
vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, {
|
||||||
|
group = highlight_name,
|
||||||
|
buffer = bufnr,
|
||||||
|
callback = function() vim.lsp.buf.document_highlight() end,
|
||||||
|
})
|
||||||
|
vim.api.nvim_create_autocmd("CursorMoved", {
|
||||||
|
group = highlight_name,
|
||||||
|
buffer = bufnr,
|
||||||
|
callback = function() vim.lsp.buf.clear_references() end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
if capabilities.hoverProvider then
|
||||||
|
lsp_mappings.n["K"] = { function() vim.lsp.buf.hover() end, desc = "Hover symbol details" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if capabilities.implementationProvider then
|
||||||
|
lsp_mappings.n["gI"] = { function() vim.lsp.buf.implementation() end, desc = "Implementation of current symbol" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if capabilities.referencesProvider then
|
||||||
|
lsp_mappings.n["gr"] = { function() vim.lsp.buf.references() end, desc = "References of current symbol" }
|
||||||
|
lsp_mappings.n["<leader>lR"] = { function() vim.lsp.buf.references() end, desc = "Search references" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if capabilities.renameProvider then
|
||||||
|
lsp_mappings.n["<leader>lr"] = { function() vim.lsp.buf.rename() end, desc = "Rename current symbol" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if capabilities.signatureHelpProvider then
|
||||||
|
lsp_mappings.n["<leader>lh"] = { function() vim.lsp.buf.signature_help() end, desc = "Signature help" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if capabilities.typeDefinitionProvider then
|
||||||
|
lsp_mappings.n["gT"] = { function() vim.lsp.buf.type_definition() end, desc = "Definition of current type" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if capabilities.workspaceSymbolProvider then
|
||||||
|
lsp_mappings.n["<leader>lG"] = { function() vim.lsp.buf.workspace_symbol() end, desc = "Search workspace symbols" }
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_available "telescope.nvim" then -- setup telescope mappings if available
|
||||||
|
if lsp_mappings.n.gd then lsp_mappings.n.gd[1] = function() require("telescope.builtin").lsp_definitions() end end
|
||||||
|
if lsp_mappings.n.gI then
|
||||||
|
lsp_mappings.n.gI[1] = function() require("telescope.builtin").lsp_implementations() end
|
||||||
|
end
|
||||||
|
if lsp_mappings.n.gr then lsp_mappings.n.gr[1] = function() require("telescope.builtin").lsp_references() end end
|
||||||
|
if lsp_mappings.n["<leader>lR"] then
|
||||||
|
lsp_mappings.n["<leader>lR"][1] = function() require("telescope.builtin").lsp_references() end
|
||||||
|
end
|
||||||
|
if lsp_mappings.n.gT then
|
||||||
|
lsp_mappings.n.gT[1] = function() require("telescope.builtin").lsp_type_definitions() end
|
||||||
|
end
|
||||||
|
if lsp_mappings.n["<leader>lG"] then
|
||||||
|
lsp_mappings.n["<leader>lG"][1] = function() require("telescope.builtin").lsp_workspace_symbols() end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
astronvim.set_mappings(user_plugin_opts("lsp.mappings", lsp_mappings), { buffer = bufnr })
|
||||||
|
if not vim.tbl_isempty(lsp_mappings.v) then
|
||||||
|
astronvim.which_key_register({ v = { ["<leader>"] = { l = { name = "LSP" } } } }, { buffer = bufnr })
|
||||||
|
end
|
||||||
|
|
||||||
|
local on_attach_override = user_plugin_opts("lsp.on_attach", nil, false)
|
||||||
|
conditional_func(on_attach_override, true, client, bufnr)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- The default AstroNvim LSP capabilities
|
||||||
|
astronvim.lsp.capabilities = vim.lsp.protocol.make_client_capabilities()
|
||||||
|
astronvim.lsp.capabilities.textDocument.completion.completionItem.documentationFormat = { "markdown", "plaintext" }
|
||||||
|
astronvim.lsp.capabilities.textDocument.completion.completionItem.snippetSupport = true
|
||||||
|
astronvim.lsp.capabilities.textDocument.completion.completionItem.preselectSupport = true
|
||||||
|
astronvim.lsp.capabilities.textDocument.completion.completionItem.insertReplaceSupport = true
|
||||||
|
astronvim.lsp.capabilities.textDocument.completion.completionItem.labelDetailsSupport = true
|
||||||
|
astronvim.lsp.capabilities.textDocument.completion.completionItem.deprecatedSupport = true
|
||||||
|
astronvim.lsp.capabilities.textDocument.completion.completionItem.commitCharactersSupport = true
|
||||||
|
astronvim.lsp.capabilities.textDocument.completion.completionItem.tagSupport = { valueSet = { 1 } }
|
||||||
|
astronvim.lsp.capabilities.textDocument.completion.completionItem.resolveSupport = {
|
||||||
|
properties = { "documentation", "detail", "additionalTextEdits" },
|
||||||
|
}
|
||||||
|
astronvim.lsp.capabilities = user_plugin_opts("lsp.capabilities", astronvim.lsp.capabilities)
|
||||||
|
astronvim.lsp.flags = user_plugin_opts "lsp.flags"
|
||||||
|
|
||||||
|
--- Get the server settings for a given language server to be provided to the server's `setup()` call
|
||||||
|
-- @param server_name the name of the server
|
||||||
|
-- @return the table of LSP options used when setting up the given language server
|
||||||
|
function astronvim.lsp.server_settings(server_name)
|
||||||
|
local server = require("lspconfig")[server_name]
|
||||||
|
local opts = user_plugin_opts( -- get user server-settings
|
||||||
|
"lsp.server-settings." .. server_name, -- TODO: RENAME lsp.server-settings to lsp.config in v3
|
||||||
|
user_plugin_opts("server-settings." .. server_name, { -- get default server-settings
|
||||||
|
capabilities = vim.tbl_deep_extend("force", astronvim.lsp.capabilities, server.capabilities or {}),
|
||||||
|
flags = vim.tbl_deep_extend("force", astronvim.lsp.flags, server.flags or {}),
|
||||||
|
}, true, "configs")
|
||||||
|
)
|
||||||
|
local old_on_attach = server.on_attach
|
||||||
|
local user_on_attach = opts.on_attach
|
||||||
|
opts.on_attach = function(client, bufnr)
|
||||||
|
conditional_func(old_on_attach, true, client, bufnr)
|
||||||
|
astronvim.lsp.on_attach(client, bufnr)
|
||||||
|
conditional_func(user_on_attach, true, client, bufnr)
|
||||||
|
end
|
||||||
|
return opts
|
||||||
|
end
|
||||||
|
|
||||||
|
return astronvim.lsp
|
|
@ -0,0 +1,95 @@
|
||||||
|
--- ### AstroNvim Mason Utils
|
||||||
|
--
|
||||||
|
-- This module is automatically loaded by AstroNvim on during it's initialization into global variable `astronvim.mason`
|
||||||
|
--
|
||||||
|
-- This module can also be manually loaded with `local updater = require("core.utils").mason`
|
||||||
|
--
|
||||||
|
-- @module core.utils.mason
|
||||||
|
-- @see core.utils
|
||||||
|
-- @copyright 2022
|
||||||
|
-- @license GNU General Public License v3.0
|
||||||
|
|
||||||
|
astronvim.mason = {}
|
||||||
|
|
||||||
|
--- Update a mason package
|
||||||
|
-- @param pkg_name string of the name of the package as defined in Mason (Not mason-lspconfig or mason-null-ls)
|
||||||
|
-- @param auto_install boolean of whether or not to install a package that is not currently installed (default: True)
|
||||||
|
function astronvim.mason.update(pkg_name, auto_install)
|
||||||
|
if auto_install == nil then auto_install = true end
|
||||||
|
local registry_avail, registry = pcall(require, "mason-registry")
|
||||||
|
if not registry_avail then
|
||||||
|
vim.api.nvim_err_writeln "Unable to access mason registry"
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local pkg_avail, pkg = pcall(registry.get_package, pkg_name)
|
||||||
|
if not pkg_avail then
|
||||||
|
astronvim.notify(("Mason: %s is not available"):format(pkg_name), "error")
|
||||||
|
else
|
||||||
|
if not pkg:is_installed() then
|
||||||
|
if auto_install then
|
||||||
|
astronvim.notify(("Mason: Installing %s"):format(pkg.name))
|
||||||
|
pkg:install()
|
||||||
|
else
|
||||||
|
astronvim.notify(("Mason: %s not installed"):format(pkg.name), "warn")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
pkg:check_new_version(function(update_available, version)
|
||||||
|
if update_available then
|
||||||
|
astronvim.notify(("Mason: Updating %s to %s"):format(pkg.name, version.latest_version))
|
||||||
|
pkg:install():on("closed", function() astronvim.notify(("Mason: Updated %s"):format(pkg.name)) end)
|
||||||
|
else
|
||||||
|
astronvim.notify(("Mason: No updates available for %s"):format(pkg.name))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Update all packages in Mason
|
||||||
|
function astronvim.mason.update_all()
|
||||||
|
local registry_avail, registry = pcall(require, "mason-registry")
|
||||||
|
if not registry_avail then
|
||||||
|
vim.api.nvim_err_writeln "Unable to access mason registry"
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local installed_pkgs = registry.get_installed_packages()
|
||||||
|
local running = #installed_pkgs
|
||||||
|
local no_pkgs = running == 0
|
||||||
|
astronvim.notify "Mason: Checking for package updates..."
|
||||||
|
|
||||||
|
if no_pkgs then
|
||||||
|
astronvim.notify "Mason: No updates available"
|
||||||
|
astronvim.event "MasonUpdateComplete"
|
||||||
|
else
|
||||||
|
local updated = false
|
||||||
|
for _, pkg in ipairs(installed_pkgs) do
|
||||||
|
pkg:check_new_version(function(update_available, version)
|
||||||
|
if update_available then
|
||||||
|
updated = true
|
||||||
|
astronvim.notify(("Mason: Updating %s to %s"):format(pkg.name, version.latest_version))
|
||||||
|
pkg:install():on("closed", function()
|
||||||
|
running = running - 1
|
||||||
|
if running == 0 then
|
||||||
|
astronvim.notify "Mason: Update Complete"
|
||||||
|
astronvim.event "MasonUpdateComplete"
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
running = running - 1
|
||||||
|
if running == 0 then
|
||||||
|
if updated then
|
||||||
|
astronvim.notify "Mason: Update Complete"
|
||||||
|
else
|
||||||
|
astronvim.notify "Mason: No updates available"
|
||||||
|
end
|
||||||
|
astronvim.event "MasonUpdateComplete"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return astronvim.mason
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,188 @@
|
||||||
|
--- ### AstroNvim UI Options
|
||||||
|
--
|
||||||
|
-- This module is automatically loaded by AstroNvim on during it's initialization into global variable `astronvim.ui`
|
||||||
|
--
|
||||||
|
-- This module can also be manually loaded with `local updater = require("core.utils").ui`
|
||||||
|
--
|
||||||
|
-- @module core.utils.ui
|
||||||
|
-- @see core.utils
|
||||||
|
-- @copyright 2022
|
||||||
|
-- @license GNU General Public License v3.0
|
||||||
|
|
||||||
|
astronvim.ui = {}
|
||||||
|
|
||||||
|
local function bool2str(bool) return bool and "on" or "off" end
|
||||||
|
|
||||||
|
local function ui_notify(str)
|
||||||
|
if vim.g.ui_notifications_enabled then astronvim.notify(str) end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle notifications for UI toggles
|
||||||
|
function astronvim.ui.toggle_ui_notifications()
|
||||||
|
vim.g.ui_notifications_enabled = not vim.g.ui_notifications_enabled
|
||||||
|
ui_notify(string.format("ui notifications %s", bool2str(vim.g.ui_notifications_enabled)))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle autopairs
|
||||||
|
function astronvim.ui.toggle_autopairs()
|
||||||
|
local ok, autopairs = pcall(require, "nvim-autopairs")
|
||||||
|
if ok then
|
||||||
|
if autopairs.state.disabled then
|
||||||
|
autopairs.enable()
|
||||||
|
else
|
||||||
|
autopairs.disable()
|
||||||
|
end
|
||||||
|
vim.g.autopairs_enabled = autopairs.state.disabled
|
||||||
|
ui_notify(string.format("autopairs %s", bool2str(not autopairs.state.disabled)))
|
||||||
|
else
|
||||||
|
ui_notify "autopairs not available"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle diagnostics
|
||||||
|
function astronvim.ui.toggle_diagnostics()
|
||||||
|
local status = "on"
|
||||||
|
if vim.g.status_diagnostics_enabled then
|
||||||
|
if vim.g.diagnostics_enabled then
|
||||||
|
vim.g.diagnostics_enabled = false
|
||||||
|
status = "virtual text off"
|
||||||
|
else
|
||||||
|
vim.g.status_diagnostics_enabled = false
|
||||||
|
status = "fully off"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
vim.g.diagnostics_enabled = true
|
||||||
|
vim.g.status_diagnostics_enabled = true
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.diagnostic.config(astronvim.lsp.diagnostics[bool2str(vim.g.diagnostics_enabled)])
|
||||||
|
ui_notify(string.format("diagnostics %s", status))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle background="dark"|"light"
|
||||||
|
function astronvim.ui.toggle_background()
|
||||||
|
vim.go.background = vim.go.background == "light" and "dark" or "light"
|
||||||
|
ui_notify(string.format("background=%s", vim.go.background))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle cmp entrirely
|
||||||
|
function astronvim.ui.toggle_cmp()
|
||||||
|
vim.g.cmp_enabled = not vim.g.cmp_enabled
|
||||||
|
local ok, _ = pcall(require, "cmp")
|
||||||
|
ui_notify(ok and string.format("completion %s", bool2str(vim.g.cmp_enabled)) or "completion not available")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle auto format
|
||||||
|
function astronvim.ui.toggle_autoformat()
|
||||||
|
vim.g.autoformat_enabled = not vim.g.autoformat_enabled
|
||||||
|
ui_notify(string.format("Autoformatting %s", bool2str(vim.g.autoformat_enabled)))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle showtabline=2|0
|
||||||
|
function astronvim.ui.toggle_tabline()
|
||||||
|
vim.opt.showtabline = vim.opt.showtabline:get() == 0 and 2 or 0
|
||||||
|
ui_notify(string.format("tabline %s", bool2str(vim.opt.showtabline:get() == 2)))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle conceal=2|0
|
||||||
|
function astronvim.ui.toggle_conceal()
|
||||||
|
vim.opt.conceallevel = vim.opt.conceallevel:get() == 0 and 2 or 0
|
||||||
|
ui_notify(string.format("conceal %s", bool2str(vim.opt.conceallevel:get() == 2)))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle laststatus=3|2|0
|
||||||
|
function astronvim.ui.toggle_statusline()
|
||||||
|
local laststatus = vim.opt.laststatus:get()
|
||||||
|
local status
|
||||||
|
if laststatus == 0 then
|
||||||
|
vim.opt.laststatus = 2
|
||||||
|
status = "local"
|
||||||
|
elseif laststatus == 2 then
|
||||||
|
vim.opt.laststatus = 3
|
||||||
|
status = "global"
|
||||||
|
elseif laststatus == 3 then
|
||||||
|
vim.opt.laststatus = 0
|
||||||
|
status = "off"
|
||||||
|
end
|
||||||
|
ui_notify(string.format("statusline %s", status))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle signcolumn="auto"|"no"
|
||||||
|
function astronvim.ui.toggle_signcolumn()
|
||||||
|
if vim.wo.signcolumn == "no" then
|
||||||
|
vim.wo.signcolumn = "yes"
|
||||||
|
elseif vim.wo.signcolumn == "yes" then
|
||||||
|
vim.wo.signcolumn = "auto"
|
||||||
|
else
|
||||||
|
vim.wo.signcolumn = "no"
|
||||||
|
end
|
||||||
|
ui_notify(string.format("signcolumn=%s", vim.wo.signcolumn))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Set the indent and tab related numbers
|
||||||
|
function astronvim.ui.set_indent()
|
||||||
|
local input_avail, input = pcall(vim.fn.input, "Set indent value (>0 expandtab, <=0 noexpandtab): ")
|
||||||
|
if input_avail then
|
||||||
|
local indent = tonumber(input)
|
||||||
|
if not indent or indent == 0 then return end
|
||||||
|
vim.bo.expandtab = (indent > 0) -- local to buffer
|
||||||
|
indent = math.abs(indent)
|
||||||
|
vim.bo.tabstop = indent -- local to buffer
|
||||||
|
vim.bo.softtabstop = indent -- local to buffer
|
||||||
|
vim.bo.shiftwidth = indent -- local to buffer
|
||||||
|
ui_notify(string.format("indent=%d %s", indent, vim.bo.expandtab and "expandtab" or "noexpandtab"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Change the number display modes
|
||||||
|
function astronvim.ui.change_number()
|
||||||
|
local number = vim.wo.number -- local to window
|
||||||
|
local relativenumber = vim.wo.relativenumber -- local to window
|
||||||
|
if not number and not relativenumber then
|
||||||
|
vim.wo.number = true
|
||||||
|
elseif number and not relativenumber then
|
||||||
|
vim.wo.relativenumber = true
|
||||||
|
elseif number and relativenumber then
|
||||||
|
vim.wo.number = false
|
||||||
|
else -- not number and relativenumber
|
||||||
|
vim.wo.relativenumber = false
|
||||||
|
end
|
||||||
|
ui_notify(string.format("number %s, relativenumber %s", bool2str(vim.wo.number), bool2str(vim.wo.relativenumber)))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle spell
|
||||||
|
function astronvim.ui.toggle_spell()
|
||||||
|
vim.wo.spell = not vim.wo.spell -- local to window
|
||||||
|
ui_notify(string.format("spell %s", bool2str(vim.wo.spell)))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle paste
|
||||||
|
function astronvim.ui.toggle_paste()
|
||||||
|
vim.opt.paste = not vim.opt.paste:get() -- local to window
|
||||||
|
ui_notify(string.format("paste %s", bool2str(vim.opt.paste:get())))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle wrap
|
||||||
|
function astronvim.ui.toggle_wrap()
|
||||||
|
vim.wo.wrap = not vim.wo.wrap -- local to window
|
||||||
|
ui_notify(string.format("wrap %s", bool2str(vim.wo.wrap)))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle syntax highlighting and treesitter
|
||||||
|
function astronvim.ui.toggle_syntax()
|
||||||
|
local ts_avail, parsers = pcall(require, "nvim-treesitter.parsers")
|
||||||
|
if vim.g.syntax_on then -- global var for on//off
|
||||||
|
if ts_avail and parsers.has_parser() then vim.cmd.TSBufDisable "highlight" end
|
||||||
|
vim.cmd.syntax "off" -- set vim.g.syntax_on = false
|
||||||
|
else
|
||||||
|
if ts_avail and parsers.has_parser() then vim.cmd.TSBufEnable "highlight" end
|
||||||
|
vim.cmd.syntax "on" -- set vim.g.syntax_on = true
|
||||||
|
end
|
||||||
|
ui_notify(string.format("syntax %s", bool2str(vim.g.syntax_on)))
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Toggle URL/URI syntax highlighting rules
|
||||||
|
function astronvim.ui.toggle_url_match()
|
||||||
|
vim.g.highlighturl_enabled = not vim.g.highlighturl_enabled
|
||||||
|
astronvim.set_url_match()
|
||||||
|
end
|
|
@ -0,0 +1,296 @@
|
||||||
|
--- ### AstroNvim Updater
|
||||||
|
--
|
||||||
|
-- This module is automatically loaded by AstroNvim on during it's initialization into global variable `astronvim.updater`
|
||||||
|
--
|
||||||
|
-- This module can also be manually loaded with `local updater = require("core.utils").updater`
|
||||||
|
--
|
||||||
|
-- @module core.utils.updater
|
||||||
|
-- @see core.utils
|
||||||
|
-- @copyright 2022
|
||||||
|
-- @license GNU General Public License v3.0
|
||||||
|
|
||||||
|
local fn = vim.fn
|
||||||
|
local git = require "core.utils.git"
|
||||||
|
--- Updater settings overridden with any user provided configuration
|
||||||
|
local options = astronvim.user_plugin_opts("updater", {
|
||||||
|
remote = "origin",
|
||||||
|
channel = "stable",
|
||||||
|
show_changelog = true,
|
||||||
|
auto_reload = true,
|
||||||
|
auto_quit = true,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- set the install channel
|
||||||
|
if options.branch then options.channel = "nightly" end
|
||||||
|
if astronvim.install.is_stable ~= nil then options.channel = astronvim.install.is_stable and "stable" or "nightly" end
|
||||||
|
|
||||||
|
astronvim.updater = { options = options }
|
||||||
|
-- if the channel is stable or the user has chosen to pin the system plugins
|
||||||
|
if options.pin_plugins == nil and options.channel == "stable" or options.pin_plugins then
|
||||||
|
-- load the current packer snapshot from the installation home location
|
||||||
|
local loaded, snapshot = pcall(fn.readfile, astronvim.install.home .. "/packer_snapshot")
|
||||||
|
if loaded then
|
||||||
|
-- decode the snapshot JSON and save it to a variable
|
||||||
|
loaded, snapshot = pcall(fn.json_decode, snapshot)
|
||||||
|
astronvim.updater.snapshot = type(snapshot) == "table" and snapshot or nil
|
||||||
|
end
|
||||||
|
-- if there is an error loading the snapshot, print an error
|
||||||
|
if not loaded then vim.api.nvim_err_writeln "Error loading packer snapshot" end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the current AstroNvim version
|
||||||
|
-- @param quiet boolean to quietly execute or send a notification
|
||||||
|
-- @return the current AstroNvim version string
|
||||||
|
function astronvim.updater.version(quiet)
|
||||||
|
local version = astronvim.install.version or git.current_version(false)
|
||||||
|
if version and not quiet then astronvim.notify("Version: " .. version) end
|
||||||
|
return version
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Get the full AstroNvim changelog
|
||||||
|
-- @param quiet boolean to quietly execute or display the changelog
|
||||||
|
-- @return the current AstroNvim changelog table of commit messages
|
||||||
|
function astronvim.updater.changelog(quiet)
|
||||||
|
local summary = {}
|
||||||
|
vim.list_extend(summary, git.pretty_changelog(git.get_commit_range()))
|
||||||
|
if not quiet then astronvim.echo(summary) end
|
||||||
|
return summary
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Attempt an update of AstroNvim
|
||||||
|
-- @param target the target if checking out a specific tag or commit or nil if just pulling
|
||||||
|
local function attempt_update(target)
|
||||||
|
-- if updating to a new stable version or a specific commit checkout the provided target
|
||||||
|
if options.channel == "stable" or options.commit then
|
||||||
|
return git.checkout(target, false)
|
||||||
|
-- if no target, pull the latest
|
||||||
|
else
|
||||||
|
return git.pull(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Cancelled update message
|
||||||
|
local cancelled_message = { { "Update cancelled", "WarningMsg" } }
|
||||||
|
|
||||||
|
--- Reload the AstroNvim configuration live (Experimental)
|
||||||
|
-- @param quiet boolean to quietly execute or send a notification
|
||||||
|
function astronvim.updater.reload(quiet)
|
||||||
|
-- stop LSP if it is running
|
||||||
|
if vim.fn.exists ":LspStop" ~= 0 then vim.cmd.LspStop() end
|
||||||
|
local reload_module = require("plenary.reload").reload_module
|
||||||
|
-- unload AstroNvim configuration files
|
||||||
|
reload_module "user"
|
||||||
|
reload_module "configs"
|
||||||
|
reload_module "default_theme"
|
||||||
|
reload_module "core"
|
||||||
|
-- manual unload some plugins that need it if they exist
|
||||||
|
reload_module "cmp"
|
||||||
|
reload_module "which-key"
|
||||||
|
-- source the AstroNvim configuration
|
||||||
|
local reloaded, _ = pcall(dofile, vim.fn.expand "$MYVIMRC")
|
||||||
|
-- if successful reload and not quiet, display a notification
|
||||||
|
if reloaded and not quiet then astronvim.notify "Reloaded AstroNvim" end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Sync Packer and then update Mason
|
||||||
|
function astronvim.updater.update_packages()
|
||||||
|
vim.api.nvim_create_autocmd("User", {
|
||||||
|
once = true,
|
||||||
|
desc = "Update Mason with Packer",
|
||||||
|
group = vim.api.nvim_create_augroup("astro_sync", { clear = true }),
|
||||||
|
pattern = "PackerComplete",
|
||||||
|
callback = function()
|
||||||
|
if astronvim.is_available "mason.nvim" then
|
||||||
|
vim.api.nvim_create_autocmd("User", {
|
||||||
|
pattern = "AstroMasonUpdateComplete",
|
||||||
|
once = true,
|
||||||
|
callback = function() astronvim.event "UpdatePackagesComplete" end,
|
||||||
|
})
|
||||||
|
astronvim.mason.update_all()
|
||||||
|
else
|
||||||
|
astronvim.event "UpdatePackagesComplete"
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
vim.cmd.PackerSync()
|
||||||
|
end
|
||||||
|
|
||||||
|
--- AstroNvim's updater function
|
||||||
|
function astronvim.updater.update()
|
||||||
|
-- if the git command is not available, then throw an error
|
||||||
|
if not git.available() then
|
||||||
|
astronvim.notify(
|
||||||
|
"git command is not available, please verify it is accessible in a command line. This may be an issue with your PATH",
|
||||||
|
"error"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- if installed with an external package manager, disable the internal updater
|
||||||
|
if not git.is_repo() then
|
||||||
|
astronvim.notify("Updater not available for non-git installations", "error")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- set up any remotes defined by the user if they do not exist
|
||||||
|
for remote, entry in pairs(options.remotes and options.remotes or {}) do
|
||||||
|
local url = git.parse_remote_url(entry)
|
||||||
|
local current_url = git.remote_url(remote, false)
|
||||||
|
local check_needed = false
|
||||||
|
if not current_url then
|
||||||
|
git.remote_add(remote, url)
|
||||||
|
check_needed = true
|
||||||
|
elseif
|
||||||
|
current_url ~= url
|
||||||
|
and astronvim.confirm_prompt {
|
||||||
|
{ "Remote " },
|
||||||
|
{ remote, "Title" },
|
||||||
|
{ " is currently set to " },
|
||||||
|
{ current_url, "WarningMsg" },
|
||||||
|
{ "\nWould you like us to set it to " },
|
||||||
|
{ url, "String" },
|
||||||
|
{ "?" },
|
||||||
|
}
|
||||||
|
then
|
||||||
|
git.remote_update(remote, url)
|
||||||
|
check_needed = true
|
||||||
|
end
|
||||||
|
if check_needed and git.remote_url(remote, false) ~= url then
|
||||||
|
vim.api.nvim_err_writeln("Error setting up remote " .. remote .. " to " .. url)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local is_stable = options.channel == "stable"
|
||||||
|
if is_stable then
|
||||||
|
options.branch = "main"
|
||||||
|
elseif not options.branch then
|
||||||
|
options.branch = "nightly"
|
||||||
|
end
|
||||||
|
-- fetch the latest remote
|
||||||
|
if not git.fetch(options.remote) then
|
||||||
|
vim.api.nvim_err_writeln("Error fetching remote: " .. options.remote)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- switch to the necessary branch only if not on the stable channel
|
||||||
|
if not is_stable then
|
||||||
|
local local_branch = (options.remote == "origin" and "" or (options.remote .. "_")) .. options.branch
|
||||||
|
if git.current_branch() ~= local_branch then
|
||||||
|
astronvim.echo {
|
||||||
|
{ "Switching to branch: " },
|
||||||
|
{ options.remote .. "/" .. options.branch .. "\n\n", "String" },
|
||||||
|
}
|
||||||
|
if not git.checkout(local_branch, false) then
|
||||||
|
git.checkout("-b " .. local_branch .. " " .. options.remote .. "/" .. options.branch, false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- check if the branch was switched to successfully
|
||||||
|
if git.current_branch() ~= local_branch then
|
||||||
|
vim.api.nvim_err_writeln("Error checking out branch: " .. options.remote .. "/" .. options.branch)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local source = git.local_head() -- calculate current commit
|
||||||
|
local target -- calculate target commit
|
||||||
|
if is_stable then -- if stable get tag commit
|
||||||
|
local version_search = options.version or "latest"
|
||||||
|
options.version = git.latest_version(git.get_versions(version_search))
|
||||||
|
if not options.version then -- continue only if stable version is found
|
||||||
|
vim.api.nvim_err_writeln("Error finding version: " .. version_search)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
target = git.tag_commit(options.version)
|
||||||
|
elseif options.commit then -- if commit specified use it
|
||||||
|
target = git.branch_contains(options.remote, options.branch, options.commit) and options.commit or nil
|
||||||
|
else -- get most recent commit
|
||||||
|
target = git.remote_head(options.remote, options.branch)
|
||||||
|
end
|
||||||
|
if not source or not target then -- continue if current and target commits were found
|
||||||
|
vim.api.nvim_err_writeln "Error checking for updates"
|
||||||
|
return
|
||||||
|
elseif source == target then
|
||||||
|
astronvim.echo { { "No updates available", "String" } }
|
||||||
|
return
|
||||||
|
elseif -- prompt user if they want to accept update
|
||||||
|
not options.skip_prompts
|
||||||
|
and not astronvim.confirm_prompt {
|
||||||
|
{ "Update available to ", "Title" },
|
||||||
|
{ is_stable and options.version or target, "String" },
|
||||||
|
{ "\nUpdating requires a restart, continue?" },
|
||||||
|
}
|
||||||
|
then
|
||||||
|
astronvim.echo(cancelled_message)
|
||||||
|
return
|
||||||
|
else -- perform update
|
||||||
|
-- calculate and print the changelog
|
||||||
|
local changelog = git.get_commit_range(source, target)
|
||||||
|
local breaking = git.breaking_changes(changelog)
|
||||||
|
local breaking_prompt = { { "Update contains the following breaking changes:\n", "WarningMsg" } }
|
||||||
|
vim.list_extend(breaking_prompt, git.pretty_changelog(breaking))
|
||||||
|
vim.list_extend(breaking_prompt, { { "\nWould you like to continue?" } })
|
||||||
|
if #breaking > 0 and not options.skip_prompts and not astronvim.confirm_prompt(breaking_prompt) then
|
||||||
|
astronvim.echo(cancelled_message)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- attempt an update
|
||||||
|
local updated = attempt_update(target)
|
||||||
|
-- check for local file conflicts and prompt user to continue or abort
|
||||||
|
if
|
||||||
|
not updated
|
||||||
|
and not options.skip_prompts
|
||||||
|
and not astronvim.confirm_prompt {
|
||||||
|
{ "Unable to pull due to local modifications to base files.\n", "ErrorMsg" },
|
||||||
|
{ "Reset local files and continue?" },
|
||||||
|
}
|
||||||
|
then
|
||||||
|
astronvim.echo(cancelled_message)
|
||||||
|
return
|
||||||
|
-- if continued and there were errors reset the base config and attempt another update
|
||||||
|
elseif not updated then
|
||||||
|
git.hard_reset(source)
|
||||||
|
updated = attempt_update(target)
|
||||||
|
end
|
||||||
|
-- if update was unsuccessful throw an error
|
||||||
|
if not updated then
|
||||||
|
vim.api.nvim_err_writeln "Error ocurred performing update"
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- print a summary of the update with the changelog
|
||||||
|
local summary = {
|
||||||
|
{ "AstroNvim updated successfully to ", "Title" },
|
||||||
|
{ git.current_version(), "String" },
|
||||||
|
{ "!\n", "Title" },
|
||||||
|
{
|
||||||
|
options.auto_reload and "AstroNvim will now sync packer and quit.\n\n"
|
||||||
|
or "Please restart and run :PackerSync.\n\n",
|
||||||
|
"WarningMsg",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if options.show_changelog and #changelog > 0 then
|
||||||
|
vim.list_extend(summary, { { "Changelog:\n", "Title" } })
|
||||||
|
vim.list_extend(summary, git.pretty_changelog(changelog))
|
||||||
|
end
|
||||||
|
astronvim.echo(summary)
|
||||||
|
|
||||||
|
-- if the user wants to auto quit, create an autocommand to quit AstroNvim on the update completing
|
||||||
|
if options.auto_quit then
|
||||||
|
vim.api.nvim_create_autocmd("User", { pattern = "AstroUpdateComplete", command = "quitall" })
|
||||||
|
end
|
||||||
|
|
||||||
|
-- if the user wants to reload and sync packer
|
||||||
|
if options.auto_reload then
|
||||||
|
-- perform a reload
|
||||||
|
vim.opt.modifiable = true
|
||||||
|
astronvim.updater.reload(true) -- run quiet to not show notification on reload
|
||||||
|
vim.api.nvim_create_autocmd("User", {
|
||||||
|
once = true,
|
||||||
|
pattern = "AstroUpdatePackagesComplete",
|
||||||
|
callback = function() astronvim.event "UpdateComplete" end,
|
||||||
|
})
|
||||||
|
require "core.plugins"
|
||||||
|
astronvim.updater.update_packages()
|
||||||
|
-- if packer isn't available send successful update event
|
||||||
|
else
|
||||||
|
-- send user event of successful update
|
||||||
|
astronvim.event "UpdateComplete"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,363 @@
|
||||||
|
-- AstroNvim Configuration Table
|
||||||
|
-- All configuration changes should go inside of the table below
|
||||||
|
|
||||||
|
-- You can think of a Lua "table" as a dictionary like data structure the
|
||||||
|
-- normal format is "key = value". These also handle array like data structures
|
||||||
|
-- where a value with no key simply has an implicit numeric key
|
||||||
|
local config = {
|
||||||
|
|
||||||
|
-- Configure AstroNvim updates
|
||||||
|
updater = {
|
||||||
|
remote = "origin", -- remote to use
|
||||||
|
channel = "nightly", -- "stable" or "nightly"
|
||||||
|
version = "latest", -- "latest", tag name, or regex search like "v1.*" to only do updates before v2 (STABLE ONLY)
|
||||||
|
branch = "main", -- branch name (NIGHTLY ONLY)
|
||||||
|
commit = nil, -- commit hash (NIGHTLY ONLY)
|
||||||
|
pin_plugins = nil, -- nil, true, false (nil will pin plugins on stable only)
|
||||||
|
skip_prompts = false, -- skip prompts about breaking changes
|
||||||
|
show_changelog = true, -- show the changelog after performing an update
|
||||||
|
auto_reload = false, -- automatically reload and sync packer after a successful update
|
||||||
|
auto_quit = false, -- automatically quit the current session after a successful update
|
||||||
|
-- remotes = { -- easily add new remotes to track
|
||||||
|
-- ["remote_name"] = "https://remote_url.come/repo.git", -- full remote url
|
||||||
|
-- ["remote2"] = "github_user/repo", -- GitHub user/repo shortcut,
|
||||||
|
-- ["remote3"] = "github_user", -- GitHub user assume AstroNvim fork
|
||||||
|
-- },
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Set colorscheme to use
|
||||||
|
colorscheme = "default_theme",
|
||||||
|
|
||||||
|
-- Add highlight groups in any theme
|
||||||
|
highlights = {
|
||||||
|
-- init = { -- this table overrides highlights in all themes
|
||||||
|
-- Normal = { bg = "#000000" },
|
||||||
|
-- }
|
||||||
|
-- duskfox = { -- a table of overrides/changes to the duskfox theme
|
||||||
|
-- Normal = { bg = "#000000" },
|
||||||
|
-- },
|
||||||
|
},
|
||||||
|
|
||||||
|
-- set vim options here (vim.<first_key>.<second_key> = value)
|
||||||
|
options = {
|
||||||
|
opt = {
|
||||||
|
-- set to true or false etc.
|
||||||
|
relativenumber = true, -- sets vim.opt.relativenumber
|
||||||
|
number = true, -- sets vim.opt.number
|
||||||
|
spell = false, -- sets vim.opt.spell
|
||||||
|
signcolumn = "auto", -- sets vim.opt.signcolumn to auto
|
||||||
|
wrap = false, -- sets vim.opt.wrap
|
||||||
|
},
|
||||||
|
g = {
|
||||||
|
mapleader = " ", -- sets vim.g.mapleader
|
||||||
|
autoformat_enabled = true, -- enable or disable auto formatting at start (lsp.formatting.format_on_save must be enabled)
|
||||||
|
cmp_enabled = true, -- enable completion at start
|
||||||
|
autopairs_enabled = true, -- enable autopairs at start
|
||||||
|
diagnostics_enabled = true, -- enable diagnostics at start
|
||||||
|
status_diagnostics_enabled = true, -- enable diagnostics in statusline
|
||||||
|
icons_enabled = true, -- disable icons in the UI (disable if no nerd font is available, requires :PackerSync after changing)
|
||||||
|
ui_notifications_enabled = true, -- disable notifications when toggling UI elements
|
||||||
|
heirline_bufferline = false, -- enable new heirline based bufferline (requires :PackerSync after changing)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
-- If you need more control, you can use the function()...end notation
|
||||||
|
-- options = function(local_vim)
|
||||||
|
-- local_vim.opt.relativenumber = true
|
||||||
|
-- local_vim.g.mapleader = " "
|
||||||
|
-- local_vim.opt.whichwrap = vim.opt.whichwrap - { 'b', 's' } -- removing option from list
|
||||||
|
-- local_vim.opt.shortmess = vim.opt.shortmess + { I = true } -- add to option list
|
||||||
|
--
|
||||||
|
-- return local_vim
|
||||||
|
-- end,
|
||||||
|
|
||||||
|
-- Set dashboard header
|
||||||
|
header = {
|
||||||
|
" █████ ███████ ████████ ██████ ██████",
|
||||||
|
"██ ██ ██ ██ ██ ██ ██ ██",
|
||||||
|
"███████ ███████ ██ ██████ ██ ██",
|
||||||
|
"██ ██ ██ ██ ██ ██ ██ ██",
|
||||||
|
"██ ██ ███████ ██ ██ ██ ██████",
|
||||||
|
" ",
|
||||||
|
" ███ ██ ██ ██ ██ ███ ███",
|
||||||
|
" ████ ██ ██ ██ ██ ████ ████",
|
||||||
|
" ██ ██ ██ ██ ██ ██ ██ ████ ██",
|
||||||
|
" ██ ██ ██ ██ ██ ██ ██ ██ ██",
|
||||||
|
" ██ ████ ████ ██ ██ ██",
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Default theme configuration
|
||||||
|
default_theme = {
|
||||||
|
-- Modify the color palette for the default theme
|
||||||
|
colors = {
|
||||||
|
fg = "#abb2bf",
|
||||||
|
bg = "#1e222a",
|
||||||
|
},
|
||||||
|
highlights = function(hl) -- or a function that returns a new table of colors to set
|
||||||
|
local C = require "default_theme.colors"
|
||||||
|
|
||||||
|
hl.Normal = { fg = C.fg, bg = C.bg }
|
||||||
|
|
||||||
|
-- New approach instead of diagnostic_style
|
||||||
|
hl.DiagnosticError.italic = true
|
||||||
|
hl.DiagnosticHint.italic = true
|
||||||
|
hl.DiagnosticInfo.italic = true
|
||||||
|
hl.DiagnosticWarn.italic = true
|
||||||
|
|
||||||
|
return hl
|
||||||
|
end,
|
||||||
|
-- enable or disable highlighting for extra plugins
|
||||||
|
plugins = {
|
||||||
|
aerial = true,
|
||||||
|
beacon = false,
|
||||||
|
bufferline = true,
|
||||||
|
cmp = true,
|
||||||
|
dashboard = true,
|
||||||
|
highlighturl = true,
|
||||||
|
hop = false,
|
||||||
|
indent_blankline = true,
|
||||||
|
lightspeed = false,
|
||||||
|
["neo-tree"] = true,
|
||||||
|
notify = true,
|
||||||
|
["nvim-tree"] = false,
|
||||||
|
["nvim-web-devicons"] = true,
|
||||||
|
rainbow = true,
|
||||||
|
symbols_outline = false,
|
||||||
|
telescope = true,
|
||||||
|
treesitter = true,
|
||||||
|
vimwiki = false,
|
||||||
|
["which-key"] = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Diagnostics configuration (for vim.diagnostics.config({...})) when diagnostics are on
|
||||||
|
diagnostics = {
|
||||||
|
virtual_text = true,
|
||||||
|
underline = true,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Extend LSP configuration
|
||||||
|
lsp = {
|
||||||
|
-- enable servers that you already have installed without mason
|
||||||
|
servers = {
|
||||||
|
-- "pyright"
|
||||||
|
},
|
||||||
|
formatting = {
|
||||||
|
-- control auto formatting on save
|
||||||
|
format_on_save = {
|
||||||
|
enabled = true, -- enable or disable format on save globally
|
||||||
|
allow_filetypes = { -- enable format on save for specified filetypes only
|
||||||
|
-- "go",
|
||||||
|
},
|
||||||
|
ignore_filetypes = { -- disable format on save for specified filetypes
|
||||||
|
-- "python",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
disabled = { -- disable formatting capabilities for the listed language servers
|
||||||
|
-- "sumneko_lua",
|
||||||
|
},
|
||||||
|
timeout_ms = 1000, -- default format timeout
|
||||||
|
-- filter = function(client) -- fully override the default formatting function
|
||||||
|
-- return true
|
||||||
|
-- end
|
||||||
|
},
|
||||||
|
-- easily add or disable built in mappings added during LSP attaching
|
||||||
|
mappings = {
|
||||||
|
n = {
|
||||||
|
-- ["<leader>lf"] = false -- disable formatting keymap
|
||||||
|
},
|
||||||
|
},
|
||||||
|
-- add to the global LSP on_attach function
|
||||||
|
-- on_attach = function(client, bufnr)
|
||||||
|
-- end,
|
||||||
|
|
||||||
|
-- override the mason server-registration function
|
||||||
|
-- server_registration = function(server, opts)
|
||||||
|
-- require("lspconfig")[server].setup(opts)
|
||||||
|
-- end,
|
||||||
|
|
||||||
|
-- Add overrides for LSP server settings, the keys are the name of the server
|
||||||
|
["server-settings"] = {
|
||||||
|
-- example for addings schemas to yamlls
|
||||||
|
-- yamlls = { -- override table for require("lspconfig").yamlls.setup({...})
|
||||||
|
-- settings = {
|
||||||
|
-- yaml = {
|
||||||
|
-- schemas = {
|
||||||
|
-- ["http://json.schemastore.org/github-workflow"] = ".github/workflows/*.{yml,yaml}",
|
||||||
|
-- ["http://json.schemastore.org/github-action"] = ".github/action.{yml,yaml}",
|
||||||
|
-- ["http://json.schemastore.org/ansible-stable-2.9"] = "roles/tasks/*.{yml,yaml}",
|
||||||
|
-- },
|
||||||
|
-- },
|
||||||
|
-- },
|
||||||
|
-- },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Mapping data with "desc" stored directly by vim.keymap.set().
|
||||||
|
--
|
||||||
|
-- Please use this mappings table to set keyboard mapping since this is the
|
||||||
|
-- lower level configuration and more robust one. (which-key will
|
||||||
|
-- automatically pick-up stored data by this setting.)
|
||||||
|
mappings = {
|
||||||
|
-- first key is the mode
|
||||||
|
n = {
|
||||||
|
-- second key is the lefthand side of the map
|
||||||
|
-- mappings seen under group name "Buffer"
|
||||||
|
["<leader>bb"] = { "<cmd>tabnew<cr>", desc = "New tab" },
|
||||||
|
["<leader>bc"] = { "<cmd>BufferLinePickClose<cr>", desc = "Pick to close" },
|
||||||
|
["<leader>bj"] = { "<cmd>BufferLinePick<cr>", desc = "Pick to jump" },
|
||||||
|
["<leader>bt"] = { "<cmd>BufferLineSortByTabs<cr>", desc = "Sort by tabs" },
|
||||||
|
-- quick save
|
||||||
|
-- ["<C-s>"] = { ":w!<cr>", desc = "Save File" }, -- change description but the same command
|
||||||
|
},
|
||||||
|
t = {
|
||||||
|
-- setting a mapping to false will disable it
|
||||||
|
-- ["<esc>"] = false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Configure plugins
|
||||||
|
plugins = {
|
||||||
|
init = {
|
||||||
|
-- You can disable default plugins as follows:
|
||||||
|
-- ["goolord/alpha-nvim"] = { disable = true },
|
||||||
|
|
||||||
|
-- You can also add new plugins here as well:
|
||||||
|
-- Add plugins, the packer syntax without the "use"
|
||||||
|
-- { "andweeb/presence.nvim" },
|
||||||
|
-- {
|
||||||
|
-- "ray-x/lsp_signature.nvim",
|
||||||
|
-- event = "BufRead",
|
||||||
|
-- config = function()
|
||||||
|
-- require("lsp_signature").setup()
|
||||||
|
-- end,
|
||||||
|
-- },
|
||||||
|
|
||||||
|
-- We also support a key value style plugin definition similar to NvChad:
|
||||||
|
-- ["ray-x/lsp_signature.nvim"] = {
|
||||||
|
-- event = "BufRead",
|
||||||
|
-- config = function()
|
||||||
|
-- require("lsp_signature").setup()
|
||||||
|
-- end,
|
||||||
|
-- },
|
||||||
|
},
|
||||||
|
-- All other entries override the require("<key>").setup({...}) call for default plugins
|
||||||
|
["null-ls"] = function(config) -- overrides `require("null-ls").setup(config)`
|
||||||
|
-- config variable is the default configuration table for the setup function call
|
||||||
|
-- local null_ls = require "null-ls"
|
||||||
|
|
||||||
|
-- Check supported formatters and linters
|
||||||
|
-- https://github.com/jose-elias-alvarez/null-ls.nvim/tree/main/lua/null-ls/builtins/formatting
|
||||||
|
-- https://github.com/jose-elias-alvarez/null-ls.nvim/tree/main/lua/null-ls/builtins/diagnostics
|
||||||
|
config.sources = {
|
||||||
|
-- Set a formatter
|
||||||
|
-- null_ls.builtins.formatting.stylua,
|
||||||
|
-- null_ls.builtins.formatting.prettier,
|
||||||
|
}
|
||||||
|
return config -- return final config table
|
||||||
|
end,
|
||||||
|
treesitter = { -- overrides `require("treesitter").setup(...)`
|
||||||
|
-- ensure_installed = { "lua" },
|
||||||
|
},
|
||||||
|
-- use mason-lspconfig to configure LSP installations
|
||||||
|
["mason-lspconfig"] = { -- overrides `require("mason-lspconfig").setup(...)`
|
||||||
|
-- ensure_installed = { "sumneko_lua" },
|
||||||
|
},
|
||||||
|
-- use mason-null-ls to configure Formatters/Linter installation for null-ls sources
|
||||||
|
["mason-null-ls"] = { -- overrides `require("mason-null-ls").setup(...)`
|
||||||
|
-- ensure_installed = { "prettier", "stylua" },
|
||||||
|
},
|
||||||
|
["mason-nvim-dap"] = { -- overrides `require("mason-nvim-dap").setup(...)`
|
||||||
|
-- ensure_installed = { "python" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
-- LuaSnip Options
|
||||||
|
luasnip = {
|
||||||
|
-- Extend filetypes
|
||||||
|
filetype_extend = {
|
||||||
|
-- javascript = { "javascriptreact" },
|
||||||
|
},
|
||||||
|
-- Configure luasnip loaders (vscode, lua, and/or snipmate)
|
||||||
|
vscode = {
|
||||||
|
-- Add paths for including more VS Code style snippets in luasnip
|
||||||
|
paths = {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
-- CMP Source Priorities
|
||||||
|
-- modify here the priorities of default cmp sources
|
||||||
|
-- higher value == higher priority
|
||||||
|
-- The value can also be set to a boolean for disabling default sources:
|
||||||
|
-- false == disabled
|
||||||
|
-- true == 1000
|
||||||
|
cmp = {
|
||||||
|
source_priority = {
|
||||||
|
nvim_lsp = 1000,
|
||||||
|
luasnip = 750,
|
||||||
|
buffer = 500,
|
||||||
|
path = 250,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Customize Heirline options
|
||||||
|
heirline = {
|
||||||
|
-- -- Customize different separators between sections
|
||||||
|
-- separators = {
|
||||||
|
-- tab = { "", "" },
|
||||||
|
-- },
|
||||||
|
-- -- Customize colors for each element each element has a `_fg` and a `_bg`
|
||||||
|
-- colors = function(colors)
|
||||||
|
-- colors.git_branch_fg = astronvim.get_hlgroup "Conditional"
|
||||||
|
-- return colors
|
||||||
|
-- end,
|
||||||
|
-- -- Customize attributes of highlighting in Heirline components
|
||||||
|
-- attributes = {
|
||||||
|
-- -- styling choices for each heirline element, check possible attributes with `:h attr-list`
|
||||||
|
-- git_branch = { bold = true }, -- bold the git branch statusline component
|
||||||
|
-- },
|
||||||
|
-- -- Customize if icons should be highlighted
|
||||||
|
-- icon_highlights = {
|
||||||
|
-- breadcrumbs = false, -- LSP symbols in the breadcrumbs
|
||||||
|
-- file_icon = {
|
||||||
|
-- winbar = false, -- Filetype icon in the winbar inactive windows
|
||||||
|
-- statusline = true, -- Filetype icon in the statusline
|
||||||
|
-- },
|
||||||
|
-- },
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Modify which-key registration (Use this with mappings table in the above.)
|
||||||
|
["which-key"] = {
|
||||||
|
-- Add bindings which show up as group name
|
||||||
|
register = {
|
||||||
|
-- first key is the mode, n == normal mode
|
||||||
|
n = {
|
||||||
|
-- second key is the prefix, <leader> prefixes
|
||||||
|
["<leader>"] = {
|
||||||
|
-- third key is the key to bring up next level and its displayed
|
||||||
|
-- group name in which-key top level menu
|
||||||
|
["b"] = { name = "Buffer" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
-- This function is run last and is a good place to configuring
|
||||||
|
-- augroups/autocommands and custom filetypes also this just pure lua so
|
||||||
|
-- anything that doesn't fit in the normal config locations above can go here
|
||||||
|
polish = function()
|
||||||
|
-- Set up custom filetypes
|
||||||
|
-- vim.filetype.add {
|
||||||
|
-- extension = {
|
||||||
|
-- foo = "fooscript",
|
||||||
|
-- },
|
||||||
|
-- filename = {
|
||||||
|
-- ["Foofile"] = "fooscript",
|
||||||
|
-- },
|
||||||
|
-- pattern = {
|
||||||
|
-- ["~/%.config/foo/.*"] = "fooscript",
|
||||||
|
-- },
|
||||||
|
-- }
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
|
@ -0,0 +1,21 @@
|
||||||
|
FROM archlinux:base-devel
|
||||||
|
WORKDIR /setup
|
||||||
|
RUN pacman -Sy git neovim python --noconfirm
|
||||||
|
RUN useradd -m test
|
||||||
|
|
||||||
|
USER test
|
||||||
|
RUN git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim
|
||||||
|
RUN mkdir -p /home/test/.cache/nvim/packer.nvim
|
||||||
|
RUN touch /home/test/.cache/nvim/packer.nvim/test_completion{,1,2,3}
|
||||||
|
|
||||||
|
USER test
|
||||||
|
RUN mkdir -p /home/test/.local/share/nvim/site/pack/packer/start/packer.nvim/
|
||||||
|
WORKDIR /home/test/.local/share/nvim/site/pack/packer/start/packer.nvim/
|
||||||
|
COPY . ./
|
||||||
|
|
||||||
|
USER root
|
||||||
|
RUN chmod 777 -R /home/test/.local/share/nvim/site/pack/packer/start/packer.nvim
|
||||||
|
RUN touch /home/test/.cache/nvim/packer.nvim/not_writeable
|
||||||
|
|
||||||
|
USER test
|
||||||
|
ENTRYPOINT make test
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Wil Thomason
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,6 @@
|
||||||
|
test:
|
||||||
|
nvim --headless --noplugin -u tests/minimal.vim -c "PlenaryBustedDirectory tests/ { minimal_init = './tests/minimal.vim' }"
|
||||||
|
run:
|
||||||
|
docker build . -t neovim-stable:latest && docker run --rm -it --entrypoint bash neovim-stable:latest
|
||||||
|
run-test:
|
||||||
|
docker build . -t neovim-stable:latest && docker run --rm neovim-stable:latest
|
|
@ -0,0 +1,676 @@
|
||||||
|
# packer.nvim
|
||||||
|
|
||||||
|
[![Gitter](https://badges.gitter.im/packer-nvim/community.svg)](https://gitter.im/packer-nvim/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||||
|
|
||||||
|
[`use-package`](https://github.com/jwiegley/use-package) inspired plugin/package management for
|
||||||
|
Neovim.
|
||||||
|
|
||||||
|
Have questions? Start a [discussion](https://github.com/wbthomason/packer.nvim/discussions).
|
||||||
|
|
||||||
|
Have a problem or idea? Make an [issue](https://github.com/wbthomason/packer.nvim/issues) or a [PR](https://github.com/wbthomason/packer.nvim/pulls).
|
||||||
|
|
||||||
|
**Packer is built on native packages. You may wish to read `:h packages` before continuing**
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
1. [Features](#features)
|
||||||
|
2. [Requirements](#requirements)
|
||||||
|
3. [Quickstart](#quickstart)
|
||||||
|
4. [Bootstrapping](#bootstrapping)
|
||||||
|
5. [Usage](#usage)
|
||||||
|
1. [The startup function](#the-startup-function)
|
||||||
|
2. [Custom Initialization](#custom-initialization)
|
||||||
|
3. [Specifying Plugins](#specifying-plugins)
|
||||||
|
4. [Performing plugin management operations](#performing-plugin-management-operations)
|
||||||
|
5. [Extending packer](#extending-packer)
|
||||||
|
6. [Compiling Lazy-Loaders](#compiling-lazy-loaders)
|
||||||
|
7. [User autocommands](#user-autocommands)
|
||||||
|
8. [Using a floating window](#using-a-floating-window)
|
||||||
|
6. [Profiling](#profiling)
|
||||||
|
7. [Debugging](#debugging)
|
||||||
|
8. [Compatibility and known issues](#compatibility-and-known-issues)
|
||||||
|
9. [Contributors](#contributors)
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Declarative plugin specification
|
||||||
|
- Support for dependencies
|
||||||
|
- Support for Luarocks dependencies
|
||||||
|
- Expressive configuration and lazy-loading options
|
||||||
|
- Automatically compiles efficient lazy-loading code to improve startup time
|
||||||
|
- Uses native packages
|
||||||
|
- Extensible
|
||||||
|
- Written in Lua, configured in Lua
|
||||||
|
- Post-install/update hooks
|
||||||
|
- Uses jobs for async installation
|
||||||
|
- Support for `git` tags, branches, revisions, submodules
|
||||||
|
- Support for local plugins
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
- You need to be running **Neovim v0.5.0+**
|
||||||
|
- If you are on Windows 10, you need developer mode enabled in order to use local plugins (creating
|
||||||
|
symbolic links requires admin privileges on Windows - credit to @TimUntersberger for this note)
|
||||||
|
|
||||||
|
## Quickstart
|
||||||
|
To get started, first clone this repository to somewhere on your `packpath`, e.g.:
|
||||||
|
|
||||||
|
> Unix, Linux Installation
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git clone --depth 1 https://github.com/wbthomason/packer.nvim\
|
||||||
|
~/.local/share/nvim/site/pack/packer/start/packer.nvim
|
||||||
|
```
|
||||||
|
|
||||||
|
If you use Arch Linux, there is also [an AUR
|
||||||
|
package](https://aur.archlinux.org/packages/nvim-packer-git/).
|
||||||
|
|
||||||
|
> Windows Powershell Installation
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git clone https://github.com/wbthomason/packer.nvim "$env:LOCALAPPDATA\nvim-data\site\pack\packer\start\packer.nvim"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can write your plugin specification in Lua, e.g. (in `~/.config/nvim/lua/plugins.lua`):
|
||||||
|
|
||||||
|
```lua
|
||||||
|
-- This file can be loaded by calling `lua require('plugins')` from your init.vim
|
||||||
|
|
||||||
|
-- Only required if you have packer configured as `opt`
|
||||||
|
vim.cmd [[packadd packer.nvim]]
|
||||||
|
|
||||||
|
return require('packer').startup(function(use)
|
||||||
|
-- Packer can manage itself
|
||||||
|
use 'wbthomason/packer.nvim'
|
||||||
|
|
||||||
|
-- Simple plugins can be specified as strings
|
||||||
|
use 'rstacruz/vim-closer'
|
||||||
|
|
||||||
|
-- Lazy loading:
|
||||||
|
-- Load on specific commands
|
||||||
|
use {'tpope/vim-dispatch', opt = true, cmd = {'Dispatch', 'Make', 'Focus', 'Start'}}
|
||||||
|
|
||||||
|
-- Load on an autocommand event
|
||||||
|
use {'andymass/vim-matchup', event = 'VimEnter'}
|
||||||
|
|
||||||
|
-- Load on a combination of conditions: specific filetypes or commands
|
||||||
|
-- Also run code after load (see the "config" key)
|
||||||
|
use {
|
||||||
|
'w0rp/ale',
|
||||||
|
ft = {'sh', 'zsh', 'bash', 'c', 'cpp', 'cmake', 'html', 'markdown', 'racket', 'vim', 'tex'},
|
||||||
|
cmd = 'ALEEnable',
|
||||||
|
config = 'vim.cmd[[ALEEnable]]'
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Plugins can have dependencies on other plugins
|
||||||
|
use {
|
||||||
|
'haorenW1025/completion-nvim',
|
||||||
|
opt = true,
|
||||||
|
requires = {{'hrsh7th/vim-vsnip', opt = true}, {'hrsh7th/vim-vsnip-integ', opt = true}}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Plugins can also depend on rocks from luarocks.org:
|
||||||
|
use {
|
||||||
|
'my/supercoolplugin',
|
||||||
|
rocks = {'lpeg', {'lua-cjson', version = '2.1.0'}}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- You can specify rocks in isolation
|
||||||
|
use_rocks 'penlight'
|
||||||
|
use_rocks {'lua-resty-http', 'lpeg'}
|
||||||
|
|
||||||
|
-- Local plugins can be included
|
||||||
|
use '~/projects/personal/hover.nvim'
|
||||||
|
|
||||||
|
-- Plugins can have post-install/update hooks
|
||||||
|
use {'iamcco/markdown-preview.nvim', run = 'cd app && yarn install', cmd = 'MarkdownPreview'}
|
||||||
|
|
||||||
|
-- Post-install/update hook with neovim command
|
||||||
|
use { 'nvim-treesitter/nvim-treesitter', run = ':TSUpdate' }
|
||||||
|
|
||||||
|
-- Post-install/update hook with call of vimscript function with argument
|
||||||
|
use { 'glacambre/firenvim', run = function() vim.fn['firenvim#install'](0) end }
|
||||||
|
|
||||||
|
-- Use specific branch, dependency and run lua file after load
|
||||||
|
use {
|
||||||
|
'glepnir/galaxyline.nvim', branch = 'main', config = function() require'statusline' end,
|
||||||
|
requires = {'kyazdani42/nvim-web-devicons'}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Use dependency and run lua function after load
|
||||||
|
use {
|
||||||
|
'lewis6991/gitsigns.nvim', requires = { 'nvim-lua/plenary.nvim' },
|
||||||
|
config = function() require('gitsigns').setup() end
|
||||||
|
}
|
||||||
|
|
||||||
|
-- You can specify multiple plugins in a single call
|
||||||
|
use {'tjdevries/colorbuddy.vim', {'nvim-treesitter/nvim-treesitter', opt = true}}
|
||||||
|
|
||||||
|
-- You can alias plugin names
|
||||||
|
use {'dracula/vim', as = 'dracula'}
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that if you get linter complaints about `use` being an undefined global, these errors are
|
||||||
|
spurious - `packer` injects `use` into the scope of the function passed to `startup`.
|
||||||
|
If these errors bother you, the easiest fix is to simply specify `use` as an argument to the
|
||||||
|
function you pass to `startup`, e.g.
|
||||||
|
```lua
|
||||||
|
packer.startup(function(use)
|
||||||
|
...your config...
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
`packer` provides the following commands after you've run and configured `packer` with `require('packer').startup(...)`:
|
||||||
|
|
||||||
|
```
|
||||||
|
-- You must run this or `PackerSync` whenever you make changes to your plugin configuration
|
||||||
|
-- Regenerate compiled loader file
|
||||||
|
:PackerCompile
|
||||||
|
|
||||||
|
-- Remove any disabled or unused plugins
|
||||||
|
:PackerClean
|
||||||
|
|
||||||
|
-- Clean, then install missing plugins
|
||||||
|
:PackerInstall
|
||||||
|
|
||||||
|
-- Clean, then update and install plugins
|
||||||
|
-- supports the `--preview` flag as an optional first argument to preview updates
|
||||||
|
:PackerUpdate
|
||||||
|
|
||||||
|
-- Perform `PackerUpdate` and then `PackerCompile`
|
||||||
|
-- supports the `--preview` flag as an optional first argument to preview updates
|
||||||
|
:PackerSync
|
||||||
|
|
||||||
|
-- Show list of installed plugins
|
||||||
|
:PackerStatus
|
||||||
|
|
||||||
|
-- Loads opt plugin immediately
|
||||||
|
:PackerLoad completion-nvim ale
|
||||||
|
```
|
||||||
|
|
||||||
|
You can configure Neovim to automatically run `:PackerCompile` whenever `plugins.lua` is updated with
|
||||||
|
[an autocommand](https://neovim.io/doc/user/autocmd.html#:autocmd):
|
||||||
|
|
||||||
|
```
|
||||||
|
augroup packer_user_config
|
||||||
|
autocmd!
|
||||||
|
autocmd BufWritePost plugins.lua source <afile> | PackerCompile
|
||||||
|
augroup end
|
||||||
|
```
|
||||||
|
|
||||||
|
This autocommand can be placed in your `init.vim`, or any other startup file as per your setup.
|
||||||
|
Placing this in `plugins.lua` could look like this:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
vim.cmd([[
|
||||||
|
augroup packer_user_config
|
||||||
|
autocmd!
|
||||||
|
autocmd BufWritePost plugins.lua source <afile> | PackerCompile
|
||||||
|
augroup end
|
||||||
|
]])
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bootstrapping
|
||||||
|
|
||||||
|
If you want to automatically install and set up `packer.nvim` on any machine you clone your configuration to,
|
||||||
|
add the following snippet (which is due to @Iron-E and @khuedoan) somewhere in your config **before** your first usage of `packer`:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local ensure_packer = function()
|
||||||
|
local fn = vim.fn
|
||||||
|
local install_path = fn.stdpath('data')..'/site/pack/packer/start/packer.nvim'
|
||||||
|
if fn.empty(fn.glob(install_path)) > 0 then
|
||||||
|
fn.system({'git', 'clone', '--depth', '1', 'https://github.com/wbthomason/packer.nvim', install_path})
|
||||||
|
vim.cmd [[packadd packer.nvim]]
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local packer_bootstrap = ensure_packer()
|
||||||
|
|
||||||
|
return require('packer').startup(function(use)
|
||||||
|
use 'wbthomason/packer.nvim'
|
||||||
|
-- My plugins here
|
||||||
|
-- use 'foo1/bar1.nvim'
|
||||||
|
-- use 'foo2/bar2.nvim'
|
||||||
|
|
||||||
|
-- Automatically set up your configuration after cloning packer.nvim
|
||||||
|
-- Put this at the end after all plugins
|
||||||
|
if packer_bootstrap then
|
||||||
|
require('packer').sync()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also use the following command (with `packer` bootstrapped) to have `packer` setup your
|
||||||
|
configuration (or simply run updates) and close once all operations are completed:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ nvim --headless -c 'autocmd User PackerComplete quitall' -c 'PackerSync'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The above snippets give some examples of `packer` features and use. Examples include:
|
||||||
|
|
||||||
|
- My dotfiles:
|
||||||
|
- [Specification file](https://github.com/wbthomason/dotfiles/blob/linux/neovim/.config/nvim/lua/plugins.lua)
|
||||||
|
- [Loading file](https://github.com/wbthomason/dotfiles/blob/linux/neovim/.config/nvim/lua/plugins.lua)
|
||||||
|
- [Generated lazy-loader file](https://github.com/wbthomason/dotfiles/blob/linux/neovim/.config/nvim/plugin/packer_compiled.lua)
|
||||||
|
- An example using the `startup` method: [tjdevries](https://github.com/tjdevries/config_manager/blob/master/xdg_config/nvim/lua/tj/plugins.lua)
|
||||||
|
- Using this method, you do not require a "loading" file. You can simply `lua require('plugins')` from your `init.vim`
|
||||||
|
|
||||||
|
The following is a more in-depth explanation of `packer`'s features and use.
|
||||||
|
|
||||||
|
### The `startup` function
|
||||||
|
`packer` provides `packer.startup(spec)`, which is used in the above examples.
|
||||||
|
|
||||||
|
`startup` is a convenience function for simple setup and can be invoked as follows:
|
||||||
|
- `spec` can be a function: `packer.startup(function() use 'tjdevries/colorbuddy.vim' end)`
|
||||||
|
- `spec` can be a table with a function as its first element and config overrides as another element:
|
||||||
|
`packer.startup({function() use 'tjdevries/colorbuddy.vim' end, config = { ... }})`
|
||||||
|
- `spec` can be a table with a table of plugin specifications as its first element, config overrides as another element, and optional rock specifications as another element:
|
||||||
|
`packer.startup({{'tjdevries/colorbuddy.vim'}, config = { ... }, rocks = { ... }})`
|
||||||
|
|
||||||
|
### Custom Initialization
|
||||||
|
You are not required to use `packer.startup` if you prefer a more manual setup with finer control
|
||||||
|
over configuration and loading.
|
||||||
|
|
||||||
|
To take this approach, load `packer` like any other Lua module. You must call `packer.init()` before
|
||||||
|
performing any operations; it is recommended to call `packer.reset()` if you may be re-running your
|
||||||
|
specification code (e.g. by sourcing your plugin specification file with `luafile`).
|
||||||
|
|
||||||
|
You may pass a table of configuration values to `packer.init()` to customize its operation. The
|
||||||
|
default configuration values (and structure of the configuration table) are:
|
||||||
|
```lua
|
||||||
|
{
|
||||||
|
ensure_dependencies = true, -- Should packer install plugin dependencies?
|
||||||
|
snapshot = nil, -- Name of the snapshot you would like to load at startup
|
||||||
|
snapshot_path = join_paths(stdpath 'cache', 'packer.nvim'), -- Default save directory for snapshots
|
||||||
|
package_root = util.join_paths(vim.fn.stdpath('data'), 'site', 'pack'),
|
||||||
|
compile_path = util.join_paths(vim.fn.stdpath('config'), 'plugin', 'packer_compiled.lua'),
|
||||||
|
plugin_package = 'packer', -- The default package for plugins
|
||||||
|
max_jobs = nil, -- Limit the number of simultaneous jobs. nil means no limit
|
||||||
|
auto_clean = true, -- During sync(), remove unused plugins
|
||||||
|
compile_on_sync = true, -- During sync(), run packer.compile()
|
||||||
|
disable_commands = false, -- Disable creating commands
|
||||||
|
opt_default = false, -- Default to using opt (as opposed to start) plugins
|
||||||
|
transitive_opt = true, -- Make dependencies of opt plugins also opt by default
|
||||||
|
transitive_disable = true, -- Automatically disable dependencies of disabled plugins
|
||||||
|
auto_reload_compiled = true, -- Automatically reload the compiled file after creating it.
|
||||||
|
preview_updates = false, -- If true, always preview updates before choosing which plugins to update, same as `PackerUpdate --preview`.
|
||||||
|
git = {
|
||||||
|
cmd = 'git', -- The base command for git operations
|
||||||
|
subcommands = { -- Format strings for git subcommands
|
||||||
|
update = 'pull --ff-only --progress --rebase=false',
|
||||||
|
install = 'clone --depth %i --no-single-branch --progress',
|
||||||
|
fetch = 'fetch --depth 999999 --progress',
|
||||||
|
checkout = 'checkout %s --',
|
||||||
|
update_branch = 'merge --ff-only @{u}',
|
||||||
|
current_branch = 'branch --show-current',
|
||||||
|
diff = 'log --color=never --pretty=format:FMT --no-show-signature HEAD@{1}...HEAD',
|
||||||
|
diff_fmt = '%%h %%s (%%cr)',
|
||||||
|
get_rev = 'rev-parse --short HEAD',
|
||||||
|
get_msg = 'log --color=never --pretty=format:FMT --no-show-signature HEAD -n 1',
|
||||||
|
submodules = 'submodule update --init --recursive --progress'
|
||||||
|
},
|
||||||
|
depth = 1, -- Git clone depth
|
||||||
|
clone_timeout = 60, -- Timeout, in seconds, for git clones
|
||||||
|
default_url_format = 'https://github.com/%s' -- Lua format string used for "aaa/bbb" style plugins
|
||||||
|
},
|
||||||
|
display = {
|
||||||
|
non_interactive = false, -- If true, disable display windows for all operations
|
||||||
|
compact = false, -- If true, fold updates results by default
|
||||||
|
open_fn = nil, -- An optional function to open a window for packer's display
|
||||||
|
open_cmd = '65vnew \\[packer\\]', -- An optional command to open a window for packer's display
|
||||||
|
working_sym = '⟳', -- The symbol for a plugin being installed/updated
|
||||||
|
error_sym = '✗', -- The symbol for a plugin with an error in installation/updating
|
||||||
|
done_sym = '✓', -- The symbol for a plugin which has completed installation/updating
|
||||||
|
removed_sym = '-', -- The symbol for an unused plugin which was removed
|
||||||
|
moved_sym = '→', -- The symbol for a plugin which was moved (e.g. from opt to start)
|
||||||
|
header_sym = '━', -- The symbol for the header line in packer's display
|
||||||
|
show_all_info = true, -- Should packer show all update details automatically?
|
||||||
|
prompt_border = 'double', -- Border style of prompt popups.
|
||||||
|
keybindings = { -- Keybindings for the display window
|
||||||
|
quit = 'q',
|
||||||
|
toggle_update = 'u', -- only in preview
|
||||||
|
continue = 'c', -- only in preview
|
||||||
|
toggle_info = '<CR>',
|
||||||
|
diff = 'd',
|
||||||
|
prompt_revert = 'r',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
luarocks = {
|
||||||
|
python_cmd = 'python' -- Set the python command to use for running hererocks
|
||||||
|
},
|
||||||
|
log = { level = 'warn' }, -- The default print log level. One of: "trace", "debug", "info", "warn", "error", "fatal".
|
||||||
|
profile = {
|
||||||
|
enable = false,
|
||||||
|
threshold = 1, -- integer in milliseconds, plugins which load faster than this won't be shown in profile output
|
||||||
|
},
|
||||||
|
autoremove = false, -- Remove disabled or unused plugins without prompting the user
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Specifying plugins
|
||||||
|
|
||||||
|
`packer` is based around declarative specification of plugins. You can declare a plugin using the
|
||||||
|
function `packer.use`, which I highly recommend locally binding to `use` for conciseness.
|
||||||
|
|
||||||
|
`use` takes either a string or a table. If a string is provided, it is treated as a plugin location
|
||||||
|
for a non-optional plugin with no additional configuration. Plugin locations may be specified as
|
||||||
|
|
||||||
|
1. Absolute paths to a local plugin
|
||||||
|
2. Full URLs (treated as plugins managed with `git`)
|
||||||
|
3. `username/repo` paths (treated as Github `git` plugins)
|
||||||
|
|
||||||
|
A table given to `use` can take two forms:
|
||||||
|
|
||||||
|
1. A list of plugin specifications (strings or tables)
|
||||||
|
2. A table specifying a single plugin. It must have a plugin location string as its first element,
|
||||||
|
and may additionally have a number of optional keyword elements, shown below:
|
||||||
|
```lua
|
||||||
|
use {
|
||||||
|
'myusername/example', -- The plugin location string
|
||||||
|
-- The following keys are all optional
|
||||||
|
disable = boolean, -- Mark a plugin as inactive
|
||||||
|
as = string, -- Specifies an alias under which to install the plugin
|
||||||
|
installer = function, -- Specifies custom installer. See "custom installers" below.
|
||||||
|
updater = function, -- Specifies custom updater. See "custom installers" below.
|
||||||
|
after = string or list, -- Specifies plugins to load before this plugin. See "sequencing" below
|
||||||
|
rtp = string, -- Specifies a subdirectory of the plugin to add to runtimepath.
|
||||||
|
opt = boolean, -- Manually marks a plugin as optional.
|
||||||
|
bufread = boolean, -- Manually specifying if a plugin needs BufRead after being loaded
|
||||||
|
branch = string, -- Specifies a git branch to use
|
||||||
|
tag = string, -- Specifies a git tag to use. Supports '*' for "latest tag"
|
||||||
|
commit = string, -- Specifies a git commit to use
|
||||||
|
lock = boolean, -- Skip updating this plugin in updates/syncs. Still cleans.
|
||||||
|
run = string, function, or table, -- Post-update/install hook. See "update/install hooks".
|
||||||
|
requires = string or list, -- Specifies plugin dependencies. See "dependencies".
|
||||||
|
rocks = string or list, -- Specifies Luarocks dependencies for the plugin
|
||||||
|
config = string or function, -- Specifies code to run after this plugin is loaded.
|
||||||
|
-- The setup key implies opt = true
|
||||||
|
setup = string or function, -- Specifies code to run before this plugin is loaded. The code is ran even if
|
||||||
|
-- the plugin is waiting for other conditions (ft, cond...) to be met.
|
||||||
|
-- The following keys all imply lazy-loading and imply opt = true
|
||||||
|
cmd = string or list, -- Specifies commands which load this plugin. Can be an autocmd pattern.
|
||||||
|
ft = string or list, -- Specifies filetypes which load this plugin.
|
||||||
|
keys = string or list, -- Specifies maps which load this plugin. See "Keybindings".
|
||||||
|
event = string or list, -- Specifies autocommand events which load this plugin.
|
||||||
|
fn = string or list -- Specifies functions which load this plugin.
|
||||||
|
cond = string, function, or list of strings/functions, -- Specifies a conditional test to load this plugin
|
||||||
|
module = string or list -- Specifies Lua module names for require. When requiring a string which starts
|
||||||
|
-- with one of these module names, the plugin will be loaded.
|
||||||
|
module_pattern = string/list -- Specifies Lua pattern of Lua module names for require. When
|
||||||
|
-- requiring a string which matches one of these patterns, the plugin will be loaded.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For the `cmd` option, the command may be a full command, or an autocommand pattern. If the command contains any
|
||||||
|
non-alphanumeric characters, it is assumed to be a pattern, and instead of creating a stub command, it creates
|
||||||
|
a CmdUndefined autocmd to load the plugin when a command that matches the pattern is invoked.
|
||||||
|
|
||||||
|
#### Checking plugin statuses
|
||||||
|
You can check whether or not a particular plugin is installed with `packer` as well as if that plugin is loaded.
|
||||||
|
To do this you can check for the plugin's name in the `packer_plugins` global table.
|
||||||
|
Plugins in this table are saved using only the last section of their names
|
||||||
|
e.g. `tpope/vim-fugitive` if installed will be under the key `vim-fugitive`.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
if packer_plugins["vim-fugitive"] and packer_plugins["vim-fugitive"].loaded then
|
||||||
|
print("Vim fugitive is loaded")
|
||||||
|
-- other custom logic
|
||||||
|
end
|
||||||
|
```
|
||||||
|
**NOTE:** this table is only available *after* `packer_compiled.vim` is loaded so cannot be used till *after* plugins
|
||||||
|
have been loaded.
|
||||||
|
|
||||||
|
#### Luarocks support
|
||||||
|
|
||||||
|
You may specify that a plugin requires one or more Luarocks packages using the `rocks` key. This key
|
||||||
|
takes either a string specifying the name of a package (e.g. `rocks=lpeg`), or a list specifying one or more packages.
|
||||||
|
Entries in the list may either be strings, a list of strings or a table --- the latter case is used to specify arguments such as the
|
||||||
|
particular version of a package.
|
||||||
|
all supported luarocks keys are allowed except: `tree` and `local`. Environment variables for the luarocks command can also be
|
||||||
|
specified using the `env` key which takes a table as the value as shown below.
|
||||||
|
```lua
|
||||||
|
rocks = {'lpeg', {'lua-cjson', version = '2.1.0'}}
|
||||||
|
use_rocks {'lua-cjson', 'lua-resty-http'}
|
||||||
|
use_rocks {'luaformatter', server = 'https://luarocks.org/dev'}
|
||||||
|
use_rocks {'openssl' env = {OPENSSL_DIR = "/path/to/dir"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Currently, `packer` only supports equality constraints on package versions.
|
||||||
|
|
||||||
|
`packer` also provides the function `packer.luarocks.install_commands()`, which creates the
|
||||||
|
`PackerRocks <cmd> <packages...>` command. `<cmd>` must be one of "install" or "remove";
|
||||||
|
`<packages...>` is one or more package names (currently, version restrictions are not supported with
|
||||||
|
this command). Running `PackerRocks` will install or remove the given packages. You can use this
|
||||||
|
command even if you don't use `packer` to manage your plugins. However, please note that (1)
|
||||||
|
packages installed through `PackerRocks` **will** be removed by calls to `packer.luarocks.clean()`
|
||||||
|
(unless they are also part of a `packer` plugin specification), and (2) you will need to manually
|
||||||
|
invoke `packer.luarocks.setup_paths` (or otherwise modify your `package.path`) to ensure that Neovim
|
||||||
|
can find the installed packages.
|
||||||
|
|
||||||
|
Finally, `packer` provides the function `packer.use_rocks`, which takes a string or table specifying
|
||||||
|
one or more Luarocks packages as in the `rocks` key. You can use this to ensure that `packer`
|
||||||
|
downloads and manages some rocks which you want to use, but which are not associated with any
|
||||||
|
particular plugin.
|
||||||
|
|
||||||
|
#### Custom installers
|
||||||
|
|
||||||
|
You may specify a custom installer & updater for a plugin using the `installer` and `updater` keys.
|
||||||
|
Note that either both or none of these keys are required. These keys should be functions which take
|
||||||
|
as an argument a `display` object (from `lua/packer/display.lua`) and return an async function (per
|
||||||
|
`lua/packer/async.lua`) which (respectively) installs/updates the given plugin.
|
||||||
|
|
||||||
|
Providing the `installer`/`updater` keys overrides plugin type detection, but you still need to
|
||||||
|
provide a location string for the name of the plugin.
|
||||||
|
|
||||||
|
#### Update/install hooks
|
||||||
|
|
||||||
|
You may specify operations to be run after successful installs/updates of a plugin with the `run`
|
||||||
|
key. This key may either be a Lua function, which will be called with the `plugin` table for this
|
||||||
|
plugin (containing the information passed to `use` as well as output from the installation/update
|
||||||
|
commands, the installation path of the plugin, etc.), a string, or a table of functions and strings.
|
||||||
|
|
||||||
|
If an element of `run` is a string, then either:
|
||||||
|
|
||||||
|
1. If the first character of `run` is ":", it is treated as a Neovim command and executed.
|
||||||
|
2. Otherwise, `run` is treated as a shell command and run in the installation directory of the
|
||||||
|
plugin via `$SHELL -c '<run>'`.
|
||||||
|
|
||||||
|
#### Dependencies
|
||||||
|
|
||||||
|
Plugins may specify dependencies via the `requires` key. This key can be a string or a list (table).
|
||||||
|
|
||||||
|
If `requires` is a string, it is treated as specifying a single plugin. If a plugin with the name
|
||||||
|
given in `requires` is already known in the managed set, nothing happens. Otherwise, the string is
|
||||||
|
treated as a plugin location string and the corresponding plugin is added to the managed set.
|
||||||
|
|
||||||
|
If `requires` is a list, it is treated as a list of plugin specifications following the format given
|
||||||
|
above.
|
||||||
|
|
||||||
|
If `ensure_dependencies` is true, the plugins specified in `requires` will be installed.
|
||||||
|
|
||||||
|
Plugins specified in `requires` are removed when no active plugins require them.
|
||||||
|
|
||||||
|
#### Sequencing
|
||||||
|
|
||||||
|
You may specify a loading order for plugins using the `after` key. This key can be a string or a
|
||||||
|
list (table).
|
||||||
|
|
||||||
|
If `after` is a string, it must be the name of another plugin managed by `packer` (e.g. the final segment of a plugin's path - for a Github plugin `FooBar/Baz`, the name would be just `Baz`). If `after` is a table, it must be a list of plugin names. If a plugin has an alias (i.e. uses the `as` key), this alias is its name.
|
||||||
|
|
||||||
|
The set of plugins specified in a plugin's `after` key must **all** be loaded before the plugin
|
||||||
|
using `after` will be loaded. For example, in the specification
|
||||||
|
```lua
|
||||||
|
use {'FooBar/Baz', ft = 'bax'}
|
||||||
|
use {'Something/Else', after = 'Baz'}
|
||||||
|
```
|
||||||
|
the plugin `Else` will only be loaded after the plugin `Baz`, which itself is only loaded for files
|
||||||
|
with `bax` filetype.
|
||||||
|
|
||||||
|
#### Keybindings
|
||||||
|
|
||||||
|
Plugins may be lazy-loaded on the use of keybindings/maps. Individual keybindings are specified either as a string (in which case they are treated as normal mode maps) or a table in the format `{mode, map}`.
|
||||||
|
|
||||||
|
### Performing plugin management operations
|
||||||
|
`packer` exposes the following functions for common plugin management operations. In all of the
|
||||||
|
below, `plugins` is an optional table of plugin names; if not provided, the default is "all managed
|
||||||
|
plugins":
|
||||||
|
|
||||||
|
- `packer.install(plugins)`: Install the specified plugins if they are not already installed
|
||||||
|
- `packer.update(plugins)`: Update the specified plugins, installing any that are missing
|
||||||
|
- `packer.update(opts, plugins)`: First argument can be a table specifying options, such as `{preview_updates = true}` to preview potential changes before updating (same as `PackerUpdate --preview`).
|
||||||
|
- `packer.clean()`: Remove any disabled or no longer managed plugins
|
||||||
|
- `packer.sync(plugins)`: Perform a `clean` followed by an `update`.
|
||||||
|
- `packer.sync(opts, plugins)`: Can take same optional options as `update`.
|
||||||
|
- `packer.compile(path)`: Compile lazy-loader code and save to `path`.
|
||||||
|
- `packer.snapshot(snapshot_name, ...)`: Creates a snapshot file that will live under `config.snapshot_path/<snapshot_name>`. If `snapshot_name` is an absolute path, then that will be the location where the snapshot will be taken. Optionally, a list of plugins name can be provided to selectively choose the plugins to snapshot.
|
||||||
|
- `packer.rollback(snapshot_name, ...)`: Rollback plugins status a snapshot file that will live under `config.snapshot_path/<snapshot_name>`. If `snapshot_name` is an absolute path, then that will be the location where the snapshot will be taken. Optionally, a list of plugins name can be provided to selectively choose which plugins to revert.
|
||||||
|
- `packer.delete(snapshot_name)`: Deletes a snapshot file under `config.snapshot_path/<snapshot_name>`. If `snapshot_name` is an absolute path, then that will be the location where the snapshot will be deleted.
|
||||||
|
|
||||||
|
### Extending `packer`
|
||||||
|
You can add custom key handlers to `packer` by calling `packer.set_handler(name, func)` where `name`
|
||||||
|
is the key you wish to handle and `func` is a function with the signature `func(plugins, plugin,
|
||||||
|
value)` where `plugins` is the global table of managed plugins, `plugin` is the table for a specific
|
||||||
|
plugin, and `value` is the value associated with key `name` in `plugin`.
|
||||||
|
|
||||||
|
### Compiling Lazy-Loaders
|
||||||
|
To optimize startup time, `packer.nvim` compiles code to perform the lazy-loading operations you
|
||||||
|
specify. This means that you do not need to load `packer.nvim` unless you want to perform some
|
||||||
|
plugin management operations.
|
||||||
|
|
||||||
|
To generate the compiled code, call `packer.compile(path)`, where `path` is some file path on your
|
||||||
|
`runtimepath`, with a `.vim` extension. This will generate a blend of Lua and Vimscript to load and
|
||||||
|
configure all your lazy-loaded plugins (e.g. generating commands, autocommands, etc.) and save it to
|
||||||
|
`path`. Then, when you start vim, the file at `path` is loaded (because `path` must be on your
|
||||||
|
`runtimepath`), and lazy-loading works.
|
||||||
|
|
||||||
|
If `path` is not provided to `packer.compile`, the output file will default to the value of
|
||||||
|
`config.compile_path`.
|
||||||
|
|
||||||
|
The option `compile_on_sync`, which defaults to `true`, will run `packer.compile()` during
|
||||||
|
`packer.sync()`, if set to `true`. Note that otherwise, you **must** run `packer.compile` yourself
|
||||||
|
to generate the lazy-loader file!
|
||||||
|
|
||||||
|
**NOTE:** If you use a function value for `config` or `setup` keys in any plugin specifications, it
|
||||||
|
**must not** have any upvalues (i.e. captures). We currently use Lua's `string.dump` to compile
|
||||||
|
config/setup functions to bytecode, which has this limitation.
|
||||||
|
Additionally, if functions are given for these keys, the functions will be passed the plugin
|
||||||
|
name and information table as arguments.
|
||||||
|
|
||||||
|
### User autocommands
|
||||||
|
`packer` runs most of its operations asyncronously. If you would like to implement automations that
|
||||||
|
require knowing when the operations are complete, you can use the following `User` autocmds (see
|
||||||
|
`:help User` for more info on how to use):
|
||||||
|
|
||||||
|
- `PackerComplete`: Fires after install, update, clean, and sync asynchronous operations finish.
|
||||||
|
- `PackerCompileDone`: Fires after compiling (see [the section on compilation](#compiling-lazy-loaders))
|
||||||
|
|
||||||
|
### Using a floating window
|
||||||
|
You can configure Packer to use a floating window for command outputs by passing a utility
|
||||||
|
function to `packer`'s config:
|
||||||
|
```lua
|
||||||
|
packer.startup({function()
|
||||||
|
-- Your plugins here
|
||||||
|
end,
|
||||||
|
config = {
|
||||||
|
display = {
|
||||||
|
open_fn = require('packer.util').float,
|
||||||
|
}
|
||||||
|
}})
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, this floating window will show doubled borders. If you want to customize the window
|
||||||
|
appearance, you can pass a configuration to `float`, which is the same configuration that would be
|
||||||
|
passed to `nvim_open_win`:
|
||||||
|
```lua
|
||||||
|
packer.startup({function()
|
||||||
|
-- Your plugins here
|
||||||
|
end,
|
||||||
|
config = {
|
||||||
|
display = {
|
||||||
|
open_fn = function()
|
||||||
|
return require('packer.util').float({ border = 'single' })
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}})
|
||||||
|
```
|
||||||
|
|
||||||
|
## Profiling
|
||||||
|
Packer has built in functionality that can allow you to profile the time taken loading your plugins.
|
||||||
|
In order to use this functionality you must either enable profiling in your config, or pass in an argument
|
||||||
|
when running packer compile.
|
||||||
|
|
||||||
|
#### Setup via config
|
||||||
|
```lua
|
||||||
|
config = {
|
||||||
|
profile = {
|
||||||
|
enable = true,
|
||||||
|
threshold = 1 -- the amount in ms that a plugin's load time must be over for it to be included in the profile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Using the packer compile command
|
||||||
|
```vim
|
||||||
|
:PackerCompile profile=true
|
||||||
|
" or
|
||||||
|
:PackerCompile profile=false
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Profiling usage
|
||||||
|
This will rebuild your `packer_compiled.vim` with profiling code included. In order to visualise the output of the profile
|
||||||
|
restart your neovim and run `PackerProfile`. This will open a window with the output of your profiling.
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
`packer.nvim` logs to `stdpath(cache)/packer.nvim.log`. Looking at this file is usually a good start
|
||||||
|
if something isn't working as expected.
|
||||||
|
|
||||||
|
## Compatibility and known issues
|
||||||
|
|
||||||
|
- **2021-07-31:** If you're on macOS, note that building Neovim with the version of `luv` from `homebrew` [will cause any `packer` command to crash](https://github.com/wbthomason/packer.nvim/issues/496#issuecomment-890371022). More about this issue at [neovim/neovim#15054](https://github.com/neovim/neovim/issues/15054).
|
||||||
|
- **2021-07-28:** `packer` will now highlight commits/plugin names with potentially breaking changes
|
||||||
|
(determined by looking for `breaking change` or `breaking_change`, case insensitive, in the update
|
||||||
|
commit bodies and headers) as `WarningMsg` in the status window.
|
||||||
|
- **2021-06-06**: Your Neovim must include https://github.com/neovim/neovim/pull/14659; `packer` uses the `noautocmd` key.
|
||||||
|
- **2021-04-19**: `packer` now provides built-in profiling for your config via the `packer_compiled`
|
||||||
|
file. Take a look at [the docs](#profiling) for more information!
|
||||||
|
- **2021-02-18**: Having trouble with Luarocks on macOS? See [this issue](https://github.com/wbthomason/packer.nvim/issues/180).
|
||||||
|
- **2021-01-19**: Basic Luarocks support has landed! Use the `rocks` key with a string or table to specify packages to install.
|
||||||
|
- **2020-12-10**: The `disable_commands` configuration flag now affects non-`startup` use as well. This means that, by default, `packer` will create commands for basic operations for you.
|
||||||
|
- **2020-11-13**: There is now a default implementation for a floating window `open_fn` in `packer.util`.
|
||||||
|
- **2020-09-04:** Due to changes to the Neovim `extmark` api (see: https://github.com/neovim/neovim/commit/3853276d9cacc99a2698117e904475dbf7033383), users will need to update to a version of Neovim **after** the aforementioned PR was merged. There are currently shims around the changed functions which should maintain support for earlier versions of Neovim, but these are intended to be temporary and will be removed by **2020-10-04**. Therefore Packer will not work with Neovim v0.4.4, which was released before the `extmark` change.
|
||||||
|
|
||||||
|
## Contributors
|
||||||
|
Many thanks to those who have contributed to the project! PRs and issues are always welcome. This
|
||||||
|
list is infrequently updated; please feel free to bug me if you're not listed here and you would
|
||||||
|
like to be.
|
||||||
|
|
||||||
|
- [@akinsho](https://github.com/akinsho)
|
||||||
|
- [@nanotee](https://github.com/nanotee)
|
||||||
|
- [@weilbith](https://github.com/weilbith)
|
||||||
|
- [@Iron-E](https://github.com/Iron-E)
|
||||||
|
- [@tjdevries](https://github.com/tjdevries)
|
||||||
|
- [@numToStr](https://github.com/numToStr)
|
||||||
|
- [@fsouza](https://github.com/fsouza)
|
||||||
|
- [@gbrlsnchs](https://github.com/gbrlsnchs)
|
||||||
|
- [@lewis6991](https://github.com/lewis6991)
|
||||||
|
- [@TimUntersberger](https://github.com/TimUntersberger)
|
||||||
|
- [@bfredl](https://github.com/bfredl)
|
||||||
|
- [@sunjon](https://github.com/sunjon)
|
||||||
|
- [@gwerbin](https://github.com/gwerbin)
|
||||||
|
- [@shadmansaleh](https://github.com/shadmansaleh)
|
||||||
|
- [@ur4ltz](https://github.com/ur4ltz)
|
||||||
|
- [@EdenEast](https://github.com/EdenEast)
|
||||||
|
- [@khuedoan](https://github.com/khuedoan)
|
||||||
|
- [@kevinhwang91](https://github.com/kevinhwang91)
|
||||||
|
- [@runiq](https://github.com/runiq)
|
||||||
|
- [@n3wborn](https://github.com/n3wborn)
|
||||||
|
- [@deathlyfrantic](https://github.com/deathlyfrantic)
|
||||||
|
- [@doctoromer](https://github.com/doctoromer)
|
||||||
|
- [@elianiva](https://github.com/elianiva)
|
||||||
|
- [@dundargoc](https://github.com/dundargoc)
|
||||||
|
- [@jdelkins](https://github.com/jdelkins)
|
||||||
|
- [@dsully](https://github.com/dsully)
|
|
@ -0,0 +1,618 @@
|
||||||
|
*packer.txt* A use-package inspired Neovim plugin manager
|
||||||
|
*packer.nvim*
|
||||||
|
|
||||||
|
Author: Wil Thomason <wil.thomason@gmail.com>
|
||||||
|
|
||||||
|
CONTENTS *packer-contents*
|
||||||
|
Introduction |packer-introduction|
|
||||||
|
Features |packer-intro-features|
|
||||||
|
Requirements |packer-intro-requirements|
|
||||||
|
Quickstart |packer-intro-quickstart|
|
||||||
|
Usage |packer-usage|
|
||||||
|
API |packer-api|
|
||||||
|
==============================================================================
|
||||||
|
INTRODUCTION *packer-introduction*
|
||||||
|
|
||||||
|
This is a Neovim plugin manager. It is written in Lua, uses the native
|
||||||
|
|packages| feature, and has features for declarative plugin configuration
|
||||||
|
inspired by the `use-package` library from Emacs.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
REQUIREMENTS *packer-intro-requirements*
|
||||||
|
|
||||||
|
- You need to be running Neovim v0.5.0+; `packer` makes use of extmarks and
|
||||||
|
other newly-added Neovim features.
|
||||||
|
- Your version of Neovim must be compiled with LuaJIT support; `packer` relies
|
||||||
|
on this to detect whether you are running Windows or a Unix-like OS (for path
|
||||||
|
separators)
|
||||||
|
- If you are on Windows 10, you need developer mode enabled in order to use
|
||||||
|
local plugins (creating symbolic links requires admin privileges on Windows
|
||||||
|
- credit to @TimUntersberger for this note)
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
FEATURES *packer-intro-features*
|
||||||
|
|
||||||
|
- Declarative plugin specification
|
||||||
|
- Support for dependencies
|
||||||
|
- Support for Luarocks dependencies
|
||||||
|
- Expressive configuration and lazy-loading options
|
||||||
|
- Automatically compiles efficient lazy-loading code to improve startup time
|
||||||
|
- Uses native packages
|
||||||
|
- Extensible
|
||||||
|
- Written in Lua, configured in Lua
|
||||||
|
- Post-install/update hooks
|
||||||
|
- Uses jobs for async installation
|
||||||
|
- Support for `git` tags, branches, revisions, submodules
|
||||||
|
- Support for local plugins
|
||||||
|
- Support for saving/restoring snapshots for plugin versions (`git` only)
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
QUICKSTART *packer-intro-quickstart*
|
||||||
|
|
||||||
|
To get started, first clone this repository to somewhere on your `packpath`, e.g.: >sh
|
||||||
|
git clone https://github.com/wbthomason/packer.nvim\
|
||||||
|
~/.local/share/nvim/site/pack/packer/opt/packer.nvim
|
||||||
|
|
||||||
|
|
||||||
|
Then you can write your plugin specification in Lua, e.g. (in `~/.config/nvim/lua/plugins.lua`): >lua
|
||||||
|
|
||||||
|
-- This file can be loaded by calling `lua require('plugins')` from your init.vim
|
||||||
|
|
||||||
|
-- Only required if you have packer in your `opt` pack
|
||||||
|
vim.cmd [[packadd packer.nvim]]
|
||||||
|
-- Only if your version of Neovim doesn't have https://github.com/neovim/neovim/pull/12632 merged
|
||||||
|
vim._update_package_paths()
|
||||||
|
|
||||||
|
return require('packer').startup(function()
|
||||||
|
-- Packer can manage itself as an optional plugin
|
||||||
|
use {'wbthomason/packer.nvim', opt = true}
|
||||||
|
|
||||||
|
-- Simple plugins can be specified as strings
|
||||||
|
use '9mm/vim-closer'
|
||||||
|
|
||||||
|
-- Lazy loading:
|
||||||
|
-- Load on specific commands
|
||||||
|
use {'tpope/vim-dispatch', opt = true, cmd = {'Dispatch', 'Make', 'Focus', 'Start'}}
|
||||||
|
|
||||||
|
-- Load on an autocommand event
|
||||||
|
use {'andymass/vim-matchup', event = 'VimEnter *'}
|
||||||
|
|
||||||
|
-- Load on a combination of conditions: specific filetypes or commands
|
||||||
|
-- Also run code after load (see the "config" key)
|
||||||
|
use {
|
||||||
|
'w0rp/ale',
|
||||||
|
ft = {'sh', 'zsh', 'bash', 'c', 'cpp', 'cmake', 'html', 'markdown', 'racket', 'vim', 'tex'},
|
||||||
|
cmd = 'ALEEnable',
|
||||||
|
config = 'vim.cmd[[ALEEnable]]'
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Plugins can have dependencies on other plugins
|
||||||
|
use {
|
||||||
|
'haorenW1025/completion-nvim',
|
||||||
|
opt = true,
|
||||||
|
requires = {{'hrsh7th/vim-vsnip', opt = true}, {'hrsh7th/vim-vsnip-integ', opt = true}}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Local plugins can be included
|
||||||
|
use '~/projects/personal/hover.nvim'
|
||||||
|
|
||||||
|
-- Plugins can have post-install/update hooks
|
||||||
|
use {'iamcco/markdown-preview.nvim', run = 'cd app && yarn install', cmd = 'MarkdownPreview'}
|
||||||
|
|
||||||
|
-- You can specify multiple plugins in a single call
|
||||||
|
use {'tjdevries/colorbuddy.vim', {'nvim-treesitter/nvim-treesitter', opt = true}}
|
||||||
|
|
||||||
|
-- You can alias plugin names
|
||||||
|
use {'dracula/vim', as = 'dracula'}
|
||||||
|
end)
|
||||||
|
|
||||||
|
`packer` provides the following commands after you've run and configured `packer` with `require('packer').startup(...)`: *packer-default-commands* *packer-commands*
|
||||||
|
|
||||||
|
`PackerClean` *packer-commands-clean*
|
||||||
|
Remove any disabled or unused plugins.
|
||||||
|
|
||||||
|
`PackerCompile` *packer-commands-compile*
|
||||||
|
You must run this or `PackerSync` whenever you make changes to your plugin
|
||||||
|
configuration. Regenerate compiled loader file.
|
||||||
|
|
||||||
|
`PackerInstall` *packer-commands-install*
|
||||||
|
Clean, then install missing plugins.
|
||||||
|
|
||||||
|
`PackerUpdate` *packer-commands-update*
|
||||||
|
Clean, then update and install plugins.
|
||||||
|
Supports the `--preview` flag as an optional first argument to preview
|
||||||
|
updates.
|
||||||
|
|
||||||
|
`PackerSync` *packer-commands-sync*
|
||||||
|
Perform `PackerUpdate` and then `PackerCompile`.
|
||||||
|
Supports the `--preview` flag as an optional first argument to preview
|
||||||
|
updates.
|
||||||
|
|
||||||
|
`PackerLoad` *packer-commands-load*
|
||||||
|
Loads opt plugin immediately
|
||||||
|
|
||||||
|
`PackerSnapshot` *packer-commands-snapshot*
|
||||||
|
Snapshots your plugins to a file
|
||||||
|
|
||||||
|
`PackerSnapshotDelete` *packer-commands-delete*
|
||||||
|
Deletes a snapshot
|
||||||
|
|
||||||
|
`PackerSnapshotRollback` *packer-commands-rollback*
|
||||||
|
Rolls back plugins' commit specified by the snapshot
|
||||||
|
==============================================================================
|
||||||
|
USAGE *packer-usage*
|
||||||
|
|
||||||
|
Although the example in |packer-intro-quickstart| will be enough to get you
|
||||||
|
going for basic usage, `packer` has a number of other features and options
|
||||||
|
detailed in this section.
|
||||||
|
|
||||||
|
STARTUP *packer-startup*
|
||||||
|
|
||||||
|
The easiest way to use `packer` is via the |packer.startup()| function. In
|
||||||
|
short, `startup` is a convenience function for simple setup, and is invoked as
|
||||||
|
`packer.startup(spec)`, where:
|
||||||
|
|
||||||
|
- `spec` can be a function: >lua
|
||||||
|
packer.startup(function() use 'tjdevries/colorbuddy.vim' end)
|
||||||
|
- `spec` can be a table with a function as its first element and config
|
||||||
|
overrides as another element: >lua
|
||||||
|
packer.startup({
|
||||||
|
function() use 'tjdevries/colorbuddy.vim' end, config = { ... }
|
||||||
|
})
|
||||||
|
- `spec` can be a table with a table of plugin specifications as its first
|
||||||
|
element, config overrides as another element, and optional rock
|
||||||
|
specifications as another element: >lua
|
||||||
|
packer.startup({{'tjdevries/colorbuddy.vim'}, config = { ... }, rocks = { ... }})
|
||||||
|
|
||||||
|
See |packer-configuration| for the allowed configuration keys.
|
||||||
|
|
||||||
|
`startup` will handle calling |packer.init()| and |packer.reset()| for you, as
|
||||||
|
well as creating the commands given in |packer-commands|.
|
||||||
|
|
||||||
|
CUSTOM INITIALIZATION *packer-custom-initialization*
|
||||||
|
If you prefer a more manual setup with finer control over configuration and
|
||||||
|
loading, you may use custom initialization for `packer`. This approach has the
|
||||||
|
benefit of not requiring that the `packer` plugin be loaded unless you want to
|
||||||
|
perform plugin management operations, but it is more involved to use.
|
||||||
|
|
||||||
|
To take this approach, load `packer` like any other Lua module. You must call
|
||||||
|
|packer.init()| before performing any operations; it is recommended to call
|
||||||
|
|packer.reset()| if you may be re-running your specification code (e.g. by
|
||||||
|
sourcing your plugin specification file with `luafile`).
|
||||||
|
|
||||||
|
See |packer.init()| for more details on initialization; in short, `init` takes
|
||||||
|
a table of configuration values like that which can be passed to `startup`.
|
||||||
|
|
||||||
|
If you use custom initialization, you'll probably want to define commands to
|
||||||
|
load `packer` and perform common package management operations. The following
|
||||||
|
commands work well for this purpose: >vim
|
||||||
|
|
||||||
|
command! -nargs=* -complete=customlist,v:lua.require'packer'.plugin_complete PackerInstall lua require('packer').install(<f-args>)
|
||||||
|
command! -nargs=* -complete=customlist,v:lua.require'packer'.plugin_complete PackerUpdate lua require('packer').update(<f-args>)
|
||||||
|
command! -nargs=* -complete=customlist,v:lua.require'packer'.plugin_complete PackerSync lua require('packer').sync(<f-args>)
|
||||||
|
command! PackerClean packadd packer.nvim | lua require('plugins').clean()
|
||||||
|
command! PackerCompile packadd packer.nvim | lua require('plugins').compile('~/.config/nvim/plugin/packer_load.vim')
|
||||||
|
command! -bang -nargs=+ -complete=customlist,v:lua.require'packer'.loader_complete PackerLoad lua require('packer').loader(<f-args>, '<bang>')
|
||||||
|
|
||||||
|
CONFIGURATION *packer-configuration*
|
||||||
|
`packer` provides the following configuration variables, presented in the
|
||||||
|
structure of the `config` table expected by `startup` or `init`, with their
|
||||||
|
default values: >lua
|
||||||
|
{
|
||||||
|
ensure_dependencies = true, -- Should packer install plugin dependencies?
|
||||||
|
package_root = util.join_paths(vim.fn.stdpath('data'), 'site', 'pack'),
|
||||||
|
compile_path = util.join_paths(vim.fn.stdpath('config'), 'plugin', 'packer_compiled.lua'),
|
||||||
|
plugin_package = 'packer', -- The default package for plugins
|
||||||
|
max_jobs = nil, -- Limit the number of simultaneous jobs. nil means no limit
|
||||||
|
auto_clean = true, -- During sync(), remove unused plugins
|
||||||
|
compile_on_sync = true, -- During sync(), run packer.compile()
|
||||||
|
disable_commands = false, -- Disable creating commands
|
||||||
|
opt_default = false, -- Default to using opt (as opposed to start) plugins
|
||||||
|
transitive_opt = true, -- Make dependencies of opt plugins also opt by default
|
||||||
|
transitive_disable = true, -- Automatically disable dependencies of disabled plugins
|
||||||
|
auto_reload_compiled = true, -- Automatically reload the compiled file after creating it.
|
||||||
|
preview_updates = false, -- If true, always preview updates before choosing which plugins to update, same as `PackerUpdate --preview`.
|
||||||
|
git = {
|
||||||
|
cmd = 'git', -- The base command for git operations
|
||||||
|
subcommands = { -- Format strings for git subcommands
|
||||||
|
update = 'pull --ff-only --progress --rebase=false',
|
||||||
|
install = 'clone --depth %i --no-single-branch --progress',
|
||||||
|
fetch = 'fetch --depth 999999 --progress',
|
||||||
|
checkout = 'checkout %s --',
|
||||||
|
update_branch = 'merge --ff-only @{u}',
|
||||||
|
current_branch = 'branch --show-current',
|
||||||
|
diff = 'log --color=never --pretty=format:FMT --no-show-signature HEAD@{1}...HEAD',
|
||||||
|
diff_fmt = '%%h %%s (%%cr)',
|
||||||
|
get_rev = 'rev-parse --short HEAD',
|
||||||
|
get_msg = 'log --color=never --pretty=format:FMT --no-show-signature HEAD -n 1',
|
||||||
|
submodules = 'submodule update --init --recursive --progress'
|
||||||
|
},
|
||||||
|
depth = 1, -- Git clone depth
|
||||||
|
clone_timeout = 60, -- Timeout, in seconds, for git clones
|
||||||
|
default_url_format = 'https://github.com/%s' -- Lua format string used for "aaa/bbb" style plugins
|
||||||
|
},
|
||||||
|
log = { level = 'warn' }, -- The default print log level. One of: "trace", "debug", "info", "warn", "error", "fatal".
|
||||||
|
display = {
|
||||||
|
non_interactive = false, -- If true, disable display windows for all operations
|
||||||
|
compact = false, -- If true, fold updates results by default
|
||||||
|
open_fn = nil, -- An optional function to open a window for packer's display
|
||||||
|
open_cmd = '65vnew \\[packer\\]', -- An optional command to open a window for packer's display
|
||||||
|
working_sym = '⟳', -- The symbol for a plugin being installed/updated
|
||||||
|
error_sym = '✗', -- The symbol for a plugin with an error in installation/updating
|
||||||
|
done_sym = '✓', -- The symbol for a plugin which has completed installation/updating
|
||||||
|
removed_sym = '-', -- The symbol for an unused plugin which was removed
|
||||||
|
moved_sym = '→', -- The symbol for a plugin which was moved (e.g. from opt to start)
|
||||||
|
header_sym = '━', -- The symbol for the header line in packer's display
|
||||||
|
show_all_info = true, -- Should packer show all update details automatically?
|
||||||
|
prompt_border = 'double', -- Border style of prompt popups.
|
||||||
|
keybindings = { -- Keybindings for the display window
|
||||||
|
quit = 'q',
|
||||||
|
toggle_update = 'u', -- only in preview
|
||||||
|
continue = 'c', -- only in preview
|
||||||
|
toggle_info = '<CR>',
|
||||||
|
diff = 'd',
|
||||||
|
prompt_revert = 'r',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
autoremove = false, -- Remove disabled or unused plugins without prompting the user
|
||||||
|
}
|
||||||
|
|
||||||
|
SPECIFYING PLUGINS *packer-specifying-plugins*
|
||||||
|
`packer` is based around declarative specification of plugins. You can declare
|
||||||
|
a plugin using the function |packer.use()|, which I highly recommend locally
|
||||||
|
binding to `use` for conciseness.
|
||||||
|
|
||||||
|
`use` takes either a string or a table. If a string is provided, it is treated
|
||||||
|
as a plugin location for a non-optional plugin with no additional
|
||||||
|
configuration. Plugin locations may be specified as:
|
||||||
|
1. Absolute paths to a local plugin
|
||||||
|
2. Full URLs (treated as plugins managed with `git`)
|
||||||
|
3. `username/repo` paths (treated as Github `git` plugins)
|
||||||
|
|
||||||
|
A table given to `use` can take two forms:
|
||||||
|
1. A list of plugin specifications (strings or tables)
|
||||||
|
2. A table specifying a single plugin. It must have a plugin location string
|
||||||
|
as its first element, and may additionally have a number of optional keyword
|
||||||
|
elements, detailed in |packer.use()|
|
||||||
|
|
||||||
|
CONFIGURING PLUGINS *packer-plugin-configuration*
|
||||||
|
`packer` allows you to configure plugins either before they are loaded (the
|
||||||
|
`setup` key described in |packer.use()|) or after they are loaded (the
|
||||||
|
`config` key described in |packer.use()|).
|
||||||
|
If functions are given for these keys, the functions will be passed the plugin
|
||||||
|
name and information table as arguments.
|
||||||
|
|
||||||
|
PLUGIN STATUSES *packer-plugin-status*
|
||||||
|
You can check whether or not a particular plugin is installed with `packer` as
|
||||||
|
well as if that plugin is loaded. To do this you can check for the plugin's
|
||||||
|
name in the `packer_plugins` global table. Plugins in this table are saved
|
||||||
|
using only the last section of their names e.g. `tpope/vim-fugitive` if
|
||||||
|
installed will be under the key `vim-fugitive`.
|
||||||
|
>lua
|
||||||
|
if packer_plugins["vim-fugitive"] and packer_plugins["vim-fugitive"].loaded then
|
||||||
|
print("Vim fugitive is loaded")
|
||||||
|
-- other custom logic
|
||||||
|
end
|
||||||
|
|
||||||
|
CUSTOM INSTALLERS *packer-custom-installers*
|
||||||
|
You may specify a custom installer & updater for a plugin using the
|
||||||
|
`installer` and `updater` keys in a plugin specification. Note that either
|
||||||
|
both or none of these keys are required. These keys should be functions which
|
||||||
|
take as an argument a `display` object (from `lua/packer/display.lua`) and
|
||||||
|
return an async function (per `lua/packer/async.lua`) which (respectively)
|
||||||
|
installs/updates the given plugin.
|
||||||
|
|
||||||
|
Providing the `installer`/`updater` keys overrides plugin type detection, but
|
||||||
|
you still need to provide a location string for the name of the plugin.
|
||||||
|
|
||||||
|
POST-UPDATE HOOKS *packer-plugin-hooks*
|
||||||
|
You may specify operations to be run after successful installs/updates of a
|
||||||
|
plugin with the `run` key. This key may either be a Lua function, which will be
|
||||||
|
called with the `plugin` table for this plugin (containing the information
|
||||||
|
passed to `use` as well as output from the installation/update commands, the
|
||||||
|
installation path of the plugin, etc.), a string, or a table of functions and
|
||||||
|
strings.
|
||||||
|
|
||||||
|
If an element of `run` is a string, then either:
|
||||||
|
|
||||||
|
1. If the first character of `run` is ":", it is treated as a Neovim command and
|
||||||
|
executed.
|
||||||
|
2. Otherwise, `run` is treated as a shell command and run in the installation
|
||||||
|
directory of the plugin via `$SHELL -c '<run>'`.
|
||||||
|
|
||||||
|
DEPENDENCIES *packer-plugin-dependencies*
|
||||||
|
Plugins may specify dependencies via the `requires` key in their specification
|
||||||
|
table. This key can be a string or a list (table).
|
||||||
|
|
||||||
|
If `requires` is a string, it is treated as specifying a single plugin. If a
|
||||||
|
plugin with the name given in `requires` is already known in the managed set,
|
||||||
|
nothing happens. Otherwise, the string is treated as a plugin location string
|
||||||
|
and the corresponding plugin is added to the managed set.
|
||||||
|
|
||||||
|
If `requires` is a list, it is treated as a list of plugin specifications
|
||||||
|
following the format given above.
|
||||||
|
|
||||||
|
If `ensure_dependencies` is true, the plugins specified in `requires` will be
|
||||||
|
installed.
|
||||||
|
|
||||||
|
Plugins specified in `requires` are removed when no active plugins require
|
||||||
|
them.
|
||||||
|
|
||||||
|
LUAROCKS *packer-plugin-luarocks*
|
||||||
|
|
||||||
|
You may specify that a plugin requires one or more Luarocks packages using the
|
||||||
|
`rocks` key. This key takes either a string specifying the name of a package
|
||||||
|
(e.g. `rocks=lpeg`), or a list specifying one or more packages. Entries in the
|
||||||
|
list may either be strings or lists --- the latter case is used to specify a
|
||||||
|
particular version of a package, e.g. `rocks = {'lpeg', {'lua-cjson',
|
||||||
|
'2.1.0'}}`.
|
||||||
|
|
||||||
|
Currently, `packer` only supports equality constraints on package versions.
|
||||||
|
|
||||||
|
`packer` also provides the function `packer.luarocks.install_commands()`, which
|
||||||
|
creates the `PackerRocks <cmd> <packages...>` command. `<cmd>` must be one of
|
||||||
|
"install" or "remove"; `<packages...>` is one or more package names (currently,
|
||||||
|
version restrictions are not supported with this command). Running `PackerRocks`
|
||||||
|
will install or remove the given packages. You can use this command even if you
|
||||||
|
don't use `packer` to manage your plugins. However, please note that (1)
|
||||||
|
packages installed through `PackerRocks` **will** be removed by calls to
|
||||||
|
`packer.luarocks.clean()` (unless they are also part of a `packer` plugin
|
||||||
|
specification), and (2) you will need to manually invoke
|
||||||
|
`packer.luarocks.setup_paths` (or otherwise modify your `package.path`) to
|
||||||
|
ensure that Neovim can find the installed packages.
|
||||||
|
|
||||||
|
Finally, `packer` provides the function `packer.use_rocks`, which takes a string
|
||||||
|
or table specifying one or more Luarocks packages as in the `rocks` key. You can
|
||||||
|
use this to ensure that `packer` downloads and manages some rocks which you want
|
||||||
|
to use, but which are not associated with any particular plugin.
|
||||||
|
|
||||||
|
SEQUENCING *packer-plugin-sequencing*
|
||||||
|
|
||||||
|
You may specify a loading order for plugins using the `after` key. This key can
|
||||||
|
be a string or a list (table).
|
||||||
|
|
||||||
|
If `after` is a string, it must be the name of another plugin managed by
|
||||||
|
`packer` (e.g. the final segment of a plugin's path - for a Github plugin
|
||||||
|
`FooBar/Baz`, the name would be just `Baz`). If `after` is a table, it must be a
|
||||||
|
list of plugin names. If a plugin has an alias (i.e. uses the `as` key), this
|
||||||
|
alias is its name.
|
||||||
|
|
||||||
|
The set of plugins specified in a plugin's `after` key must *all* be loaded
|
||||||
|
before the plugin using `after` will be loaded. For example, in the
|
||||||
|
specification >lua
|
||||||
|
use {'FooBar/Baz', ft = 'bax'}
|
||||||
|
use {'Something/Else', after = 'Baz'}
|
||||||
|
|
||||||
|
the plugin `Else` will only be loaded after the plugin `Baz`, which itself is
|
||||||
|
only loaded for files with `bax` filetype.
|
||||||
|
|
||||||
|
KEYBINDINGS *packer-plugin-keybindings*
|
||||||
|
Plugins may be lazy-loaded on the use of keybindings/maps. Individual
|
||||||
|
keybindings are specified under the `keys` key in a plugin specification
|
||||||
|
either as a string (in which case they are treated as normal mode maps) or a
|
||||||
|
table in the format `{mode, map}`.
|
||||||
|
|
||||||
|
LAZY-LOADING *packer-lazy-load*
|
||||||
|
To optimize startup time, `packer.nvim` compiles code to perform the
|
||||||
|
lazy-loading operations you specify. This means that you do not need to load
|
||||||
|
`packer.nvim` unless you want to perform some plugin management operations.
|
||||||
|
|
||||||
|
To generate the compiled code, call `packer.compile(path)`, where `path` is
|
||||||
|
some file path on your `runtimepath`, with a `.vim` extension. This will
|
||||||
|
generate a blend of Lua and Vimscript to load and configure all your
|
||||||
|
lazy-loaded plugins (e.g. generating commands, autocommands, etc.) and save it
|
||||||
|
to `path`. Then, when you start vim, the file at `path` is loaded (because
|
||||||
|
`path` must be on your `runtimepath`), and lazy-loading works.
|
||||||
|
|
||||||
|
If `path` is not provided to |packer.compile()|, the output file will default
|
||||||
|
to the value of `config.compile_path`.
|
||||||
|
|
||||||
|
The option `compile_on_sync`, which defaults to `true`, will run
|
||||||
|
`packer.compile()` during `packer.sync()`, if set to `true`.
|
||||||
|
Note that otherwise, you **must** run `packer.compile` yourself to generate
|
||||||
|
the lazy-loader file!
|
||||||
|
|
||||||
|
USING A FLOATING WINDOW *packer-floating-window*
|
||||||
|
You can configure Packer to use a floating window for command outputs by
|
||||||
|
passing a utility function to `packer`'s config: >lua
|
||||||
|
|
||||||
|
packer.startup({function()
|
||||||
|
-- Your plugins here
|
||||||
|
end,
|
||||||
|
config = {
|
||||||
|
display = {
|
||||||
|
open_fn = require('packer.util').float,
|
||||||
|
}
|
||||||
|
}})
|
||||||
|
<
|
||||||
|
By default, this floating window will show doubled borders. If you want to
|
||||||
|
customize the window appearance, you can pass a configuration to `float`,
|
||||||
|
which is the same configuration that would be passed to |nvim_open_win|: >lua
|
||||||
|
|
||||||
|
packer.startup({function()
|
||||||
|
-- Your plugins here
|
||||||
|
end,
|
||||||
|
config = {
|
||||||
|
display = {
|
||||||
|
open_fn = function()
|
||||||
|
return require('packer.util').float({ border = 'single' })
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}})
|
||||||
|
<
|
||||||
|
PROFILING PLUGINS *packer-profiling*
|
||||||
|
You can measure how long it takes your plugins to load using packer's builtin
|
||||||
|
profiling functionality.
|
||||||
|
In order to use this functionality you must either enable profiling in your config, or pass in an argument
|
||||||
|
when running packer compile.
|
||||||
|
|
||||||
|
Setup via config >lua
|
||||||
|
config = {
|
||||||
|
profile = {
|
||||||
|
enable = true,
|
||||||
|
threshold = 1 -- the amount in ms that a plugin's load time must be over for it to be included in the profile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<
|
||||||
|
|
||||||
|
Using the packer compile command
|
||||||
|
>vim
|
||||||
|
:PackerCompile profile=true
|
||||||
|
" or
|
||||||
|
:PackerCompile profile=false
|
||||||
|
<
|
||||||
|
|
||||||
|
NOTE you can also set a `threshold` in your profile config which is a number
|
||||||
|
in `ms` above which plugin load times will be show e.g. if you set a threshold
|
||||||
|
value of `3` then any plugin that loads slower than `3ms` will not be included in
|
||||||
|
the output window.
|
||||||
|
|
||||||
|
This will rebuild your `packer_compiled.vim` with profiling code included. In order to visualise the output of the profile
|
||||||
|
Restart your neovim and run `PackerProfile`. This will open a window with the output of your profiling.
|
||||||
|
|
||||||
|
EXTENDING PACKER *packer-extending*
|
||||||
|
You can add custom key handlers to `packer` by calling
|
||||||
|
`packer.set_handler(name, func)` where `name` is the key you wish to handle
|
||||||
|
and `func` is a function with the signature `func(plugins, plugin, value)`
|
||||||
|
where `plugins` is the global table of managed plugins, `plugin` is the table
|
||||||
|
for a specific plugin, and `value` is the value associated with key `name` in
|
||||||
|
`plugin`.
|
||||||
|
|
||||||
|
RESULTS WINDOW KEYBINDINGS *packer-results-keybindings*
|
||||||
|
Once an operation completes, the results are shown in the display window.
|
||||||
|
`packer` sets up default keybindings for this window:
|
||||||
|
|
||||||
|
q close the display window
|
||||||
|
<CR> toggle information about a particular plugin
|
||||||
|
r revert an update
|
||||||
|
|
||||||
|
They can be configured by changing the value of `config.display.keybindings`
|
||||||
|
(see |packer-configuration|). Setting it to `false` will disable all keybindings.
|
||||||
|
Setting any of its keys to `false` will disable the corresponding keybinding.
|
||||||
|
|
||||||
|
USER AUTOCMDS *packer-user-autocmds*
|
||||||
|
`packer` runs most of its operations asyncronously. If you would like to
|
||||||
|
implement automations that require knowing when the operations are complete,
|
||||||
|
you can use the following User autocmds (see |User| for more info on how to
|
||||||
|
use):
|
||||||
|
|
||||||
|
`PackerComplete` Fires after install, update, clean, and sync
|
||||||
|
asynchronous operations finish.
|
||||||
|
`PackerCompileDone` Fires after compiling (see |packer-lazy-load|)
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
API *packer-api*
|
||||||
|
|
||||||
|
clean() *packer.clean()*
|
||||||
|
`clean` scans for and removes all disabled or no longer managed plugins. It is
|
||||||
|
invoked without arguments.
|
||||||
|
|
||||||
|
compile() *packer.compile()*
|
||||||
|
`compile` builds lazy-loader code from your plugin specification and saves it
|
||||||
|
to either `config.compile_path` if it is invoked with no argument, or to the
|
||||||
|
path it is invoked with if it is given a single argument. This path should end
|
||||||
|
in `.vim` and be on your |runtimepath| in order for lazy-loading to work. You
|
||||||
|
**must** call `compile` to update lazy-loaders after your configuration
|
||||||
|
changes.
|
||||||
|
|
||||||
|
init() *packer.init()*
|
||||||
|
Initializes `packer`; must be called before any calls to any other `packer`
|
||||||
|
function. Takes an optional table of configuration values as described in
|
||||||
|
|packer-configuration|.
|
||||||
|
|
||||||
|
install() *packer.install()*
|
||||||
|
`install` installs any missing plugins, runs post-update hooks, and updates
|
||||||
|
rplugins (|remote-plugin|) and helptags.
|
||||||
|
|
||||||
|
It can be invoked with no arguments or with a list of plugin names to install.
|
||||||
|
These plugin names must already be managed by `packer` via a call to
|
||||||
|
|packer.use()|.
|
||||||
|
|
||||||
|
reset() *packer.reset()*
|
||||||
|
`reset` empties the set of managed plugins. Called with no arguments; used to
|
||||||
|
ensure plugin specifications are reinitialized if the specification file is
|
||||||
|
reloaded. Called by |packer.startup()| or manually before calling
|
||||||
|
|packer.use()|.
|
||||||
|
|
||||||
|
set_handler() *packer.set_handler()*
|
||||||
|
`set_handler` allows custom extension of `packer`. See |packer-extending| for
|
||||||
|
details.
|
||||||
|
|
||||||
|
startup() *packer.startup()*
|
||||||
|
`startup` is a convenience function for simple setup. See |packer-startup| for
|
||||||
|
details.
|
||||||
|
|
||||||
|
sync() *packer.sync()*
|
||||||
|
`sync` runs |packer.clean()| followed by |packer.update()|.
|
||||||
|
|
||||||
|
Supports options as the first argument, see |packer.update()|.
|
||||||
|
|
||||||
|
update() *packer.update()*
|
||||||
|
`update` installs any missing plugins, updates all installed plugins, runs
|
||||||
|
post-update hooks, and updates rplugins (|remote-plugin|) and helptags.
|
||||||
|
|
||||||
|
It can be invoked with no arguments or with a list of plugin names to update.
|
||||||
|
These plugin names must already be managed by `packer` via a call to
|
||||||
|
|packer.use()|.
|
||||||
|
|
||||||
|
Additionally, the first argument can be a table specifying options,
|
||||||
|
such as `update({preview_updates = true}, ...)` to preview potential changes before updating
|
||||||
|
(same as `PackerUpdate --preview`).
|
||||||
|
|
||||||
|
snapshot(snapshot_name, ...) *packer.snapshot()*
|
||||||
|
`snapshot` takes the rev of all the installed plugins and serializes them into a Lua table which will be saved under `config.snapshot_path` (which is the directory that will hold all the snapshots files) as `config.snapshot_path/<snapshot_name>` or an absolute path provided by the users.
|
||||||
|
Optionally plugins name can be specified so that only those plugins will be
|
||||||
|
snapshotted.
|
||||||
|
Snapshot files can be loaded manually via `dofile` which will return a table with the plugins name as keys the commit short hash as value.
|
||||||
|
|
||||||
|
delete(snapshot_name) *packer.delete()*
|
||||||
|
`delete` deletes a snapshot given the name or the absolute path.
|
||||||
|
|
||||||
|
rollback(snapshot_name, ...) *packer.rollback()*
|
||||||
|
`rollback` reverts all plugins or only the specified as extra arguments to the commit specified in the snapshot file
|
||||||
|
|
||||||
|
use() *packer.use()*
|
||||||
|
`use` allows you to add one or more plugins to the managed set. It can be
|
||||||
|
invoked as follows:
|
||||||
|
- With a single plugin location string, e.g. `use <STRING>`
|
||||||
|
- With a single plugin specification table, e.g. >lua
|
||||||
|
use {
|
||||||
|
'myusername/example', -- The plugin location string
|
||||||
|
-- The following keys are all optional
|
||||||
|
disable = boolean, -- Mark a plugin as inactive
|
||||||
|
as = string, -- Specifies an alias under which to install the plugin
|
||||||
|
installer = function, -- Specifies custom installer. See |packer-custom-installers|
|
||||||
|
updater = function, -- Specifies custom updater. See |packer-custom-installers|
|
||||||
|
after = string or list, -- Specifies plugins to load before this plugin.
|
||||||
|
rtp = string, -- Specifies a subdirectory of the plugin to add to runtimepath.
|
||||||
|
opt = boolean, -- Manually marks a plugin as optional.
|
||||||
|
bufread = boolean, -- Manually specifying if a plugin needs BufRead after being loaded
|
||||||
|
branch = string, -- Specifies a git branch to use
|
||||||
|
tag = string, -- Specifies a git tag to use. Supports '*' for "latest tag"
|
||||||
|
commit = string, -- Specifies a git commit to use
|
||||||
|
lock = boolean, -- Skip updating this plugin in updates/syncs. Still cleans.
|
||||||
|
run = string, function, or table -- Post-update/install hook. See |packer-plugin-hooks|
|
||||||
|
requires = string or list -- Specifies plugin dependencies. See |packer-plugin-dependencies|
|
||||||
|
config = string or function, -- Specifies code to run after this plugin is loaded.
|
||||||
|
rocks = string or list, -- Specifies Luarocks dependencies for the plugin
|
||||||
|
-- The following keys all imply lazy-loading
|
||||||
|
cmd = string or list, -- Specifies commands which load this plugin. Can be an autocmd pattern.
|
||||||
|
ft = string or list, -- Specifies filetypes which load this plugin.
|
||||||
|
keys = string or list, -- Specifies maps which load this plugin. See |packer-plugin-keybindings|
|
||||||
|
event = string or list, -- Specifies autocommand events which load this plugin.
|
||||||
|
fn = string or list -- Specifies functions which load this plugin.
|
||||||
|
cond = string, function, or list of strings/functions, -- Specifies a conditional test to load this plugin
|
||||||
|
setup = string or function, -- Specifies code to run before this plugin is loaded. The code is ran even if
|
||||||
|
-- the plugin is waiting for other conditions (ft, cond...) to be met.
|
||||||
|
module = string or list -- Specifies Lua module names for require. When requiring a string which starts
|
||||||
|
-- with one of these module names, the plugin will be loaded.
|
||||||
|
module_pattern = string/list -- Specifies Lua pattern of Lua module names for require. When requiring a string
|
||||||
|
-- which matches one of these patterns, the plugin will be loaded.
|
||||||
|
}
|
||||||
|
- With a list of plugins specified in either of the above two forms
|
||||||
|
|
||||||
|
For the *cmd* option, the command may be a full command, or an autocommand pattern. If the command contains any
|
||||||
|
non-alphanumeric characters, it is assumed to be a pattern, and instead of creating a stub command, it creates
|
||||||
|
a CmdUndefined autocmd to load the plugin when a command that matches the pattern is invoked.
|
||||||
|
|
||||||
|
vim:tw=78:ts=2:ft=help:norl:
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,132 @@
|
||||||
|
-- Adapted from https://ms-jpq.github.io/neovim-async-tutorial/
|
||||||
|
local log = require 'packer.log'
|
||||||
|
local yield = coroutine.yield
|
||||||
|
local resume = coroutine.resume
|
||||||
|
local thread_create = coroutine.create
|
||||||
|
|
||||||
|
local function EMPTY_CALLBACK() end
|
||||||
|
local function step(func, callback)
|
||||||
|
local thread = thread_create(func)
|
||||||
|
local tick = nil
|
||||||
|
tick = function(...)
|
||||||
|
local ok, val = resume(thread, ...)
|
||||||
|
if ok then
|
||||||
|
if type(val) == 'function' then
|
||||||
|
val(tick)
|
||||||
|
else
|
||||||
|
(callback or EMPTY_CALLBACK)(val)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.error('Error in coroutine: ' .. val);
|
||||||
|
(callback or EMPTY_CALLBACK)(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tick()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function wrap(func)
|
||||||
|
return function(...)
|
||||||
|
local params = { ... }
|
||||||
|
return function(tick)
|
||||||
|
params[#params + 1] = tick
|
||||||
|
return func(unpack(params))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function join(...)
|
||||||
|
local thunks = { ... }
|
||||||
|
local thunk_all = function(s)
|
||||||
|
if #thunks == 0 then
|
||||||
|
return s()
|
||||||
|
end
|
||||||
|
local to_go = #thunks
|
||||||
|
local results = {}
|
||||||
|
for i, thunk in ipairs(thunks) do
|
||||||
|
local callback = function(...)
|
||||||
|
results[i] = { ... }
|
||||||
|
if to_go == 1 then
|
||||||
|
s(unpack(results))
|
||||||
|
else
|
||||||
|
to_go = to_go - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
thunk(callback)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return thunk_all
|
||||||
|
end
|
||||||
|
|
||||||
|
local function wait_all(...)
|
||||||
|
return yield(join(...))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function pool(n, interrupt_check, ...)
|
||||||
|
local thunks = { ... }
|
||||||
|
return function(s)
|
||||||
|
if #thunks == 0 then
|
||||||
|
return s()
|
||||||
|
end
|
||||||
|
local remaining = { select(n + 1, unpack(thunks)) }
|
||||||
|
local results = {}
|
||||||
|
local to_go = #thunks
|
||||||
|
local make_callback = nil
|
||||||
|
make_callback = function(idx, left)
|
||||||
|
local i = (left == nil) and idx or (idx + left)
|
||||||
|
return function(...)
|
||||||
|
results[i] = { ... }
|
||||||
|
to_go = to_go - 1
|
||||||
|
if to_go == 0 then
|
||||||
|
s(unpack(results))
|
||||||
|
elseif not interrupt_check or not interrupt_check() then
|
||||||
|
if remaining and #remaining > 0 then
|
||||||
|
local next_task = table.remove(remaining)
|
||||||
|
next_task(make_callback(n, #remaining + 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, math.min(n, #thunks) do
|
||||||
|
local thunk = thunks[i]
|
||||||
|
thunk(make_callback(i))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function wait_pool(limit, ...)
|
||||||
|
return yield(pool(limit, false, ...))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function interruptible_wait_pool(limit, interrupt_check, ...)
|
||||||
|
return yield(pool(limit, interrupt_check, ...))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function main(f)
|
||||||
|
vim.schedule(f)
|
||||||
|
end
|
||||||
|
|
||||||
|
local M = {
|
||||||
|
--- Wrapper for functions that do not take a callback to make async functions
|
||||||
|
sync = wrap(step),
|
||||||
|
--- Alias for yielding to await the result of an async function
|
||||||
|
wait = yield,
|
||||||
|
--- Await the completion of a full set of async functions
|
||||||
|
wait_all = wait_all,
|
||||||
|
--- Await the completion of a full set of async functions, with a limit on how many functions can
|
||||||
|
-- run simultaneously
|
||||||
|
wait_pool = wait_pool,
|
||||||
|
--- Like wait_pool, but additionally checks at every function completion to see if a condition is
|
||||||
|
-- met indicating that it should keep running the remaining tasks
|
||||||
|
interruptible_wait_pool = interruptible_wait_pool,
|
||||||
|
--- Wrapper for functions that do take a callback to make async functions
|
||||||
|
wrap = wrap,
|
||||||
|
--- Convenience function to ensure a function runs on the main "thread" (i.e. for functions which
|
||||||
|
-- use Neovim functions, etc.)
|
||||||
|
main = main,
|
||||||
|
}
|
||||||
|
|
||||||
|
return M
|
|
@ -0,0 +1,92 @@
|
||||||
|
local plugin_utils = require 'packer.plugin_utils'
|
||||||
|
local a = require 'packer.async'
|
||||||
|
local display = require 'packer.display'
|
||||||
|
local log = require 'packer.log'
|
||||||
|
local util = require 'packer.util'
|
||||||
|
|
||||||
|
local await = a.wait
|
||||||
|
local async = a.sync
|
||||||
|
|
||||||
|
local config
|
||||||
|
|
||||||
|
local PLUGIN_OPTIONAL_LIST = 1
|
||||||
|
local PLUGIN_START_LIST = 2
|
||||||
|
|
||||||
|
local function is_dirty(plugin, typ)
|
||||||
|
return (plugin.opt and typ == PLUGIN_START_LIST) or (not plugin.opt and typ == PLUGIN_OPTIONAL_LIST)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Find and remove any plugins not currently configured for use
|
||||||
|
local clean_plugins = function(_, plugins, fs_state, results)
|
||||||
|
return async(function()
|
||||||
|
log.debug 'Starting clean'
|
||||||
|
local dirty_plugins = {}
|
||||||
|
results = results or {}
|
||||||
|
results.removals = results.removals or {}
|
||||||
|
local opt_plugins = vim.deepcopy(fs_state.opt)
|
||||||
|
local start_plugins = vim.deepcopy(fs_state.start)
|
||||||
|
local missing_plugins = fs_state.missing
|
||||||
|
-- test for dirty / 'missing' plugins
|
||||||
|
for _, plugin_config in pairs(plugins) do
|
||||||
|
local path = plugin_config.install_path
|
||||||
|
local plugin_source = nil
|
||||||
|
if opt_plugins[path] then
|
||||||
|
plugin_source = PLUGIN_OPTIONAL_LIST
|
||||||
|
opt_plugins[path] = nil
|
||||||
|
elseif start_plugins[path] then
|
||||||
|
plugin_source = PLUGIN_START_LIST
|
||||||
|
start_plugins[path] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- We don't want to report paths which don't exist for removal; that will confuse people
|
||||||
|
local path_exists = false
|
||||||
|
if missing_plugins[plugin_config.short_name] or plugin_config.disable then
|
||||||
|
path_exists = vim.loop.fs_stat(path) ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local plugin_missing = path_exists and missing_plugins[plugin_config.short_name]
|
||||||
|
local disabled_but_installed = path_exists and plugin_config.disable
|
||||||
|
if plugin_missing or is_dirty(plugin_config, plugin_source) or disabled_but_installed then
|
||||||
|
dirty_plugins[#dirty_plugins + 1] = path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Any path which was not set to `nil` above will be set to dirty here
|
||||||
|
local function mark_remaining_as_dirty(plugin_list)
|
||||||
|
for path, _ in pairs(plugin_list) do
|
||||||
|
dirty_plugins[#dirty_plugins + 1] = path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mark_remaining_as_dirty(opt_plugins)
|
||||||
|
mark_remaining_as_dirty(start_plugins)
|
||||||
|
if next(dirty_plugins) then
|
||||||
|
local lines = {}
|
||||||
|
for _, path in ipairs(dirty_plugins) do
|
||||||
|
table.insert(lines, ' - ' .. path)
|
||||||
|
end
|
||||||
|
await(a.main)
|
||||||
|
if config.autoremove or await(display.ask_user('Removing the following directories. OK? (y/N)', lines)) then
|
||||||
|
results.removals = dirty_plugins
|
||||||
|
log.debug('Removed ' .. vim.inspect(dirty_plugins))
|
||||||
|
for _, path in ipairs(dirty_plugins) do
|
||||||
|
local result = vim.fn.delete(path, 'rf')
|
||||||
|
if result == -1 then
|
||||||
|
log.warn('Could not remove ' .. path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.warn 'Cleaning cancelled!'
|
||||||
|
end
|
||||||
|
else
|
||||||
|
log.info 'Already clean!'
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function cfg(_config)
|
||||||
|
config = _config
|
||||||
|
end
|
||||||
|
|
||||||
|
local clean = setmetatable({ cfg = cfg }, { __call = clean_plugins })
|
||||||
|
return clean
|
|
@ -0,0 +1,824 @@
|
||||||
|
-- Compiling plugin specifications to Lua for lazy-loading
|
||||||
|
local util = require 'packer.util'
|
||||||
|
local log = require 'packer.log'
|
||||||
|
local fmt = string.format
|
||||||
|
local luarocks = require 'packer.luarocks'
|
||||||
|
|
||||||
|
local config
|
||||||
|
local function cfg(_config)
|
||||||
|
config = _config.profile
|
||||||
|
end
|
||||||
|
|
||||||
|
local feature_guard = [[
|
||||||
|
if !has('nvim-0.5')
|
||||||
|
echohl WarningMsg
|
||||||
|
echom "Invalid Neovim version for packer.nvim!"
|
||||||
|
echohl None
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
packadd packer.nvim
|
||||||
|
|
||||||
|
try
|
||||||
|
]]
|
||||||
|
|
||||||
|
local feature_guard_lua = [[
|
||||||
|
if vim.api.nvim_call_function('has', {'nvim-0.5'}) ~= 1 then
|
||||||
|
vim.api.nvim_command('echohl WarningMsg | echom "Invalid Neovim version for packer.nvim! | echohl None"')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.api.nvim_command('packadd packer.nvim')
|
||||||
|
|
||||||
|
local no_errors, error_msg = pcall(function()
|
||||||
|
]]
|
||||||
|
|
||||||
|
local enter_packer_compile = [[
|
||||||
|
_G._packer = _G._packer or {}
|
||||||
|
_G._packer.inside_compile = true
|
||||||
|
]]
|
||||||
|
|
||||||
|
local exit_packer_compile = [[
|
||||||
|
|
||||||
|
_G._packer.inside_compile = false
|
||||||
|
if _G._packer.needs_bufread == true then
|
||||||
|
vim.cmd("doautocmd BufRead")
|
||||||
|
end
|
||||||
|
_G._packer.needs_bufread = false
|
||||||
|
]]
|
||||||
|
|
||||||
|
local catch_errors = [[
|
||||||
|
catch
|
||||||
|
echohl ErrorMsg
|
||||||
|
echom "Error in packer_compiled: " .. v:exception
|
||||||
|
echom "Please check your config for correctness"
|
||||||
|
echohl None
|
||||||
|
endtry
|
||||||
|
]]
|
||||||
|
|
||||||
|
local catch_errors_lua = [[
|
||||||
|
end)
|
||||||
|
|
||||||
|
if not no_errors then
|
||||||
|
error_msg = error_msg:gsub('"', '\\"')
|
||||||
|
vim.api.nvim_command('echohl ErrorMsg | echom "Error in packer_compiled: '..error_msg..'" | echom "Please check your config for correctness" | echohl None')
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
|
||||||
|
---@param should_profile boolean
|
||||||
|
---@return string
|
||||||
|
local profile_time = function(should_profile)
|
||||||
|
return fmt(
|
||||||
|
[[
|
||||||
|
local time
|
||||||
|
local profile_info
|
||||||
|
local should_profile = %s
|
||||||
|
if should_profile then
|
||||||
|
local hrtime = vim.loop.hrtime
|
||||||
|
profile_info = {}
|
||||||
|
time = function(chunk, start)
|
||||||
|
if start then
|
||||||
|
profile_info[chunk] = hrtime()
|
||||||
|
else
|
||||||
|
profile_info[chunk] = (hrtime() - profile_info[chunk]) / 1e6
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
time = function(chunk, start) end
|
||||||
|
end
|
||||||
|
]],
|
||||||
|
vim.inspect(should_profile)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
local profile_output = [[
|
||||||
|
local function save_profiles(threshold)
|
||||||
|
local sorted_times = {}
|
||||||
|
for chunk_name, time_taken in pairs(profile_info) do
|
||||||
|
sorted_times[#sorted_times + 1] = {chunk_name, time_taken}
|
||||||
|
end
|
||||||
|
table.sort(sorted_times, function(a, b) return a[2] > b[2] end)
|
||||||
|
local results = {}
|
||||||
|
for i, elem in ipairs(sorted_times) do
|
||||||
|
if not threshold or threshold and elem[2] > threshold then
|
||||||
|
results[i] = elem[1] .. ' took ' .. elem[2] .. 'ms'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if threshold then
|
||||||
|
table.insert(results, '(Only showing plugins that took longer than ' .. threshold .. ' ms ' .. 'to load)')
|
||||||
|
end
|
||||||
|
|
||||||
|
_G._packer.profile_output = results
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
|
||||||
|
---@param threshold number
|
||||||
|
---@return string
|
||||||
|
local conditionally_output_profile = function(threshold)
|
||||||
|
if threshold then
|
||||||
|
return fmt(
|
||||||
|
[[
|
||||||
|
if should_profile then save_profiles(%d) end
|
||||||
|
]],
|
||||||
|
threshold
|
||||||
|
)
|
||||||
|
else
|
||||||
|
return [[
|
||||||
|
if should_profile then save_profiles() end
|
||||||
|
]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local try_loadstring = [[
|
||||||
|
local function try_loadstring(s, component, name)
|
||||||
|
local success, result = pcall(loadstring(s), name, _G.packer_plugins[name])
|
||||||
|
if not success then
|
||||||
|
vim.schedule(function()
|
||||||
|
vim.api.nvim_notify('packer.nvim: Error running ' .. component .. ' for ' .. name .. ': ' .. result, vim.log.levels.ERROR, {})
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
|
||||||
|
local module_loader = [[
|
||||||
|
local lazy_load_called = {['packer.load'] = true}
|
||||||
|
local function lazy_load_module(module_name)
|
||||||
|
local to_load = {}
|
||||||
|
if lazy_load_called[module_name] then return nil end
|
||||||
|
lazy_load_called[module_name] = true
|
||||||
|
for module_pat, plugin_name in pairs(module_lazy_loads) do
|
||||||
|
if not _G.packer_plugins[plugin_name].loaded and string.match(module_name, module_pat) then
|
||||||
|
to_load[#to_load + 1] = plugin_name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #to_load > 0 then
|
||||||
|
require('packer.load')(to_load, {module = module_name}, _G.packer_plugins)
|
||||||
|
local loaded_mod = package.loaded[module_name]
|
||||||
|
if loaded_mod then
|
||||||
|
return function(modname) return loaded_mod end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not vim.g.packer_custom_loader_enabled then
|
||||||
|
table.insert(package.loaders, 1, lazy_load_module)
|
||||||
|
vim.g.packer_custom_loader_enabled = true
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
|
||||||
|
local function timed_chunk(chunk, name, output_table)
|
||||||
|
output_table = output_table or {}
|
||||||
|
output_table[#output_table + 1] = 'time([[' .. name .. ']], true)'
|
||||||
|
if type(chunk) == 'string' then
|
||||||
|
output_table[#output_table + 1] = chunk
|
||||||
|
else
|
||||||
|
vim.list_extend(output_table, chunk)
|
||||||
|
end
|
||||||
|
|
||||||
|
output_table[#output_table + 1] = 'time([[' .. name .. ']], false)'
|
||||||
|
return output_table
|
||||||
|
end
|
||||||
|
|
||||||
|
local function dump_loaders(loaders)
|
||||||
|
local result = vim.deepcopy(loaders)
|
||||||
|
for k, _ in pairs(result) do
|
||||||
|
if result[k].only_setup or result[k].only_sequence then
|
||||||
|
result[k].loaded = true
|
||||||
|
end
|
||||||
|
result[k].only_setup = nil
|
||||||
|
result[k].only_sequence = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return vim.inspect(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function make_try_loadstring(item, chunk, name)
|
||||||
|
local bytecode = string.dump(item, true)
|
||||||
|
local executable_string = 'try_loadstring(' .. vim.inspect(bytecode) .. ', "' .. chunk .. '", "' .. name .. '")'
|
||||||
|
return executable_string, bytecode
|
||||||
|
end
|
||||||
|
|
||||||
|
local after_plugin_pattern = table.concat({ 'after', 'plugin', [[**/*.\(vim\|lua\)]] }, util.get_separator())
|
||||||
|
local function detect_after_plugin(name, plugin_path)
|
||||||
|
local path = plugin_path .. util.get_separator() .. after_plugin_pattern
|
||||||
|
local glob_ok, files = pcall(vim.fn.glob, path, false, true)
|
||||||
|
if not glob_ok then
|
||||||
|
if string.find(files, 'E77') then
|
||||||
|
return { path }
|
||||||
|
else
|
||||||
|
log.error('Error compiling ' .. name .. ': ' .. vim.inspect(files))
|
||||||
|
error(files)
|
||||||
|
end
|
||||||
|
elseif #files > 0 then
|
||||||
|
return files
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local ftdetect_patterns = {
|
||||||
|
table.concat({ 'ftdetect', [[**/*.\(vim\|lua\)]] }, util.get_separator()),
|
||||||
|
table.concat({ 'after', 'ftdetect', [[**/*.\(vim\|lua\)]] }, util.get_separator()),
|
||||||
|
}
|
||||||
|
local function detect_ftdetect(name, plugin_path)
|
||||||
|
local paths = {
|
||||||
|
plugin_path .. util.get_separator() .. ftdetect_patterns[1],
|
||||||
|
plugin_path .. util.get_separator() .. ftdetect_patterns[2],
|
||||||
|
}
|
||||||
|
local source_paths = {}
|
||||||
|
for i = 1, 2 do
|
||||||
|
local path = paths[i]
|
||||||
|
local glob_ok, files = pcall(vim.fn.glob, path, false, true)
|
||||||
|
if not glob_ok then
|
||||||
|
if string.find(files, 'E77') then
|
||||||
|
source_paths[#source_paths + 1] = path
|
||||||
|
else
|
||||||
|
log.error('Error compiling ' .. name .. ': ' .. vim.inspect(files))
|
||||||
|
error(files)
|
||||||
|
end
|
||||||
|
elseif #files > 0 then
|
||||||
|
vim.list_extend(source_paths, files)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return source_paths
|
||||||
|
end
|
||||||
|
|
||||||
|
local source_dirs = { 'ftdetect', 'ftplugin', 'after/ftdetect', 'after/ftplugin' }
|
||||||
|
local function detect_bufread(plugin_path)
|
||||||
|
local path = plugin_path
|
||||||
|
for i = 1, 4 do
|
||||||
|
if #vim.fn.finddir(source_dirs[i], path) > 0 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function make_loaders(_, plugins, output_lua, should_profile)
|
||||||
|
local loaders = {}
|
||||||
|
local configs = {}
|
||||||
|
local rtps = {}
|
||||||
|
local setup = {}
|
||||||
|
local fts = {}
|
||||||
|
local events = {}
|
||||||
|
local condition_ids = {}
|
||||||
|
local commands = {}
|
||||||
|
local keymaps = {}
|
||||||
|
local after = {}
|
||||||
|
local fns = {}
|
||||||
|
local ftdetect_paths = {}
|
||||||
|
local module_lazy_loads = {}
|
||||||
|
for name, plugin in pairs(plugins) do
|
||||||
|
if not plugin.disable then
|
||||||
|
plugin.simple_load = true
|
||||||
|
local quote_name = "'" .. name .. "'"
|
||||||
|
if plugin.config and not plugin.executable_config then
|
||||||
|
plugin.simple_load = false
|
||||||
|
plugin.executable_config = {}
|
||||||
|
if type(plugin.config) ~= 'table' then
|
||||||
|
plugin.config = { plugin.config }
|
||||||
|
end
|
||||||
|
for i, config_item in ipairs(plugin.config) do
|
||||||
|
local executable_string = config_item
|
||||||
|
if type(config_item) == 'function' then
|
||||||
|
local bytecode
|
||||||
|
executable_string, bytecode = make_try_loadstring(config_item, 'config', name)
|
||||||
|
plugin.config[i] = bytecode
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(plugin.executable_config, executable_string)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local path = plugin.install_path
|
||||||
|
if plugin.rtp then
|
||||||
|
path = util.join_paths(plugin.install_path, plugin.rtp)
|
||||||
|
table.insert(rtps, path)
|
||||||
|
end
|
||||||
|
|
||||||
|
loaders[name] = {
|
||||||
|
loaded = not plugin.opt,
|
||||||
|
config = plugin.config,
|
||||||
|
path = path,
|
||||||
|
only_sequence = plugin.manual_opt == nil,
|
||||||
|
only_setup = false,
|
||||||
|
}
|
||||||
|
|
||||||
|
if plugin.opt then
|
||||||
|
plugin.simple_load = false
|
||||||
|
loaders[name].after_files = detect_after_plugin(name, loaders[name].path)
|
||||||
|
if plugin.bufread ~= nil then
|
||||||
|
loaders[name].needs_bufread = plugin.bufread
|
||||||
|
else
|
||||||
|
loaders[name].needs_bufread = detect_bufread(loaders[name].path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.setup then
|
||||||
|
plugin.simple_load = false
|
||||||
|
if type(plugin.setup) ~= 'table' then
|
||||||
|
plugin.setup = { plugin.setup }
|
||||||
|
end
|
||||||
|
for i, setup_item in ipairs(plugin.setup) do
|
||||||
|
if type(setup_item) == 'function' then
|
||||||
|
plugin.setup[i], _ = make_try_loadstring(setup_item, 'setup', name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
loaders[name].only_setup = plugin.manual_opt == nil
|
||||||
|
setup[name] = plugin.setup
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Keep this as first opt loader to maintain only_cond ?
|
||||||
|
if plugin.cond ~= nil then
|
||||||
|
plugin.simple_load = false
|
||||||
|
loaders[name].only_sequence = false
|
||||||
|
loaders[name].only_setup = false
|
||||||
|
loaders[name].only_cond = true
|
||||||
|
if type(plugin.cond) ~= 'table' then
|
||||||
|
plugin.cond = { plugin.cond }
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, condition in ipairs(plugin.cond) do
|
||||||
|
loaders[name].cond = {}
|
||||||
|
if type(condition) == 'function' then
|
||||||
|
_, condition = make_try_loadstring(condition, 'condition', name)
|
||||||
|
elseif type(condition) == 'string' then
|
||||||
|
condition = 'return ' .. condition
|
||||||
|
end
|
||||||
|
|
||||||
|
condition_ids[condition] = condition_ids[condition] or {}
|
||||||
|
table.insert(loaders[name].cond, condition)
|
||||||
|
table.insert(condition_ids[condition], name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Add the git URL for displaying in PackerStatus and PackerSync. https://github.com/wbthomason/packer.nvim/issues/542
|
||||||
|
loaders[name].url = plugin.url
|
||||||
|
|
||||||
|
if plugin.ft then
|
||||||
|
plugin.simple_load = false
|
||||||
|
loaders[name].only_sequence = false
|
||||||
|
loaders[name].only_setup = false
|
||||||
|
loaders[name].only_cond = false
|
||||||
|
vim.list_extend(ftdetect_paths, detect_ftdetect(name, loaders[name].path))
|
||||||
|
if type(plugin.ft) == 'string' then
|
||||||
|
plugin.ft = { plugin.ft }
|
||||||
|
end
|
||||||
|
for _, ft in ipairs(plugin.ft) do
|
||||||
|
fts[ft] = fts[ft] or {}
|
||||||
|
table.insert(fts[ft], quote_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.event then
|
||||||
|
plugin.simple_load = false
|
||||||
|
loaders[name].only_sequence = false
|
||||||
|
loaders[name].only_setup = false
|
||||||
|
loaders[name].only_cond = false
|
||||||
|
if type(plugin.event) == 'string' then
|
||||||
|
if not plugin.event:find '%s' then
|
||||||
|
plugin.event = { plugin.event .. ' *' }
|
||||||
|
else
|
||||||
|
plugin.event = { plugin.event }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, event in ipairs(plugin.event) do
|
||||||
|
if event:sub(#event, -1) ~= '*' and not event:find '%s' then
|
||||||
|
event = event .. ' *'
|
||||||
|
end
|
||||||
|
events[event] = events[event] or {}
|
||||||
|
table.insert(events[event], quote_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.cmd then
|
||||||
|
plugin.simple_load = false
|
||||||
|
loaders[name].only_sequence = false
|
||||||
|
loaders[name].only_setup = false
|
||||||
|
loaders[name].only_cond = false
|
||||||
|
if type(plugin.cmd) == 'string' then
|
||||||
|
plugin.cmd = { plugin.cmd }
|
||||||
|
end
|
||||||
|
|
||||||
|
loaders[name].commands = {}
|
||||||
|
for _, command in ipairs(plugin.cmd) do
|
||||||
|
commands[command] = commands[command] or {}
|
||||||
|
table.insert(loaders[name].commands, command)
|
||||||
|
table.insert(commands[command], quote_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.keys then
|
||||||
|
plugin.simple_load = false
|
||||||
|
loaders[name].only_sequence = false
|
||||||
|
loaders[name].only_setup = false
|
||||||
|
loaders[name].only_cond = false
|
||||||
|
if type(plugin.keys) == 'string' then
|
||||||
|
plugin.keys = { plugin.keys }
|
||||||
|
end
|
||||||
|
loaders[name].keys = {}
|
||||||
|
for _, keymap in ipairs(plugin.keys) do
|
||||||
|
if type(keymap) == 'string' then
|
||||||
|
keymap = { '', keymap }
|
||||||
|
end
|
||||||
|
keymaps[keymap] = keymaps[keymap] or {}
|
||||||
|
table.insert(loaders[name].keys, keymap)
|
||||||
|
table.insert(keymaps[keymap], quote_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.after then
|
||||||
|
plugin.simple_load = false
|
||||||
|
loaders[name].only_setup = false
|
||||||
|
|
||||||
|
if type(plugin.after) == 'string' then
|
||||||
|
plugin.after = { plugin.after }
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, other_plugin in ipairs(plugin.after) do
|
||||||
|
after[other_plugin] = after[other_plugin] or {}
|
||||||
|
table.insert(after[other_plugin], name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.wants then
|
||||||
|
plugin.simple_load = false
|
||||||
|
if type(plugin.wants) == 'string' then
|
||||||
|
plugin.wants = { plugin.wants }
|
||||||
|
end
|
||||||
|
loaders[name].wants = plugin.wants
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.fn then
|
||||||
|
plugin.simple_load = false
|
||||||
|
loaders[name].only_sequence = false
|
||||||
|
loaders[name].only_setup = false
|
||||||
|
if type(plugin.fn) == 'string' then
|
||||||
|
plugin.fn = { plugin.fn }
|
||||||
|
end
|
||||||
|
for _, fn in ipairs(plugin.fn) do
|
||||||
|
fns[fn] = fns[fn] or {}
|
||||||
|
table.insert(fns[fn], quote_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.module or plugin.module_pattern then
|
||||||
|
plugin.simple_load = false
|
||||||
|
loaders[name].only_sequence = false
|
||||||
|
loaders[name].only_setup = false
|
||||||
|
loaders[name].only_cond = false
|
||||||
|
|
||||||
|
if plugin.module then
|
||||||
|
if type(plugin.module) == 'string' then
|
||||||
|
plugin.module = { plugin.module }
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, module_name in ipairs(plugin.module) do
|
||||||
|
module_lazy_loads['^' .. vim.pesc(module_name)] = name
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if type(plugin.module_pattern) == 'string' then
|
||||||
|
plugin.module_pattern = { plugin.module_pattern }
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, module_pattern in ipairs(plugin.module_pattern) do
|
||||||
|
module_lazy_loads[module_pattern] = name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.config and (not plugin.opt or loaders[name].only_setup) then
|
||||||
|
plugin.simple_load = false
|
||||||
|
plugin.only_config = true
|
||||||
|
configs[name] = plugin.executable_config
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local ft_aucmds = {}
|
||||||
|
for ft, names in pairs(fts) do
|
||||||
|
table.insert(
|
||||||
|
ft_aucmds,
|
||||||
|
fmt(
|
||||||
|
'vim.cmd [[au FileType %s ++once lua require("packer.load")({%s}, { ft = "%s" }, _G.packer_plugins)]]',
|
||||||
|
ft,
|
||||||
|
table.concat(names, ', '),
|
||||||
|
ft
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
local event_aucmds = {}
|
||||||
|
for event, names in pairs(events) do
|
||||||
|
table.insert(
|
||||||
|
event_aucmds,
|
||||||
|
fmt(
|
||||||
|
'vim.cmd [[au %s ++once lua require("packer.load")({%s}, { event = "%s" }, _G.packer_plugins)]]',
|
||||||
|
event,
|
||||||
|
table.concat(names, ', '),
|
||||||
|
event:gsub([[\]], [[\\]])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
local config_lines = {}
|
||||||
|
for name, plugin_config in pairs(configs) do
|
||||||
|
local lines = { '-- Config for: ' .. name }
|
||||||
|
timed_chunk(plugin_config, 'Config for ' .. name, lines)
|
||||||
|
vim.list_extend(config_lines, lines)
|
||||||
|
end
|
||||||
|
|
||||||
|
local rtp_line = ''
|
||||||
|
for _, rtp in ipairs(rtps) do
|
||||||
|
rtp_line = rtp_line .. ' .. ",' .. vim.fn.escape(rtp, '\\,') .. '"'
|
||||||
|
end
|
||||||
|
|
||||||
|
if rtp_line ~= '' then
|
||||||
|
rtp_line = 'vim.o.runtimepath = vim.o.runtimepath' .. rtp_line
|
||||||
|
end
|
||||||
|
|
||||||
|
local setup_lines = {}
|
||||||
|
for name, plugin_setup in pairs(setup) do
|
||||||
|
local lines = { '-- Setup for: ' .. name }
|
||||||
|
timed_chunk(plugin_setup, 'Setup for ' .. name, lines)
|
||||||
|
if loaders[name].only_setup then
|
||||||
|
timed_chunk('vim.cmd [[packadd ' .. name .. ']]', 'packadd for ' .. name, lines)
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.list_extend(setup_lines, lines)
|
||||||
|
end
|
||||||
|
|
||||||
|
local conditionals = {}
|
||||||
|
for _, names in pairs(condition_ids) do
|
||||||
|
for _, name in ipairs(names) do
|
||||||
|
if loaders[name].only_cond then
|
||||||
|
timed_chunk(
|
||||||
|
fmt(' require("packer.load")({"%s"}, {}, _G.packer_plugins)', name),
|
||||||
|
'Conditional loading of ' .. name,
|
||||||
|
conditionals
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local command_defs = {}
|
||||||
|
for command, names in pairs(commands) do
|
||||||
|
local command_line
|
||||||
|
if string.match(command, '^%w+$') then
|
||||||
|
-- Better command completions here are due to @folke and @lewis6991
|
||||||
|
command_line = fmt(
|
||||||
|
[[pcall(vim.api.nvim_create_user_command, '%s', function(cmdargs)
|
||||||
|
require('packer.load')({%s}, { cmd = '%s', l1 = cmdargs.line1, l2 = cmdargs.line2, bang = cmdargs.bang, args = cmdargs.args, mods = cmdargs.mods }, _G.packer_plugins)
|
||||||
|
end,
|
||||||
|
{nargs = '*', range = true, bang = true, complete = function()
|
||||||
|
require('packer.load')({%s}, { cmd = '%s' }, _G.packer_plugins)
|
||||||
|
return vim.fn.getcompletion('%s ', 'cmdline')
|
||||||
|
end})]],
|
||||||
|
command,
|
||||||
|
table.concat(names, ', '),
|
||||||
|
command,
|
||||||
|
table.concat(names, ', '),
|
||||||
|
command,
|
||||||
|
command
|
||||||
|
)
|
||||||
|
else
|
||||||
|
command_line = fmt(
|
||||||
|
'pcall(vim.cmd, [[au CmdUndefined %s ++once lua require"packer.load"({%s}, {}, _G.packer_plugins)]])',
|
||||||
|
command,
|
||||||
|
table.concat(names, ', ')
|
||||||
|
)
|
||||||
|
end
|
||||||
|
command_defs[#command_defs + 1] = command_line
|
||||||
|
end
|
||||||
|
|
||||||
|
local keymap_defs = {}
|
||||||
|
for keymap, names in pairs(keymaps) do
|
||||||
|
local prefix = nil
|
||||||
|
if keymap[1] ~= 'i' then
|
||||||
|
prefix = ''
|
||||||
|
end
|
||||||
|
local escaped_map_lt = string.gsub(keymap[2], '<', '<lt>')
|
||||||
|
local escaped_map = string.gsub(escaped_map_lt, '([\\"])', '\\%1')
|
||||||
|
local keymap_line = fmt(
|
||||||
|
'vim.cmd [[%snoremap <silent> %s <cmd>lua require("packer.load")({%s}, { keys = "%s"%s }, _G.packer_plugins)<cr>]]',
|
||||||
|
keymap[1],
|
||||||
|
keymap[2],
|
||||||
|
table.concat(names, ', '),
|
||||||
|
escaped_map,
|
||||||
|
prefix == nil and '' or (', prefix = "' .. prefix .. '"')
|
||||||
|
)
|
||||||
|
|
||||||
|
table.insert(keymap_defs, keymap_line)
|
||||||
|
end
|
||||||
|
|
||||||
|
local sequence_loads = {}
|
||||||
|
for pre, posts in pairs(after) do
|
||||||
|
if plugins[pre] == nil then
|
||||||
|
error(string.format('Dependency %s for %s not found', pre, vim.inspect(posts)))
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugins[pre].opt then
|
||||||
|
loaders[pre].after = posts
|
||||||
|
elseif plugins[pre].only_config then
|
||||||
|
loaders[pre].after = posts
|
||||||
|
loaders[pre].only_sequence = true
|
||||||
|
loaders[pre].only_config = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugins[pre].simple_load or plugins[pre].opt or plugins[pre].only_config then
|
||||||
|
for _, name in ipairs(posts) do
|
||||||
|
loaders[name].load_after = {}
|
||||||
|
sequence_loads[name] = sequence_loads[name] or {}
|
||||||
|
table.insert(sequence_loads[name], pre)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local fn_aucmds = {}
|
||||||
|
for fn, names in pairs(fns) do
|
||||||
|
table.insert(
|
||||||
|
fn_aucmds,
|
||||||
|
fmt(
|
||||||
|
'vim.cmd[[au FuncUndefined %s ++once lua require("packer.load")({%s}, {}, _G.packer_plugins)]]',
|
||||||
|
fn,
|
||||||
|
table.concat(names, ', ')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
local sequence_lines = {}
|
||||||
|
local graph = {}
|
||||||
|
for name, precedents in pairs(sequence_loads) do
|
||||||
|
graph[name] = graph[name] or { in_links = {}, out_links = {} }
|
||||||
|
for _, pre in ipairs(precedents) do
|
||||||
|
graph[pre] = graph[pre] or { in_links = {}, out_links = {} }
|
||||||
|
graph[name].in_links[pre] = true
|
||||||
|
table.insert(graph[pre].out_links, name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local frontier = {}
|
||||||
|
for name, links in pairs(graph) do
|
||||||
|
if next(links.in_links) == nil then
|
||||||
|
table.insert(frontier, name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
while next(frontier) ~= nil do
|
||||||
|
local plugin = table.remove(frontier)
|
||||||
|
if loaders[plugin].only_sequence and not (loaders[plugin].only_setup or loaders[plugin].only_config) then
|
||||||
|
table.insert(sequence_lines, 'vim.cmd [[ packadd ' .. plugin .. ' ]]')
|
||||||
|
if plugins[plugin].config then
|
||||||
|
local lines = { '', '-- Config for: ' .. plugin }
|
||||||
|
vim.list_extend(lines, plugins[plugin].executable_config)
|
||||||
|
table.insert(lines, '')
|
||||||
|
vim.list_extend(sequence_lines, lines)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, name in ipairs(graph[plugin].out_links) do
|
||||||
|
if not loaders[plugin].only_sequence then
|
||||||
|
loaders[name].only_sequence = false
|
||||||
|
loaders[name].load_after[plugin] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
graph[name].in_links[plugin] = nil
|
||||||
|
if next(graph[name].in_links) == nil then
|
||||||
|
table.insert(frontier, name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
graph[plugin] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if next(graph) then
|
||||||
|
log.warn 'Cycle detected in sequenced loads! Load order may be incorrect'
|
||||||
|
-- TODO: This should actually just output the cycle, then continue with toposort. But I'm too
|
||||||
|
-- lazy to do that right now, so.
|
||||||
|
for plugin, _ in pairs(graph) do
|
||||||
|
table.insert(sequence_lines, 'vim.cmd [[ packadd ' .. plugin .. ' ]]')
|
||||||
|
if plugins[plugin].config then
|
||||||
|
local lines = { '-- Config for: ' .. plugin }
|
||||||
|
vim.list_extend(lines, plugins[plugin].config)
|
||||||
|
vim.list_extend(sequence_lines, lines)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Output everything:
|
||||||
|
|
||||||
|
-- First, the Lua code
|
||||||
|
local result = { (output_lua and '--' or '"') .. ' Automatically generated packer.nvim plugin loader code\n' }
|
||||||
|
if output_lua then
|
||||||
|
table.insert(result, feature_guard_lua)
|
||||||
|
else
|
||||||
|
table.insert(result, feature_guard)
|
||||||
|
table.insert(result, 'lua << END')
|
||||||
|
end
|
||||||
|
table.insert(result, enter_packer_compile)
|
||||||
|
table.insert(result, profile_time(should_profile))
|
||||||
|
table.insert(result, profile_output)
|
||||||
|
timed_chunk(luarocks.generate_path_setup(), 'Luarocks path setup', result)
|
||||||
|
timed_chunk(try_loadstring, 'try_loadstring definition', result)
|
||||||
|
timed_chunk(fmt('_G.packer_plugins = %s\n', dump_loaders(loaders)), 'Defining packer_plugins', result)
|
||||||
|
-- Then the runtimepath line
|
||||||
|
if rtp_line ~= '' then
|
||||||
|
table.insert(result, '-- Runtimepath customization')
|
||||||
|
timed_chunk(rtp_line, 'Runtimepath customization', result)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Then the module lazy loads
|
||||||
|
if next(module_lazy_loads) then
|
||||||
|
table.insert(result, 'local module_lazy_loads = ' .. vim.inspect(module_lazy_loads))
|
||||||
|
table.insert(result, module_loader)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Then setups, configs, and conditionals
|
||||||
|
if next(setup_lines) then
|
||||||
|
vim.list_extend(result, setup_lines)
|
||||||
|
end
|
||||||
|
if next(config_lines) then
|
||||||
|
vim.list_extend(result, config_lines)
|
||||||
|
end
|
||||||
|
if next(conditionals) then
|
||||||
|
table.insert(result, '-- Conditional loads')
|
||||||
|
vim.list_extend(result, conditionals)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The sequenced loads
|
||||||
|
if next(sequence_lines) then
|
||||||
|
table.insert(result, '-- Load plugins in order defined by `after`')
|
||||||
|
timed_chunk(sequence_lines, 'Sequenced loading', result)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The command and keymap definitions
|
||||||
|
if next(command_defs) then
|
||||||
|
table.insert(result, '\n-- Command lazy-loads')
|
||||||
|
timed_chunk(command_defs, 'Defining lazy-load commands', result)
|
||||||
|
table.insert(result, '')
|
||||||
|
end
|
||||||
|
|
||||||
|
if next(keymap_defs) then
|
||||||
|
table.insert(result, '-- Keymap lazy-loads')
|
||||||
|
timed_chunk(keymap_defs, 'Defining lazy-load keymaps', result)
|
||||||
|
table.insert(result, '')
|
||||||
|
end
|
||||||
|
|
||||||
|
-- The filetype, event and function autocommands
|
||||||
|
local some_ft = next(ft_aucmds) ~= nil
|
||||||
|
local some_event = next(event_aucmds) ~= nil
|
||||||
|
local some_fn = next(fn_aucmds) ~= nil
|
||||||
|
if some_ft or some_event or some_fn then
|
||||||
|
table.insert(result, 'vim.cmd [[augroup packer_load_aucmds]]\nvim.cmd [[au!]]')
|
||||||
|
end
|
||||||
|
|
||||||
|
if some_ft then
|
||||||
|
table.insert(result, ' -- Filetype lazy-loads')
|
||||||
|
timed_chunk(ft_aucmds, 'Defining lazy-load filetype autocommands', result)
|
||||||
|
end
|
||||||
|
|
||||||
|
if some_event then
|
||||||
|
table.insert(result, ' -- Event lazy-loads')
|
||||||
|
timed_chunk(event_aucmds, 'Defining lazy-load event autocommands', result)
|
||||||
|
end
|
||||||
|
|
||||||
|
if some_fn then
|
||||||
|
table.insert(result, ' -- Function lazy-loads')
|
||||||
|
timed_chunk(fn_aucmds, 'Defining lazy-load function autocommands', result)
|
||||||
|
end
|
||||||
|
|
||||||
|
if some_ft or some_event or some_fn then
|
||||||
|
table.insert(result, 'vim.cmd("augroup END")')
|
||||||
|
end
|
||||||
|
if next(ftdetect_paths) then
|
||||||
|
table.insert(result, 'vim.cmd [[augroup filetypedetect]]')
|
||||||
|
for _, path in ipairs(ftdetect_paths) do
|
||||||
|
local escaped_path = vim.fn.escape(path, ' ')
|
||||||
|
timed_chunk('vim.cmd [[source ' .. escaped_path .. ']]', 'Sourcing ftdetect script at: ' .. escaped_path, result)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(result, 'vim.cmd("augroup END")')
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(result, exit_packer_compile)
|
||||||
|
|
||||||
|
table.insert(result, conditionally_output_profile(config.threshold))
|
||||||
|
if output_lua then
|
||||||
|
table.insert(result, catch_errors_lua)
|
||||||
|
else
|
||||||
|
table.insert(result, 'END\n')
|
||||||
|
table.insert(result, catch_errors)
|
||||||
|
end
|
||||||
|
return table.concat(result, '\n')
|
||||||
|
end
|
||||||
|
|
||||||
|
local compile = setmetatable({ cfg = cfg }, { __call = make_loaders })
|
||||||
|
|
||||||
|
compile.opt_keys = { 'after', 'cmd', 'ft', 'keys', 'event', 'cond', 'setup', 'fn', 'module', 'module_pattern' }
|
||||||
|
|
||||||
|
return compile
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,11 @@
|
||||||
|
local config = nil
|
||||||
|
|
||||||
|
local function cfg(_config)
|
||||||
|
config = _config
|
||||||
|
end
|
||||||
|
|
||||||
|
local handlers = {
|
||||||
|
cfg = cfg,
|
||||||
|
}
|
||||||
|
|
||||||
|
return handlers
|
|
@ -0,0 +1,58 @@
|
||||||
|
local a = require 'packer.async'
|
||||||
|
local log = require 'packer.log'
|
||||||
|
local util = require 'packer.util'
|
||||||
|
local display = require 'packer.display'
|
||||||
|
local plugin_utils = require 'packer.plugin_utils'
|
||||||
|
|
||||||
|
local fmt = string.format
|
||||||
|
local async = a.sync
|
||||||
|
local await = a.wait
|
||||||
|
|
||||||
|
local config = nil
|
||||||
|
|
||||||
|
local function install_plugin(plugin, display_win, results)
|
||||||
|
local plugin_name = util.get_plugin_full_name(plugin)
|
||||||
|
return async(function()
|
||||||
|
display_win:task_start(plugin_name, 'installing...')
|
||||||
|
-- TODO: If the user provided a custom function as an installer, we would like to use pcall
|
||||||
|
-- here. Need to figure out how that integrates with async code
|
||||||
|
local r = await(plugin.installer(display_win))
|
||||||
|
r = r:and_then(await, plugin_utils.post_update_hook(plugin, display_win))
|
||||||
|
if r.ok then
|
||||||
|
display_win:task_succeeded(plugin_name, 'installed')
|
||||||
|
log.debug('Installed ' .. plugin_name)
|
||||||
|
else
|
||||||
|
display_win:task_failed(plugin_name, 'failed to install')
|
||||||
|
log.debug(fmt('Failed to install %s: %s', plugin_name, vim.inspect(r.err)))
|
||||||
|
end
|
||||||
|
|
||||||
|
results.installs[plugin_name] = r
|
||||||
|
results.plugins[plugin_name] = plugin
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function do_install(_, plugins, missing_plugins, results)
|
||||||
|
results = results or {}
|
||||||
|
results.installs = results.installs or {}
|
||||||
|
results.plugins = results.plugins or {}
|
||||||
|
local display_win = nil
|
||||||
|
local tasks = {}
|
||||||
|
if #missing_plugins > 0 then
|
||||||
|
display_win = display.open(config.display.open_fn or config.display.open_cmd)
|
||||||
|
for _, v in ipairs(missing_plugins) do
|
||||||
|
if not plugins[v].disable then
|
||||||
|
table.insert(tasks, install_plugin(plugins[v], display_win, results))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return tasks, display_win
|
||||||
|
end
|
||||||
|
|
||||||
|
local function cfg(_config)
|
||||||
|
config = _config
|
||||||
|
end
|
||||||
|
|
||||||
|
local install = setmetatable({ cfg = cfg }, { __call = do_install })
|
||||||
|
|
||||||
|
return install
|
|
@ -0,0 +1,216 @@
|
||||||
|
-- Interface with Neovim job control and provide a simple job sequencing structure
|
||||||
|
local split = vim.split
|
||||||
|
local loop = vim.loop
|
||||||
|
local a = require 'packer.async'
|
||||||
|
local log = require 'packer.log'
|
||||||
|
local result = require 'packer.result'
|
||||||
|
|
||||||
|
--- Utility function to make a "standard" logging callback for a given set of tables
|
||||||
|
-- Arguments:
|
||||||
|
-- - err_tbl: table to which err messages will be logged
|
||||||
|
-- - data_tbl: table to which data (non-err messages) will be logged
|
||||||
|
-- - pipe: the pipe for which this callback will be used. Passed in so that we can make sure all
|
||||||
|
-- output flushes before finishing reading
|
||||||
|
-- - disp: optional packer.display object for updating task status. Requires `name`
|
||||||
|
-- - name: optional string name for a current task. Used to update task status
|
||||||
|
local function make_logging_callback(err_tbl, data_tbl, pipe, disp, name)
|
||||||
|
return function(err, data)
|
||||||
|
if err then
|
||||||
|
table.insert(err_tbl, vim.trim(err))
|
||||||
|
end
|
||||||
|
if data ~= nil then
|
||||||
|
local trimmed = vim.trim(data)
|
||||||
|
table.insert(data_tbl, trimmed)
|
||||||
|
if disp then
|
||||||
|
disp:task_update(name, split(trimmed, '\n')[1])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
loop.read_stop(pipe)
|
||||||
|
loop.close(pipe)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Utility function to make a table for capturing output with "standard" structure
|
||||||
|
local function make_output_table()
|
||||||
|
return { err = { stdout = {}, stderr = {} }, data = { stdout = {}, stderr = {} } }
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Utility function to merge stdout and stderr from two tables with "standard" structure (either
|
||||||
|
-- the err or data subtables, specifically)
|
||||||
|
local function extend_output(to, from)
|
||||||
|
vim.list_extend(to.stdout, from.stdout)
|
||||||
|
vim.list_extend(to.stderr, from.stderr)
|
||||||
|
return to
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Wrapper for vim.loop.spawn. Takes a command, options, and callback just like vim.loop.spawn, but
|
||||||
|
-- (1) makes an async function and (2) ensures that all output from the command has been flushed
|
||||||
|
-- before calling the callback
|
||||||
|
local spawn = a.wrap(function(cmd, options, callback)
|
||||||
|
local handle = nil
|
||||||
|
local timer = nil
|
||||||
|
handle = loop.spawn(cmd, options, function(exit_code, signal)
|
||||||
|
handle:close()
|
||||||
|
if timer ~= nil then
|
||||||
|
timer:stop()
|
||||||
|
timer:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
loop.close(options.stdio[1])
|
||||||
|
local check = loop.new_check()
|
||||||
|
loop.check_start(check, function()
|
||||||
|
for _, pipe in pairs(options.stdio) do
|
||||||
|
if not loop.is_closing(pipe) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
loop.check_stop(check)
|
||||||
|
callback(exit_code, signal)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
if options.stdio then
|
||||||
|
for i, pipe in pairs(options.stdio) do
|
||||||
|
if options.stdio_callbacks[i] then
|
||||||
|
loop.read_start(pipe, options.stdio_callbacks[i])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if options.timeout then
|
||||||
|
timer = loop.new_timer()
|
||||||
|
timer:start(options.timeout, 0, function()
|
||||||
|
timer:stop()
|
||||||
|
timer:close()
|
||||||
|
if loop.is_active(handle) then
|
||||||
|
log.warn('Killing ' .. cmd .. ' due to timeout!')
|
||||||
|
loop.process_kill(handle, 'sigint')
|
||||||
|
handle:close()
|
||||||
|
for _, pipe in pairs(options.stdio) do
|
||||||
|
loop.close(pipe)
|
||||||
|
end
|
||||||
|
callback(-9999, 'sigint')
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
--- Utility function to perform a common check for process success and return a result object
|
||||||
|
local function was_successful(r)
|
||||||
|
if r.exit_code == 0 and (not r.output or not r.output.err or #r.output.err == 0) then
|
||||||
|
return result.ok(r)
|
||||||
|
else
|
||||||
|
return result.err(r)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Main exposed function for the jobs module. Takes a task and options and returns an async
|
||||||
|
-- function that will run the task with the given opts via vim.loop.spawn
|
||||||
|
-- Arguments:
|
||||||
|
-- - task: either a string or table. If string, split, and the first component is treated as the
|
||||||
|
-- command. If table, first element is treated as the command. All subsequent elements are passed
|
||||||
|
-- as args
|
||||||
|
-- - opts: table of options. Can include the keys "options" (like the options table passed to
|
||||||
|
-- vim.loop.spawn), "success_test" (a function, called like `was_successful` (above)),
|
||||||
|
-- "capture_output" (either a boolean, in which case default output capture is set up and the
|
||||||
|
-- resulting tables are included in the result, or a set of tables, in which case output is logged
|
||||||
|
-- to the given tables)
|
||||||
|
local run_job = function(task, opts)
|
||||||
|
return a.sync(function()
|
||||||
|
local options = opts.options or { hide = true }
|
||||||
|
local stdout = nil
|
||||||
|
local stderr = nil
|
||||||
|
local job_result = { exit_code = -1, signal = -1 }
|
||||||
|
local success_test = opts.success_test or was_successful
|
||||||
|
local uv_err
|
||||||
|
local output = make_output_table()
|
||||||
|
local callbacks = {}
|
||||||
|
local output_valid = false
|
||||||
|
if opts.capture_output then
|
||||||
|
if type(opts.capture_output) == 'boolean' then
|
||||||
|
stdout, uv_err = loop.new_pipe(false)
|
||||||
|
if uv_err then
|
||||||
|
log.error('Failed to open stdout pipe: ' .. uv_err)
|
||||||
|
return result.err()
|
||||||
|
end
|
||||||
|
|
||||||
|
stderr, uv_err = loop.new_pipe(false)
|
||||||
|
if uv_err then
|
||||||
|
log.error('Failed to open stderr pipe: ' .. uv_err)
|
||||||
|
return job_result
|
||||||
|
end
|
||||||
|
|
||||||
|
callbacks.stdout = make_logging_callback(output.err.stdout, output.data.stdout, stdout)
|
||||||
|
callbacks.stderr = make_logging_callback(output.err.stderr, output.data.stderr, stderr)
|
||||||
|
output_valid = true
|
||||||
|
elseif type(opts.capture_output) == 'table' then
|
||||||
|
if opts.capture_output.stdout then
|
||||||
|
stdout, uv_err = loop.new_pipe(false)
|
||||||
|
if uv_err then
|
||||||
|
log.error('Failed to open stdout pipe: ' .. uv_err)
|
||||||
|
return job_result
|
||||||
|
end
|
||||||
|
|
||||||
|
callbacks.stdout = function(err, data)
|
||||||
|
if data ~= nil then
|
||||||
|
opts.capture_output.stdout(err, data)
|
||||||
|
else
|
||||||
|
loop.read_stop(stdout)
|
||||||
|
loop.close(stdout)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if opts.capture_output.stderr then
|
||||||
|
stderr, uv_err = loop.new_pipe(false)
|
||||||
|
if uv_err then
|
||||||
|
log.error('Failed to open stderr pipe: ' .. uv_err)
|
||||||
|
return job_result
|
||||||
|
end
|
||||||
|
|
||||||
|
callbacks.stderr = function(err, data)
|
||||||
|
if data ~= nil then
|
||||||
|
opts.capture_output.stderr(err, data)
|
||||||
|
else
|
||||||
|
loop.read_stop(stderr)
|
||||||
|
loop.close(stderr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(task) == 'string' then
|
||||||
|
local split_pattern = '%s+'
|
||||||
|
task = split(task, split_pattern)
|
||||||
|
end
|
||||||
|
|
||||||
|
local cmd = task[1]
|
||||||
|
if opts.timeout then
|
||||||
|
options.timeout = 1000 * opts.timeout
|
||||||
|
end
|
||||||
|
|
||||||
|
options.cwd = opts.cwd
|
||||||
|
|
||||||
|
local stdin = loop.new_pipe(false)
|
||||||
|
options.args = { unpack(task, 2) }
|
||||||
|
options.stdio = { stdin, stdout, stderr }
|
||||||
|
options.stdio_callbacks = { nil, callbacks.stdout, callbacks.stderr }
|
||||||
|
|
||||||
|
local exit_code, signal = a.wait(spawn(cmd, options))
|
||||||
|
job_result = { exit_code = exit_code, signal = signal }
|
||||||
|
if output_valid then
|
||||||
|
job_result.output = output
|
||||||
|
end
|
||||||
|
return success_test(job_result)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local jobs = {
|
||||||
|
run = run_job,
|
||||||
|
logging_callback = make_logging_callback,
|
||||||
|
output_table = make_output_table,
|
||||||
|
extend_output = extend_output,
|
||||||
|
}
|
||||||
|
|
||||||
|
return jobs
|
|
@ -0,0 +1,185 @@
|
||||||
|
local packer_load = nil
|
||||||
|
local cmd = vim.api.nvim_command
|
||||||
|
local fmt = string.format
|
||||||
|
|
||||||
|
local function verify_conditions(conds, name)
|
||||||
|
if conds == nil then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
for _, cond in ipairs(conds) do
|
||||||
|
local success, result
|
||||||
|
if type(cond) == 'boolean' then
|
||||||
|
result = cond
|
||||||
|
elseif type(cond) == 'string' then
|
||||||
|
success, result = pcall(loadstring(cond))
|
||||||
|
if not success then
|
||||||
|
vim.schedule(function()
|
||||||
|
vim.api.nvim_notify(
|
||||||
|
'packer.nvim: Error running cond for ' .. name .. ': ' .. result,
|
||||||
|
vim.log.levels.ERROR,
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if result == false then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function loader_clear_loaders(plugin)
|
||||||
|
if plugin.commands then
|
||||||
|
for _, del_cmd in ipairs(plugin.commands) do
|
||||||
|
cmd('silent! delcommand ' .. del_cmd)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.keys then
|
||||||
|
for _, key in ipairs(plugin.keys) do
|
||||||
|
cmd(fmt('silent! %sunmap %s', key[1], key[2]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function loader_apply_config(plugin, name)
|
||||||
|
if plugin.config then
|
||||||
|
for _, config_line in ipairs(plugin.config) do
|
||||||
|
local success, err = pcall(loadstring(config_line), name, plugin)
|
||||||
|
if not success then
|
||||||
|
vim.schedule(function()
|
||||||
|
vim.api.nvim_notify('packer.nvim: Error running config for ' .. name .. ': ' .. err, vim.log.levels.ERROR, {})
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function loader_apply_wants(plugin, plugins)
|
||||||
|
if plugin.wants then
|
||||||
|
for _, wanted_name in ipairs(plugin.wants) do
|
||||||
|
packer_load({ wanted_name }, {}, plugins)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function loader_apply_after(plugin, plugins, name)
|
||||||
|
if plugin.after then
|
||||||
|
for _, after_name in ipairs(plugin.after) do
|
||||||
|
local after_plugin = plugins[after_name]
|
||||||
|
after_plugin.load_after[name] = nil
|
||||||
|
if next(after_plugin.load_after) == nil then
|
||||||
|
packer_load({ after_name }, {}, plugins)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function apply_cause_side_effects(cause)
|
||||||
|
if cause.cmd then
|
||||||
|
local lines = cause.l1 == cause.l2 and '' or (cause.l1 .. ',' .. cause.l2)
|
||||||
|
-- This is a hack to deal with people who haven't recompiled after updating to the new command
|
||||||
|
-- creation logic
|
||||||
|
local bang = ''
|
||||||
|
if type(cause.bang) == 'string' then
|
||||||
|
bang = cause.bang
|
||||||
|
elseif type(cause.bang) == 'boolean' and cause.bang then
|
||||||
|
bang = '!'
|
||||||
|
end
|
||||||
|
cmd(fmt('%s %s%s%s %s', cause.mods or '', lines, cause.cmd, bang, cause.args))
|
||||||
|
elseif cause.keys then
|
||||||
|
local extra = ''
|
||||||
|
while true do
|
||||||
|
local c = vim.fn.getchar(0)
|
||||||
|
if c == 0 then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
extra = extra .. vim.fn.nr2char(c)
|
||||||
|
end
|
||||||
|
|
||||||
|
if cause.prefix then
|
||||||
|
local prefix = vim.v.count ~= 0 and vim.v.count or ''
|
||||||
|
prefix = prefix .. '"' .. vim.v.register .. cause.prefix
|
||||||
|
if vim.fn.mode 'full' == 'no' then
|
||||||
|
if vim.v.operator == 'c' then
|
||||||
|
prefix = '' .. prefix
|
||||||
|
end
|
||||||
|
prefix = prefix .. vim.v.operator
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.fn.feedkeys(prefix, 'n')
|
||||||
|
end
|
||||||
|
|
||||||
|
local escaped_keys = vim.api.nvim_replace_termcodes(cause.keys .. extra, true, true, true)
|
||||||
|
vim.api.nvim_feedkeys(escaped_keys, 'm', true)
|
||||||
|
elseif cause.event then
|
||||||
|
cmd(fmt('doautocmd <nomodeline> %s', cause.event))
|
||||||
|
elseif cause.ft then
|
||||||
|
cmd(fmt('doautocmd <nomodeline> %s FileType %s', 'filetypeplugin', cause.ft))
|
||||||
|
cmd(fmt('doautocmd <nomodeline> %s FileType %s', 'filetypeindent', cause.ft))
|
||||||
|
cmd(fmt('doautocmd <nomodeline> %s FileType %s', 'syntaxset', cause.ft))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
packer_load = function(names, cause, plugins, force)
|
||||||
|
local some_unloaded = false
|
||||||
|
local needs_bufread = false
|
||||||
|
local num_names = #names
|
||||||
|
for i = 1, num_names do
|
||||||
|
local plugin = plugins[names[i]]
|
||||||
|
if not plugin then
|
||||||
|
local err_message = 'Error: attempted to load ' .. names[i] .. ' which is not present in plugins table!'
|
||||||
|
vim.notify(err_message, vim.log.levels.ERROR, { title = 'packer.nvim' })
|
||||||
|
error(err_message)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not plugin.loaded then
|
||||||
|
loader_clear_loaders(plugin)
|
||||||
|
if force or verify_conditions(plugin.cond, names[i]) then
|
||||||
|
-- Set the plugin as loaded before config is run in case something in the config tries to load
|
||||||
|
-- this same plugin again
|
||||||
|
plugin.loaded = true
|
||||||
|
some_unloaded = true
|
||||||
|
needs_bufread = needs_bufread or plugin.needs_bufread
|
||||||
|
loader_apply_wants(plugin, plugins)
|
||||||
|
cmd('packadd ' .. names[i])
|
||||||
|
if plugin.after_files then
|
||||||
|
for _, file in ipairs(plugin.after_files) do
|
||||||
|
cmd('silent source ' .. file)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
loader_apply_config(plugin, names[i])
|
||||||
|
loader_apply_after(plugin, plugins, names[i])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not some_unloaded then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if needs_bufread then
|
||||||
|
if _G._packer and _G._packer.inside_compile == true then
|
||||||
|
-- delaying BufRead to end of packer_compiled
|
||||||
|
_G._packer.needs_bufread = true
|
||||||
|
else
|
||||||
|
cmd 'doautocmd BufRead'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Retrigger cmd/keymap...
|
||||||
|
apply_cause_side_effects(cause)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function load_wrapper(names, cause, plugins, force)
|
||||||
|
local success, err_msg = pcall(packer_load, names, cause, plugins, force)
|
||||||
|
if not success then
|
||||||
|
vim.cmd 'echohl ErrorMsg'
|
||||||
|
vim.cmd('echomsg "Error in packer_compiled: ' .. vim.fn.escape(err_msg, '"') .. '"')
|
||||||
|
vim.cmd 'echomsg "Please check your config for correctness"'
|
||||||
|
vim.cmd 'echohl None'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return load_wrapper
|
|
@ -0,0 +1,163 @@
|
||||||
|
-- log.lua
|
||||||
|
--
|
||||||
|
-- Inspired by rxi/log.lua
|
||||||
|
-- Modified by tjdevries and can be found at github.com/tjdevries/vlog.nvim
|
||||||
|
--
|
||||||
|
-- This library is free software; you can redistribute it and/or modify it
|
||||||
|
-- under the terms of the MIT license. See LICENSE for details.
|
||||||
|
-- User configuration section
|
||||||
|
local default_config = {
|
||||||
|
-- Name of the plugin. Prepended to log messages
|
||||||
|
plugin = 'packer.nvim',
|
||||||
|
|
||||||
|
-- Should print the output to neovim while running
|
||||||
|
use_console = true,
|
||||||
|
|
||||||
|
-- Should highlighting be used in console (using echohl)
|
||||||
|
highlights = true,
|
||||||
|
|
||||||
|
-- Should write to a file
|
||||||
|
use_file = true,
|
||||||
|
|
||||||
|
-- Any messages above this level will be logged.
|
||||||
|
level = 'debug',
|
||||||
|
|
||||||
|
-- Level configuration
|
||||||
|
modes = {
|
||||||
|
{ name = 'trace', hl = 'Comment' },
|
||||||
|
{ name = 'debug', hl = 'Comment' },
|
||||||
|
{ name = 'info', hl = 'None' },
|
||||||
|
{ name = 'warn', hl = 'WarningMsg' },
|
||||||
|
{ name = 'error', hl = 'ErrorMsg' },
|
||||||
|
{ name = 'fatal', hl = 'ErrorMsg' },
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Which levels should be logged?
|
||||||
|
active_levels = { [1] = true, [2] = true, [3] = true, [4] = true, [5] = true, [6] = true },
|
||||||
|
|
||||||
|
-- Can limit the number of decimals displayed for floats
|
||||||
|
float_precision = 0.01,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- {{{ NO NEED TO CHANGE
|
||||||
|
local log = {}
|
||||||
|
|
||||||
|
local unpack = unpack or table.unpack
|
||||||
|
|
||||||
|
local level_ids = { trace = 1, debug = 2, info = 3, warn = 4, error = 5, fatal = 6 }
|
||||||
|
log.cfg = function(_config)
|
||||||
|
local min_active_level = level_ids[_config.log.level]
|
||||||
|
local config = { active_levels = {} }
|
||||||
|
if min_active_level then
|
||||||
|
for i = min_active_level, 6 do
|
||||||
|
config.active_levels[i] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
log.new(config, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
log.new = function(config, standalone)
|
||||||
|
config = vim.tbl_deep_extend('force', default_config, config)
|
||||||
|
local outfile = string.format('%s/%s.log', vim.fn.stdpath 'cache', config.plugin)
|
||||||
|
vim.fn.mkdir(vim.fn.stdpath 'cache', 'p')
|
||||||
|
local obj
|
||||||
|
if standalone then
|
||||||
|
obj = log
|
||||||
|
else
|
||||||
|
obj = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local levels = {}
|
||||||
|
for i, v in ipairs(config.modes) do
|
||||||
|
levels[v.name] = i
|
||||||
|
end
|
||||||
|
|
||||||
|
local round = function(x, increment)
|
||||||
|
increment = increment or 1
|
||||||
|
x = x / increment
|
||||||
|
return (x > 0 and math.floor(x + 0.5) or math.ceil(x - 0.5)) * increment
|
||||||
|
end
|
||||||
|
|
||||||
|
local make_string = function(...)
|
||||||
|
local t = {}
|
||||||
|
for i = 1, select('#', ...) do
|
||||||
|
local x = select(i, ...)
|
||||||
|
|
||||||
|
if type(x) == 'number' and config.float_precision then
|
||||||
|
x = tostring(round(x, config.float_precision))
|
||||||
|
elseif type(x) == 'table' then
|
||||||
|
x = vim.inspect(x)
|
||||||
|
else
|
||||||
|
x = tostring(x)
|
||||||
|
end
|
||||||
|
|
||||||
|
t[#t + 1] = x
|
||||||
|
end
|
||||||
|
return table.concat(t, ' ')
|
||||||
|
end
|
||||||
|
|
||||||
|
local console_output = vim.schedule_wrap(function(level_config, info, nameupper, msg)
|
||||||
|
local console_lineinfo = vim.fn.fnamemodify(info.short_src, ':t') .. ':' .. info.currentline
|
||||||
|
local console_string = string.format('[%-6s%s] %s: %s', nameupper, os.date '%H:%M:%S', console_lineinfo, msg)
|
||||||
|
-- Heuristic to check for nvim-notify
|
||||||
|
local is_fancy_notify = type(vim.notify) == 'table'
|
||||||
|
vim.notify(
|
||||||
|
string.format([[%s%s]], is_fancy_notify and '' or ('[' .. config.plugin .. '] '), console_string),
|
||||||
|
vim.log.levels[level_config.name:upper()],
|
||||||
|
{ title = config.plugin }
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
|
local log_at_level = function(level, level_config, message_maker, ...)
|
||||||
|
-- Return early if we're below the config.level
|
||||||
|
if level < levels[config.level] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local nameupper = level_config.name:upper()
|
||||||
|
|
||||||
|
local msg = message_maker(...)
|
||||||
|
local info = debug.getinfo(2, 'Sl')
|
||||||
|
local lineinfo = info.short_src .. ':' .. info.currentline
|
||||||
|
|
||||||
|
-- Output to console
|
||||||
|
if config.use_console and config.active_levels[level] then
|
||||||
|
console_output(level_config, info, nameupper, msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Output to log file
|
||||||
|
if config.use_file and config.active_levels[level] then
|
||||||
|
local fp, err = io.open(outfile, 'a')
|
||||||
|
if not fp then
|
||||||
|
print(err)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local str = string.format('[%-6s%s %s] %s: %s\n', nameupper, os.date(), vim.loop.hrtime(), lineinfo, msg)
|
||||||
|
fp:write(str)
|
||||||
|
fp:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i, x in ipairs(config.modes) do
|
||||||
|
obj[x.name] = function(...)
|
||||||
|
return log_at_level(i, x, make_string, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
obj[('fmt_%s'):format(x.name)] = function()
|
||||||
|
return log_at_level(i, x, function(...)
|
||||||
|
local passed = { ... }
|
||||||
|
local fmt = table.remove(passed, 1)
|
||||||
|
local inspected = {}
|
||||||
|
for _, v in ipairs(passed) do
|
||||||
|
table.insert(inspected, vim.inspect(v))
|
||||||
|
end
|
||||||
|
return string.format(fmt, unpack(inspected))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
log.new(default_config, true)
|
||||||
|
-- }}}
|
||||||
|
|
||||||
|
return log
|
|
@ -0,0 +1,577 @@
|
||||||
|
-- Add support for installing and cleaning Luarocks dependencies
|
||||||
|
-- Based off of plenary/neorocks/init.lua in https://github.com/nvim-lua/plenary.nvim
|
||||||
|
local a = require 'packer.async'
|
||||||
|
local jobs = require 'packer.jobs'
|
||||||
|
local log = require 'packer.log'
|
||||||
|
local result = require 'packer.result'
|
||||||
|
local util = require 'packer.util'
|
||||||
|
|
||||||
|
local fmt = string.format
|
||||||
|
local async = a.sync
|
||||||
|
local await = a.wait
|
||||||
|
|
||||||
|
local config = nil
|
||||||
|
local function cfg(_config)
|
||||||
|
config = _config.luarocks
|
||||||
|
end
|
||||||
|
local function warn_need_luajit()
|
||||||
|
log.error 'LuaJIT is required for Luarocks functionality!'
|
||||||
|
end
|
||||||
|
|
||||||
|
local lua_version = nil
|
||||||
|
if jit then
|
||||||
|
local jit_version = string.gsub(jit.version, 'LuaJIT ', '')
|
||||||
|
lua_version = { lua = string.gsub(_VERSION, 'Lua ', ''), jit = jit_version, dir = jit_version }
|
||||||
|
else
|
||||||
|
return {
|
||||||
|
handle_command = warn_need_luajit,
|
||||||
|
install_commands = warn_need_luajit,
|
||||||
|
list = warn_need_luajit,
|
||||||
|
install_hererocks = warn_need_luajit,
|
||||||
|
setup_paths = warn_need_luajit,
|
||||||
|
uninstall = warn_need_luajit,
|
||||||
|
clean = warn_need_luajit,
|
||||||
|
install = warn_need_luajit,
|
||||||
|
ensure = warn_need_luajit,
|
||||||
|
generate_path_setup = function()
|
||||||
|
return ''
|
||||||
|
end,
|
||||||
|
cfg = cfg,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local cache_path = vim.fn.stdpath 'cache'
|
||||||
|
local rocks_path = util.join_paths(cache_path, 'packer_hererocks')
|
||||||
|
local hererocks_file = util.join_paths(rocks_path, 'hererocks.py')
|
||||||
|
local hererocks_install_dir = util.join_paths(rocks_path, lua_version.dir)
|
||||||
|
local shell_hererocks_dir = vim.fn.shellescape(hererocks_install_dir)
|
||||||
|
local _hererocks_setup_done = false
|
||||||
|
local function hererocks_is_setup()
|
||||||
|
if _hererocks_setup_done then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
local path_info = vim.loop.fs_stat(util.join_paths(hererocks_install_dir, 'lib'))
|
||||||
|
_hererocks_setup_done = (path_info ~= nil) and (path_info['type'] == 'directory')
|
||||||
|
return _hererocks_setup_done
|
||||||
|
end
|
||||||
|
|
||||||
|
local function hererocks_installer(disp)
|
||||||
|
return async(function()
|
||||||
|
local hererocks_url = 'https://raw.githubusercontent.com/luarocks/hererocks/master/hererocks.py'
|
||||||
|
local hererocks_cmd
|
||||||
|
await(a.main)
|
||||||
|
vim.fn.mkdir(rocks_path, 'p')
|
||||||
|
if vim.fn.executable 'curl' > 0 then
|
||||||
|
hererocks_cmd = 'curl ' .. hererocks_url .. ' -o ' .. hererocks_file
|
||||||
|
elseif vim.fn.executable 'wget' > 0 then
|
||||||
|
hererocks_cmd = 'wget ' .. hererocks_url .. ' -O ' .. hererocks_file .. ' --verbose'
|
||||||
|
else
|
||||||
|
return result.err '"curl" or "wget" is required to install hererocks'
|
||||||
|
end
|
||||||
|
|
||||||
|
if disp ~= nil then
|
||||||
|
disp:task_start('luarocks-hererocks', 'installing hererocks...')
|
||||||
|
end
|
||||||
|
local output = jobs.output_table()
|
||||||
|
local callbacks = {
|
||||||
|
stdout = jobs.logging_callback(output.err.stdout, output.data.stdout, nil, disp, 'luarocks-hererocks'),
|
||||||
|
stderr = jobs.logging_callback(output.err.stderr, output.data.stderr),
|
||||||
|
}
|
||||||
|
|
||||||
|
local opts = { capture_output = callbacks }
|
||||||
|
local r = await(jobs.run(hererocks_cmd, opts)):map_err(function(err)
|
||||||
|
return { msg = 'Error installing hererocks', data = err, output = output }
|
||||||
|
end)
|
||||||
|
|
||||||
|
local luarocks_cmd = config.python_cmd
|
||||||
|
.. ' '
|
||||||
|
.. hererocks_file
|
||||||
|
.. ' --verbose -j '
|
||||||
|
.. lua_version.jit
|
||||||
|
.. ' -r latest '
|
||||||
|
.. hererocks_install_dir
|
||||||
|
r:and_then(await, jobs.run(luarocks_cmd, opts))
|
||||||
|
:map_ok(function()
|
||||||
|
if disp then
|
||||||
|
disp:task_succeeded('luarocks-hererocks', 'installed hererocks!')
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
:map_err(function(err)
|
||||||
|
if disp then
|
||||||
|
disp:task_failed('luarocks-hererocks', 'failed to install hererocks!')
|
||||||
|
end
|
||||||
|
log.error('Failed to install hererocks: ' .. vim.inspect(err))
|
||||||
|
return { msg = 'Error installing luarocks', data = err, output = output }
|
||||||
|
end)
|
||||||
|
return r
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function package_patterns(dir)
|
||||||
|
local sep = util.get_separator()
|
||||||
|
return fmt('%s%s?.lua;%s%s?%sinit.lua', dir, sep, dir, sep, sep)
|
||||||
|
end
|
||||||
|
|
||||||
|
local package_paths = (function()
|
||||||
|
local install_path = util.join_paths(hererocks_install_dir, 'lib', 'luarocks', fmt('rocks-%s', lua_version.lua))
|
||||||
|
local share_path = util.join_paths(hererocks_install_dir, 'share', 'lua', lua_version.lua)
|
||||||
|
return package_patterns(share_path) .. ';' .. package_patterns(install_path)
|
||||||
|
end)()
|
||||||
|
|
||||||
|
local nvim_paths_are_setup = false
|
||||||
|
local function setup_nvim_paths()
|
||||||
|
if not hererocks_is_setup() then
|
||||||
|
log.warn 'Tried to setup Neovim Lua paths before hererocks was setup!'
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if nvim_paths_are_setup then
|
||||||
|
log.warn 'Tried to setup Neovim Lua paths redundantly!'
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not string.find(package.path, package_paths, 1, true) then
|
||||||
|
package.path = package.path .. ';' .. package_paths
|
||||||
|
end
|
||||||
|
|
||||||
|
local install_cpath = util.join_paths(hererocks_install_dir, 'lib', 'lua', lua_version.lua)
|
||||||
|
local install_cpath_pattern = fmt('%s%s?.so', install_cpath, util.get_separator())
|
||||||
|
if not string.find(package.cpath, install_cpath_pattern, 1, true) then
|
||||||
|
package.cpath = package.cpath .. ';' .. install_cpath_pattern
|
||||||
|
end
|
||||||
|
|
||||||
|
nvim_paths_are_setup = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function generate_path_setup_code()
|
||||||
|
local package_path_str = vim.inspect(package_paths)
|
||||||
|
local install_cpath = util.join_paths(hererocks_install_dir, 'lib', 'lua', lua_version.lua)
|
||||||
|
local install_cpath_pattern = fmt('"%s%s?.so"', install_cpath, util.get_separator())
|
||||||
|
install_cpath_pattern = vim.fn.escape(install_cpath_pattern, [[\]])
|
||||||
|
return [[
|
||||||
|
local package_path_str = ]] .. package_path_str .. [[
|
||||||
|
|
||||||
|
local install_cpath_pattern = ]] .. install_cpath_pattern .. [[
|
||||||
|
|
||||||
|
if not string.find(package.path, package_path_str, 1, true) then
|
||||||
|
package.path = package.path .. ';' .. package_path_str
|
||||||
|
end
|
||||||
|
|
||||||
|
if not string.find(package.cpath, install_cpath_pattern, 1, true) then
|
||||||
|
package.cpath = package.cpath .. ';' .. install_cpath_pattern
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
end
|
||||||
|
|
||||||
|
local function activate_hererocks_cmd(install_path)
|
||||||
|
local activate_file = 'activate'
|
||||||
|
local user_shell = os.getenv 'SHELL'
|
||||||
|
local shell = user_shell:gmatch '([^/]*)$'()
|
||||||
|
if shell == 'fish' then
|
||||||
|
activate_file = 'activate.fish'
|
||||||
|
elseif shell == 'csh' then
|
||||||
|
activate_file = 'activate.csh'
|
||||||
|
end
|
||||||
|
|
||||||
|
return fmt('source %s', util.join_paths(install_path, 'bin', activate_file))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function run_luarocks(args, disp, operation_name)
|
||||||
|
local cmd = {
|
||||||
|
os.getenv 'SHELL',
|
||||||
|
'-c',
|
||||||
|
fmt('%s && luarocks --tree=%s %s', activate_hererocks_cmd(hererocks_install_dir), shell_hererocks_dir, args),
|
||||||
|
}
|
||||||
|
return async(function()
|
||||||
|
local output = jobs.output_table()
|
||||||
|
local callbacks = {
|
||||||
|
stdout = jobs.logging_callback(output.err.stdout, output.data.stdout, nil, disp, operation_name),
|
||||||
|
stderr = jobs.logging_callback(output.err.stderr, output.data.stderr),
|
||||||
|
}
|
||||||
|
|
||||||
|
local opts = { capture_output = callbacks }
|
||||||
|
return await(jobs.run(cmd, opts))
|
||||||
|
:map_err(function(err)
|
||||||
|
return { msg = fmt('Error running luarocks %s', args), data = err, output = output }
|
||||||
|
end)
|
||||||
|
:map_ok(function(data)
|
||||||
|
return { data = data, output = output }
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local luarocks_keys = { only_server = 'only-server', only_source = 'only-sources' }
|
||||||
|
|
||||||
|
local function is_valid_luarock_key(key)
|
||||||
|
return not (key == 'tree' or key == 'local')
|
||||||
|
end
|
||||||
|
|
||||||
|
local function format_luarocks_args(package)
|
||||||
|
if type(package) ~= 'table' then
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
local args = {}
|
||||||
|
for key, value in pairs(package) do
|
||||||
|
if type(key) == 'string' and is_valid_luarock_key(key) then
|
||||||
|
local luarock_key = luarocks_keys[key] and luarocks_keys[key] or key
|
||||||
|
if luarock_key and type(value) == 'string' then
|
||||||
|
table.insert(args, string.format('--%s=%s', key, value))
|
||||||
|
elseif key == 'env' and type(value) == 'table' then
|
||||||
|
for name, env_value in pairs(value) do
|
||||||
|
table.insert(args, string.format('%s=%s', name, env_value))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ' ' .. table.concat(args, ' ')
|
||||||
|
end
|
||||||
|
|
||||||
|
local function luarocks_install(package, results, disp)
|
||||||
|
return async(function()
|
||||||
|
local package_name = type(package) == 'table' and package[1] or package
|
||||||
|
if disp then
|
||||||
|
disp:task_update('luarocks-install', 'installing ' .. package_name)
|
||||||
|
end
|
||||||
|
local args = format_luarocks_args(package)
|
||||||
|
local version = package.version and ' ' .. package.version .. ' ' or ''
|
||||||
|
local install_result = await(run_luarocks('install ' .. package_name .. version .. args, disp, 'luarocks-install'))
|
||||||
|
if results then
|
||||||
|
results.luarocks.installs[package_name] = install_result
|
||||||
|
end
|
||||||
|
return install_result
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function install_packages(packages, results, disp)
|
||||||
|
return async(function()
|
||||||
|
local r = result.ok()
|
||||||
|
if not hererocks_is_setup() then
|
||||||
|
r:and_then(await, hererocks_installer(disp))
|
||||||
|
end
|
||||||
|
if disp then
|
||||||
|
disp:task_start('luarocks-install', 'installing rocks...')
|
||||||
|
end
|
||||||
|
if results then
|
||||||
|
results.luarocks.installs = {}
|
||||||
|
end
|
||||||
|
for _, package in ipairs(packages) do
|
||||||
|
r:and_then(await, luarocks_install(package, results, disp))
|
||||||
|
end
|
||||||
|
r:map_ok(function()
|
||||||
|
if disp then
|
||||||
|
disp:task_succeeded('luarocks-install', 'rocks installed!')
|
||||||
|
end
|
||||||
|
end):map_err(function()
|
||||||
|
if disp then
|
||||||
|
disp:task_failed('luarocks-install', 'installing rocks failed!')
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
return r
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Install the packages specified with `packages` synchronously
|
||||||
|
local function install_sync(packages)
|
||||||
|
return async(function()
|
||||||
|
return await(install_packages(packages))
|
||||||
|
end)()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function chunk_output(output)
|
||||||
|
-- Merge the output to a single line, then split again. Helps to deal with inconsistent
|
||||||
|
-- chunking in the output collection
|
||||||
|
local res = table.concat(output, '\n')
|
||||||
|
return vim.split(res, '\n')
|
||||||
|
end
|
||||||
|
|
||||||
|
local function luarocks_list(disp)
|
||||||
|
return async(function()
|
||||||
|
local r = result.ok()
|
||||||
|
if not hererocks_is_setup() then
|
||||||
|
r:and_then(await, hererocks_installer(disp))
|
||||||
|
end
|
||||||
|
r:and_then(await, run_luarocks 'list --porcelain')
|
||||||
|
return r:map_ok(function(data)
|
||||||
|
local results = {}
|
||||||
|
local output = chunk_output(data.output.data.stdout)
|
||||||
|
for _, line in ipairs(output) do
|
||||||
|
for l_package, version, status, install_path in string.gmatch(line, '([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)') do
|
||||||
|
table.insert(results, {
|
||||||
|
name = l_package,
|
||||||
|
version = version,
|
||||||
|
status = status,
|
||||||
|
install_path = install_path,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return results
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function luarocks_show(package, disp)
|
||||||
|
return async(function()
|
||||||
|
local r = result.ok()
|
||||||
|
if not hererocks_is_setup() then
|
||||||
|
r:and_then(await, hererocks_installer(disp))
|
||||||
|
end
|
||||||
|
r:and_then(await, run_luarocks('show --porcelain ' .. package))
|
||||||
|
return r:map_ok(function(data)
|
||||||
|
local output = chunk_output(data.output.data.stdout)
|
||||||
|
local dependencies = {}
|
||||||
|
for _, line in ipairs(output) do
|
||||||
|
local components = {}
|
||||||
|
for component in string.gmatch(line, '([^%s]+)') do
|
||||||
|
components[#components + 1] = component
|
||||||
|
end
|
||||||
|
|
||||||
|
if (components[1] == 'dependency' or components[1] == 'indirect_dependency') and (components[2] ~= 'lua') then
|
||||||
|
dependencies[components[2]] = components[2]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return dependencies
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function luarocks_remove(package, results, disp)
|
||||||
|
return async(function()
|
||||||
|
if disp then
|
||||||
|
disp:task_update('luarocks-remove', 'removing ' .. package)
|
||||||
|
end
|
||||||
|
local remove_result = await(run_luarocks('remove ' .. package, disp, 'luarocks-remove'))
|
||||||
|
if results then
|
||||||
|
results.luarocks.removals[package] = remove_result
|
||||||
|
end
|
||||||
|
return remove_result
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function uninstall_packages(packages, results, disp)
|
||||||
|
return async(function()
|
||||||
|
local r = result.ok()
|
||||||
|
if not hererocks_is_setup() then
|
||||||
|
r:and_then(await, hererocks_installer(disp))
|
||||||
|
end
|
||||||
|
if disp then
|
||||||
|
disp:task_start('luarocks-remove', 'uninstalling rocks...')
|
||||||
|
end
|
||||||
|
if results then
|
||||||
|
results.luarocks.removals = {}
|
||||||
|
end
|
||||||
|
for _, package in ipairs(packages) do
|
||||||
|
local name = type(package) == 'table' and package[1] or package
|
||||||
|
r:and_then(await, luarocks_remove(name, results, disp))
|
||||||
|
end
|
||||||
|
r:map_ok(function()
|
||||||
|
if disp then
|
||||||
|
disp:task_succeeded('luarocks-remove', 'rocks cleaned!')
|
||||||
|
end
|
||||||
|
end):map_err(function()
|
||||||
|
if disp then
|
||||||
|
disp:task_failed('luarocks-remove', 'cleaning rocks failed!')
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
return r
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Uninstall the packages specified with `packages` synchronously
|
||||||
|
local function uninstall_sync(packages)
|
||||||
|
return async(function()
|
||||||
|
return await(uninstall_packages(packages))
|
||||||
|
end)()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function clean_rocks(rocks, results, disp)
|
||||||
|
return async(function()
|
||||||
|
local r = result.ok()
|
||||||
|
if not hererocks_is_setup() then
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
r:and_then(await, luarocks_list(disp))
|
||||||
|
local installed_packages
|
||||||
|
if r.ok then
|
||||||
|
installed_packages = r.ok
|
||||||
|
else
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
local dependency_info = {}
|
||||||
|
for _, package in ipairs(installed_packages) do
|
||||||
|
r:and_then(await, luarocks_show(package.name, disp))
|
||||||
|
if r.ok then
|
||||||
|
dependency_info[package.name] = r.ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
r = r:map_ok(function()
|
||||||
|
local to_remove = {}
|
||||||
|
for _, package in ipairs(installed_packages) do
|
||||||
|
to_remove[package.name] = package
|
||||||
|
end
|
||||||
|
for _, rock in pairs(rocks) do
|
||||||
|
if type(rock) == 'table' then
|
||||||
|
if to_remove[rock[1]] and (not rock.version or to_remove[rock[1]].version == rock.version) then
|
||||||
|
to_remove[rock[1]] = nil
|
||||||
|
end
|
||||||
|
else
|
||||||
|
to_remove[rock] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for rock, dependencies in pairs(dependency_info) do
|
||||||
|
if rocks[rock] ~= nil then
|
||||||
|
for _, dependency in pairs(dependencies) do
|
||||||
|
to_remove[dependency] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Toposort to ensure that we remove packages before their dependencies
|
||||||
|
local removal_order = {}
|
||||||
|
local frontier = {}
|
||||||
|
for rock, _ in pairs(to_remove) do
|
||||||
|
if next(dependency_info[rock]) == nil then
|
||||||
|
frontier[#frontier + 1] = rock
|
||||||
|
dependency_info[rock] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local inverse_dependencies = {}
|
||||||
|
for rock, depends in pairs(dependency_info) do
|
||||||
|
for d, _ in pairs(depends) do
|
||||||
|
inverse_dependencies[d] = inverse_dependencies[d] or {}
|
||||||
|
inverse_dependencies[d][rock] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
while #frontier > 0 do
|
||||||
|
local rock = table.remove(frontier)
|
||||||
|
removal_order[#removal_order + 1] = rock
|
||||||
|
local inv_depends = inverse_dependencies[rock]
|
||||||
|
if inv_depends ~= nil then
|
||||||
|
for depends, _ in pairs(inverse_dependencies[rock]) do
|
||||||
|
table.remove(dependency_info[depends])
|
||||||
|
if #dependency_info[depends] == 0 then
|
||||||
|
frontier[#frontier + 1] = depends
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local reverse_order = {}
|
||||||
|
for i = #removal_order, 1, -1 do
|
||||||
|
reverse_order[#reverse_order + 1] = removal_order[i]
|
||||||
|
end
|
||||||
|
return reverse_order
|
||||||
|
end)
|
||||||
|
|
||||||
|
if results ~= nil then
|
||||||
|
results.luarocks = results.luarocks or {}
|
||||||
|
end
|
||||||
|
return r:and_then(await, uninstall_packages(r.ok, results, disp))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ensure_rocks(rocks, results, disp)
|
||||||
|
return async(function()
|
||||||
|
local to_install = {}
|
||||||
|
for _, rock in pairs(rocks) do
|
||||||
|
if type(rock) == 'table' then
|
||||||
|
to_install[rock[1]:lower()] = rock
|
||||||
|
else
|
||||||
|
to_install[rock:lower()] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local r = result.ok()
|
||||||
|
if next(to_install) == nil then
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
if disp == nil then
|
||||||
|
disp = require('packer.display').open(config.display.open_fn or config.display.open_cmd)
|
||||||
|
end
|
||||||
|
if not hererocks_is_setup() then
|
||||||
|
r = r:and_then(await, hererocks_installer(disp))
|
||||||
|
end
|
||||||
|
r:and_then(await, luarocks_list(disp))
|
||||||
|
r:map_ok(function(installed_packages)
|
||||||
|
for _, package in ipairs(installed_packages) do
|
||||||
|
local spec = to_install[package.name]
|
||||||
|
if spec then
|
||||||
|
if type(spec) == 'table' then
|
||||||
|
-- if the package is on the system and the spec has no version
|
||||||
|
-- or it has a version and that is the version on the system do not install it again
|
||||||
|
if not spec.version or (spec.version and spec.version == package.version) then
|
||||||
|
to_install[package.name] = nil
|
||||||
|
end
|
||||||
|
else
|
||||||
|
to_install[package.name] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local package_specs = {}
|
||||||
|
for name, spec in pairs(to_install) do
|
||||||
|
if type(spec) == 'table' then
|
||||||
|
table.insert(package_specs, spec)
|
||||||
|
else
|
||||||
|
table.insert(package_specs, { name })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return package_specs
|
||||||
|
end)
|
||||||
|
|
||||||
|
results.luarocks = results.luarocks or {}
|
||||||
|
return r:and_then(await, install_packages(r.ok, results, disp))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function handle_command(cmd, ...)
|
||||||
|
local task
|
||||||
|
local packages = { ... }
|
||||||
|
if cmd == 'install' then
|
||||||
|
task = install_packages(packages)
|
||||||
|
elseif cmd == 'remove' then
|
||||||
|
task = uninstall_packages(packages)
|
||||||
|
else
|
||||||
|
log.warn 'Unrecognized command!'
|
||||||
|
return result.err 'Unrecognized command'
|
||||||
|
end
|
||||||
|
|
||||||
|
return async(function()
|
||||||
|
local r = await(task)
|
||||||
|
await(a.main)
|
||||||
|
local package_names = vim.fn.escape(vim.inspect(packages), '"')
|
||||||
|
return r:map_ok(function(data)
|
||||||
|
local operation_name = cmd:sub(1, 1):upper() .. cmd:sub(2)
|
||||||
|
log.info(fmt('%sed packages %s', operation_name, package_names))
|
||||||
|
return data
|
||||||
|
end):map_err(function(err)
|
||||||
|
log.error(fmt('Failed to %s packages %s: %s', cmd, package_names, vim.fn.escape(vim.inspect(err), '"\n')))
|
||||||
|
return err
|
||||||
|
end)
|
||||||
|
end)()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function make_commands()
|
||||||
|
vim.cmd [[ command! -nargs=+ PackerRocks lua require('packer.luarocks').handle_command(<f-args>) ]]
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
handle_command = handle_command,
|
||||||
|
install_commands = make_commands,
|
||||||
|
list = luarocks_list,
|
||||||
|
install_hererocks = hererocks_installer,
|
||||||
|
setup_paths = setup_nvim_paths,
|
||||||
|
uninstall = uninstall_sync,
|
||||||
|
clean = clean_rocks,
|
||||||
|
install = install_sync,
|
||||||
|
ensure = ensure_rocks,
|
||||||
|
generate_path_setup = generate_path_setup_code,
|
||||||
|
cfg = cfg,
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
local config
|
||||||
|
|
||||||
|
local function cfg(_config)
|
||||||
|
config = _config
|
||||||
|
end
|
||||||
|
|
||||||
|
local plugin_types = setmetatable({ cfg = cfg }, {
|
||||||
|
__index = function(self, k)
|
||||||
|
local v = require('packer.plugin_types.' .. k)
|
||||||
|
v.cfg(config)
|
||||||
|
self[k] = v
|
||||||
|
return v
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
return plugin_types
|
|
@ -0,0 +1,565 @@
|
||||||
|
local util = require 'packer.util'
|
||||||
|
local jobs = require 'packer.jobs'
|
||||||
|
local a = require 'packer.async'
|
||||||
|
local result = require 'packer.result'
|
||||||
|
local log = require 'packer.log'
|
||||||
|
local await = a.wait
|
||||||
|
local async = a.sync
|
||||||
|
local fmt = string.format
|
||||||
|
|
||||||
|
local vim = vim
|
||||||
|
|
||||||
|
local git = {}
|
||||||
|
|
||||||
|
local blocked_env_vars = {
|
||||||
|
GIT_DIR = true,
|
||||||
|
GIT_INDEX_FILE = true,
|
||||||
|
GIT_OBJECT_DIRECTORY = true,
|
||||||
|
GIT_TERMINAL_PROMPT = true,
|
||||||
|
GIT_WORK_TREE = true,
|
||||||
|
GIT_COMMON_DIR = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
local function ensure_git_env()
|
||||||
|
if git.job_env == nil then
|
||||||
|
local job_env = {}
|
||||||
|
for k, v in pairs(vim.fn.environ()) do
|
||||||
|
if not blocked_env_vars[k] then
|
||||||
|
table.insert(job_env, k .. '=' .. v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(job_env, 'GIT_TERMINAL_PROMPT=0')
|
||||||
|
git.job_env = job_env
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function has_wildcard(tag)
|
||||||
|
if not tag then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return string.match(tag, '*') ~= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local break_tag_pattern = [=[[bB][rR][eE][aA][kK]!?:]=]
|
||||||
|
local breaking_change_pattern = [=[[bB][rR][eE][aA][kK][iI][nN][gG][ _][cC][hH][aA][nN][gG][eE]]=]
|
||||||
|
local type_exclam_pattern = [=[[a-zA-Z]+!:]=]
|
||||||
|
local type_scope_exclam_pattern = [=[[a-zA-Z]+%([^)]+%)!:]=]
|
||||||
|
local function mark_breaking_commits(plugin, commit_bodies)
|
||||||
|
local commits = vim.gsplit(table.concat(commit_bodies, '\n'), '===COMMIT_START===', true)
|
||||||
|
for commit in commits do
|
||||||
|
local commit_parts = vim.split(commit, '===BODY_START===')
|
||||||
|
local body = commit_parts[2]
|
||||||
|
local lines = vim.split(commit_parts[1], '\n')
|
||||||
|
local is_breaking = (
|
||||||
|
body ~= nil
|
||||||
|
and (
|
||||||
|
(string.match(body, breaking_change_pattern) ~= nil)
|
||||||
|
or (string.match(body, break_tag_pattern) ~= nil)
|
||||||
|
or (string.match(body, type_exclam_pattern) ~= nil)
|
||||||
|
or (string.match(body, type_scope_exclam_pattern) ~= nil)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
or (
|
||||||
|
lines[2] ~= nil
|
||||||
|
and (
|
||||||
|
(string.match(lines[2], breaking_change_pattern) ~= nil)
|
||||||
|
or (string.match(lines[2], break_tag_pattern) ~= nil)
|
||||||
|
or (string.match(lines[2], type_exclam_pattern) ~= nil)
|
||||||
|
or (string.match(lines[2], type_scope_exclam_pattern) ~= nil)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if is_breaking then
|
||||||
|
plugin.breaking_commits[#plugin.breaking_commits + 1] = lines[1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local config = nil
|
||||||
|
git.cfg = function(_config)
|
||||||
|
config = _config.git
|
||||||
|
config.base_dir = _config.package_root
|
||||||
|
config.default_base_dir = util.join_paths(config.base_dir, _config.plugin_package)
|
||||||
|
config.exec_cmd = config.cmd .. ' '
|
||||||
|
ensure_git_env()
|
||||||
|
end
|
||||||
|
|
||||||
|
---Resets a git repo `dest` to `commit`
|
||||||
|
---@param dest string @ path to the local git repo
|
||||||
|
---@param commit string @ commit hash
|
||||||
|
---@return function @ async function
|
||||||
|
local function reset(dest, commit)
|
||||||
|
local reset_cmd = fmt(config.exec_cmd .. config.subcommands.revert_to, commit)
|
||||||
|
local opts = { capture_output = true, cwd = dest, options = { env = git.job_env } }
|
||||||
|
return async(function()
|
||||||
|
return await(jobs.run(reset_cmd, opts))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local handle_checkouts = function(plugin, dest, disp, opts)
|
||||||
|
local plugin_name = util.get_plugin_full_name(plugin)
|
||||||
|
return async(function()
|
||||||
|
if disp ~= nil then
|
||||||
|
disp:task_update(plugin_name, 'fetching reference...')
|
||||||
|
end
|
||||||
|
local output = jobs.output_table()
|
||||||
|
local callbacks = {
|
||||||
|
stdout = jobs.logging_callback(output.err.stdout, output.data.stdout, nil, disp, plugin_name),
|
||||||
|
stderr = jobs.logging_callback(output.err.stderr, output.data.stderr),
|
||||||
|
}
|
||||||
|
|
||||||
|
local job_opts = { capture_output = callbacks, cwd = dest, options = { env = git.job_env } }
|
||||||
|
|
||||||
|
local r = result.ok()
|
||||||
|
|
||||||
|
if plugin.tag and has_wildcard(plugin.tag) then
|
||||||
|
disp:task_update(plugin_name, fmt('getting tag for wildcard %s...', plugin.tag))
|
||||||
|
local fetch_tags = config.exec_cmd .. fmt(config.subcommands.tags_expand_fmt, plugin.tag)
|
||||||
|
r:and_then(await, jobs.run(fetch_tags, job_opts))
|
||||||
|
local data = output.data.stdout[1]
|
||||||
|
if data then
|
||||||
|
plugin.tag = vim.split(data, '\n')[1]
|
||||||
|
else
|
||||||
|
log.warn(
|
||||||
|
fmt('Wildcard expansion did not found any tag for plugin %s: defaulting to latest commit...', plugin.name)
|
||||||
|
)
|
||||||
|
plugin.tag = nil -- Wildcard is not found, then we bypass the tag
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.branch or (plugin.tag and not opts.preview_updates) then
|
||||||
|
local branch_or_tag = plugin.branch and plugin.branch or plugin.tag
|
||||||
|
if disp ~= nil then
|
||||||
|
disp:task_update(plugin_name, fmt('checking out %s %s...', plugin.branch and 'branch' or 'tag', branch_or_tag))
|
||||||
|
end
|
||||||
|
r:and_then(await, jobs.run(config.exec_cmd .. fmt(config.subcommands.checkout, branch_or_tag), job_opts))
|
||||||
|
:map_err(function(err)
|
||||||
|
return {
|
||||||
|
msg = fmt(
|
||||||
|
'Error checking out %s %s for %s',
|
||||||
|
plugin.branch and 'branch' or 'tag',
|
||||||
|
branch_or_tag,
|
||||||
|
plugin_name
|
||||||
|
),
|
||||||
|
data = err,
|
||||||
|
output = output,
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.commit then
|
||||||
|
if disp ~= nil then
|
||||||
|
disp:task_update(plugin_name, fmt('checking out %s...', plugin.commit))
|
||||||
|
end
|
||||||
|
r:and_then(await, jobs.run(config.exec_cmd .. fmt(config.subcommands.checkout, plugin.commit), job_opts))
|
||||||
|
:map_err(function(err)
|
||||||
|
return {
|
||||||
|
msg = fmt('Error checking out commit %s for %s', plugin.commit, plugin_name),
|
||||||
|
data = err,
|
||||||
|
output = output,
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return r:map_ok(function(ok)
|
||||||
|
return { status = ok, output = output }
|
||||||
|
end):map_err(function(err)
|
||||||
|
if not err.msg then
|
||||||
|
return {
|
||||||
|
msg = fmt('Error updating %s: %s', plugin_name, table.concat(err, '\n')),
|
||||||
|
data = err,
|
||||||
|
output = output,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
err.output = output
|
||||||
|
return err
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local get_rev = function(plugin)
|
||||||
|
local plugin_name = util.get_plugin_full_name(plugin)
|
||||||
|
|
||||||
|
local rev_cmd = config.exec_cmd .. config.subcommands.get_rev
|
||||||
|
|
||||||
|
return async(function()
|
||||||
|
local rev = await(jobs.run(rev_cmd, { cwd = plugin.install_path, options = { env = git.job_env }, capture_output = true }))
|
||||||
|
:map_ok(function(ok)
|
||||||
|
local _, r = next(ok.output.data.stdout)
|
||||||
|
return r
|
||||||
|
end)
|
||||||
|
:map_err(function(err)
|
||||||
|
local _, msg = fmt('%s: %s', plugin_name, next(err.output.data.stderr))
|
||||||
|
return msg
|
||||||
|
end)
|
||||||
|
|
||||||
|
return rev
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local split_messages = function(messages)
|
||||||
|
local lines = {}
|
||||||
|
for _, message in ipairs(messages) do
|
||||||
|
vim.list_extend(lines, vim.split(message, '\n'))
|
||||||
|
table.insert(lines, '')
|
||||||
|
end
|
||||||
|
return lines
|
||||||
|
end
|
||||||
|
|
||||||
|
git.setup = function(plugin)
|
||||||
|
local plugin_name = util.get_plugin_full_name(plugin)
|
||||||
|
local install_to = plugin.install_path
|
||||||
|
local install_cmd =
|
||||||
|
vim.split(config.exec_cmd .. fmt(config.subcommands.install, plugin.commit and 999999 or config.depth), '%s+')
|
||||||
|
|
||||||
|
local submodule_cmd = config.exec_cmd .. config.subcommands.submodules
|
||||||
|
local rev_cmd = config.exec_cmd .. config.subcommands.get_rev
|
||||||
|
local update_cmd = config.exec_cmd .. config.subcommands.update
|
||||||
|
local update_head_cmd = config.exec_cmd .. config.subcommands.update_head
|
||||||
|
local fetch_cmd = config.exec_cmd .. config.subcommands.fetch
|
||||||
|
if plugin.commit or plugin.tag then
|
||||||
|
update_cmd = fetch_cmd
|
||||||
|
end
|
||||||
|
|
||||||
|
local branch_cmd = config.exec_cmd .. config.subcommands.current_branch
|
||||||
|
local current_commit_cmd = vim.split(config.exec_cmd .. config.subcommands.get_header, '%s+')
|
||||||
|
for i, arg in ipairs(current_commit_cmd) do
|
||||||
|
current_commit_cmd[i] = string.gsub(arg, 'FMT', config.subcommands.diff_fmt)
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.branch or (plugin.tag and not has_wildcard(plugin.tag)) then
|
||||||
|
install_cmd[#install_cmd + 1] = '--branch'
|
||||||
|
install_cmd[#install_cmd + 1] = plugin.branch and plugin.branch or plugin.tag
|
||||||
|
end
|
||||||
|
|
||||||
|
install_cmd[#install_cmd + 1] = plugin.url
|
||||||
|
install_cmd[#install_cmd + 1] = install_to
|
||||||
|
|
||||||
|
local needs_checkout = plugin.tag ~= nil or plugin.commit ~= nil or plugin.branch ~= nil
|
||||||
|
|
||||||
|
plugin.installer = function(disp)
|
||||||
|
local output = jobs.output_table()
|
||||||
|
local callbacks = {
|
||||||
|
stdout = jobs.logging_callback(output.err.stdout, output.data.stdout),
|
||||||
|
stderr = jobs.logging_callback(output.err.stderr, output.data.stderr, nil, disp, plugin_name),
|
||||||
|
}
|
||||||
|
|
||||||
|
local installer_opts = {
|
||||||
|
capture_output = callbacks,
|
||||||
|
timeout = config.clone_timeout,
|
||||||
|
options = { env = git.job_env },
|
||||||
|
}
|
||||||
|
|
||||||
|
return async(function()
|
||||||
|
disp:task_update(plugin_name, 'cloning...')
|
||||||
|
local r = await(jobs.run(install_cmd, installer_opts))
|
||||||
|
|
||||||
|
installer_opts.cwd = install_to
|
||||||
|
r:and_then(await, jobs.run(submodule_cmd, installer_opts))
|
||||||
|
|
||||||
|
if plugin.commit then
|
||||||
|
disp:task_update(plugin_name, fmt('checking out %s...', plugin.commit))
|
||||||
|
r:and_then(await, jobs.run(config.exec_cmd .. fmt(config.subcommands.checkout, plugin.commit), installer_opts))
|
||||||
|
:map_err(function(err)
|
||||||
|
return {
|
||||||
|
msg = fmt('Error checking out commit %s for %s', plugin.commit, plugin_name),
|
||||||
|
data = { err, output },
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
r:and_then(await, jobs.run(current_commit_cmd, installer_opts))
|
||||||
|
:map_ok(function(_)
|
||||||
|
plugin.messages = output.data.stdout
|
||||||
|
end)
|
||||||
|
:map_err(function(err)
|
||||||
|
plugin.output = { err = output.data.stderr }
|
||||||
|
if not err.msg then
|
||||||
|
return {
|
||||||
|
msg = fmt('Error installing %s: %s', plugin_name, table.concat(output.data.stderr, '\n')),
|
||||||
|
data = { err, output },
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
return r
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin.remote_url = function()
|
||||||
|
return async(function()
|
||||||
|
return await(
|
||||||
|
jobs.run(
|
||||||
|
fmt('%s remote get-url origin', config.exec_cmd),
|
||||||
|
{ capture_output = true, cwd = plugin.install_path, options = { env = git.job_env } }
|
||||||
|
)
|
||||||
|
):map_ok(function(data)
|
||||||
|
return { remote = data.output.data.stdout[1] }
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin.updater = function(disp, opts)
|
||||||
|
return async(function()
|
||||||
|
local update_info = { err = {}, revs = {}, output = {}, messages = {} }
|
||||||
|
local function exit_ok(r)
|
||||||
|
if #update_info.err > 0 or r.exit_code ~= 0 then
|
||||||
|
return result.err(r)
|
||||||
|
end
|
||||||
|
return result.ok(r)
|
||||||
|
end
|
||||||
|
|
||||||
|
local rev_onread = jobs.logging_callback(update_info.err, update_info.revs)
|
||||||
|
local rev_callbacks = { stdout = rev_onread, stderr = rev_onread }
|
||||||
|
disp:task_update(plugin_name, 'checking current commit...')
|
||||||
|
local r = await(
|
||||||
|
jobs.run(
|
||||||
|
rev_cmd,
|
||||||
|
{ success_test = exit_ok, capture_output = rev_callbacks, cwd = install_to, options = { env = git.job_env } }
|
||||||
|
)
|
||||||
|
):map_err(function(err)
|
||||||
|
plugin.output = { err = vim.list_extend(update_info.err, update_info.revs), data = {} }
|
||||||
|
|
||||||
|
return {
|
||||||
|
msg = fmt('Error getting current commit for %s: %s', plugin_name, table.concat(update_info.revs, '\n')),
|
||||||
|
data = err,
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
local current_branch
|
||||||
|
disp:task_update(plugin_name, 'checking current branch...')
|
||||||
|
r:and_then(
|
||||||
|
await,
|
||||||
|
jobs.run(
|
||||||
|
branch_cmd,
|
||||||
|
{ success_test = exit_ok, capture_output = true, cwd = install_to, options = { env = git.job_env } }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
:map_ok(function(ok)
|
||||||
|
current_branch = ok.output.data.stdout[1]
|
||||||
|
end)
|
||||||
|
:map_err(function(err)
|
||||||
|
plugin.output = { err = vim.list_extend(update_info.err, update_info.revs), data = {} }
|
||||||
|
|
||||||
|
return {
|
||||||
|
msg = fmt('Error checking current branch for %s: %s', plugin_name, table.concat(update_info.revs, '\n')),
|
||||||
|
data = err,
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
if not needs_checkout then
|
||||||
|
local origin_branch = ''
|
||||||
|
disp:task_update(plugin_name, 'checking origin branch...')
|
||||||
|
local origin_refs_path = util.join_paths(install_to, '.git', 'refs', 'remotes', 'origin', 'HEAD')
|
||||||
|
local origin_refs_file = vim.loop.fs_open(origin_refs_path, 'r', 438)
|
||||||
|
if origin_refs_file ~= nil then
|
||||||
|
local origin_refs_stat = vim.loop.fs_fstat(origin_refs_file)
|
||||||
|
-- NOTE: This should check for errors
|
||||||
|
local origin_refs = vim.split(vim.loop.fs_read(origin_refs_file, origin_refs_stat.size, 0), '\n')
|
||||||
|
vim.loop.fs_close(origin_refs_file)
|
||||||
|
if #origin_refs > 0 then
|
||||||
|
origin_branch = string.match(origin_refs[1], [[^ref: refs/remotes/origin/(.*)]])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if current_branch ~= origin_branch then
|
||||||
|
needs_checkout = true
|
||||||
|
plugin.branch = origin_branch
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local update_callbacks = {
|
||||||
|
stdout = jobs.logging_callback(update_info.err, update_info.output),
|
||||||
|
stderr = jobs.logging_callback(update_info.err, update_info.output, nil, disp, plugin_name),
|
||||||
|
}
|
||||||
|
local update_opts = {
|
||||||
|
success_test = exit_ok,
|
||||||
|
capture_output = update_callbacks,
|
||||||
|
cwd = install_to,
|
||||||
|
options = { env = git.job_env },
|
||||||
|
}
|
||||||
|
|
||||||
|
if needs_checkout then
|
||||||
|
r:and_then(await, jobs.run(config.exec_cmd .. config.subcommands.fetch, update_opts))
|
||||||
|
r:and_then(await, handle_checkouts(plugin, install_to, disp, opts))
|
||||||
|
local function merge_output(res)
|
||||||
|
if res.output ~= nil then
|
||||||
|
vim.list_extend(update_info.err, res.output.err.stderr)
|
||||||
|
vim.list_extend(update_info.err, res.output.err.stdout)
|
||||||
|
vim.list_extend(update_info.output, res.output.data.stdout)
|
||||||
|
vim.list_extend(update_info.output, res.output.data.stderr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
r:map_ok(merge_output)
|
||||||
|
r:map_err(function(err)
|
||||||
|
merge_output(err)
|
||||||
|
plugin.output = { err = vim.list_extend(update_info.err, update_info.output), data = {} }
|
||||||
|
local errmsg = '<unknown error>'
|
||||||
|
if err ~= nil and err.msg ~= nil then
|
||||||
|
errmsg = err.msg
|
||||||
|
end
|
||||||
|
return { msg = errmsg .. ' ' .. table.concat(update_info.output, '\n'), data = err.data }
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
if opts.preview_updates then
|
||||||
|
disp:task_update(plugin_name, 'fetching updates...')
|
||||||
|
r:and_then(await, jobs.run(fetch_cmd, update_opts))
|
||||||
|
elseif opts.pull_head then
|
||||||
|
disp:task_update(plugin_name, 'pulling updates from head...')
|
||||||
|
r:and_then(await, jobs.run(update_head_cmd, update_opts))
|
||||||
|
else
|
||||||
|
disp:task_update(plugin_name, 'pulling updates...')
|
||||||
|
r:and_then(await, jobs.run(update_cmd, update_opts)):and_then(await, jobs.run(submodule_cmd, update_opts))
|
||||||
|
end
|
||||||
|
r:map_err(function(err)
|
||||||
|
plugin.output = { err = vim.list_extend(update_info.err, update_info.output), data = {} }
|
||||||
|
|
||||||
|
return {
|
||||||
|
msg = fmt('Error getting updates for %s: %s', plugin_name, table.concat(update_info.output, '\n')),
|
||||||
|
data = err,
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
local post_rev_cmd
|
||||||
|
if plugin.tag ~= nil then
|
||||||
|
-- NOTE that any tag wildcard should already been expanded to a specific commit at this point
|
||||||
|
post_rev_cmd = string.gsub(rev_cmd, 'HEAD', string.format('%s^{}', plugin.tag))
|
||||||
|
elseif opts.preview_updates then
|
||||||
|
post_rev_cmd = string.gsub(rev_cmd, 'HEAD', 'FETCH_HEAD')
|
||||||
|
else
|
||||||
|
post_rev_cmd = rev_cmd
|
||||||
|
end
|
||||||
|
disp:task_update(plugin_name, 'checking updated commit...')
|
||||||
|
r:and_then(
|
||||||
|
await,
|
||||||
|
jobs.run(post_rev_cmd, {
|
||||||
|
success_test = exit_ok,
|
||||||
|
capture_output = rev_callbacks,
|
||||||
|
cwd = install_to,
|
||||||
|
options = { env = git.job_env },
|
||||||
|
})
|
||||||
|
):map_err(function(err)
|
||||||
|
plugin.output = { err = vim.list_extend(update_info.err, update_info.revs), data = {} }
|
||||||
|
return {
|
||||||
|
msg = fmt('Error checking updated commit for %s: %s', plugin_name, table.concat(update_info.revs, '\n')),
|
||||||
|
data = err,
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
if r.ok then
|
||||||
|
if update_info.revs[1] ~= update_info.revs[2] then
|
||||||
|
local commit_headers_onread = jobs.logging_callback(update_info.err, update_info.messages)
|
||||||
|
local commit_headers_callbacks = { stdout = commit_headers_onread, stderr = commit_headers_onread }
|
||||||
|
|
||||||
|
local diff_cmd = string.format(config.subcommands.diff, update_info.revs[1], update_info.revs[2])
|
||||||
|
local commit_headers_cmd = vim.split(config.exec_cmd .. diff_cmd, '%s+')
|
||||||
|
for i, arg in ipairs(commit_headers_cmd) do
|
||||||
|
commit_headers_cmd[i] = string.gsub(arg, 'FMT', config.subcommands.diff_fmt)
|
||||||
|
end
|
||||||
|
|
||||||
|
disp:task_update(plugin_name, 'getting commit messages...')
|
||||||
|
r:and_then(
|
||||||
|
await,
|
||||||
|
jobs.run(commit_headers_cmd, {
|
||||||
|
success_test = exit_ok,
|
||||||
|
capture_output = commit_headers_callbacks,
|
||||||
|
cwd = install_to,
|
||||||
|
options = { env = git.job_env },
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
plugin.output = { err = update_info.err, data = update_info.output }
|
||||||
|
if r.ok then
|
||||||
|
plugin.messages = update_info.messages
|
||||||
|
plugin.revs = update_info.revs
|
||||||
|
end
|
||||||
|
|
||||||
|
if config.mark_breaking_changes then
|
||||||
|
local commit_bodies = { err = {}, output = {} }
|
||||||
|
local commit_bodies_onread = jobs.logging_callback(commit_bodies.err, commit_bodies.output)
|
||||||
|
local commit_bodies_callbacks = { stdout = commit_bodies_onread, stderr = commit_bodies_onread }
|
||||||
|
local commit_bodies_cmd = config.exec_cmd .. config.subcommands.get_bodies
|
||||||
|
if opts.preview_updates then
|
||||||
|
commit_bodies_cmd = config.exec_cmd .. config.subcommands.get_fetch_bodies
|
||||||
|
end
|
||||||
|
disp:task_update(plugin_name, 'checking for breaking changes...')
|
||||||
|
r:and_then(
|
||||||
|
await,
|
||||||
|
jobs.run(commit_bodies_cmd, {
|
||||||
|
success_test = exit_ok,
|
||||||
|
capture_output = commit_bodies_callbacks,
|
||||||
|
cwd = install_to,
|
||||||
|
options = { env = git.job_env },
|
||||||
|
})
|
||||||
|
):map_ok(function(ok)
|
||||||
|
plugin.breaking_commits = {}
|
||||||
|
mark_breaking_commits(plugin, commit_bodies.output)
|
||||||
|
return ok
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
plugin.revs = update_info.revs
|
||||||
|
plugin.messages = update_info.messages
|
||||||
|
end
|
||||||
|
else
|
||||||
|
plugin.output.err = vim.list_extend(plugin.output.err, update_info.messages)
|
||||||
|
end
|
||||||
|
|
||||||
|
r.info = update_info
|
||||||
|
return r
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin.diff = function(commit, callback)
|
||||||
|
async(function()
|
||||||
|
local diff_cmd = config.exec_cmd .. fmt(config.subcommands.git_diff_fmt, commit)
|
||||||
|
local diff_info = { err = {}, output = {}, messages = {} }
|
||||||
|
local diff_onread = jobs.logging_callback(diff_info.err, diff_info.messages)
|
||||||
|
local diff_callbacks = { stdout = diff_onread, stderr = diff_onread }
|
||||||
|
return await(jobs.run(diff_cmd, { capture_output = diff_callbacks, cwd = install_to, options = { env = git.job_env } }))
|
||||||
|
:map_ok(function(_)
|
||||||
|
return callback(split_messages(diff_info.messages))
|
||||||
|
end)
|
||||||
|
:map_err(function(err)
|
||||||
|
return callback(nil, err)
|
||||||
|
end)
|
||||||
|
end)()
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin.revert_last = function()
|
||||||
|
local r = result.ok()
|
||||||
|
async(function()
|
||||||
|
local revert_cmd = config.exec_cmd .. config.subcommands.revert
|
||||||
|
r:and_then(
|
||||||
|
await,
|
||||||
|
jobs.run(revert_cmd, { capture_output = true, cwd = install_to, options = { env = git.job_env } })
|
||||||
|
)
|
||||||
|
if needs_checkout then
|
||||||
|
r:and_then(await, handle_checkouts(plugin, install_to, nil, {}))
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end)()
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
---Reset the plugin to `commit`
|
||||||
|
---@param commit string
|
||||||
|
plugin.revert_to = function(commit)
|
||||||
|
assert(type(commit) == 'string', fmt("commit: string expected but '%s' provided", type(commit)))
|
||||||
|
return async(function()
|
||||||
|
require('packer.log').debug(fmt("Reverting '%s' to commit '%s'", plugin.name, commit))
|
||||||
|
return await(reset(install_to, commit))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Returns HEAD's short hash
|
||||||
|
---@return string
|
||||||
|
plugin.get_rev = function()
|
||||||
|
return get_rev(plugin)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return git
|
|
@ -0,0 +1,69 @@
|
||||||
|
local a = require 'packer.async'
|
||||||
|
local log = require 'packer.log'
|
||||||
|
local util = require 'packer.util'
|
||||||
|
local result = require 'packer.result'
|
||||||
|
|
||||||
|
local async = a.sync
|
||||||
|
local await = a.wait
|
||||||
|
local fmt = string.format
|
||||||
|
|
||||||
|
local config = nil
|
||||||
|
local function cfg(_config)
|
||||||
|
config = _config
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Due to #679, we know that fs_symlink requires admin privileges on Windows. This is a workaround,
|
||||||
|
-- as suggested by @nonsleepr.
|
||||||
|
|
||||||
|
local symlink_fn
|
||||||
|
if util.is_windows then
|
||||||
|
symlink_fn = function(path, new_path, flags, callback)
|
||||||
|
flags = flags or {}
|
||||||
|
flags.junction = true
|
||||||
|
return vim.loop.fs_symlink(path, new_path, flags, callback)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
symlink_fn = vim.loop.fs_symlink
|
||||||
|
end
|
||||||
|
|
||||||
|
local symlink = a.wrap(symlink_fn)
|
||||||
|
local unlink = a.wrap(vim.loop.fs_unlink)
|
||||||
|
|
||||||
|
local function setup_local(plugin)
|
||||||
|
local from = vim.loop.fs_realpath(util.strip_trailing_sep(plugin.path))
|
||||||
|
local to = util.strip_trailing_sep(plugin.install_path)
|
||||||
|
|
||||||
|
local plugin_name = util.get_plugin_full_name(plugin)
|
||||||
|
plugin.installer = function(disp)
|
||||||
|
return async(function()
|
||||||
|
disp:task_update(plugin_name, 'making symlink...')
|
||||||
|
local err, success = await(symlink(from, to, { dir = true }))
|
||||||
|
if not success then
|
||||||
|
plugin.output = { err = { err } }
|
||||||
|
return result.err(err)
|
||||||
|
end
|
||||||
|
return result.ok()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin.updater = function(disp)
|
||||||
|
return async(function()
|
||||||
|
local r = result.ok()
|
||||||
|
disp:task_update(plugin_name, 'checking symlink...')
|
||||||
|
local resolved_path = vim.loop.fs_realpath(to)
|
||||||
|
if resolved_path ~= from then
|
||||||
|
disp:task_update(plugin_name, 'updating symlink...')
|
||||||
|
r = await(unlink(to)):and_then(symlink(from, to, { dir = true }))
|
||||||
|
end
|
||||||
|
|
||||||
|
return r
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin.revert_last = function(_)
|
||||||
|
log.warn "Can't revert a local plugin!"
|
||||||
|
return result.ok()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return { setup = setup_local, cfg = cfg }
|
|
@ -0,0 +1,287 @@
|
||||||
|
local a = require 'packer.async'
|
||||||
|
local jobs = require 'packer.jobs'
|
||||||
|
local util = require 'packer.util'
|
||||||
|
local result = require 'packer.result'
|
||||||
|
local log = require 'packer.log'
|
||||||
|
|
||||||
|
local await = a.wait
|
||||||
|
|
||||||
|
local config = nil
|
||||||
|
local plugin_utils = {}
|
||||||
|
plugin_utils.cfg = function(_config)
|
||||||
|
config = _config
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin_utils.custom_plugin_type = 'custom'
|
||||||
|
plugin_utils.local_plugin_type = 'local'
|
||||||
|
plugin_utils.git_plugin_type = 'git'
|
||||||
|
|
||||||
|
plugin_utils.guess_type = function(plugin)
|
||||||
|
if plugin.installer then
|
||||||
|
plugin.type = plugin_utils.custom_plugin_type
|
||||||
|
elseif vim.fn.isdirectory(plugin.path) ~= 0 then
|
||||||
|
plugin.url = plugin.path
|
||||||
|
plugin.type = plugin_utils.local_plugin_type
|
||||||
|
elseif
|
||||||
|
string.sub(plugin.path, 1, 6) == 'git://'
|
||||||
|
or string.sub(plugin.path, 1, 4) == 'http'
|
||||||
|
or string.match(plugin.path, '@')
|
||||||
|
then
|
||||||
|
plugin.url = plugin.path
|
||||||
|
plugin.type = plugin_utils.git_plugin_type
|
||||||
|
else
|
||||||
|
local path = table.concat(vim.split(plugin.path, '\\', true), '/')
|
||||||
|
plugin.url = string.format(config.git.default_url_format, path)
|
||||||
|
plugin.type = plugin_utils.git_plugin_type
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin_utils.guess_dir_type = function(dir)
|
||||||
|
local globdir = vim.fn.glob(dir)
|
||||||
|
local dir_type = (vim.loop.fs_lstat(globdir) or { type = 'noexist' }).type
|
||||||
|
|
||||||
|
--[[ NOTE: We're assuming here that:
|
||||||
|
1. users only create custom plugins for non-git repos;
|
||||||
|
2. custom plugins don't use symlinks to install;
|
||||||
|
otherwise, there's no consistent way to tell from a dir alone… ]]
|
||||||
|
if dir_type == 'link' then
|
||||||
|
return plugin_utils.local_plugin_type
|
||||||
|
elseif vim.loop.fs_stat(globdir .. '/.git') then
|
||||||
|
return plugin_utils.git_plugin_type
|
||||||
|
elseif dir_type ~= 'noexist' then
|
||||||
|
return plugin_utils.custom_plugin_type
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin_utils.helptags_stale = function(dir)
|
||||||
|
-- Adapted directly from minpac.vim
|
||||||
|
local txts = vim.fn.glob(util.join_paths(dir, '*.txt'), true, true)
|
||||||
|
vim.list_extend(txts, vim.fn.glob(util.join_paths(dir, '*.[a-z][a-z]x'), true, true))
|
||||||
|
local tags = vim.fn.glob(util.join_paths(dir, 'tags'), true, true)
|
||||||
|
vim.list_extend(tags, vim.fn.glob(util.join_paths(dir, 'tags-[a-z][a-z]'), true, true))
|
||||||
|
local txt_ftimes = util.map(vim.fn.getftime, txts)
|
||||||
|
local tag_ftimes = util.map(vim.fn.getftime, tags)
|
||||||
|
if #txt_ftimes == 0 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if #tag_ftimes == 0 then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
local txt_newest = math.max(unpack(txt_ftimes))
|
||||||
|
local tag_oldest = math.min(unpack(tag_ftimes))
|
||||||
|
return txt_newest > tag_oldest
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin_utils.update_helptags = vim.schedule_wrap(function(...)
|
||||||
|
for _, dir in ipairs(...) do
|
||||||
|
local doc_dir = util.join_paths(dir, 'doc')
|
||||||
|
if plugin_utils.helptags_stale(doc_dir) then
|
||||||
|
log.info('Updating helptags for ' .. doc_dir)
|
||||||
|
vim.cmd('silent! helptags ' .. vim.fn.fnameescape(doc_dir))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
plugin_utils.update_rplugins = vim.schedule_wrap(function()
|
||||||
|
if vim.fn.exists ':UpdateRemotePlugins' == 2 then
|
||||||
|
vim.cmd [[silent UpdateRemotePlugins]]
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
plugin_utils.ensure_dirs = function()
|
||||||
|
if vim.fn.isdirectory(config.opt_dir) == 0 then
|
||||||
|
vim.fn.mkdir(config.opt_dir, 'p')
|
||||||
|
end
|
||||||
|
|
||||||
|
if vim.fn.isdirectory(config.start_dir) == 0 then
|
||||||
|
vim.fn.mkdir(config.start_dir, 'p')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin_utils.list_installed_plugins = function()
|
||||||
|
local opt_plugins = {}
|
||||||
|
local start_plugins = {}
|
||||||
|
local opt_dir_handle = vim.loop.fs_opendir(config.opt_dir, nil, 50)
|
||||||
|
if opt_dir_handle then
|
||||||
|
local opt_dir_items = vim.loop.fs_readdir(opt_dir_handle)
|
||||||
|
while opt_dir_items do
|
||||||
|
for _, item in ipairs(opt_dir_items) do
|
||||||
|
opt_plugins[util.join_paths(config.opt_dir, item.name)] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
opt_dir_items = vim.loop.fs_readdir(opt_dir_handle)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local start_dir_handle = vim.loop.fs_opendir(config.start_dir, nil, 50)
|
||||||
|
if start_dir_handle then
|
||||||
|
local start_dir_items = vim.loop.fs_readdir(start_dir_handle)
|
||||||
|
while start_dir_items do
|
||||||
|
for _, item in ipairs(start_dir_items) do
|
||||||
|
start_plugins[util.join_paths(config.start_dir, item.name)] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
start_dir_items = vim.loop.fs_readdir(start_dir_handle)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return opt_plugins, start_plugins
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin_utils.find_missing_plugins = function(plugins, opt_plugins, start_plugins)
|
||||||
|
return a.sync(function()
|
||||||
|
if opt_plugins == nil or start_plugins == nil then
|
||||||
|
opt_plugins, start_plugins = plugin_utils.list_installed_plugins()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- NOTE/TODO: In the case of a plugin gaining/losing an alias, this will force a clean and
|
||||||
|
-- reinstall
|
||||||
|
local missing_plugins = {}
|
||||||
|
for _, plugin_name in ipairs(vim.tbl_keys(plugins)) do
|
||||||
|
local plugin = plugins[plugin_name]
|
||||||
|
if not plugin.disable then
|
||||||
|
local plugin_path = util.join_paths(config[plugin.opt and 'opt_dir' or 'start_dir'], plugin.short_name)
|
||||||
|
local plugin_installed = (plugin.opt and opt_plugins or start_plugins)[plugin_path]
|
||||||
|
|
||||||
|
await(a.main)
|
||||||
|
local guessed_type = plugin_utils.guess_dir_type(plugin_path)
|
||||||
|
if not plugin_installed or plugin.type ~= guessed_type then
|
||||||
|
missing_plugins[plugin_name] = true
|
||||||
|
elseif guessed_type == plugin_utils.git_plugin_type then
|
||||||
|
local r = await(plugin.remote_url())
|
||||||
|
local remote = r.ok and r.ok.remote or nil
|
||||||
|
if remote then
|
||||||
|
-- Form a Github-style user/repo string
|
||||||
|
local parts = vim.split(remote, '[:/]')
|
||||||
|
local repo_name = parts[#parts - 1] .. '/' .. parts[#parts]
|
||||||
|
repo_name = repo_name:gsub('%.git', '')
|
||||||
|
|
||||||
|
-- Also need to test for "full URL" plugin names, but normalized to get rid of the
|
||||||
|
-- protocol
|
||||||
|
local normalized_remote = remote:gsub('https://', ''):gsub('ssh://git@', '')
|
||||||
|
local normalized_plugin_name = plugin.name:gsub('https://', ''):gsub('ssh://git@', ''):gsub('\\', '/')
|
||||||
|
if (normalized_remote ~= normalized_plugin_name) and (repo_name ~= normalized_plugin_name) then
|
||||||
|
missing_plugins[plugin_name] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return missing_plugins
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin_utils.get_fs_state = function(plugins)
|
||||||
|
log.debug 'Updating FS state'
|
||||||
|
local opt_plugins, start_plugins = plugin_utils.list_installed_plugins()
|
||||||
|
return a.sync(function()
|
||||||
|
local missing_plugins = await(plugin_utils.find_missing_plugins(plugins, opt_plugins, start_plugins))
|
||||||
|
return { opt = opt_plugins, start = start_plugins, missing = missing_plugins }
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin_utils.load_plugin = function(plugin)
|
||||||
|
if plugin.opt then
|
||||||
|
vim.cmd('packadd ' .. plugin.short_name)
|
||||||
|
else
|
||||||
|
vim.o.runtimepath = vim.o.runtimepath .. ',' .. plugin.install_path
|
||||||
|
for _, pat in ipairs {
|
||||||
|
table.concat({ 'plugin', '**/*.vim' }, util.get_separator()),
|
||||||
|
table.concat({ 'after', 'plugin', '**/*.vim' }, util.get_separator()),
|
||||||
|
} do
|
||||||
|
local path = util.join_paths(plugin.install_path, pat)
|
||||||
|
local glob_ok, files = pcall(vim.fn.glob, path, false, true)
|
||||||
|
if not glob_ok then
|
||||||
|
if string.find(files, 'E77') then
|
||||||
|
vim.cmd('silent exe "source ' .. path .. '"')
|
||||||
|
else
|
||||||
|
error(files)
|
||||||
|
end
|
||||||
|
elseif #files > 0 then
|
||||||
|
for _, file in ipairs(files) do
|
||||||
|
file = file:gsub('\\', '/')
|
||||||
|
vim.cmd('silent exe "source ' .. file .. '"')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
plugin_utils.post_update_hook = function(plugin, disp)
|
||||||
|
local plugin_name = util.get_plugin_full_name(plugin)
|
||||||
|
return a.sync(function()
|
||||||
|
if plugin.run or not plugin.opt then
|
||||||
|
await(a.main)
|
||||||
|
plugin_utils.load_plugin(plugin)
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.run then
|
||||||
|
if type(plugin.run) ~= 'table' then
|
||||||
|
plugin.run = { plugin.run }
|
||||||
|
end
|
||||||
|
disp:task_update(plugin_name, 'running post update hooks...')
|
||||||
|
local hook_result = result.ok()
|
||||||
|
for _, task in ipairs(plugin.run) do
|
||||||
|
if type(task) == 'function' then
|
||||||
|
local success, err = pcall(task, plugin, disp)
|
||||||
|
if not success then
|
||||||
|
return result.err {
|
||||||
|
msg = 'Error running post update hook: ' .. vim.inspect(err),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
elseif type(task) == 'string' then
|
||||||
|
if string.sub(task, 1, 1) == ':' then
|
||||||
|
await(a.main)
|
||||||
|
vim.cmd(string.sub(task, 2))
|
||||||
|
else
|
||||||
|
local hook_output = { err = {}, output = {} }
|
||||||
|
local hook_callbacks = {
|
||||||
|
stderr = jobs.logging_callback(hook_output.err, hook_output.output, nil, disp, plugin_name),
|
||||||
|
stdout = jobs.logging_callback(hook_output.err, hook_output.output, nil, disp, plugin_name),
|
||||||
|
}
|
||||||
|
local cmd
|
||||||
|
local shell = os.getenv 'SHELL' or vim.o.shell
|
||||||
|
if shell:find 'cmd.exe$' then
|
||||||
|
cmd = { shell, '/c', task }
|
||||||
|
else
|
||||||
|
cmd = { shell, '-c', task }
|
||||||
|
end
|
||||||
|
hook_result = await(jobs.run(cmd, { capture_output = hook_callbacks, cwd = plugin.install_path })):map_err(
|
||||||
|
function(err)
|
||||||
|
return {
|
||||||
|
msg = string.format('Error running post update hook: %s', table.concat(hook_output.output, '\n')),
|
||||||
|
data = err,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
if hook_result.err then
|
||||||
|
return hook_result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- TODO/NOTE: This case should also capture output in case of error. The minor difficulty is
|
||||||
|
-- what to do if the plugin's run table (i.e. this case) already specifies output handling.
|
||||||
|
|
||||||
|
hook_result = await(jobs.run(task)):map_err(function(err)
|
||||||
|
return {
|
||||||
|
msg = string.format('Error running post update hook: %s', vim.inspect(err)),
|
||||||
|
data = err,
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
|
||||||
|
if hook_result.err then
|
||||||
|
return hook_result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return hook_result
|
||||||
|
else
|
||||||
|
return result.ok()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return plugin_utils
|
|
@ -0,0 +1,74 @@
|
||||||
|
-- A simple Result<V, E> type to simplify control flow with installers and updaters
|
||||||
|
local result = {}
|
||||||
|
|
||||||
|
local ok_result_mt = {
|
||||||
|
and_then = function(self, f, ...)
|
||||||
|
local r = f(...)
|
||||||
|
if r == nil then
|
||||||
|
return result.err('Nil result in and_then! ' .. vim.inspect(debug.traceback()))
|
||||||
|
end
|
||||||
|
|
||||||
|
self.ok = r.ok
|
||||||
|
self.err = r.err
|
||||||
|
setmetatable(self, getmetatable(r))
|
||||||
|
return self
|
||||||
|
end,
|
||||||
|
or_else = function(self)
|
||||||
|
return self
|
||||||
|
end,
|
||||||
|
map_ok = function(self, f)
|
||||||
|
self.ok = f(self.ok) or self.ok
|
||||||
|
return self
|
||||||
|
end,
|
||||||
|
map_err = function(self)
|
||||||
|
return self
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
ok_result_mt.__index = ok_result_mt
|
||||||
|
|
||||||
|
local err_result_mt = {
|
||||||
|
and_then = function(self)
|
||||||
|
return self
|
||||||
|
end,
|
||||||
|
or_else = function(self, f, ...)
|
||||||
|
local r = f(...)
|
||||||
|
if r == nil then
|
||||||
|
return result.err('Nil result in or_else! ' .. vim.inspect(debug.traceback()))
|
||||||
|
end
|
||||||
|
|
||||||
|
self.ok = r.ok
|
||||||
|
self.err = r.err
|
||||||
|
setmetatable(self, getmetatable(r))
|
||||||
|
return self
|
||||||
|
end,
|
||||||
|
map_ok = function(self)
|
||||||
|
return self
|
||||||
|
end,
|
||||||
|
map_err = function(self, f)
|
||||||
|
self.err = f(self.err) or self.err
|
||||||
|
return self
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
|
||||||
|
err_result_mt.__index = err_result_mt
|
||||||
|
|
||||||
|
result.ok = function(val)
|
||||||
|
if val == nil then
|
||||||
|
val = true
|
||||||
|
end
|
||||||
|
local r = setmetatable({}, ok_result_mt)
|
||||||
|
r.ok = val
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
result.err = function(err)
|
||||||
|
if err == nil then
|
||||||
|
err = true
|
||||||
|
end
|
||||||
|
local r = setmetatable({}, err_result_mt)
|
||||||
|
r.err = err
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
|
@ -0,0 +1,212 @@
|
||||||
|
local a = require 'packer.async'
|
||||||
|
local util = require 'packer.util'
|
||||||
|
local log = require 'packer.log'
|
||||||
|
local plugin_utils = require 'packer.plugin_utils'
|
||||||
|
local plugin_complete = require('packer').plugin_complete
|
||||||
|
local result = require 'packer.result'
|
||||||
|
local async = a.sync
|
||||||
|
local await = a.wait
|
||||||
|
local fmt = string.format
|
||||||
|
|
||||||
|
local config = {}
|
||||||
|
|
||||||
|
local snapshot = {
|
||||||
|
completion = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshot.cfg = function(_config)
|
||||||
|
config = _config
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Completion for listing snapshots in `config.snapshot_path`
|
||||||
|
--- Intended to provide completion for PackerSnapshotDelete command
|
||||||
|
snapshot.completion.snapshot = function(lead, cmdline, pos)
|
||||||
|
local completion_list = {}
|
||||||
|
if config.snapshot_path == nil then
|
||||||
|
return completion_list
|
||||||
|
end
|
||||||
|
|
||||||
|
local dir = vim.loop.fs_opendir(config.snapshot_path)
|
||||||
|
|
||||||
|
if dir ~= nil then
|
||||||
|
local res = vim.loop.fs_readdir(dir)
|
||||||
|
while res ~= nil do
|
||||||
|
for _, entry in ipairs(res) do
|
||||||
|
if entry.type == 'file' and vim.startswith(entry.name, lead) then
|
||||||
|
completion_list[#completion_list + 1] = entry.name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
res = vim.loop.fs_readdir(dir)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.loop.fs_closedir(dir)
|
||||||
|
return completion_list
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Completion for listing single plugins before taking snapshot
|
||||||
|
--- Intended to provide completion for PackerSnapshot command
|
||||||
|
snapshot.completion.create = function(lead, cmdline, pos)
|
||||||
|
local cmd_args = (vim.fn.split(cmdline, ' '))
|
||||||
|
|
||||||
|
if #cmd_args > 1 then
|
||||||
|
return plugin_complete(lead, cmdline, pos)
|
||||||
|
end
|
||||||
|
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Completion for listing snapshots in `config.snapshot_path` and single plugins after
|
||||||
|
--- the first argument is provided
|
||||||
|
--- Intended to provide completion for PackerSnapshotRollback command
|
||||||
|
snapshot.completion.rollback = function(lead, cmdline, pos)
|
||||||
|
local cmd_args = vim.split(cmdline, ' ')
|
||||||
|
|
||||||
|
if #cmd_args > 2 then
|
||||||
|
return plugin_complete(lead)
|
||||||
|
else
|
||||||
|
return snapshot.completion.snapshot(lead, cmdline, pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Creates a with with `completed` and `failed` keys, each containing a map with plugin name as key and commit hash/error as value
|
||||||
|
--- @param plugins list
|
||||||
|
--- @return { ok: { failed : table<string, string>, completed : table<string, string>}}
|
||||||
|
local function generate_snapshot(plugins)
|
||||||
|
local completed = {}
|
||||||
|
local failed = {}
|
||||||
|
local opt, start = plugin_utils.list_installed_plugins()
|
||||||
|
local installed = vim.tbl_extend('error', start, opt)
|
||||||
|
|
||||||
|
plugins = vim.tbl_filter(function(plugin)
|
||||||
|
if installed[plugin.install_path] and plugin.type == plugin_utils.git_plugin_type then -- this plugin is installed
|
||||||
|
return plugin
|
||||||
|
end
|
||||||
|
end, plugins)
|
||||||
|
return async(function()
|
||||||
|
for _, plugin in pairs(plugins) do
|
||||||
|
local rev = await(plugin.get_rev())
|
||||||
|
|
||||||
|
if rev.err then
|
||||||
|
failed[plugin.short_name] =
|
||||||
|
fmt("Snapshotting %s failed because of error '%s'", plugin.short_name, vim.inspect(rev.err))
|
||||||
|
else
|
||||||
|
completed[plugin.short_name] = { commit = rev.ok }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return result.ok { failed = failed, completed = completed }
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Serializes a table of git-plugins with `short_name` as table key and another
|
||||||
|
---table with `commit`; the serialized tables will be written in the path `snapshot_path`
|
||||||
|
---provided, if there is already a snapshot it will be overwritten
|
||||||
|
---Snapshotting work only with `plugin_utils.git_plugin_type` type of plugins,
|
||||||
|
---other will be ignored.
|
||||||
|
---@param snapshot_path string realpath for snapshot file
|
||||||
|
---@param plugins table<string, any>[]
|
||||||
|
snapshot.create = function(snapshot_path, plugins)
|
||||||
|
assert(type(snapshot_path) == 'string', fmt("filename needs to be a string but '%s' provided", type(snapshot_path)))
|
||||||
|
assert(type(plugins) == 'table', fmt("plugins needs to be an array but '%s' provided", type(plugins)))
|
||||||
|
return async(function()
|
||||||
|
local commits = await(generate_snapshot(plugins))
|
||||||
|
|
||||||
|
await(a.main)
|
||||||
|
local snapshot_content = vim.fn.json_encode(commits.ok.completed)
|
||||||
|
|
||||||
|
local status, res = pcall(function()
|
||||||
|
return vim.fn.writefile({ snapshot_content }, snapshot_path) == 0
|
||||||
|
end)
|
||||||
|
|
||||||
|
if status and res then
|
||||||
|
return result.ok {
|
||||||
|
message = fmt("Snapshot '%s' complete", snapshot_path),
|
||||||
|
completed = commits.ok.completed,
|
||||||
|
failed = commits.ok.failed,
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return result.err { message = fmt("Error on creation of snapshot '%s': '%s'", snapshot_path, res) }
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function fetch(plugin)
|
||||||
|
local git = require 'packer.plugin_types.git'
|
||||||
|
local opts = { capture_output = true, cwd = plugin.install_path, options = { env = git.job_env } }
|
||||||
|
|
||||||
|
return async(function()
|
||||||
|
return await(require('packer.jobs').run('git ' .. config.git.subcommands.fetch, opts))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Rollbacks `plugins` to the hash specified in `snapshot_path` if exists.
|
||||||
|
---It automatically runs `git fetch --depth 999999 --progress` to retrieve the history
|
||||||
|
---@param snapshot_path string @ realpath to the snapshot file
|
||||||
|
---@param plugins list @ of `plugin_utils.git_plugin_type` type of plugins
|
||||||
|
---@return {ok: {completed: table<string, string>, failed: table<string, string[]>}}
|
||||||
|
snapshot.rollback = function(snapshot_path, plugins)
|
||||||
|
assert(type(snapshot_path) == 'string', 'snapshot_path: expected string but got ' .. type(snapshot_path))
|
||||||
|
assert(type(plugins) == 'table', 'plugins: expected table but got ' .. type(snapshot_path))
|
||||||
|
log.debug('Rolling back to ' .. snapshot_path)
|
||||||
|
local content = vim.fn.readfile(snapshot_path)
|
||||||
|
---@type string
|
||||||
|
local plugins_snapshot = vim.fn.json_decode(content)
|
||||||
|
if plugins_snapshot == nil then -- not valid snapshot file
|
||||||
|
return result.err(fmt("Couldn't load '%s' file", snapshot_path))
|
||||||
|
end
|
||||||
|
|
||||||
|
local completed = {}
|
||||||
|
local failed = {}
|
||||||
|
|
||||||
|
return async(function()
|
||||||
|
for _, plugin in pairs(plugins) do
|
||||||
|
local function err_handler(err)
|
||||||
|
failed[plugin.short_name] = failed[plugin.short_name] or {}
|
||||||
|
failed[plugin.short_name][#failed[plugin.short_name] + 1] = err
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugins_snapshot[plugin.short_name] then
|
||||||
|
local commit = plugins_snapshot[plugin.short_name].commit
|
||||||
|
if commit ~= nil then
|
||||||
|
await(fetch(plugin))
|
||||||
|
:map_err(err_handler)
|
||||||
|
:and_then(await, plugin.revert_to(commit))
|
||||||
|
:map_ok(function(ok)
|
||||||
|
completed[plugin.short_name] = ok
|
||||||
|
end)
|
||||||
|
:map_err(err_handler)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return result.ok { completed = completed, failed = failed }
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Deletes the snapshot provided
|
||||||
|
---@param snapshot_name string absolute path or just a snapshot name
|
||||||
|
snapshot.delete = function(snapshot_name)
|
||||||
|
assert(type(snapshot_name) == 'string', fmt('Expected string, got %s', type(snapshot_name)))
|
||||||
|
---@type string
|
||||||
|
local snapshot_path = vim.loop.fs_realpath(snapshot_name)
|
||||||
|
or vim.loop.fs_realpath(util.join_paths(config.snapshot_path, snapshot_name))
|
||||||
|
|
||||||
|
if snapshot_path == nil then
|
||||||
|
local warn = fmt("Snapshot '%s' is wrong or doesn't exist", snapshot_name)
|
||||||
|
log.warn(warn)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
log.debug('Deleting ' .. snapshot_path)
|
||||||
|
if vim.loop.fs_unlink(snapshot_path) then
|
||||||
|
local info = 'Deleted ' .. snapshot_path
|
||||||
|
log.info(info)
|
||||||
|
else
|
||||||
|
local warn = "Couldn't delete " .. snapshot_path
|
||||||
|
log.warn(warn)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return snapshot
|
|
@ -0,0 +1,141 @@
|
||||||
|
local util = require 'packer.util'
|
||||||
|
local result = require 'packer.result'
|
||||||
|
local display = require 'packer.display'
|
||||||
|
local a = require 'packer.async'
|
||||||
|
local log = require 'packer.log'
|
||||||
|
local plugin_utils = require 'packer.plugin_utils'
|
||||||
|
|
||||||
|
local fmt = string.format
|
||||||
|
local async = a.sync
|
||||||
|
local await = a.wait
|
||||||
|
|
||||||
|
local config = nil
|
||||||
|
|
||||||
|
local function get_plugin_status(plugins, plugin_name, start_plugins, opt_plugins)
|
||||||
|
local status = {}
|
||||||
|
local plugin = plugins[plugin_name]
|
||||||
|
status.wrong_type = (plugin.opt and vim.tbl_contains(start_plugins, util.join_paths(config.start_dir, plugin_name)))
|
||||||
|
or vim.tbl_contains(opt_plugins, util.join_paths(config.opt_dir, plugin_name))
|
||||||
|
return status
|
||||||
|
end
|
||||||
|
|
||||||
|
local function cfg(_config)
|
||||||
|
config = _config
|
||||||
|
end
|
||||||
|
|
||||||
|
local function fix_plugin_type(plugin, results, fs_state)
|
||||||
|
local from
|
||||||
|
local to
|
||||||
|
if plugin.opt then
|
||||||
|
from = util.join_paths(config.start_dir, plugin.short_name)
|
||||||
|
to = util.join_paths(config.opt_dir, plugin.short_name)
|
||||||
|
fs_state.opt[to] = true
|
||||||
|
fs_state.start[from] = nil
|
||||||
|
fs_state.missing[plugin.short_name] = nil
|
||||||
|
else
|
||||||
|
from = util.join_paths(config.opt_dir, plugin.short_name)
|
||||||
|
to = util.join_paths(config.start_dir, plugin.short_name)
|
||||||
|
fs_state.start[to] = true
|
||||||
|
fs_state.opt[from] = nil
|
||||||
|
fs_state.missing[plugin.short_name] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- NOTE: If we stored all plugins somewhere off-package-path and used symlinks to put them in the
|
||||||
|
-- right directories, this could be lighter-weight
|
||||||
|
local success, msg = os.rename(from, to)
|
||||||
|
if not success then
|
||||||
|
log.error('Failed to move ' .. from .. ' to ' .. to .. ': ' .. msg)
|
||||||
|
results.moves[plugin.short_name] = { from = from, to = to, result = result.err(success) }
|
||||||
|
else
|
||||||
|
log.debug('Moved ' .. plugin.short_name .. ' from ' .. from .. ' to ' .. to)
|
||||||
|
results.moves[plugin.short_name] = { from = from, to = to, result = result.ok(success) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function fix_plugin_types(plugins, plugin_names, results, fs_state)
|
||||||
|
log.debug 'Fixing plugin types'
|
||||||
|
results = results or {}
|
||||||
|
results.moves = results.moves or {}
|
||||||
|
-- NOTE: This function can only be run on plugins already installed
|
||||||
|
for _, v in ipairs(plugin_names) do
|
||||||
|
local plugin = plugins[v]
|
||||||
|
local install_dir = util.join_paths(plugin.opt and config.start_dir or config.opt_dir, plugin.short_name)
|
||||||
|
if vim.loop.fs_stat(install_dir) ~= nil then
|
||||||
|
fix_plugin_type(plugin, results, fs_state)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
log.debug 'Done fixing plugin types'
|
||||||
|
end
|
||||||
|
|
||||||
|
local function update_plugin(plugin, display_win, results, opts)
|
||||||
|
local plugin_name = util.get_plugin_full_name(plugin)
|
||||||
|
-- TODO: This will have to change when separate packages are implemented
|
||||||
|
local install_path = util.join_paths(config.pack_dir, plugin.opt and 'opt' or 'start', plugin.short_name)
|
||||||
|
plugin.install_path = install_path
|
||||||
|
return async(function()
|
||||||
|
if plugin.lock or plugin.disable then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
display_win:task_start(plugin_name, 'updating...')
|
||||||
|
local r = await(plugin.updater(display_win, opts))
|
||||||
|
if r ~= nil and r.ok then
|
||||||
|
local msg = 'up to date'
|
||||||
|
if plugin.type == plugin_utils.git_plugin_type then
|
||||||
|
local info = r.info
|
||||||
|
local actual_update = info.revs[1] ~= info.revs[2]
|
||||||
|
msg = actual_update and ('updated: ' .. info.revs[1] .. '...' .. info.revs[2]) or 'already up to date'
|
||||||
|
if actual_update and not opts.preview_updates then
|
||||||
|
log.debug(fmt('Updated %s: %s', plugin_name, vim.inspect(info)))
|
||||||
|
r = r:and_then(await, plugin_utils.post_update_hook(plugin, display_win))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if r.ok then
|
||||||
|
display_win:task_succeeded(plugin_name, msg)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
display_win:task_failed(plugin_name, 'failed to update')
|
||||||
|
local errmsg = '<unknown error>'
|
||||||
|
if r ~= nil and r.err ~= nil then
|
||||||
|
errmsg = r.err
|
||||||
|
end
|
||||||
|
log.debug(fmt('Failed to update %s: %s', plugin_name, vim.inspect(errmsg)))
|
||||||
|
end
|
||||||
|
|
||||||
|
results.updates[plugin_name] = r
|
||||||
|
results.plugins[plugin_name] = plugin
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function do_update(_, plugins, update_plugins, display_win, results, opts)
|
||||||
|
results = results or {}
|
||||||
|
results.updates = results.updates or {}
|
||||||
|
results.plugins = results.plugins or {}
|
||||||
|
local tasks = {}
|
||||||
|
for _, v in ipairs(update_plugins) do
|
||||||
|
local plugin = plugins[v]
|
||||||
|
if plugin == nil then
|
||||||
|
log.error(fmt('Unknown plugin: %s', v))
|
||||||
|
end
|
||||||
|
if plugin and not plugin.frozen then
|
||||||
|
if display_win == nil then
|
||||||
|
display_win = display.open(config.display.open_fn or config.display.open_cmd)
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(tasks, update_plugin(plugin, display_win, results, opts))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #tasks == 0 then
|
||||||
|
log.info 'Nothing to update!'
|
||||||
|
end
|
||||||
|
|
||||||
|
return tasks, display_win
|
||||||
|
end
|
||||||
|
|
||||||
|
local update = setmetatable({ cfg = cfg }, { __call = do_update })
|
||||||
|
|
||||||
|
update.get_plugin_status = get_plugin_status
|
||||||
|
update.fix_plugin_types = fix_plugin_types
|
||||||
|
|
||||||
|
return update
|
|
@ -0,0 +1,168 @@
|
||||||
|
local util = {}
|
||||||
|
|
||||||
|
util.map = function(func, seq)
|
||||||
|
local result = {}
|
||||||
|
for _, v in ipairs(seq) do
|
||||||
|
table.insert(result, func(v))
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
util.partition = function(sub, seq)
|
||||||
|
local sub_vals = {}
|
||||||
|
for _, val in ipairs(sub) do
|
||||||
|
sub_vals[val] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
local result = { {}, {} }
|
||||||
|
for _, val in ipairs(seq) do
|
||||||
|
if sub_vals[val] then
|
||||||
|
table.insert(result[1], val)
|
||||||
|
else
|
||||||
|
table.insert(result[2], val)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return unpack(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
util.nonempty_or = function(opt, alt)
|
||||||
|
if #opt > 0 then
|
||||||
|
return opt
|
||||||
|
else
|
||||||
|
return alt
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if jit ~= nil then
|
||||||
|
util.is_windows = jit.os == 'Windows'
|
||||||
|
else
|
||||||
|
util.is_windows = package.config:sub(1, 1) == '\\'
|
||||||
|
end
|
||||||
|
|
||||||
|
if util.is_windows and vim.o.shellslash then
|
||||||
|
util.use_shellslash = true
|
||||||
|
else
|
||||||
|
util.use_shallslash = false
|
||||||
|
end
|
||||||
|
|
||||||
|
util.get_separator = function()
|
||||||
|
if util.is_windows and not util.use_shellslash then
|
||||||
|
return '\\'
|
||||||
|
end
|
||||||
|
return '/'
|
||||||
|
end
|
||||||
|
|
||||||
|
util.strip_trailing_sep = function(path)
|
||||||
|
local res, _ = string.gsub(path, util.get_separator() .. '$', '', 1)
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
util.join_paths = function(...)
|
||||||
|
local separator = util.get_separator()
|
||||||
|
return table.concat({ ... }, separator)
|
||||||
|
end
|
||||||
|
|
||||||
|
util.get_plugin_short_name = function(plugin)
|
||||||
|
local path = vim.fn.expand(plugin[1])
|
||||||
|
local name_segments = vim.split(path, util.get_separator())
|
||||||
|
local segment_idx = #name_segments
|
||||||
|
local name = plugin.as or name_segments[segment_idx]
|
||||||
|
while name == '' and segment_idx > 0 do
|
||||||
|
name = name_segments[segment_idx]
|
||||||
|
segment_idx = segment_idx - 1
|
||||||
|
end
|
||||||
|
return name, path
|
||||||
|
end
|
||||||
|
|
||||||
|
util.get_plugin_full_name = function(plugin)
|
||||||
|
local plugin_name = plugin.name
|
||||||
|
if plugin.branch and plugin.branch ~= 'master' then
|
||||||
|
-- NOTE: maybe have to change the seperator here too
|
||||||
|
plugin_name = plugin_name .. '/' .. plugin.branch
|
||||||
|
end
|
||||||
|
|
||||||
|
if plugin.rev then
|
||||||
|
plugin_name = plugin_name .. '@' .. plugin.rev
|
||||||
|
end
|
||||||
|
|
||||||
|
return plugin_name
|
||||||
|
end
|
||||||
|
|
||||||
|
util.remove_ending_git_url = function(url)
|
||||||
|
return vim.endswith(url, '.git') and url:sub(1, -5) or url
|
||||||
|
end
|
||||||
|
|
||||||
|
util.deep_extend = function(policy, ...)
|
||||||
|
local result = {}
|
||||||
|
local function helper(policy, k, v1, v2)
|
||||||
|
if type(v1) ~= 'table' or type(v2) ~= 'table' then
|
||||||
|
if policy == 'error' then
|
||||||
|
error('Key ' .. vim.inspect(k) .. ' is already present with value ' .. vim.inspect(v1))
|
||||||
|
elseif policy == 'force' then
|
||||||
|
return v2
|
||||||
|
else
|
||||||
|
return v1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return util.deep_extend(policy, v1, v2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, t in ipairs { ... } do
|
||||||
|
for k, v in pairs(t) do
|
||||||
|
if result[k] ~= nil then
|
||||||
|
result[k] = helper(policy, k, result[k], v)
|
||||||
|
else
|
||||||
|
result[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Credit to @crs for the original function
|
||||||
|
util.float = function(opts)
|
||||||
|
local last_win = vim.api.nvim_get_current_win()
|
||||||
|
local last_pos = vim.api.nvim_win_get_cursor(last_win)
|
||||||
|
local columns = vim.o.columns
|
||||||
|
local lines = vim.o.lines
|
||||||
|
local width = math.ceil(columns * 0.8)
|
||||||
|
local height = math.ceil(lines * 0.8 - 4)
|
||||||
|
local left = math.ceil((columns - width) * 0.5)
|
||||||
|
local top = math.ceil((lines - height) * 0.5 - 1)
|
||||||
|
|
||||||
|
--- TODO: this is an impromptu fix for
|
||||||
|
--- https://github.com/wbthomason/packer.nvim/pull/325#issuecomment-832874005
|
||||||
|
--- ideally we should decide if the string argument passed to display openers is
|
||||||
|
--- required or not
|
||||||
|
if type(opts) ~= 'table' then
|
||||||
|
opts = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
opts = vim.tbl_deep_extend('force', {
|
||||||
|
relative = 'editor',
|
||||||
|
style = 'minimal',
|
||||||
|
border = 'double',
|
||||||
|
width = width,
|
||||||
|
height = height,
|
||||||
|
col = left,
|
||||||
|
row = top,
|
||||||
|
}, opts or {})
|
||||||
|
|
||||||
|
local buf = vim.api.nvim_create_buf(false, true)
|
||||||
|
local win = vim.api.nvim_open_win(buf, true, opts)
|
||||||
|
|
||||||
|
function _G.__packer_restore_cursor()
|
||||||
|
vim.api.nvim_set_current_win(last_win)
|
||||||
|
vim.api.nvim_win_set_cursor(last_win, last_pos)
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.cmd 'autocmd! BufWipeout <buffer> lua __packer_restore_cursor()'
|
||||||
|
|
||||||
|
return true, win, buf
|
||||||
|
end
|
||||||
|
|
||||||
|
return util
|
|
@ -0,0 +1 @@
|
||||||
|
std="vim"
|
|
@ -0,0 +1,4 @@
|
||||||
|
indent_type = "Spaces"
|
||||||
|
indent_width = 2
|
||||||
|
quote_style = "AutoPreferSingle"
|
||||||
|
no_call_parentheses = true
|
|
@ -0,0 +1,27 @@
|
||||||
|
local util = require 'packer.util'
|
||||||
|
|
||||||
|
local M = { base_dir = '/tmp/__packer_tests__' }
|
||||||
|
|
||||||
|
---Create a fake git repository
|
||||||
|
---@param name string
|
||||||
|
---@param base string
|
||||||
|
function M.create_git_dir(name, base)
|
||||||
|
base = base or M.base_dir
|
||||||
|
local repo_path = util.join_paths(base, name)
|
||||||
|
local path = util.join_paths(repo_path, '.git')
|
||||||
|
if vim.fn.isdirectory(path) > 0 then
|
||||||
|
M.cleanup_dirs(path)
|
||||||
|
end
|
||||||
|
vim.fn.mkdir(path, 'p')
|
||||||
|
return repo_path
|
||||||
|
end
|
||||||
|
|
||||||
|
---Remove directories created for test purposes
|
||||||
|
---@vararg string
|
||||||
|
function M.cleanup_dirs(...)
|
||||||
|
for _, dir in ipairs { ... } do
|
||||||
|
vim.fn.delete(dir, 'rf')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
|
@ -0,0 +1,33 @@
|
||||||
|
local a = require('plenary.async_lib.tests')
|
||||||
|
local await = require('packer.async').wait
|
||||||
|
local local_plugin = require('packer.plugin_types.local')
|
||||||
|
local packer_path = vim.fn.stdpath('data') .. '/site/pack/packer/start/'
|
||||||
|
local helpers = require('tests.helpers')
|
||||||
|
|
||||||
|
a.describe('Local plugin -', function()
|
||||||
|
a.describe('installer', function()
|
||||||
|
local local_plugin_path
|
||||||
|
local repo_name = 'test.nvim'
|
||||||
|
local plugin_install_path = packer_path .. repo_name
|
||||||
|
|
||||||
|
before_each(function()
|
||||||
|
vim.fn.mkdir(packer_path, 'p')
|
||||||
|
local_plugin_path = helpers.create_git_dir(repo_name)
|
||||||
|
end)
|
||||||
|
|
||||||
|
after_each(function() helpers.cleanup_dirs(local_plugin_path, plugin_install_path) end)
|
||||||
|
|
||||||
|
a.it('should create a symlink', function()
|
||||||
|
local plugin_spec = {
|
||||||
|
name = local_plugin_path,
|
||||||
|
path = local_plugin_path,
|
||||||
|
install_path = plugin_install_path
|
||||||
|
}
|
||||||
|
|
||||||
|
local_plugin.setup(plugin_spec)
|
||||||
|
await(plugin_spec.installer({task_update = function() end}))
|
||||||
|
|
||||||
|
assert.equal('link', vim.loop.fs_lstat(plugin_install_path).type)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
|
@ -0,0 +1,3 @@
|
||||||
|
set rtp+=.
|
||||||
|
set rtp+=../plenary.nvim
|
||||||
|
runtime! plugin/plenary.vim
|
|
@ -0,0 +1,25 @@
|
||||||
|
local a = require('plenary.async_lib.tests')
|
||||||
|
local await = require('packer.async').wait
|
||||||
|
local plugin_utils = require("packer.plugin_utils")
|
||||||
|
local packer_path = vim.fn.stdpath("data") .. "/site/pack/packer/start/"
|
||||||
|
|
||||||
|
a.describe("Packer post update hooks", function()
|
||||||
|
local test_plugin_path = packer_path .. "test_plugin/"
|
||||||
|
local run_hook = plugin_utils.post_update_hook
|
||||||
|
|
||||||
|
before_each(function() vim.fn.mkdir(test_plugin_path, "p") end)
|
||||||
|
|
||||||
|
after_each(function() vim.fn.delete(test_plugin_path, "rf") end)
|
||||||
|
|
||||||
|
a.it("should run the command in the correct folder", function()
|
||||||
|
local plugin_spec = {
|
||||||
|
name = "test/test_plugin",
|
||||||
|
install_path = test_plugin_path,
|
||||||
|
run = "touch 'this_file_should_exist'"
|
||||||
|
}
|
||||||
|
|
||||||
|
await(run_hook(plugin_spec, {task_update = function() end}))
|
||||||
|
|
||||||
|
assert.truthy(vim.loop.fs_stat(test_plugin_path .. "this_file_should_exist"))
|
||||||
|
end)
|
||||||
|
end)
|
|
@ -0,0 +1,29 @@
|
||||||
|
local packer = require("packer")
|
||||||
|
local use = packer.use
|
||||||
|
local packer_path = vim.fn.stdpath("data").."/site/pack/packer/start/"
|
||||||
|
|
||||||
|
describe("Packer use tests", function()
|
||||||
|
after_each(function()
|
||||||
|
packer.reset()
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("should set the correct install path", function ()
|
||||||
|
local spec = {"test/plugin1"}
|
||||||
|
packer.startup(function()
|
||||||
|
use(spec)
|
||||||
|
end)
|
||||||
|
packer.__manage_all()
|
||||||
|
assert.truthy(spec.install_path)
|
||||||
|
assert.equal(spec.install_path, packer_path .. spec.short_name)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("should add metadata to a plugin from a spec", function ()
|
||||||
|
local spec = {"test/plugin1"}
|
||||||
|
packer.startup(function()
|
||||||
|
use(spec)
|
||||||
|
end)
|
||||||
|
packer.__manage_all()
|
||||||
|
assert.equal(spec.name, "test/plugin1")
|
||||||
|
assert.equal(spec.path, "test/plugin1")
|
||||||
|
end)
|
||||||
|
end)
|
|
@ -0,0 +1,81 @@
|
||||||
|
local a = require('plenary.async_lib.tests')
|
||||||
|
local await = require('packer.async').wait
|
||||||
|
local async = require('packer.async').sync
|
||||||
|
local plugin_utils = require('packer.plugin_utils')
|
||||||
|
local helpers = require("tests.helpers")
|
||||||
|
|
||||||
|
local fmt = string.format
|
||||||
|
|
||||||
|
a.describe('Plugin utils -', function()
|
||||||
|
|
||||||
|
a.describe('find_missing_plugins', function()
|
||||||
|
local repo_name = "test.nvim"
|
||||||
|
local path
|
||||||
|
|
||||||
|
plugin_utils.cfg({start_dir = helpers.base_dir})
|
||||||
|
|
||||||
|
before_each(function() path = helpers.create_git_dir(repo_name) end)
|
||||||
|
|
||||||
|
after_each(function() helpers.cleanup_dirs("tmp/packer") end)
|
||||||
|
|
||||||
|
a.it('should pick up plugins with a different remote URL', function()
|
||||||
|
local test_repo_name = fmt('user2/%s', repo_name)
|
||||||
|
local plugins = {
|
||||||
|
[repo_name] = {
|
||||||
|
opt = false,
|
||||||
|
type = "git",
|
||||||
|
name = fmt("user1/%s", repo_name),
|
||||||
|
short_name = repo_name,
|
||||||
|
remote_url = function()
|
||||||
|
return async(function()
|
||||||
|
return {ok = {remote = fmt('https://github.com/%s', test_repo_name)}}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local result = await(plugin_utils.find_missing_plugins(plugins, {}, {[path] = true}))
|
||||||
|
assert.truthy(result)
|
||||||
|
assert.equal(1, #vim.tbl_keys(result))
|
||||||
|
end)
|
||||||
|
|
||||||
|
a.it('should not pick up plugins with the same remote URL', function()
|
||||||
|
local test_repo_name = fmt('user1/%s', repo_name)
|
||||||
|
local plugins = {
|
||||||
|
[repo_name] = {
|
||||||
|
opt = false,
|
||||||
|
type = "git",
|
||||||
|
name = test_repo_name,
|
||||||
|
short_name = repo_name,
|
||||||
|
remote_url = function()
|
||||||
|
return async(function()
|
||||||
|
return {ok = {remote = fmt('https://github.com/%s', test_repo_name)}}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local result = await(plugin_utils.find_missing_plugins(plugins, {}, {[path] = true}))
|
||||||
|
assert.truthy(result)
|
||||||
|
assert.equal(0, #result)
|
||||||
|
end)
|
||||||
|
|
||||||
|
a.it('should handle ssh git urls', function()
|
||||||
|
local test_repo_name = fmt('user2/%s', repo_name)
|
||||||
|
local plugins = {
|
||||||
|
[repo_name] = {
|
||||||
|
opt = false,
|
||||||
|
type = "git",
|
||||||
|
name = fmt("user1/%s", repo_name),
|
||||||
|
short_name = repo_name,
|
||||||
|
remote_url = function()
|
||||||
|
return async(function()
|
||||||
|
return {ok = {remote = fmt('git@github.com:%s.git', test_repo_name)}}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
local result = await(plugin_utils.find_missing_plugins(plugins, {}, {[path] = true}))
|
||||||
|
assert.truthy(result)
|
||||||
|
assert.equal(1, #vim.tbl_keys(result))
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
|
@ -0,0 +1,176 @@
|
||||||
|
local before_each = require('plenary.busted').before_each
|
||||||
|
local a = require 'plenary.async_lib.tests'
|
||||||
|
local util = require 'packer.util'
|
||||||
|
local mocked_plugin_utils = require 'packer.plugin_utils'
|
||||||
|
local log = require 'packer.log'
|
||||||
|
local async = require('packer.async').sync
|
||||||
|
local await = require('packer.async').wait
|
||||||
|
local wait_all = require('packer.async').wait_all
|
||||||
|
local main = require('packer.async').main
|
||||||
|
local packer = require 'packer'
|
||||||
|
local jobs = require 'packer.jobs'
|
||||||
|
local git = require 'packer.plugin_types.git'
|
||||||
|
local join_paths = util.join_paths
|
||||||
|
local stdpath = vim.fn.stdpath
|
||||||
|
local fmt = string.format
|
||||||
|
|
||||||
|
local config = {
|
||||||
|
ensure_dependencies = true,
|
||||||
|
snapshot = nil,
|
||||||
|
snapshot_path = join_paths(stdpath 'cache', 'packer.nvim'),
|
||||||
|
package_root = join_paths(stdpath 'data', 'site', 'pack'),
|
||||||
|
compile_path = join_paths(stdpath 'config', 'plugin', 'packer_compiled.lua'),
|
||||||
|
plugin_package = 'packer',
|
||||||
|
max_jobs = nil,
|
||||||
|
auto_clean = true,
|
||||||
|
compile_on_sync = true,
|
||||||
|
disable_commands = false,
|
||||||
|
opt_default = false,
|
||||||
|
transitive_opt = true,
|
||||||
|
transitive_disable = true,
|
||||||
|
auto_reload_compiled = true,
|
||||||
|
git = {
|
||||||
|
mark_breaking_changes = true,
|
||||||
|
cmd = 'git',
|
||||||
|
subcommands = {
|
||||||
|
update = 'pull --ff-only --progress --rebase=false',
|
||||||
|
install = 'clone --depth %i --no-single-branch --progress',
|
||||||
|
fetch = 'fetch --depth 999999 --progress',
|
||||||
|
checkout = 'checkout %s --',
|
||||||
|
update_branch = 'merge --ff-only @{u}',
|
||||||
|
current_branch = 'rev-parse --abbrev-ref HEAD',
|
||||||
|
diff = 'log --color=never --pretty=format:FMT --no-show-signature HEAD@{1}...HEAD',
|
||||||
|
diff_fmt = '%%h %%s (%%cr)',
|
||||||
|
git_diff_fmt = 'show --no-color --pretty=medium %s',
|
||||||
|
get_rev = 'rev-parse --short HEAD',
|
||||||
|
get_header = 'log --color=never --pretty=format:FMT --no-show-signature HEAD -n 1',
|
||||||
|
get_bodies = 'log --color=never --pretty=format:"===COMMIT_START===%h%n%s===BODY_START===%b" --no-show-signature HEAD@{1}...HEAD',
|
||||||
|
submodules = 'submodule update --init --recursive --progress',
|
||||||
|
revert = 'reset --hard HEAD@{1}',
|
||||||
|
revert_to = 'reset --hard %s --',
|
||||||
|
},
|
||||||
|
depth = 1,
|
||||||
|
clone_timeout = 60,
|
||||||
|
default_url_format = 'https://github.com/%s.git',
|
||||||
|
},
|
||||||
|
display = {
|
||||||
|
non_interactive = false,
|
||||||
|
open_fn = nil,
|
||||||
|
open_cmd = '65vnew',
|
||||||
|
working_sym = '⟳',
|
||||||
|
error_sym = '✗',
|
||||||
|
done_sym = '✓',
|
||||||
|
removed_sym = '-',
|
||||||
|
moved_sym = '→',
|
||||||
|
header_sym = '━',
|
||||||
|
header_lines = 2,
|
||||||
|
title = 'packer.nvim',
|
||||||
|
show_all_info = true,
|
||||||
|
prompt_border = 'double',
|
||||||
|
keybindings = { quit = 'q', toggle_info = '<CR>', diff = 'd', prompt_revert = 'r' },
|
||||||
|
},
|
||||||
|
luarocks = { python_cmd = 'python' },
|
||||||
|
log = { level = 'trace' },
|
||||||
|
profile = { enable = false },
|
||||||
|
}
|
||||||
|
|
||||||
|
git.cfg(config)
|
||||||
|
|
||||||
|
--[[ For testing purposes the spec file is made up so that when running `packer`
|
||||||
|
it could manage itself as if it was in `~/.local/share/nvim/site/pack/packer/start/` --]]
|
||||||
|
local install_path = vim.fn.getcwd()
|
||||||
|
|
||||||
|
mocked_plugin_utils.list_installed_plugins = function()
|
||||||
|
return { [install_path] = true }, {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local old_require = _G.require
|
||||||
|
|
||||||
|
_G.require = function(modname)
|
||||||
|
if modname == 'plugin_utils' then
|
||||||
|
return mocked_plugin_utils
|
||||||
|
end
|
||||||
|
|
||||||
|
return old_require(modname)
|
||||||
|
end
|
||||||
|
|
||||||
|
local spec = { 'wbthomason/packer.nvim' }
|
||||||
|
|
||||||
|
local function exec_cmd(cmd, opts)
|
||||||
|
return async(function()
|
||||||
|
local r = await(jobs.run(cmd, opts))
|
||||||
|
if r.err then
|
||||||
|
print(fmt("Failed on command '%s': %s", cmd, vim.inspect(r.err)))
|
||||||
|
end
|
||||||
|
assert.is_not_nil(r.ok)
|
||||||
|
local _, result = next(r.ok.output.data.stdout)
|
||||||
|
return result
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local snapshotted_plugins = {}
|
||||||
|
a.describe('Packer testing ', function()
|
||||||
|
local snapshot_name = 'test'
|
||||||
|
local test_path = join_paths(config.snapshot_path, snapshot_name)
|
||||||
|
local snapshot = require 'packer.snapshot'
|
||||||
|
snapshot.cfg(config)
|
||||||
|
|
||||||
|
before_each(function()
|
||||||
|
packer.reset()
|
||||||
|
packer.init(config)
|
||||||
|
packer.use(spec)
|
||||||
|
packer.__manage_all()
|
||||||
|
end)
|
||||||
|
|
||||||
|
after_each(function()
|
||||||
|
spec = { 'wbthomason/packer.nvim' }
|
||||||
|
spec.install_path = install_path
|
||||||
|
end)
|
||||||
|
|
||||||
|
a.describe('snapshot.create()', function()
|
||||||
|
a.it(fmt("create snapshot in '%s'", test_path), function()
|
||||||
|
local result = await(snapshot.create(test_path, { spec }))
|
||||||
|
local stat = vim.loop.fs_stat(test_path)
|
||||||
|
assert.truthy(stat)
|
||||||
|
end)
|
||||||
|
|
||||||
|
a.it("checking if snapshot content corresponds to plugins'", function()
|
||||||
|
async(function()
|
||||||
|
local file_content = vim.fn.readfile(test_path)
|
||||||
|
snapshotted_plugins = vim.fn.json_decode(file_content)
|
||||||
|
local expected_rev = await(spec.get_rev())
|
||||||
|
assert.are.equals(expected_rev.ok, snapshotted_plugins['packer.nvim'].commit)
|
||||||
|
end)()
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
a.describe('packer.delete()', function()
|
||||||
|
a.it(fmt("delete '%s' snapshot", snapshot_name), function()
|
||||||
|
snapshot.delete(snapshot_name)
|
||||||
|
local stat = vim.loop.fs_stat(test_path)
|
||||||
|
assert.falsy(stat)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
a.describe('packer.rollback()', function()
|
||||||
|
local rollback_snapshot_name = 'rollback_test'
|
||||||
|
local rollback_test_path = join_paths(config.snapshot_path, rollback_snapshot_name)
|
||||||
|
local prev_commit_cmd = 'git rev-parse --short HEAD~5'
|
||||||
|
local get_rev_cmd = 'git rev-parse --short HEAD'
|
||||||
|
|
||||||
|
local opts = { capture_output = true, cwd = spec.install_path, options = { env = git.job_env } }
|
||||||
|
|
||||||
|
a.it("restore 'packer' to the commit hash HEAD~5", function()
|
||||||
|
async(function()
|
||||||
|
local commit = await(exec_cmd(prev_commit_cmd, opts))
|
||||||
|
snapshotted_plugins['packer.nvim'] = { commit = commit }
|
||||||
|
await(main)
|
||||||
|
local encoded_json = vim.fn.json_encode(snapshotted_plugins)
|
||||||
|
vim.fn.writefile({ encoded_json }, rollback_test_path)
|
||||||
|
await(snapshot.rollback(rollback_test_path, { spec }))
|
||||||
|
local rev = await(exec_cmd(get_rev_cmd, opts))
|
||||||
|
assert.are.equals(snapshotted_plugins['packer.nvim'].commit, rev)
|
||||||
|
end)()
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
|
@ -0,0 +1,49 @@
|
||||||
|
[selene]
|
||||||
|
base = "lua51"
|
||||||
|
name = "vim"
|
||||||
|
|
||||||
|
[vim]
|
||||||
|
any = true
|
||||||
|
|
||||||
|
[jit]
|
||||||
|
any = true
|
||||||
|
|
||||||
|
[[describe.args]]
|
||||||
|
type = "string"
|
||||||
|
[[describe.args]]
|
||||||
|
type = "function"
|
||||||
|
|
||||||
|
[[it.args]]
|
||||||
|
type = "string"
|
||||||
|
[[it.args]]
|
||||||
|
type = "function"
|
||||||
|
|
||||||
|
[[before_each.args]]
|
||||||
|
type = "function"
|
||||||
|
[[after_each.args]]
|
||||||
|
type = "function"
|
||||||
|
|
||||||
|
[assert.is_not]
|
||||||
|
any = true
|
||||||
|
|
||||||
|
[[assert.equals.args]]
|
||||||
|
type = "any"
|
||||||
|
[[assert.equals.args]]
|
||||||
|
type = "any"
|
||||||
|
[[assert.equals.args]]
|
||||||
|
type = "any"
|
||||||
|
required = false
|
||||||
|
|
||||||
|
[[assert.same.args]]
|
||||||
|
type = "any"
|
||||||
|
[[assert.same.args]]
|
||||||
|
type = "any"
|
||||||
|
|
||||||
|
[[assert.truthy.args]]
|
||||||
|
type = "any"
|
||||||
|
|
||||||
|
[[assert.spy.args]]
|
||||||
|
type = "any"
|
||||||
|
|
||||||
|
[[assert.stub.args]]
|
||||||
|
type = "any"
|
|
@ -0,0 +1,169 @@
|
||||||
|
-- Automatically generated packer.nvim plugin loader code
|
||||||
|
|
||||||
|
if vim.api.nvim_call_function('has', {'nvim-0.5'}) ~= 1 then
|
||||||
|
vim.api.nvim_command('echohl WarningMsg | echom "Invalid Neovim version for packer.nvim! | echohl None"')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
vim.api.nvim_command('packadd packer.nvim')
|
||||||
|
|
||||||
|
local no_errors, error_msg = pcall(function()
|
||||||
|
|
||||||
|
_G._packer = _G._packer or {}
|
||||||
|
_G._packer.inside_compile = true
|
||||||
|
|
||||||
|
local time
|
||||||
|
local profile_info
|
||||||
|
local should_profile = false
|
||||||
|
if should_profile then
|
||||||
|
local hrtime = vim.loop.hrtime
|
||||||
|
profile_info = {}
|
||||||
|
time = function(chunk, start)
|
||||||
|
if start then
|
||||||
|
profile_info[chunk] = hrtime()
|
||||||
|
else
|
||||||
|
profile_info[chunk] = (hrtime() - profile_info[chunk]) / 1e6
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
time = function(chunk, start) end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function save_profiles(threshold)
|
||||||
|
local sorted_times = {}
|
||||||
|
for chunk_name, time_taken in pairs(profile_info) do
|
||||||
|
sorted_times[#sorted_times + 1] = {chunk_name, time_taken}
|
||||||
|
end
|
||||||
|
table.sort(sorted_times, function(a, b) return a[2] > b[2] end)
|
||||||
|
local results = {}
|
||||||
|
for i, elem in ipairs(sorted_times) do
|
||||||
|
if not threshold or threshold and elem[2] > threshold then
|
||||||
|
results[i] = elem[1] .. ' took ' .. elem[2] .. 'ms'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if threshold then
|
||||||
|
table.insert(results, '(Only showing plugins that took longer than ' .. threshold .. ' ms ' .. 'to load)')
|
||||||
|
end
|
||||||
|
|
||||||
|
_G._packer.profile_output = results
|
||||||
|
end
|
||||||
|
|
||||||
|
time([[Luarocks path setup]], true)
|
||||||
|
local package_path_str = "/home/jpm/.cache/nvim/packer_hererocks/2.1.0-beta3/share/lua/5.1/?.lua;/home/jpm/.cache/nvim/packer_hererocks/2.1.0-beta3/share/lua/5.1/?/init.lua;/home/jpm/.cache/nvim/packer_hererocks/2.1.0-beta3/lib/luarocks/rocks-5.1/?.lua;/home/jpm/.cache/nvim/packer_hererocks/2.1.0-beta3/lib/luarocks/rocks-5.1/?/init.lua"
|
||||||
|
local install_cpath_pattern = "/home/jpm/.cache/nvim/packer_hererocks/2.1.0-beta3/lib/lua/5.1/?.so"
|
||||||
|
if not string.find(package.path, package_path_str, 1, true) then
|
||||||
|
package.path = package.path .. ';' .. package_path_str
|
||||||
|
end
|
||||||
|
|
||||||
|
if not string.find(package.cpath, install_cpath_pattern, 1, true) then
|
||||||
|
package.cpath = package.cpath .. ';' .. install_cpath_pattern
|
||||||
|
end
|
||||||
|
|
||||||
|
time([[Luarocks path setup]], false)
|
||||||
|
time([[try_loadstring definition]], true)
|
||||||
|
local function try_loadstring(s, component, name)
|
||||||
|
local success, result = pcall(loadstring(s), name, _G.packer_plugins[name])
|
||||||
|
if not success then
|
||||||
|
vim.schedule(function()
|
||||||
|
vim.api.nvim_notify('packer.nvim: Error running ' .. component .. ' for ' .. name .. ': ' .. result, vim.log.levels.ERROR, {})
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
time([[try_loadstring definition]], false)
|
||||||
|
time([[Defining packer_plugins]], true)
|
||||||
|
_G.packer_plugins = {
|
||||||
|
["cmp-buffer"] = {
|
||||||
|
loaded = true,
|
||||||
|
path = "/home/jpm/.local/share/nvim/site/pack/packer/start/cmp-buffer",
|
||||||
|
url = "https://github.com/hrsh7th/cmp-buffer"
|
||||||
|
},
|
||||||
|
["cmp-cmdline"] = {
|
||||||
|
loaded = true,
|
||||||
|
path = "/home/jpm/.local/share/nvim/site/pack/packer/start/cmp-cmdline",
|
||||||
|
url = "https://github.com/hrsh7th/cmp-cmdline"
|
||||||
|
},
|
||||||
|
["cmp-nvim-lsp"] = {
|
||||||
|
loaded = true,
|
||||||
|
path = "/home/jpm/.local/share/nvim/site/pack/packer/start/cmp-nvim-lsp",
|
||||||
|
url = "https://github.com/hrsh7th/cmp-nvim-lsp"
|
||||||
|
},
|
||||||
|
["cmp-path"] = {
|
||||||
|
loaded = true,
|
||||||
|
path = "/home/jpm/.local/share/nvim/site/pack/packer/start/cmp-path",
|
||||||
|
url = "https://github.com/hrsh7th/cmp-path"
|
||||||
|
},
|
||||||
|
["coc-perl"] = {
|
||||||
|
loaded = true,
|
||||||
|
path = "/home/jpm/.local/share/nvim/site/pack/packer/start/coc-perl",
|
||||||
|
url = "https://github.com/bmeneg/coc-perl"
|
||||||
|
},
|
||||||
|
["coc.nvim"] = {
|
||||||
|
loaded = true,
|
||||||
|
path = "/home/jpm/.local/share/nvim/site/pack/packer/start/coc.nvim",
|
||||||
|
url = "https://github.com/neoclide/coc.nvim"
|
||||||
|
},
|
||||||
|
["fold-cycle.nvim"] = {
|
||||||
|
loaded = true,
|
||||||
|
path = "/home/jpm/.local/share/nvim/site/pack/packer/start/fold-cycle.nvim",
|
||||||
|
url = "https://github.com/jghauser/fold-cycle.nvim"
|
||||||
|
},
|
||||||
|
["lightline.vim"] = {
|
||||||
|
loaded = true,
|
||||||
|
path = "/home/jpm/.local/share/nvim/site/pack/packer/start/lightline.vim",
|
||||||
|
url = "https://github.com/itchyny/lightline.vim"
|
||||||
|
},
|
||||||
|
nerdtree = {
|
||||||
|
loaded = true,
|
||||||
|
path = "/home/jpm/.local/share/nvim/site/pack/packer/start/nerdtree",
|
||||||
|
url = "https://github.com/preservim/nerdtree"
|
||||||
|
},
|
||||||
|
["nvim-cmp"] = {
|
||||||
|
loaded = true,
|
||||||
|
path = "/home/jpm/.local/share/nvim/site/pack/packer/start/nvim-cmp",
|
||||||
|
url = "https://github.com/hrsh7th/nvim-cmp"
|
||||||
|
},
|
||||||
|
["nvim-cursorline"] = {
|
||||||
|
config = { "\27LJ\2\nÛ\1\0\0\5\0\v\0\0156\0\0\0'\2\1\0B\0\2\0029\0\2\0005\2\6\0005\3\3\0005\4\4\0=\4\5\3=\3\a\0025\3\b\0005\4\t\0=\4\5\3=\3\n\2B\0\2\1K\0\1\0\15cursorword\1\0\2\14underline\1\tbold\2\1\0\2\15min_length\3\3\venable\2\15cursorline\1\0\0\ahl\1\0\2\14underline\1\tbold\2\1\0\3\ftimeout\3è\a\vnumber\1\venable\2\nsetup\20nvim-cursorline\frequire\0" },
|
||||||
|
loaded = true,
|
||||||
|
path = "/home/jpm/.local/share/nvim/site/pack/packer/start/nvim-cursorline",
|
||||||
|
url = "https://github.com/yamatsum/nvim-cursorline"
|
||||||
|
},
|
||||||
|
["nvim-treesitter"] = {
|
||||||
|
loaded = true,
|
||||||
|
path = "/home/jpm/.local/share/nvim/site/pack/packer/start/nvim-treesitter",
|
||||||
|
url = "https://github.com/nvim-treesitter/nvim-treesitter"
|
||||||
|
},
|
||||||
|
["packer.nvim"] = {
|
||||||
|
loaded = true,
|
||||||
|
path = "/home/jpm/.local/share/nvim/site/pack/packer/start/packer.nvim",
|
||||||
|
url = "https://github.com/wbthomason/packer.nvim"
|
||||||
|
},
|
||||||
|
["vim-gitgutter"] = {
|
||||||
|
loaded = true,
|
||||||
|
path = "/home/jpm/.local/share/nvim/site/pack/packer/start/vim-gitgutter",
|
||||||
|
url = "https://github.com/airblade/vim-gitgutter"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
time([[Defining packer_plugins]], false)
|
||||||
|
-- Config for: nvim-cursorline
|
||||||
|
time([[Config for nvim-cursorline]], true)
|
||||||
|
try_loadstring("\27LJ\2\nÛ\1\0\0\5\0\v\0\0156\0\0\0'\2\1\0B\0\2\0029\0\2\0005\2\6\0005\3\3\0005\4\4\0=\4\5\3=\3\a\0025\3\b\0005\4\t\0=\4\5\3=\3\n\2B\0\2\1K\0\1\0\15cursorword\1\0\2\14underline\1\tbold\2\1\0\2\15min_length\3\3\venable\2\15cursorline\1\0\0\ahl\1\0\2\14underline\1\tbold\2\1\0\3\ftimeout\3è\a\vnumber\1\venable\2\nsetup\20nvim-cursorline\frequire\0", "config", "nvim-cursorline")
|
||||||
|
time([[Config for nvim-cursorline]], false)
|
||||||
|
|
||||||
|
_G._packer.inside_compile = false
|
||||||
|
if _G._packer.needs_bufread == true then
|
||||||
|
vim.cmd("doautocmd BufRead")
|
||||||
|
end
|
||||||
|
_G._packer.needs_bufread = false
|
||||||
|
|
||||||
|
if should_profile then save_profiles() end
|
||||||
|
|
||||||
|
end)
|
||||||
|
|
||||||
|
if not no_errors then
|
||||||
|
error_msg = error_msg:gsub('"', '\\"')
|
||||||
|
vim.api.nvim_command('echohl ErrorMsg | echom "Error in packer_compiled: '..error_msg..'" | echom "Please check your config for correctness" | echohl None')
|
||||||
|
end
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue