Neovim plugin to automatically adjust git env vars when syncing dotfiles using the "bare git repo" method

Initial commit

ejrichards 20fd4ef1

+1
.gitignore
··· 1 + .mise.local.toml
+21
LICENSE
··· 1 + MIT License 2 + 3 + Copyright (c) 2024 ejrichards 4 + 5 + Permission is hereby granted, free of charge, to any person obtaining a copy 6 + of this software and associated documentation files (the "Software"), to deal 7 + in the Software without restriction, including without limitation the rights 8 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + copies of the Software, and to permit persons to whom the Software is 10 + furnished to do so, subject to the following conditions: 11 + 12 + The above copyright notice and this permission notice shall be included in all 13 + copies or substantial portions of the Software. 14 + 15 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 + SOFTWARE.
+50
README.md
··· 1 + # Baredot 2 + 3 + This is a Neovim plugin to automatically adjust `git` env vars when syncing dotfiles using the "bare git repo" method: 4 + 5 + [Dotfiles: Best way to store in a bare git repository](https://www.atlassian.com/git/tutorials/dotfiles) 6 + 7 + ## Details 8 + 9 + When launching and when changing directory (eg. `:cd`), the plugin will detect if the current 10 + directory is in a git repo by searching for a `.git` folder. 11 + 12 + - If a `.git` folder is found, the env vars are cleared and `git` will work as normal. 13 + - If a `.git` folder is not found, and we are in `$HOME`, the env vars will be adjusted to use the 14 + bare git repo. This will let other git plugins function using that repo. 15 + 16 + ## Setup 17 + 18 + lazy.nvim 19 + ```lua 20 + { 21 + "ejrichards/baredot.nvim", 22 + opts = { 23 + git_dir = "~/.cfg" -- Change this path 24 + } 25 + } 26 + ``` 27 + 28 + ## Configuration 29 + 30 + ```lua 31 + { 32 + -- These two options set the GIT_DIR and GIT_WORK_TREE env vars 33 + -- They are expanded using "vim.fn.expand" 34 + git_dir = "~/.cfg", 35 + git_work_tree = "~", 36 + -- Filename pattern to find that will disable Baredot 37 + disable_pattern = "%.git" 38 + } 39 + ``` 40 + 41 + ## Commands 42 + 43 + - `:BaredotInfo` - Print current status 44 + - `:BaredotToggle` - Manually toggle the env vars on / off 45 + 46 + ## Functions 47 + 48 + - `require("baredot").info()` - Print current status 49 + - `require("baredot").toggle()` - Manually toggle the env vars on / off 50 + - `require("baredot").set(boolean)` - Set the env vars on / off
+44
lua/baredot/commands.lua
··· 1 + local Commands = {} 2 + 3 + ---@type BaredotConfig 4 + local options 5 + 6 + function Commands.set(enable) 7 + if enable then 8 + vim.env.GIT_WORK_TREE = options.git_work_tree 9 + vim.env.GIT_DIR = options.git_dir 10 + else 11 + vim.env.GIT_WORK_TREE = nil 12 + vim.env.GIT_DIR = nil 13 + end 14 + end 15 + 16 + function Commands.toggle() 17 + if vim.env.GIT_DIR == nil or vim.env.GIT_WORK_TREE == nil then 18 + Commands.set(true) 19 + else 20 + Commands.set(false) 21 + end 22 + Commands.info() 23 + end 24 + 25 + function Commands.info() 26 + if vim.env.GIT_DIR == nil or vim.env.GIT_WORK_TREE == nil then 27 + vim.notify("Baredot mode off", vim.log.levels.INFO, { title = "baredot.nvim" }); 28 + else 29 + vim.notify( 30 + "Baredot mode on: GIT_DIR=" .. vim.env.GIT_DIR .. " GIT_WORK_TREE=" .. vim.env.GIT_WORK_TREE, 31 + vim.log.levels.INFO, 32 + { title = "baredot.nvim" } 33 + ); 34 + end 35 + end 36 + 37 + function Commands.setup(opt) 38 + options = opt 39 + 40 + vim.api.nvim_create_user_command("BaredotInfo", Commands.info, { desc = "BaredotInfo" }) 41 + vim.api.nvim_create_user_command("BaredotToggle", Commands.toggle, { desc = "BaredotToggle" }) 42 + end 43 + 44 + return Commands
+51
lua/baredot/init.lua
··· 1 + local commands = require("baredot.commands") 2 + local scan = require("baredot.scan") 3 + 4 + local Baredot = {} 5 + 6 + ---@class BaredotConfig 7 + local defaults = { 8 + git_dir = "~/.cfg", 9 + git_work_tree = "~", 10 + disable_pattern = "%.git" 11 + } 12 + 13 + ---@param opt? BaredotConfig 14 + function Baredot.setup(opt) 15 + ---@type BaredotConfig 16 + local options = vim.tbl_deep_extend("force", {}, defaults, opt or {}) 17 + 18 + options.git_dir = vim.fn.expand(options.git_dir) 19 + options.git_work_tree = vim.fn.expand(options.git_work_tree) 20 + 21 + commands.setup(options) 22 + scan.setup(options) 23 + 24 + if scan.in_work_tree_no_dot_git() then 25 + commands.set(true) 26 + end 27 + 28 + local group = vim.api.nvim_create_augroup("baredot", { clear = true }) 29 + vim.api.nvim_create_autocmd("DirChanged", { 30 + group = group, 31 + desc = "Baredot: scan for .git", 32 + callback = function() 33 + if vim.v.event.scope == "global" then 34 + commands.set(scan.in_work_tree_no_dot_git()) 35 + end 36 + end, 37 + }) 38 + end 39 + 40 + function Baredot.info() 41 + return commands.info() 42 + end 43 + ---@param enable boolean 44 + function Baredot.set(enable) 45 + return commands.set(enable) 46 + end 47 + function Baredot.toggle() 48 + return commands.toggle() 49 + end 50 + 51 + return Baredot
+72
lua/baredot/scan.lua
··· 1 + local Scan = {} 2 + 3 + ---@type BaredotConfig 4 + local options 5 + 6 + -- Modified from ahmedkhalf/project.nvim 7 + local function get_parent(path) 8 + path = path:match("^(.*)/") 9 + if path == "" then 10 + path = "/" 11 + end 12 + return path 13 + end 14 + 15 + local function get_files(file_dir) 16 + local files = {} 17 + local dir = vim.loop.fs_scandir(file_dir) 18 + if dir == nil then 19 + return files 20 + end 21 + 22 + while true do 23 + local file = vim.loop.fs_scandir_next(dir) 24 + if file == nil then 25 + return files 26 + end 27 + 28 + table.insert(files, file) 29 + end 30 + end 31 + 32 + local function has(dir, pattern) 33 + for _, file in ipairs(get_files(dir)) do 34 + if file:match(pattern) ~= nil then 35 + return true 36 + end 37 + end 38 + return false 39 + end 40 + 41 + function Scan.in_work_tree_no_dot_git() 42 + local search_dir = vim.fn.getcwd() 43 + local work_tree_root = options.git_work_tree 44 + if vim.fn.has("win32") > 0 then 45 + search_dir = search_dir:gsub("\\", "/") 46 + work_tree_root = work_tree_root:gsub("\\", "/") 47 + end 48 + 49 + while true do 50 + if search_dir == work_tree_root then 51 + return true 52 + end 53 + 54 + local pattern = options.disable_pattern 55 + if has(search_dir, pattern) then 56 + return false 57 + end 58 + 59 + local parent = get_parent(search_dir) 60 + if parent == nil or parent == search_dir then 61 + return false 62 + end 63 + 64 + search_dir = parent 65 + end 66 + end 67 + 68 + function Scan.setup(opt) 69 + options = opt 70 + end 71 + 72 + return Scan