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