From 36cb57ecceee4fc61a9af2418da3832b714569c3 Mon Sep 17 00:00:00 2001 From: Aki Date: Thu, 19 Aug 2021 12:33:11 +0530 Subject: [PATCH] NvChad Updater | Chadrc Fixes | Cleanup and Formatting | Misc (#288) * tree-wide: Format files ugh why do people don't push formatted stuff * mappings|init: Move init mappings to a function, only call when required | Show err message for init because mappings.lua is called from multiple places, so there should't be any code that executes without calling a specific function show error message when something fails in init.lua makes no sense to not rearrange plugin functions alphabetically, but keep misc at top * feat: Do not depend on user config | Fix merging of configs because it is a user config, so our config shoudn't break even we if dont have it use our own table merge function move loading config to a function use a global variable to store the config, so no need to call the table function everytime * Add NvChadUpdate command and shortcut for it map leader+uu to it summary of what it does: first ask the user for confirmation and tell that the updater is gonna run git reset --hard in config repo and chadrc will be restored take backup of chadrc in a lua string and locally in a file with chadrc.bak.(random numbers) git reset on config dir and git pull whether success or error, restore the chadrc file if restore fails, then print backup file path for more deep understanding, read the comments in utils.lua * NvChadUpdater: Make update repo and url configurable | Improvr logging --- init.lua | 6 +- lua/chadrc.lua | 10 +- lua/default_config.lua | 4 + lua/mappings.lua | 235 +++++++++++++------------- lua/options.lua | 10 +- lua/pluginList.lua | 2 +- lua/plugins/bufferline.lua | 26 +-- lua/plugins/chadsheet.lua | 2 +- lua/plugins/telescope.lua | 4 +- lua/telescope/_extensions/terms.lua | 39 +++-- lua/theme.lua | 2 +- lua/utils.lua | 248 ++++++++++++++++++++++++---- 12 files changed, 390 insertions(+), 198 deletions(-) diff --git a/init.lua b/init.lua index b65c997..6353271 100644 --- a/init.lua +++ b/init.lua @@ -4,5 +4,9 @@ local chad_modules = { } for i = 1, #chad_modules, 1 do - pcall(require, chad_modules[i]) + if not pcall(require, chad_modules[i]) then + error("Error loading " .. chad_modules[i] .. "\n") + end end + +require("mappings").misc() diff --git a/lua/chadrc.lua b/lua/chadrc.lua index 5489172..e6f9821 100644 --- a/lua/chadrc.lua +++ b/lua/chadrc.lua @@ -13,7 +13,7 @@ M.ui = { hidden_statusline = { -- these are filetypes, not pattern matched "NvimTree", - -- "terminal", + -- "terminal", }, } @@ -28,7 +28,7 @@ M.options = { timeoutlen = 400, clipboard = "unnamedplus", number = true, - -- relative numbers in normal mode tool at the bottom of options.lua + -- relative numbers in normal mode tool at the bottom of options.lua relativenumber = false, numberwidth = 2, expandtab = true, @@ -37,6 +37,9 @@ M.options = { mapleader = " ", autosave = false, enable_insertNav = true, -- navigation in insertmode + -- used for updater + update_url = "https://github.com/NvChad/NvChad", + update_branch = "main", } -- enable and disable plugins (false for disable) @@ -140,9 +143,8 @@ M.mappings = { copywhole_file = "", toggle_linenr = "n", -- show or hide line number theme_toggle = "x", + update_nvchad = "uu", }, } -M = vim.tbl_deep_extend("force", require "default_config", M) - return M diff --git a/lua/default_config.lua b/lua/default_config.lua index 0abbee5..f8bd1aa 100644 --- a/lua/default_config.lua +++ b/lua/default_config.lua @@ -37,6 +37,9 @@ M.options = { mapleader = " ", autosave = false, enable_insertNav = true, -- navigation in insertmode + -- used for updater + update_url = "https://github.com/NvChad/NvChad", + update_branch = "main", } -- enable and disable plugins (false for disable) @@ -140,6 +143,7 @@ M.mappings = { copywhole_file = "", toggle_linenr = "n", -- show or hide line number theme_toggle = "x", + update_nvchad = "uu", }, } diff --git a/lua/mappings.lua b/lua/mappings.lua index 17e8d9e..9be5fde 100644 --- a/lua/mappings.lua +++ b/lua/mappings.lua @@ -1,7 +1,6 @@ -local user_map = require("chadrc").mappings +local user_map = require("utils").load_config().mappings local miscMap = user_map.misc -local M = {} local cmd = vim.cmd local function map(mode, lhs, rhs, opts) @@ -12,65 +11,117 @@ local function map(mode, lhs, rhs, opts) vim.api.nvim_set_keymap(mode, lhs, rhs, options) end +local M = {} local opt = {} --- dont copy any deleted text , this is disabled by default so uncomment the below mappings if you want them ---[[ remove this line - -map("n", "dd", [=[ "_dd ]=], opt) -map("v", "dd", [=[ "_dd ]=], opt) -map("v", "x", [=[ "_x ]=], opt) +-- these mappings will only be called during initialization +M.misc = function() + -- dont copy any deleted text , this is disabled by default so uncomment the below mappings if you want them + -- map("n", "dd", [=[ "_dd ]=], opt) + -- map("v", "dd", [=[ "_dd ]=], opt) + -- map("v", "x", [=[ "_x ]=], opt) + -- todo: this should be configurable via chadrc + + -- Don't copy the replaced text after pasting in visual mode + map("v", "p", '"_dP', opt) + + -- Allow moving the cursor through wrapped lines with j, k, and + -- http://www.reddit.com/r/vim/comments/2k4cbr/problem_with_gj_and_gk/ + -- empty mode is same as using :map + map("", "j", 'v:count ? "j" : "gj"', { expr = true }) + map("", "k", 'v:count ? "k" : "gk"', { expr = true }) + map("", "", 'v:count ? "j" : "gj"', { expr = true }) + map("", "", 'v:count ? "k" : "gk"', { expr = true }) + + -- copy whole file content + map("n", miscMap.copywhole_file, ":%y+", opt) + + -- toggle numbers + map("n", miscMap.toggle_linenr, ":set nu!", opt) + + -- terminals + local function terms() + local m = user_map.terms + + -- get out of terminal mode + map("t", m.esc_termmode, "", opt) + -- hide a term from within terminal mode + map("t", m.esc_hide_termmode, " :lua require('utils').close_buffer() ", opt) + -- pick a hidden term + map("n", m.pick_term, ":Telescope terms ", opt) + + -- Open terminals + -- TODO this opens on top of an existing vert/hori term, fixme + map("n", m.new_wind, ":execute 'terminal' | let b:term_type = 'wind' | startinsert ", opt) + map("n", m.new_vert, ":execute 'vnew +terminal' | let b:term_type = 'vert' | startinsert ", opt) + map("n", m.new_hori, ":execute 15 .. 'new +terminal' | let b:term_type = 'hori' | startinsert ", opt) + end + terms() - this line too ]] --- + -- ctrl + s to save file + map("n", "", ":w ", opt) --- Don't copy the replaced text after pasting in visual mode -map("v", "p", '"_dP', opt) + -- use ESC to turn off search highlighting + map("n", "", ":noh", opt) --- Allow moving the cursor through wrapped lines with j, k, and --- http://www.reddit.com/r/vim/comments/2k4cbr/problem_with_gj_and_gk/ --- empty mode is same as using :map -map("", "j", 'v:count ? "j" : "gj"', { expr = true }) -map("", "k", 'v:count ? "k" : "gk"', { expr = true }) -map("", "", 'v:count ? "j" : "gj"', { expr = true }) -map("", "", 'v:count ? "k" : "gk"', { expr = true }) + -- navigation within insert mode + local check_insertNav = require("utils").load_config().options.enable_insertNav --- copy whole file content -map("n", miscMap.copywhole_file, ":%y+", opt) + if check_insertNav == true then + local m = user_map.insert_nav --- toggle numbers -map("n", miscMap.toggle_linenr, ":set nu!", opt) + map("i", m.forward, "", opt) + map("i", m.backward, "", opt) + map("i", m.top_of_line, "^i", opt) + map("i", m.end_of_line, "", opt) + map("i", m.next_line, "", opt) + map("i", m.prev_line, "", opt) + end + -- check the theme toggler + local theme_toggler = require("utils").load_config().ui.theme_toggler + if theme_toggler == true then + local m = user_map.misc.theme_toggle --- terminals -local function terms() - local m = user_map.terms + map("n", m, ":lua require('utils').toggle_theme(require('utils').load_config().ui.fav_themes)", opt) + end - -- get out of terminal mode - map("t", m.esc_termmode, "", opt) - -- hide a term from within terminal mode - map("t", m.esc_hide_termmode, " :lua require('utils').close_buffer() ", opt) - -- pick a hidden term - map("n", m.pick_term, ":Telescope terms ", opt) + -- Packer commands till because we are not loading it at startup + cmd "silent! command PackerCompile lua require 'pluginList' require('packer').compile()" + cmd "silent! command PackerInstall lua require 'pluginList' require('packer').install()" + cmd "silent! command PackerStatus lua require 'pluginList' require('packer').status()" + cmd "silent! command PackerSync lua require 'pluginList' require('packer').sync()" + cmd "silent! command PackerUpdate lua require 'pluginList' require('packer').update()" - -- Open terminals - -- TODO this opens on top of an existing vert/hori term, fixme - map("n", m.new_wind, ":execute 'terminal' | let b:term_type = 'wind' | startinsert ", opt) - map("n", m.new_vert, ":execute 'vnew +terminal' | let b:term_type = 'vert' | startinsert ", opt) - map("n", m.new_hori, ":execute 15 .. 'new +terminal' | let b:term_type = 'hori' | startinsert ", opt) + -- add NvChadUpdate command and mapping + cmd "silent! command! NvChadUpdate lua require('utils').update_nvchad()" + map("n", user_map.misc.update_nvchad, ":NvChadUpdate", opt) end -terms() +M.bufferline = function() + local m = user_map.bufferline -M.truezen = function() - local m = user_map.truezen + map("n", m.new_buffer, ":enew", opt) -- new buffer + map("n", m.newtab, ":tabnew", opt) -- new tab + map("n", m.close, ":lua require('utils').close_buffer() ", opt) -- close buffer - map("n", m.ataraxisMode, ":TZAtaraxis", opt) - map("n", m.minimalisticmode, ":TZMinimalist", opt) - map("n", m.focusmode, ":TZFocus", opt) + -- move between tabs + + map("n", m.cycleNext, ":BufferLineCycleNext", opt) + map("n", m.cyclePrev, ":BufferLineCyclePrev", opt) end -map("n", "", ":w ", opt) +M.chadsheet = function() + local m = user_map.chadsheet + + map("n", m.default_keys, ":lua require('cheatsheet').show_cheatsheet_telescope()", opt) + map( + "n", + m.user_keys, + ":lua require('cheatsheet').show_cheatsheet_telescope{bundled_cheatsheets = false, bundled_plugin_cheatsheets = false }", + opt + ) +end M.comment_nvim = function() local m = user_map.comment_nvim.comment_toggle @@ -78,6 +129,25 @@ M.comment_nvim = function() map("v", m, ":CommentToggle", opt) end +M.dashboard = function() + local m = user_map.dashboard + + map("n", m.open, ":Dashboard", opt) + map("n", m.newfile, ":DashboardNewFile", opt) + map("n", m.bookmarks, ":DashboardJumpMarks", opt) + map("n", m.sessionload, ":SessionLoad", opt) + map("n", m.sessionsave, ":SessionSave", opt) +end + +M.fugitive = function() + local m = user_map.fugitive + + map("n", m.Git, ":Git", opt) + map("n", m.diffget_2, ":diffget //2", opt) + map("n", m.diffget_3, ":diffget //3", opt) + map("n", m.git_blame, ":Git blame", opt) +end + M.nvimtree = function() local m = user_map.nvimtree.treetoggle @@ -89,14 +159,12 @@ M.neoformat = function() map("n", m, ":Neoformat", opt) end -M.dashboard = function() - local m = user_map.dashboard +M.truezen = function() + local m = user_map.truezen - map("n", m.open, ":Dashboard", opt) - map("n", m.newfile, ":DashboardNewFile", opt) - map("n", m.bookmarks, ":DashboardJumpMarks", opt) - map("n", m.sessionload, ":SessionLoad", opt) - map("n", m.sessionsave, ":SessionSave", opt) + map("n", m.ataraxisMode, ":TZAtaraxis", opt) + map("n", m.minimalisticmode, ":TZMinimalist", opt) + map("n", m.focusmode, ":TZFocus", opt) end M.telescope = function() @@ -117,69 +185,4 @@ M.telescope_media = function() map("n", m.media_files, ":Telescope media_files ", opt) end -M.chadsheet = function() - local m = user_map.chadsheet - - map("n", m.default_keys, ":lua require('cheatsheet').show_cheatsheet_telescope()", opt) - map( - "n", - m.user_keys, - ":lua require('cheatsheet').show_cheatsheet_telescope{bundled_cheatsheets = false, bundled_plugin_cheatsheets = false }", - opt - ) -end - -M.bufferline = function() - local m = user_map.bufferline - - map("n", m.new_buffer, ":enew", opt) -- new buffer - map("n", m.newtab, ":tabnew", opt) -- new tab - map("n", m.close, ":lua require('utils').close_buffer() ", opt) -- close buffer - - -- move between tabs - - map("n", m.cycleNext, ":BufferLineCycleNext", opt) - map("n", m.cyclePrev, ":BufferLineCyclePrev", opt) -end - --- use ESC to turn off search highlighting -map("n", "", ":noh", opt) - --- Packer commands till because we are not loading it at startup -cmd "silent! command PackerCompile lua require 'pluginList' require('packer').compile()" -cmd "silent! command PackerInstall lua require 'pluginList' require('packer').install()" -cmd "silent! command PackerStatus lua require 'pluginList' require('packer').status()" -cmd "silent! command PackerSync lua require 'pluginList' require('packer').sync()" -cmd "silent! command PackerUpdate lua require 'pluginList' require('packer').update()" - -M.fugitive = function() - local m = user_map.fugitive - - map("n", m.Git, ":Git", opt) - map("n", m.diffget_2, ":diffget //2", opt) - map("n", m.diffget_3, ":diffget //3", opt) - map("n", m.git_blame, ":Git blame", opt) -end - --- navigation within insert mode -local check_insertNav = require("chadrc").options.enable_insertNav - -if check_insertNav == true then - local m = user_map.insert_nav - - map("i", m.forward, "", opt) - map("i", m.backward, "", opt) - map("i", m.top_of_line, "^i", opt) - map("i", m.end_of_line, "", opt) - map("i", m.next_line, "", opt) - map("i", m.prev_line, "", opt) -end - -local theme_toggler = require("chadrc").ui.theme_toggler - -if theme_toggler == true then - local m = user_map.misc.theme_toggle - - map("n", m, ":lua require('utils').toggle_theme(require('chadrc').ui.fav_themes)", opt) -end return M diff --git a/lua/options.lua b/lua/options.lua index 225bf58..e0aff03 100644 --- a/lua/options.lua +++ b/lua/options.lua @@ -1,7 +1,11 @@ -local options = require("chadrc").options local opt = vim.opt local g = vim.g +-- export user config as a global varibale +g.nvchad_user_config = "chadrc" + +local options = require("utils").load_config().options + opt.completeopt = { "menuone", "noselect" } opt.undofile = options.permanent_undo opt.ruler = options.ruler @@ -27,7 +31,7 @@ opt.fillchars = { eob = " " } -- Numbers opt.number = options.number opt.numberwidth = options.numberwidth -opt.relativenumber = options.relativenumber +opt.relativenumber = options.relativenumber -- Indenline opt.expandtab = options.expandtab @@ -76,7 +80,7 @@ vim.cmd [[ au TermOpen term://* setlocal nonumber norelativenumber ]] -- Don't show status line on certain windows vim.cmd [[ au TermOpen term://* setfiletype terminal ]] -vim.cmd [[ let hidden_statusline = luaeval('require("chadrc").ui.hidden_statusline') | autocmd BufEnter,BufWinEnter,WinEnter,CmdwinEnter,TermEnter * nested if index(hidden_statusline, &ft) >= 0 | set laststatus=0 | else | set laststatus=2 | endif ]] +vim.cmd [[ let hidden_statusline = luaeval('require("utils").load_config().ui.hidden_statusline') | autocmd BufEnter,BufWinEnter,WinEnter,CmdwinEnter,TermEnter * nested if index(hidden_statusline, &ft) >= 0 | set laststatus=0 | else | set laststatus=2 | endif ]] -- Open a file from its last left off position -- vim.cmd [[ au BufReadPost * if expand('%:p') !~# '\m/\.git/' && line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif ]] diff --git a/lua/pluginList.lua b/lua/pluginList.lua index df3cdcf..5c56855 100644 --- a/lua/pluginList.lua +++ b/lua/pluginList.lua @@ -1,4 +1,4 @@ -local plugin_status = require("chadrc").plugin_status +local plugin_status = require("utils").load_config().plugin_status local present, _ = pcall(require, "packerInit") local packer diff --git a/lua/plugins/bufferline.lua b/lua/plugins/bufferline.lua index d55b70c..cd7e8b4 100644 --- a/lua/plugins/bufferline.lua +++ b/lua/plugins/bufferline.lua @@ -5,7 +5,7 @@ local present, bufferline = pcall(require, "bufferline") if not present then return end - + bufferline.setup { options = { offsets = { { filetype = "NvimTree", text = "", padding = 1 } }, @@ -25,23 +25,23 @@ bufferline.setup { mappings = true, always_show_bufferline = true, custom_filter = function(buf_number) - -- Func to filter out our managed/persistent split terms - local present_type, type = pcall(function() - return vim.api.nvim_buf_get_var(buf_number, "term_type") - end) - - if present_type then - if type == "vert" then + -- Func to filter out our managed/persistent split terms + local present_type, type = pcall(function() + return vim.api.nvim_buf_get_var(buf_number, "term_type") + end) + + if present_type then + if type == "vert" then return false elseif type == "hori" then return false else - return true + return true end - else - return true - end - end, + else + return true + end + end, }, highlights = { fill = { diff --git a/lua/plugins/chadsheet.lua b/lua/plugins/chadsheet.lua index 4ccd2b5..21862c1 100644 --- a/lua/plugins/chadsheet.lua +++ b/lua/plugins/chadsheet.lua @@ -4,7 +4,7 @@ if not present then return end -local mappings = require("chadrc").mappings +local mappings = require("utils").load_config().mappings -- add user mappings to the cheetsheet for section, data in pairs(mappings) do diff --git a/lua/plugins/telescope.lua b/lua/plugins/telescope.lua index 0fe5312..4146356 100644 --- a/lua/plugins/telescope.lua +++ b/lua/plugins/telescope.lua @@ -38,8 +38,8 @@ telescope.setup { file_ignore_patterns = {}, generic_sorter = require("telescope.sorters").get_generic_fuzzy_sorter, path_display = function(opts, path) - local tail = require("telescope.utils").path_tail(path) - return string.format("%s (%s)", tail, path) + local tail = require("telescope.utils").path_tail(path) + return string.format("%s (%s)", tail, path) end, winblend = 0, border = {}, diff --git a/lua/telescope/_extensions/terms.lua b/lua/telescope/_extensions/terms.lua index 7913666..2acd08a 100644 --- a/lua/telescope/_extensions/terms.lua +++ b/lua/telescope/_extensions/terms.lua @@ -10,7 +10,7 @@ M.term_picker = function(opts) pickers = require "telescope.pickers" finders = require "telescope.finders" previewers = require "telescope.previewers" - + make_entry = require "telescope.make_entry" actions = require "telescope.actions" action_state = require "telescope.actions.state" @@ -19,26 +19,25 @@ M.term_picker = function(opts) else error "Cannot find telescope!" end - + local filter = vim.tbl_filter - + local local_utils = require "utils" -- buffer number and name local bufnr = vim.api.nvim_get_current_buf() local bufname = vim.api.nvim_buf_get_name(bufnr) - + local bufnrs = filter(function(b) local present_type, type = pcall(function() return vim.api.nvim_buf_get_var(b, "term_type") end) - + if not present_type then -- let's only terms that we created return false end - - + -- if 1 ~= vim.fn.buflisted(b) then -- return false -- end @@ -59,22 +58,22 @@ M.term_picker = function(opts) return vim.fn.getbufinfo(a)[1].lastused > vim.fn.getbufinfo(b)[1].lastused end) end - + local buffers = {} local default_selection_idx = 1 for _, bufnr in ipairs(bufnrs) do local flag = bufnr == vim.fn.bufnr "" and "%" or (bufnr == vim.fn.bufnr "#" and "#" or " ") - + if opts.sort_lastused and not opts.ignore_current_buffer and flag == "#" then default_selection_idx = 2 end - + local element = { bufnr = bufnr, flag = flag, info = vim.fn.getbufinfo(bufnr)[1], } - + if opts.sort_lastused and (flag == "#" or flag == "%") then local idx = ((buffers[1] ~= nil and buffers[1].flag == "%") and 2 or 1) table.insert(buffers, idx, element) @@ -82,12 +81,12 @@ M.term_picker = function(opts) table.insert(buffers, element) end end - + if not opts.bufnr_width then local max_bufnr = math.max(unpack(bufnrs)) opts.bufnr_width = #tostring(max_bufnr) end - + pickers.new(opts, { prompt_title = "Terminal buffers", finder = finders.new_table { @@ -103,24 +102,24 @@ M.term_picker = function(opts) actions.close(prompt_bufnr) local buf = entry.bufnr - + local chad_term, type = pcall(function() - return vim.api.nvim_buf_get_var(buf, "term_type") - end) - + return vim.api.nvim_buf_get_var(buf, "term_type") + end) + -- TODO buffer checks/error detection (make sure we do get a buf) if chad_term then if type == "wind" then -- swtich to term buff & show in bufferline - vim.cmd(string.format('b %d | setlocal bl', buf)) + vim.cmd(string.format("b %d | setlocal bl", buf)) -- vim.cmd('startinsert') TODO fix this elseif type == "vert" then - vim.cmd(string.format('vsp #%d', buf)) + vim.cmd(string.format("vsp #%d", buf)) -- vim.cmd('startinsert') TODO fix this elseif type == "hori" then -- TODO change 15 to a chad config var number - vim.cmd(string.format('15 sp #%d ', buf)) + vim.cmd(string.format("15 sp #%d ", buf)) -- vim.cmd('startinsert') TODO fix this end end diff --git a/lua/theme.lua b/lua/theme.lua index 04f0871..3002ac2 100644 --- a/lua/theme.lua +++ b/lua/theme.lua @@ -1,4 +1,4 @@ -local chad_theme = require("chadrc").ui.theme +local chad_theme = require("utils").load_config().ui.theme vim.g.nvchad_theme = chad_theme local present, base16 = pcall(require, "base16") diff --git a/lua/utils.lua b/lua/utils.lua index 367dd3e..a568feb 100644 --- a/lua/utils.lua +++ b/lua/utils.lua @@ -10,7 +10,8 @@ M.change_theme = function(current_theme, new_theme) return end - local file = vim.fn.stdpath "config" .. "/lua/chadrc.lua" + local user_config = vim.g.nvchad_user_config + local file = vim.fn.stdpath "config" .. "/lua/" .. user_config .. ".lua" -- store in data variable local data = assert(M.file("r", file)) -- escape characters which can be parsed as magic chars @@ -36,39 +37,39 @@ end M.close_buffer = function(bufexpr, force) -- This is a modification of a NeoVim plugin from - -- Author: ojroques - Olivier Roques + -- Author: ojroques - Olivier Roques -- Src: https://github.com/ojroques/nvim-bufdel -- (Author has okayed copy-paste) -- Options local opts = { - next = 'cycle', -- how to retrieve the next buffer - quit = false, -- exit when last buffer is deleted + next = "cycle", -- how to retrieve the next buffer + quit = false, -- exit when last buffer is deleted --TODO make this a chadrc flag/option } -- ---------------- -- Helper functions -- ---------------- - + -- Switch to buffer 'buf' on each window from list 'windows' local function switch_buffer(windows, buf) local cur_win = vim.fn.winnr() for _, winid in ipairs(windows) do - vim.cmd(string.format('%d wincmd w', vim.fn.win_id2win(winid))) - vim.cmd(string.format('buffer %d', buf)) + vim.cmd(string.format("%d wincmd w", vim.fn.win_id2win(winid))) + vim.cmd(string.format("buffer %d", buf)) end - vim.cmd(string.format('%d wincmd w', cur_win)) -- return to original window + vim.cmd(string.format("%d wincmd w", cur_win)) -- return to original window end - + -- Select the first buffer with a number greater than given buffer local function get_next_buf(buf) - local next = vim.fn.bufnr('#') - if opts.next == 'alternate' and vim.fn.buflisted(next) == 1 then + local next = vim.fn.bufnr "#" + if opts.next == "alternate" and vim.fn.buflisted(next) == 1 then return next end - for i = 0, vim.fn.bufnr('$') - 1 do - next = (buf + i) % vim.fn.bufnr('$') + 1 -- will loop back to 1 + for i = 0, vim.fn.bufnr "$" - 1 do + next = (buf + i) % vim.fn.bufnr "$" + 1 -- will loop back to 1 if vim.fn.buflisted(next) == 1 then return next end @@ -78,68 +79,68 @@ M.close_buffer = function(bufexpr, force) -- ---------------- -- End helper functions -- ---------------- - + local buf = vim.fn.bufnr() - if vim.fn.buflisted(buf) == 0 then -- exit if buffer number is invalid + if vim.fn.buflisted(buf) == 0 then -- exit if buffer number is invalid return end - - if #vim.fn.getbufinfo({buflisted = 1}) < 2 then + + if #vim.fn.getbufinfo { buflisted = 1 } < 2 then if opts.quit then -- exit when there is only one buffer left if force then - vim.cmd('qall!') + vim.cmd "qall!" else - vim.cmd('confirm qall') + vim.cmd "confirm qall" end return end - + local chad_term, type = pcall(function() return vim.api.nvim_buf_get_var(buf, "term_type") - end) - + end) + if chad_term then -- Must be a window type - vim.cmd(string.format('setlocal nobl', buf)) - vim.cmd('enew') + vim.cmd(string.format("setlocal nobl", buf)) + vim.cmd "enew" return end -- don't exit and create a new empty buffer - vim.cmd('enew') - vim.cmd('bp') + vim.cmd "enew" + vim.cmd "bp" end - + local next_buf = get_next_buf(buf) local windows = vim.fn.getbufinfo(buf)[1].windows - + -- force deletion of terminal buffers to avoid the prompt - if force or vim.fn.getbufvar(buf, '&buftype') == 'terminal' then + if force or vim.fn.getbufvar(buf, "&buftype") == "terminal" then local chad_term, type = pcall(function() return vim.api.nvim_buf_get_var(buf, "term_type") - end) - + end) + -- TODO this scope is error prone, make resilient if chad_term then if type == "wind" then -- hide from bufferline - vim.cmd(string.format('%d bufdo setlocal nobl', buf)) + vim.cmd(string.format("%d bufdo setlocal nobl", buf)) -- swtich to another buff -- TODO switch to next bufffer, this works too - vim.cmd('BufferLineCycleNext') + vim.cmd "BufferLineCycleNext" else local cur_win = vim.fn.winnr() -- we can close this window - vim.cmd(string.format('%d wincmd c', cur_win)) + vim.cmd(string.format("%d wincmd c", cur_win)) return end else switch_buffer(windows, next_buf) - vim.cmd(string.format('bd! %d', buf)) + vim.cmd(string.format("bd! %d", buf)) end else switch_buffer(windows, next_buf) - vim.cmd(string.format('silent! confirm bd %d', buf)) + vim.cmd(string.format("silent! confirm bd %d", buf)) end -- revert buffer switches if user has canceled deletion if vim.fn.buflisted(buf) == 1 then @@ -147,6 +148,16 @@ M.close_buffer = function(bufexpr, force) end end +-- wrapper to use vim.api.nvim_echo +-- table of {string, highlight} +-- e.g echo({{"Hello", "Title"}, {"World"}}) +M.echo = function(opts) + if opts == nil or type(opts) ~= "table" then + return + end + vim.api.nvim_echo(opts, false, {}) +end + -- 1st arg - r or w -- 2nd arg - file path -- 3rd arg - content if 1st arg is w @@ -195,6 +206,89 @@ M.list_themes = function(return_type) return themes end +-- Base code: https://gist.github.com/revolucas/184aec7998a6be5d2f61b984fac1d7f7 +-- Changes over it: preserving table 1 contents and also update with table b, without duplicating +-- 1st arg - base table, 2nd arg - table to merge +M.merge_table = function(into, from) + -- make sure both are table + if type(into) ~= "table" or type(from) ~= "table" then + return 1 + end + local stack, seen = {}, {} + local table1, table2 = into, from + while true do + for k, v in pairs(table2) do + if type(v) == "table" and type(table1[k]) == "table" then + table.insert(stack, { table1[k], table2[k] }) + else + local present = seen[v] or false + if not present then + -- add the value to seen table until value is found + for _, value in pairs(table1) do + seen[value] = true + if value == v then + present = true + break + end + end + end + seen[v] = true + if not present then + -- if type is number, then it is a sub table value, so append + if type(k) == "number" then + table1[#table1 + 1] = v + else + table1[k] = v + end + end + end + end + if #stack > 0 then + local t = stack[#stack] + table1, table2 = t[1], t[2] + stack[#stack] = nil + else + break + end + end + return into +end + +-- load config +-- 1st arg = boolean - whether to force reload +-- Modifies _G._NVCHAD_CONFIG global variable +M.load_config = function(reload) + -- only do the stuff below one time, otherwise just return the set config + if _G._NVCHAD_CONFIG_CONTENTS ~= nil and not (reload or false) then + return _G._NVCHAD_CONFIG_CONTENTS + end + + -- don't enclose in pcall, it better break when default config is faulty + _G._NVCHAD_CONFIG_CONTENTS = require "default_config" + + -- user config is not required to run nvchad but a optional + -- Make sure the config doesn't break the whole system if user config is not present or in bad state or not a table + -- print warning texts if user config file is present + local config_name = vim.g.nvchad_user_config or "chadrc" + local config_file = vim.fn.stdpath "config" .. "/lua/" .. config_name .. ".lua" + -- check if the user config is present + if vim.fn.empty(vim.fn.glob(config_file)) < 1 then + local present, config = pcall(require, config_name) + if present then + -- make sure the returned value is table + if type(config) == "table" then + -- data = require(config_name) + _G._NVCHAD_CONFIG_CONTENTS = require("utils").merge_table(_G._NVCHAD_CONFIG_CONTENTS, config) + else + print("Warning: " .. config_name .. " sourced successfully but did not return a lua table.") + end + else + print("Warning: " .. config_file .. " is present but sourcing failed.") + end + end + return _G._NVCHAD_CONFIG_CONTENTS +end + -- reload a plugin ( will try to load even if not loaded) -- can take a string or list ( table ) -- return true or false @@ -315,4 +409,86 @@ M.toggle_theme = function(themes) end end +-- update nvchad +M.update_nvchad = function() + -- in all the comments below, config means user config + local config_path = vim.fn.stdpath "config" + local config_name = vim.g.nvchad_user_config or "chadrc" + local config_file = config_path .. "/lua/" .. config_name .. ".lua" + -- generate a random file name + local config_file_backup = config_path .. "/" .. config_name .. ".lua.bak." .. math.random() + local utils = require "utils" + local echo = utils.echo + local current_config = utils.load_config() + local update_url = current_config.options.update_url or "https://github.com/NvChad/NvChad" + local update_branch = current_config.options.update_branch or "main" + + -- ask the user for confirmation to update because we are going to run git reset --hard + echo { { "Url: ", "Title" }, { update_url } } + echo { { "Branch: ", "Title" }, { update_branch } } + echo { + { "\nUpdater will run", "WarningMsg" }, + { " git reset --hard " }, + { + "in config folder, so changes to existing repo files except ", + "WarningMsg", + }, + + { config_name }, + { " will be lost!\n\nUpdate NvChad ? [y/N]", "WarningMsg" }, + } + + local ans = string.lower(vim.fn.input "-> ") == "y" + utils.clear_cmdline() + if not ans then + echo { { "Update cancelled!", "Title" } } + return + end + + -- first try to fetch contents of config, this will make sure it is readable and taking backup of its contents + local config_contents = utils.file("r", config_file) + -- also make a local backup in ~/.config/nvim, will be removed when config is succesfully restored + utils.file("w", config_file_backup, config_contents) + -- write original config file with its contents, will make sure charc is writable, this maybe overkill but a little precaution always helps + utils.file("w", config_file, config_contents) + + -- function that will executed when git commands are done + local function update_exit(_, code) + -- restore config file irrespective of whether git commands were succesfull or not + if pcall(function() + utils.file("w", config_file, config_contents) + end) then + -- config restored succesfully, remove backup file that was created + if not pcall(os.remove, config_file_backup) then + echo { { "Warning: Failed to remove backup chadrc, remove manually.", "WarningMsg" } } + echo { { "Path: ", "WarningMsg" }, { config_file_backup } } + end + else + echo { { "Error: Restoring " .. config_name .. " failed.\n", "ErrorMsg" } } + echo { { "Backed up " .. config_name .. " path: " .. config_file_backup .. "\n\n", "None" } } + end + + -- close the terminal buffer only if update was success, as in case of error, we need the error message + if code == 0 then + vim.cmd "bd!" + echo { { "NvChad succesfully updated.\n", "String" } } + else + echo { { "Error: NvChad Update failed.\n", "ErrorMsg" } } + end + end + + -- git commands that will executed, reset in case config was modfied + -- use --ff-only to not mess up if the local repo is outdated + local update_script = [[git reset --hard && git pull --set-upstream https://github.com/NvChad/NvChad main --ff-only]] + + -- open a new buffer + vim.cmd "new" + -- finally open the pseudo terminal buffer + vim.fn.termopen(update_script, { + -- change dir to config path so we don't need to move in script + cwd = config_path, + on_exit = update_exit, + }) +end + return M