├── nvim ├── init.lua ├── after │ ├── ftplugin │ │ ├── bicep.lua │ │ ├── bicep-params.lua │ │ └── cs.lua │ ├── ftdetect │ │ ├── log.lua │ │ └── bicep-params.lua │ ├── lsp │ │ └── roslyn.lua │ └── syntax │ │ └── log.vim ├── lua │ ├── plugins │ │ ├── helpview.lua │ │ ├── navic.lua │ │ ├── grug-far.lua │ │ ├── lazydev.lua │ │ ├── nvim-highlight-colors.lua │ │ ├── todo-comments.lua │ │ ├── hop.lua │ │ ├── smear-cursor.lua │ │ ├── nvim-navic.lua │ │ ├── sidekick.lua │ │ ├── markdown-preview.lua │ │ ├── render-markdown.lua │ │ ├── colourscheme.lua │ │ ├── snacks.lua │ │ ├── gitsigns.lua │ │ ├── which-key.lua │ │ ├── noice.lua │ │ ├── conform.lua │ │ ├── blinkcmp.lua │ │ ├── resession.lua │ │ ├── roslyn.lua │ │ ├── dashboard.lua │ │ ├── mason.lua │ │ ├── copilot-chat.lua │ │ ├── treesitter.lua │ │ ├── obsidian.lua │ │ └── mini.lua │ └── core │ │ ├── init.lua │ │ ├── lsp.lua │ │ ├── lazy.lua │ │ ├── options.lua │ │ ├── autocmds.lua │ │ ├── utils.lua │ │ ├── keymaps.lua │ │ └── statusline.lua ├── spell │ ├── en.utf-8.add.spl │ └── en.utf-8.add └── lsp │ ├── nil_ls.lua │ ├── taplo.lua │ ├── templ.lua │ ├── terraformls.lua │ ├── bicep.lua │ ├── jsonls.lua │ ├── ols.lua │ ├── yamlls.lua │ ├── bashls.lua │ ├── html.lua │ ├── luals.lua │ ├── basedpyright.lua │ ├── powershell_es.lua │ ├── gopls.lua │ ├── rust_analyzer.lua │ ├── ts_ls.lua │ ├── copilot.lua │ └── tailwindcss.lua ├── .gitignore ├── bat ├── config └── themes │ └── cyberdream.tmTheme ├── wezterm ├── bg-blurred.png ├── cyberdream.lua ├── cyberdream-light.lua └── wezterm.lua ├── k9s ├── aliases.yaml ├── config.yaml └── skins │ └── cyberdream.yaml ├── README.md ├── fastfetch ├── logos │ └── ascii.txt └── config.jsonc ├── alacritty ├── alacritty.toml └── cyberdream.toml ├── tmux ├── cyberdream.tmuxtheme └── .tmux.conf ├── .bash_profile ├── .gitconfig ├── lazygit └── config.yml ├── starship └── starship.toml ├── LICENSE ├── .github └── workflows │ └── sync.yml ├── setup.sh └── .bashrc /nvim/init.lua: -------------------------------------------------------------------------------- 1 | require("core") -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | nvim/lazy-lock.json 2 | -------------------------------------------------------------------------------- /bat/config: -------------------------------------------------------------------------------- 1 | --theme="cyberdream" 2 | -------------------------------------------------------------------------------- /nvim/after/ftplugin/bicep.lua: -------------------------------------------------------------------------------- 1 | vim.bo.commentstring = "// %s" 2 | -------------------------------------------------------------------------------- /nvim/after/ftplugin/bicep-params.lua: -------------------------------------------------------------------------------- 1 | vim.bo.commentstring = "// %s" 2 | -------------------------------------------------------------------------------- /wezterm/bg-blurred.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scottmckendry/dots/HEAD/wezterm/bg-blurred.png -------------------------------------------------------------------------------- /nvim/lua/plugins/helpview.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "OXY2DEV/helpview.nvim", 3 | ft = "help", 4 | } 5 | -------------------------------------------------------------------------------- /nvim/spell/en.utf-8.add.spl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scottmckendry/dots/HEAD/nvim/spell/en.utf-8.add.spl -------------------------------------------------------------------------------- /nvim/lua/plugins/navic.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "SmiteshP/nvim-navic", 3 | event = { "BufReadPre", "BufNewFile" }, 4 | } 5 | -------------------------------------------------------------------------------- /nvim/after/ftplugin/cs.lua: -------------------------------------------------------------------------------- 1 | vim.bo.commentstring = "// %s" 2 | vim.b.undo_ftplugin = (vim.b.undo_ftplugin or "") .. "\n setl commentstring<" 3 | -------------------------------------------------------------------------------- /nvim/lsp/nil_ls.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = { "nil" }, 4 | filetypes = { "nix" }, 5 | root_markers = { "flake.nix", ".git" }, 6 | } 7 | -------------------------------------------------------------------------------- /nvim/lsp/taplo.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = { "taplo", "lsp", "stdio" }, 4 | filetypes = { "toml" }, 5 | root_markers = { ".git" }, 6 | } 7 | -------------------------------------------------------------------------------- /nvim/lua/core/init.lua: -------------------------------------------------------------------------------- 1 | require("core.options") 2 | require("core.autocmds") 3 | require("core.utils") 4 | require("core.lazy") 5 | require("core.keymaps") 6 | require("core.lsp") 7 | -------------------------------------------------------------------------------- /nvim/lsp/templ.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = { "templ", "lsp" }, 4 | filetypes = { "templ" }, 5 | root_markers = { "go.work", "go.mod", ".git" }, 6 | } 7 | -------------------------------------------------------------------------------- /nvim/lsp/terraformls.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = { "terraform-ls", "serve" }, 4 | filetypes = { "terraform", "terraform-vars" }, 5 | root_markers = { ".terraform", ".git" }, 6 | } 7 | -------------------------------------------------------------------------------- /k9s/aliases.yaml: -------------------------------------------------------------------------------- 1 | aliases: 2 | dp: deployments 3 | sec: v1/secrets 4 | jo: jobs 5 | cr: clusterroles 6 | crb: clusterrolebindings 7 | ro: roles 8 | rb: rolebindings 9 | np: networkpolicies 10 | -------------------------------------------------------------------------------- /nvim/after/ftdetect/log.lua: -------------------------------------------------------------------------------- 1 | vim.filetype.add({ extension = { log = "log" } }) 2 | vim.api.nvim_create_autocmd({ "BufNewFile", "BufRead" }, { 3 | pattern = "*.log", 4 | callback = function() 5 | vim.bo.filetype = "log" 6 | end, 7 | }) 8 | -------------------------------------------------------------------------------- /nvim/lsp/bicep.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = { vim.fn.stdpath("data") .. "/mason/packages/bicep-lsp/bicep-lsp" }, 4 | filetypes = { "bicep", "bicep-params" }, 5 | root_markers = { ".git" }, 6 | init_options = {}, 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dots 2 | My dotfiles for Linux 3 | 4 | Note: this repository is mostly unmaintained. All recent commits are (most-likely) synchronised changes from [Windots](https://github.com/scottmckendry/Windots) or my NixOS [flake](https://github.com/scottmckendry/nix). 5 | -------------------------------------------------------------------------------- /nvim/lua/plugins/grug-far.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "MagicDuck/grug-far.nvim", 3 | cmd = "GrugFar", 4 | config = function() 5 | require("grug-far").setup({ 6 | windowCreationCommand = "botright vsplit %", 7 | }) 8 | end, 9 | } 10 | -------------------------------------------------------------------------------- /nvim/lsp/jsonls.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = { "vscode-json-language-server", "--stdio" }, 4 | filetypes = { "json", "jsonc" }, 5 | init_options = { 6 | provideFormatter = true, 7 | }, 8 | root_markers = { ".git" }, 9 | } 10 | -------------------------------------------------------------------------------- /nvim/lua/plugins/lazydev.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "folke/lazydev.nvim", 3 | ft = "lua", 4 | dependencies = "Bilal2453/luvit-meta", 5 | opts = { 6 | library = { 7 | { path = "luvit-meta/library", words = { "vim%.uv" } }, 8 | }, 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /nvim/after/ftdetect/bicep-params.lua: -------------------------------------------------------------------------------- 1 | vim.filetype.add({ extension = { bicep_params = "bicep-params" } }) 2 | vim.api.nvim_create_autocmd({ "BufNewFile", "BufRead" }, { 3 | pattern = "*.bicepparam", 4 | callback = function() 5 | vim.bo.filetype = "bicep-params" 6 | end, 7 | }) 8 | -------------------------------------------------------------------------------- /nvim/lsp/ols.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = { "ols" }, 4 | filetypes = { "odin" }, 5 | root_markers = { ".git", "main.odin" }, 6 | init_options = { 7 | checker_args = "-vet -strict-style", 8 | enable_references = true, 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /nvim/after/lsp/roslyn.lua: -------------------------------------------------------------------------------- 1 | -- TODO: Remove when roslyn supports lsp progress (properly) 2 | -- See: https://github.com/dotnet/roslyn/issues/79939 3 | return { 4 | handlers = { 5 | ["workspace/_roslyn_projectNeedsRestore"] = function() 6 | return {} 7 | end, 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /nvim/lsp/yamlls.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = { "yaml-language-server", "--stdio" }, 4 | filetypes = { "yaml", "yaml.docker-compose", "yaml.gitlab" }, 5 | root_markers = { ".git" }, 6 | settings = { 7 | redhat = { telemetry = { enabled = false } }, 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /nvim/lua/plugins/nvim-highlight-colors.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "brenoprata10/nvim-highlight-colors", 3 | event = "BufReadPre", 4 | config = function() 5 | require("nvim-highlight-colors").setup({ 6 | render = "virtual", 7 | virtual_symbol = "󰻂", 8 | }) 9 | end, 10 | } 11 | -------------------------------------------------------------------------------- /nvim/lsp/bashls.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = { "bash-language-server", "start" }, 4 | filetypes = { "sh", "bash" }, 5 | root_markers = { ".git" }, 6 | settings = { 7 | bashIde = { 8 | globPattern = "*@(.sh|.inc|.bash|.command)", 9 | }, 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /fastfetch/logos/ascii.txt: -------------------------------------------------------------------------------- 1 |  ▄▄▄ 2 |  ▄█████▄▄  3 | ███▀▀▀▀▀▀▀▀ 4 | ███▄ ▀ ▀▀ 5 |  ▄ █████▄ █▄ 6 | ▀▀▄▄ ▄▄▄▀██▀ 7 |  ██▀▀▀██▀ ▀ 8 |  ▀▀▀▀ ▀▀▀▀ 9 | -------------------------------------------------------------------------------- /alacritty/alacritty.toml: -------------------------------------------------------------------------------- 1 | import = ["/home/scott/.config/alacritty/cyberdream.toml"] 2 | 3 | [font] 4 | size = 10.0 5 | 6 | [font.normal] 7 | family = "JetBrainsMono Nerd Font" 8 | 9 | [window] 10 | decorations = "None" 11 | opacity = 0.75 12 | 13 | [window.dimensions] 14 | columns = 140 15 | lines = 40 16 | 17 | [window.padding] 18 | x = 5 19 | y = 5 20 | -------------------------------------------------------------------------------- /tmux/cyberdream.tmuxtheme: -------------------------------------------------------------------------------- 1 | # cyberdream theme for tmux (catppuccin) 2 | thm_bg="#3c4048" 3 | thm_fg="#ffffff" 4 | thm_cyan="#5ef1ff" 5 | thm_black="#3c4048" 6 | thm_gray="#3c4048" 7 | thm_magenta="#ff5ef1" 8 | thm_pink="#ff5ea0" 9 | thm_red="#ff6e5e" 10 | thm_green="#5ef16c" 11 | thm_yellow="#f1ff5e" 12 | thm_blue="#5ea1ff" 13 | thm_orange="#ffbd5e" 14 | thm_black4="#7b8496" 15 | -------------------------------------------------------------------------------- /nvim/lsp/html.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = { "vscode-html-language-server", "--stdio" }, 4 | filetypes = { "html", "templ" }, 5 | root_markers = { "package.json", ".git" }, 6 | settings = {}, 7 | init_options = { 8 | provideFormatter = true, 9 | embeddedLanguages = { css = true, javascript = true }, 10 | configurationSection = { "html", "css", "javascript" }, 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /nvim/lua/plugins/todo-comments.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "folke/todo-comments.nvim", 3 | cmd = "TodoTelescope", 4 | event = "BufRead", 5 | keys = { 6 | { 7 | "fd", 8 | function() 9 | Snacks.picker.todo_comments() 10 | end, 11 | desc = "Todo", 12 | }, 13 | }, 14 | config = function() 15 | require("todo-comments").setup() 16 | end, 17 | } 18 | -------------------------------------------------------------------------------- /nvim/lsp/luals.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = { "lua-language-server" }, 4 | filetypes = { "lua" }, 5 | settings = { 6 | Lua = { 7 | runtime = { 8 | version = "LuaJIT", 9 | }, 10 | workspace = { 11 | checkThirdParty = false, 12 | library = vim.api.nvim_get_runtime_file("", true), 13 | }, 14 | }, 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /nvim/lua/plugins/hop.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "smoka7/hop.nvim", 3 | opts = { 4 | keys = "etovxqpdygfblzhckisuran", 5 | }, 6 | keys = { 7 | { "S", "HopChar1", { desc = "Hop to Character" } }, 8 | { "s", "HopWord", { desc = "Hop to Word" } }, 9 | { "f", "HopLineStart", { desc = "Hop to Line Start" } }, 10 | { "F", "HopVertical", { desc = "Hop Vertically" } }, 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /.bash_profile: -------------------------------------------------------------------------------- 1 | export STARSHIP_CONFIG=~/git/dots/starship/starship.toml 2 | export PATH=$PATH:/usr/local/go/bin 3 | export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" 4 | export DOTFILES_UPDATE_AVAILABLE="" 5 | export SOFTWARE_UPDATE_AVAILABLE="" 6 | export BAT_CONFIG_DIR=~/git/dots/bat 7 | if [ -z "$BASHRC_LOADED" ]; then 8 | if [ -f ~/.bashrc ]; then 9 | source ~/.bashrc 10 | fi 11 | export BASHRC_LOADED=1 12 | fi 13 | -------------------------------------------------------------------------------- /nvim/lua/plugins/smear-cursor.lua: -------------------------------------------------------------------------------- 1 | local terminal = os.getenv("TERM") 2 | if terminal == "xterm-kitty" then 3 | return {} 4 | end 5 | 6 | return { 7 | "sphamba/smear-cursor.nvim", 8 | event = "VeryLazy", 9 | opts = { 10 | legacy_computing_symbols_support = true, 11 | min_horizontal_distance_smear = 3, 12 | min_vertical_distance_smear = 3, 13 | filetypes_disabled = { 14 | "snacks_terminal", 15 | "lazy", 16 | }, 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /nvim/lua/plugins/nvim-navic.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "smiteshp/nvim-navic", 3 | config = function() 4 | require("nvim-navic").setup({ 5 | lsp = { 6 | auto_attach = true, 7 | -- priority order for attaching LSP servers 8 | -- to the current buffer 9 | preference = { 10 | "html", 11 | "templ", 12 | }, 13 | }, 14 | separator = " 󰁔 ", 15 | }) 16 | end, 17 | } 18 | -------------------------------------------------------------------------------- /nvim/lua/plugins/sidekick.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "folke/sidekick.nvim", 3 | opts = {}, 4 | event = "BufEnter", 5 | keys = { 6 | { 7 | "", 8 | function() 9 | if require("sidekick").nes_jump_or_apply() then 10 | return 11 | end 12 | return "" 13 | end, 14 | mode = { "i", "n" }, 15 | expr = true, 16 | desc = "Goto/Apply Next Edit Suggestion", 17 | }, 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /nvim/lua/plugins/markdown-preview.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "iamcco/markdown-preview.nvim", 3 | ft = { "markdown" }, 4 | cmd = { "MarkdownPreview", "MarkdownPreviewStop", "MarkdownPreviewToggle" }, 5 | build = function() 6 | local install_path = vim.fn.stdpath("data") .. "/lazy/markdown-preview.nvim/app" 7 | vim.cmd("!cd " .. install_path .. " && npm install && git reset --hard") 8 | end, 9 | init = function() 10 | vim.g.mkdp_filetypes = { "markdown" } 11 | vim.g.mkdp_auto_close = 0 12 | end, 13 | } 14 | -------------------------------------------------------------------------------- /.gitconfig: -------------------------------------------------------------------------------- 1 | [user] 2 | name = Scott McKendry 3 | email = 39483124+scottmckendry@users.noreply.github.com 4 | 5 | [core] 6 | editor = nvim 7 | pager = delta 8 | 9 | [delta] 10 | paging = never 11 | syntax-theme = cyberdream 12 | side-by-side = true 13 | 14 | [alias] 15 | co = checkout 16 | hist = log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=short 17 | 18 | [fetch] 19 | prune = true 20 | 21 | [credential "https://github.com"] 22 | helper = !/usr/bin/gh auth git-credential 23 | 24 | [credential "https://gist.github.com"] 25 | helper = !/usr/bin/gh auth git-credential 26 | -------------------------------------------------------------------------------- /wezterm/cyberdream.lua: -------------------------------------------------------------------------------- 1 | return { 2 | foreground = "#ffffff", 3 | background = "#16181a", 4 | 5 | cursor_bg = "#ffffff", 6 | cursor_fg = "#16181a", 7 | cursor_border = "#ffffff", 8 | 9 | selection_fg = "#ffffff", 10 | selection_bg = "#3c4048", 11 | 12 | scrollbar_thumb = "#16181a", 13 | split = "#16181a", 14 | 15 | ansi = { "#16181a", "#ff6e5e", "#5eff6c", "#f1ff5e", "#5ea1ff", "#bd5eff", "#5ef1ff", "#ffffff" }, 16 | brights = { "#3c4048", "#ff6e5e", "#5eff6c", "#f1ff5e", "#5ea1ff", "#bd5eff", "#5ef1ff", "#ffffff" }, 17 | indexed = { [16] = "#ffbd5e", [17] = "#ff6e5e" }, 18 | } 19 | -------------------------------------------------------------------------------- /wezterm/cyberdream-light.lua: -------------------------------------------------------------------------------- 1 | return { 2 | foreground = "#16181a", 3 | background = "#ffffff", 4 | 5 | cursor_bg = "#16181a", 6 | cursor_fg = "#ffffff", 7 | cursor_border = "#16181a", 8 | 9 | selection_fg = "#16181a", 10 | selection_bg = "#acacac", 11 | 12 | scrollbar_thumb = "#ffffff", 13 | split = "#ffffff", 14 | 15 | ansi = { "#ffffff", "#d11500", "#008b0c", "#997b00", "#0057d1", "#a018ff", "#008c99", "#16181a" }, 16 | brights = { "#acacac", "#d11500", "#008b0c", "#997b00", "#0057d1", "#a018ff", "#008c99", "#16181a" }, 17 | indexed = { [16] = "#d17c00", [17] = "#d11500" }, 18 | } 19 | -------------------------------------------------------------------------------- /nvim/lua/plugins/render-markdown.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "MeanderingProgrammer/render-markdown.nvim", 3 | ft = "markdown", 4 | config = function() 5 | require("render-markdown").setup({ 6 | completions = { lsp = { enabled = true } }, 7 | pipe_table = { 8 | border = { "╭", "┬", "╮", "├", "┼", "┤", "╰", "┴", "╯", "│", "─" }, 9 | }, 10 | code = { 11 | width = "block", 12 | left_pad = 2, 13 | right_pad = 2, 14 | }, 15 | bullet = { 16 | left_pad = 0, 17 | right_pad = 1, 18 | }, 19 | }) 20 | end, 21 | } 22 | -------------------------------------------------------------------------------- /nvim/lsp/basedpyright.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = { "basedpyright-langserver", "--stdio" }, 4 | filetypes = { "python" }, 5 | root_markers = { 6 | "pyproject.toml", 7 | "setup.py", 8 | "setup.cfg", 9 | "requirements.txt", 10 | "Pipfile", 11 | "pyrightconfig.json", 12 | ".git", 13 | }, 14 | settings = { 15 | python = { 16 | analysis = { 17 | typeCheckingMode = "strict", 18 | autoImportCompletions = true, 19 | useLibraryCodeForTypes = true, 20 | diagnosticMode = "workspace", 21 | }, 22 | }, 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /nvim/lua/core/lsp.lua: -------------------------------------------------------------------------------- 1 | vim.lsp.inline_completion.enable(true) 2 | 3 | vim.diagnostic.config({ 4 | signs = true, 5 | underline = true, 6 | update_in_insert = true, 7 | virtual_text = { 8 | source = "if_many", 9 | prefix = "●", 10 | }, 11 | }) 12 | 13 | vim.lsp.enable({ 14 | "basedpyright", 15 | "bashls", 16 | "bicep", 17 | "copilot", 18 | "docker_compose_language_service", 19 | "gopls", 20 | "html", 21 | "jsonls", 22 | "luals", 23 | "nil_ls", 24 | "ols", 25 | "powershell_es", 26 | "rust_analyzer", 27 | "tailwindcss", 28 | "taplo", 29 | "templ", 30 | "terraformls", 31 | "ts_ls", 32 | "yamlls", 33 | }) 34 | -------------------------------------------------------------------------------- /alacritty/cyberdream.toml: -------------------------------------------------------------------------------- 1 | [[colors.indexed_colors]] 2 | color = "0xffbd5e" 3 | index = 16 4 | 5 | [[colors.indexed_colors]] 6 | color = "0xff6e5e" 7 | index = 17 8 | 9 | [colors.bright] 10 | black = "0x3c4048" 11 | blue = "0x5ea1ff" 12 | cyan = "0x5ef1ff" 13 | green = "0x5eff6c" 14 | magenta = "0xbd5eff" 15 | red = "0xff6e5e" 16 | white = "0xffffff" 17 | yellow = "0xf1ff5e" 18 | 19 | [colors.normal] 20 | black = "0x16181a" 21 | blue = "0x5ea1ff" 22 | cyan = "0x5ef1ff" 23 | green = "0x5eff6c" 24 | magenta = "0xbd5eff" 25 | red = "0xff6e5e" 26 | white = "0xffffff" 27 | yellow = "0xf1ff5e" 28 | 29 | [colors.primary] 30 | background = "0x16181a" 31 | foreground = "0xffffff" 32 | 33 | [colors.selection] 34 | background = "0x3c4048" 35 | foreground = "0xffffff" 36 | -------------------------------------------------------------------------------- /nvim/lua/plugins/colourscheme.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "scottmckendry/cyberdream.nvim", 3 | dev = true, 4 | lazy = false, 5 | priority = 1000, 6 | config = function() 7 | require("cyberdream").setup({ 8 | variant = "auto", 9 | transparent = true, 10 | italic_comments = true, 11 | hide_fillchars = true, 12 | terminal_colors = false, 13 | cache = true, 14 | borderless_pickers = true, 15 | overrides = function(c) 16 | return { 17 | CursorLine = { bg = c.bg }, 18 | CursorLineNr = { fg = c.magenta }, 19 | } 20 | end, 21 | }) 22 | 23 | vim.cmd("colorscheme cyberdream") 24 | end, 25 | } 26 | -------------------------------------------------------------------------------- /lazygit/config.yml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/jesseduffield/lazygit/master/schema/config.json 2 | notARepository: skip 3 | gui: 4 | nerdFontsVersion: "3" 5 | border: rounded 6 | mouseEvents: false 7 | 8 | theme: 9 | activeBorderColor: 10 | - "#5ef1ff" 11 | inactiveBorderColor: 12 | - "#7b8496" 13 | searchingActiveBorderColor: 14 | - "#ff5ef1" 15 | optionsTextColor: 16 | - "#3c4048" 17 | selectedLineBgColor: 18 | - "#3c4048" 19 | cherryPickedCommitBgColor: 20 | - "#3c4048" 21 | cherryPickedCommitFgColor: 22 | - "#ff5ea0" 23 | unstagedChangesColor: 24 | - "#ffbd5e" 25 | defaultFgColor: 26 | - "#ffffff" 27 | git: 28 | parseEmoji: true 29 | paging: 30 | colorArg: always 31 | useConfig: true 32 | -------------------------------------------------------------------------------- /nvim/lsp/powershell_es.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = function(dispatchers) 4 | local temp_path = vim.fn.stdpath("cache") 5 | local bundle_path = vim.fn.stdpath("data") .. "/mason/packages/powershell-editor-services" 6 | local shell = "pwsh" 7 | local command_fmt = 8 | [[& '%s/PowerShellEditorServices/Start-EditorServices.ps1' -BundledModulesPath '%s' -LogPath '%s/powershell_es.log' -SessionDetailsPath '%s/powershell_es.session.json' -FeatureFlags @() -AdditionalModules @() -HostName nvim -HostProfileId 0 -HostVersion 1.0.0 -Stdio -LogLevel Normal]] 9 | local command = command_fmt:format(bundle_path, bundle_path, temp_path, temp_path) 10 | local cmd = { shell, "-NoLogo", "-NoProfile", "-Command", command } 11 | return vim.lsp.rpc.start(cmd, dispatchers) 12 | end, 13 | filetypes = { "ps1", "psm1" }, 14 | root_markers = { "PSScriptAnalyzerSettings.psd1", ".git" }, 15 | settings = { powershell = { codeFormatting = { Preset = "Stroustrup" } } }, 16 | } 17 | -------------------------------------------------------------------------------- /nvim/lua/plugins/snacks.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "folke/snacks.nvim", 3 | lazy = false, 4 | priority = 1000, 5 | config = function() 6 | require("snacks").setup({ 7 | notifier = { enabled = true }, 8 | words = { enabled = true }, 9 | lazygit = { 10 | configure = false, 11 | win = { 12 | position = "float", 13 | width = 0.99, 14 | height = 0.99, 15 | }, 16 | }, 17 | terminal = { 18 | win = { 19 | position = "right", 20 | width = 0.5, 21 | wo = { 22 | winbar = "", -- hide terminal title 23 | }, 24 | }, 25 | }, 26 | picker = { 27 | formatters = { 28 | file = { 29 | filename_first = true, 30 | }, 31 | }, 32 | prompt = "  ", 33 | }, 34 | }) 35 | end, 36 | } 37 | -------------------------------------------------------------------------------- /starship/starship.toml: -------------------------------------------------------------------------------- 1 | "$schema" = 'https://starship.rs/config-schema.json' 2 | format = """$all $fill $cmd_duration 3 | $character""" 4 | 5 | add_newline = false 6 | 7 | [character] 8 | success_symbol = "[❯](green)" 9 | error_symbol = "[❯](red)" 10 | 11 | [cmd_duration] 12 | min_time = 10 13 | show_milliseconds = true 14 | format = "[$duration](bright-black)" 15 | 16 | [fill] 17 | symbol = ' ' 18 | 19 | [golang] 20 | symbol = " " 21 | 22 | [nodejs] 23 | detect_extensions = [] 24 | 25 | [git_metrics] 26 | disabled = false 27 | format = '(([ $added ]($added_style))([ $deleted ]($deleted_style)))' 28 | only_nonzero_diffs = true 29 | added_style = 'green' 30 | deleted_style = 'red' 31 | 32 | [line_break] 33 | disabled = true 34 | 35 | [jobs] 36 | disabled = true 37 | 38 | [battery] 39 | disabled = true 40 | 41 | [env_var.SOFTWARE_UPDATE_AVAILABLE] 42 | variable = 'SOFTWARE_UPDATE_AVAILABLE' 43 | format = '[$env_value]($style)' 44 | default = '' 45 | style = 'cyan' 46 | 47 | [env_var.DOTFILES_UPDATE_AVAILABLE] 48 | variable = 'DOTFILES_UPDATE_AVAILABLE' 49 | format = '[$env_value]($style)' 50 | default = '' 51 | style = 'cyan' 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Scott McKendry 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. 22 | -------------------------------------------------------------------------------- /k9s/config.yaml: -------------------------------------------------------------------------------- 1 | k9s: 2 | liveViewAutoRefresh: false 3 | refreshRate: 1 4 | maxConnRetry: 5 5 | readOnly: false 6 | noExitOnCtrlC: false 7 | portForwardAddress: localhost 8 | ui: 9 | enableMouse: false 10 | headless: false 11 | logoless: false 12 | crumbsless: false 13 | reactive: false 14 | noIcons: false 15 | defaultsToFullScreen: false 16 | skin: cyberdream 17 | skipLatestRevCheck: false 18 | disablePodCounting: false 19 | shellPod: 20 | image: busybox:1.35.0 21 | namespace: default 22 | limits: 23 | cpu: 100m 24 | memory: 100Mi 25 | imageScans: 26 | enable: false 27 | exclusions: 28 | namespaces: [] 29 | labels: {} 30 | logger: 31 | tail: 100 32 | buffer: 5000 33 | sinceSeconds: -1 34 | textWrap: false 35 | disableAutoscroll: false 36 | showTime: false 37 | thresholds: 38 | cpu: 39 | critical: 90 40 | warn: 70 41 | memory: 42 | critical: 90 43 | warn: 70 44 | -------------------------------------------------------------------------------- /nvim/lua/core/lazy.lua: -------------------------------------------------------------------------------- 1 | local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" 2 | if not (vim.uv or vim.loop).fs_stat(lazypath) then 3 | local lazyrepo = "https://github.com/folke/lazy.nvim.git" 4 | vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) 5 | end 6 | vim.opt.rtp:prepend(lazypath) 7 | 8 | require("lazy").setup({ 9 | spec = { 10 | { import = "plugins" }, 11 | }, 12 | defaults = { 13 | lazy = true, 14 | version = false, 15 | }, 16 | install = { 17 | missing = true, 18 | colorscheme = { "cyberdream" }, 19 | }, 20 | checker = { enabled = true }, 21 | dev = { 22 | path = "~/git", 23 | fallback = true, 24 | }, 25 | ui = { 26 | title = " lazy.nvim 💤", 27 | border = "rounded", 28 | pills = false, 29 | }, 30 | performance = { 31 | rtp = { 32 | disabled_plugins = { 33 | "gzip", 34 | "tarPlugin", 35 | "tohtml", 36 | "zipPlugin", 37 | "netrwPlugin", 38 | "tutor", 39 | }, 40 | }, 41 | }, 42 | }) 43 | -------------------------------------------------------------------------------- /nvim/lua/plugins/gitsigns.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "lewis6991/gitsigns.nvim", 3 | event = { "BufReadPre", "BufNewFile" }, 4 | opts = { 5 | signs = { 6 | add = { text = "▎" }, 7 | change = { text = "▎" }, 8 | delete = { text = "" }, 9 | topdelete = { text = "" }, 10 | changedelete = { text = "▎" }, 11 | untracked = { text = "▎" }, 12 | }, 13 | current_line_blame = true, 14 | on_attach = function(buffer) 15 | local gs = package.loaded.gitsigns 16 | local function map(l, r, desc) 17 | vim.keymap.set("n", l, r, { buffer = buffer, desc = desc }) 18 | end 19 | 20 | map("]h", gs.next_hunk, "Next Hunk") 21 | map("[h", gs.prev_hunk, "Prev Hunk") 22 | map("ghs", ":Gitsigns stage_hunk", "Stage Hunk") 23 | map("ghr", ":Gitsigns reset_hunk", "Reset Hunk") 24 | map("ghS", gs.stage_buffer, "Stage Buffer") 25 | map("ghu", gs.undo_stage_hunk, "Undo Stage Hunk") 26 | map("ghR", gs.reset_buffer, "Reset Buffer") 27 | end, 28 | }, 29 | } 30 | -------------------------------------------------------------------------------- /tmux/.tmux.conf: -------------------------------------------------------------------------------- 1 | set -g @plugin 'tmux-plugins/tpm' 2 | set -g @plugin 'catppuccin/tmux' 3 | 4 | set -g status-position top 5 | bind r source-file ~/.tmux.conf 6 | 7 | set -g @catppuccin_flavour "cyberdream" 8 | set -g @catppuccin_status_background "default" 9 | set -g @catppuccin_window_left_separator "" 10 | set -g @catppuccin_window_right_separator " " 11 | set -g @catppuccin_window_middle_separator " █" 12 | set -g @catppuccin_window_number_position "right" 13 | 14 | set -g @catppuccin_window_default_fill "number" 15 | set -g @catppuccin_window_default_text "#W" 16 | 17 | set -g @catppuccin_window_current_fill "number" 18 | set -g @catppuccin_window_current_text "#W" 19 | 20 | set -g @catppuccin_status_modules_right "directory user host session" 21 | set -g @catppuccin_status_left_separator " " 22 | set -g @catppuccin_status_right_separator "" 23 | set -g @catppuccin_status_fill "icon" 24 | set -g @catppuccin_status_connect_separator "no" 25 | 26 | set -g @catppuccin_directory_text "#{b:pane_current_path}" 27 | 28 | run '~/.tmux/plugins/tpm/tpm' 29 | 30 | # Add padding (blank row) below status line 31 | set -Fg 'status-format[1]' '#{status-format[0]}' 32 | set -g 'status-format[1]' '' 33 | set -g status 2 34 | -------------------------------------------------------------------------------- /.github/workflows/sync.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | 6 | workflow_dispatch: 7 | 8 | name: Sync 9 | 10 | jobs: 11 | sync-files: 12 | strategy: 13 | max-parallel: 3 14 | matrix: 15 | file: [.github, bat, fastfetch, k9s, nvim, starship, wezterm] 16 | repo: [dots, nix, Windots] 17 | exclude: 18 | - repo: ${{ github.event.repository.name }} 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | 24 | - name: Sync ${{ matrix.file }} to ${{ matrix.repo }} 25 | uses: scottmckendry/repo-files-clean-copy-sync@main 26 | env: 27 | API_TOKEN_GITHUB: ${{ secrets.SYNC_TOKEN }} 28 | with: 29 | source_file: "${{ matrix.file }}/" 30 | destination_repo: "scottmckendry/${{ matrix.repo }}" 31 | destination_folder: "/" 32 | user_email: "39483124+scottmckendry@users.noreply.github.com" 33 | user_name: "Scott McKendry" 34 | commit_message: "${{ github.event.head_commit.message }}\n[skip ci]\nAutomated sync from ${{ github.repository }}" 35 | git_server: "github.com" 36 | -------------------------------------------------------------------------------- /nvim/lua/plugins/which-key.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "folke/which-key.nvim", 3 | event = "VeryLazy", 4 | config = function() 5 | local wk = require("which-key") 6 | wk.setup({ 7 | preset = "helix", 8 | icons = { 9 | rules = false, 10 | }, 11 | }) 12 | wk.add({ 13 | { 14 | mode = { "n", "v" }, 15 | { "", group = "tabs" }, 16 | { "a", group = "ai/copilot" }, 17 | { "b", group = "buffer" }, 18 | { "c", group = "code" }, 19 | { "cl", group = "lsp" }, 20 | { "d", group = "diff" }, 21 | { "e", group = "explorer" }, 22 | { "f", group = "file/find" }, 23 | { "g", group = "git" }, 24 | { "o", group = "obsidian" }, 25 | { "r", group = "run" }, 26 | { "rl", group = "lua" }, 27 | { "rs", group = "shell" }, 28 | { "s", group = "search" }, 29 | { "t", group = "toggle" }, 30 | { "w", group = "windows" }, 31 | { "x", group = "diagnostics/quickfix" }, 32 | }, 33 | }) 34 | end, 35 | } 36 | -------------------------------------------------------------------------------- /nvim/lsp/gopls.lua: -------------------------------------------------------------------------------- 1 | local mod_cache = nil 2 | 3 | ---@param fname string 4 | ---@return string? 5 | local function get_root(fname) 6 | if mod_cache and fname:sub(1, #mod_cache) == mod_cache then 7 | local clients = vim.lsp.get_clients({ name = "gopls" }) 8 | if #clients > 0 then 9 | return clients[#clients].config.root_dir 10 | end 11 | end 12 | return vim.fs.root(fname, { "go.work", "go.mod", ".git" }) 13 | end 14 | 15 | --- @type vim.lsp.Config 16 | return { 17 | cmd = { "gopls" }, 18 | filetypes = { "go", "gomod", "gowork", "gotmpl" }, 19 | settings = { 20 | gopls = { 21 | completeUnimported = true, 22 | analyses = { 23 | unusedparams = true, 24 | }, 25 | staticcheck = true, 26 | }, 27 | }, 28 | root_dir = function(bufnr, on_dir) 29 | local fname = vim.api.nvim_buf_get_name(bufnr) 30 | if mod_cache then 31 | on_dir(get_root(fname)) 32 | return 33 | end 34 | local cmd = { "go", "env", "GOMODCACHE" } 35 | vim.system(cmd, { text = true }, function(output) 36 | if output.code == 0 then 37 | if output.stdout then 38 | mod_cache = vim.trim(output.stdout) 39 | end 40 | on_dir(get_root(fname)) 41 | else 42 | vim.notify(("[gopls] cmd failed with code %d: %s\n%s"):format(output.code, cmd, output.stderr)) 43 | end 44 | end) 45 | end, 46 | } 47 | -------------------------------------------------------------------------------- /nvim/lsp/rust_analyzer.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = { "rust-analyzer" }, 4 | filetypes = { "rust" }, 5 | root_dir = function(bufnr, done) 6 | local fname = vim.api.nvim_buf_get_name(bufnr) 7 | 8 | local cargo_crate_dir = vim.fs.root(fname, "Cargo.toml") 9 | 10 | if cargo_crate_dir then 11 | local r = vim.system({ 12 | "cargo", 13 | "metadata", 14 | "--no-deps", 15 | "--format-version", 16 | "1", 17 | "--manifest-path", 18 | cargo_crate_dir .. "/Cargo.toml", 19 | }):wait() 20 | 21 | if r.stdout then 22 | local result = vim.json.decode(r.stdout) 23 | if result["workspace_root"] then 24 | local cargo_workspace_root = vim.fs.normalize(result["workspace_root"]) 25 | return done(cargo_workspace_root) 26 | end 27 | end 28 | 29 | return done(cargo_crate_dir) 30 | end 31 | 32 | local dotgit = vim.fs.root(fname, ".git") 33 | if dotgit then 34 | return done(dotgit) 35 | end 36 | end, 37 | capabilities = { 38 | experimental = { 39 | serverStatusNotification = true, 40 | }, 41 | }, 42 | settings = { 43 | ["rust-analyzer"] = { 44 | checkOnSave = { 45 | command = "clippy", 46 | }, 47 | cargo = { 48 | loadOutDirsFromCheck = true, 49 | }, 50 | }, 51 | }, 52 | } 53 | -------------------------------------------------------------------------------- /nvim/lua/plugins/noice.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "folke/noice.nvim", 4 | event = "VeryLazy", 5 | config = function() 6 | require("noice").setup({ 7 | lsp = { 8 | override = { 9 | ["vim.lsp.util.convert_input_to_markdown_lines"] = true, 10 | ["vim.lsp.util.stylize_markdown"] = true, 11 | ["cmp.entry.get_documentation"] = true, 12 | }, 13 | }, 14 | routes = { 15 | { 16 | filter = { 17 | event = "msg_show", 18 | any = { 19 | { find = "%d+L, %d+B" }, 20 | { find = "; after #%d+" }, 21 | { find = "; before #%d+" }, 22 | }, 23 | }, 24 | opts = { skip = true }, 25 | }, 26 | }, 27 | presets = { 28 | bottom_search = true, 29 | long_message_to_split = true, 30 | lsp_doc_border = true, 31 | }, 32 | cmdline = { 33 | view = "cmdline", 34 | }, 35 | views = { 36 | mini = { 37 | win_options = { 38 | winblend = 0, 39 | }, 40 | }, 41 | }, 42 | }) 43 | end, 44 | }, 45 | } 46 | -------------------------------------------------------------------------------- /nvim/lua/plugins/conform.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "stevearc/conform.nvim", 3 | event = "BufReadPre", 4 | config = function() 5 | vim.g.autoformat = true 6 | require("conform").setup({ 7 | formatters_by_ft = { 8 | css = { "prettier" }, 9 | go = { "goimports_reviser", "gofmt" }, 10 | html = { "prettier" }, 11 | javascript = { "prettier" }, 12 | typescript = { "prettier" }, 13 | json = { "prettier" }, 14 | lua = { "stylua" }, 15 | markdown = { "prettier" }, 16 | nix = { "nixfmt" }, 17 | python = { "black" }, 18 | rust = { "rustfmt" }, 19 | scss = { "prettier" }, 20 | sh = { "shfmt" }, 21 | templ = { "templ" }, 22 | toml = { "taplo" }, 23 | yaml = { "prettier" }, 24 | }, 25 | 26 | format_after_save = function() 27 | if not vim.g.autoformat then 28 | return 29 | else 30 | if vim.bo.filetype == "ps1" then 31 | vim.lsp.buf.format() 32 | return 33 | end 34 | return { lsp_format = "fallback" } 35 | end 36 | end, 37 | 38 | formatters = { 39 | goimports_reviser = { 40 | command = "goimports-reviser", 41 | args = { "-output", "stdout", "$FILENAME" }, 42 | }, 43 | }, 44 | }) 45 | end, 46 | } 47 | -------------------------------------------------------------------------------- /nvim/lua/core/options.lua: -------------------------------------------------------------------------------- 1 | vim.g.mapleader = " " 2 | vim.g.maplocalleader = " " 3 | vim.g.user = os.getenv("USERNAME") or os.getenv("USER") 4 | 5 | local opt = vim.opt 6 | opt.shell = "zsh" 7 | 8 | -- Set shell to PowerShell 7 if on Win32 or Win64 9 | if vim.fn.has("win32") == 1 or vim.fn.has("win64") == 1 then 10 | opt.shell = "pwsh -NoLogo" 11 | opt.shellcmdflag = 12 | "-NoLogo -NoProfile -ExecutionPolicy RemoteSigned -Command [Console]::InputEncoding=[Console]::OutputEncoding=[System.Text.Encoding]::UTF8;" 13 | opt.shellredir = "-RedirectStandardOutput %s -NoNewWindow -Wait" 14 | opt.shellpipe = "2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode" 15 | opt.shellquote = "" 16 | opt.shellxquote = "" 17 | end 18 | 19 | -- UI/General 20 | opt.number = true 21 | opt.relativenumber = true 22 | opt.ignorecase = true 23 | opt.cursorline = true 24 | opt.clipboard = "unnamedplus" 25 | opt.termguicolors = true 26 | opt.confirm = true 27 | opt.mouse = "a" 28 | opt.undofile = true 29 | opt.swapfile = false 30 | opt.conceallevel = 1 31 | opt.scrolloff = 12 32 | opt.wrap = true 33 | opt.linebreak = true 34 | opt.spelllang = "en_nz" 35 | opt.showtabline = 0 36 | 37 | -- Set statusline 38 | opt.laststatus = 3 39 | opt.statusline = require("core.statusline").statusline 40 | 41 | -- Set tab width 42 | opt.tabstop = 4 43 | opt.shiftwidth = 4 44 | opt.expandtab = true 45 | opt.autoindent = true 46 | opt.breakindent = true 47 | opt.breakindentopt = "shift:2" 48 | opt.showbreak = "↳" 49 | 50 | -- Make cursor blink 51 | opt.guicursor = { 52 | "n-v-c:block,i-ci-ve:ver25,r-cr:hor20,o:hor50", 53 | "a:blinkwait700-blinkoff400-blinkon250-Cursor/lCursor", 54 | "sm:block-blinkwait175-blinkoff150-blinkon175", 55 | } 56 | -------------------------------------------------------------------------------- /nvim/lua/plugins/blinkcmp.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "saghen/blink.cmp", 3 | event = "InsertEnter", 4 | dependencies = "rafamadriz/friendly-snippets", 5 | version = "v1.*", 6 | config = function() 7 | local is_enabled = function() 8 | local disabled_ft = { 9 | "TelescopePrompt", 10 | "grug-far", 11 | } 12 | return not vim.tbl_contains(disabled_ft, vim.bo.filetype) 13 | and vim.b.completion ~= false 14 | and vim.bo.buftype ~= "prompt" 15 | end 16 | 17 | require("blink.cmp").setup({ 18 | enabled = is_enabled, 19 | cmdline = { completion = { menu = { auto_show = true } } }, 20 | completion = { 21 | menu = { 22 | scrollbar = false, 23 | auto_show = is_enabled, 24 | border = { 25 | { "󱐋", "WarningMsg" }, 26 | "─", 27 | "╮", 28 | "│", 29 | "╯", 30 | "─", 31 | "╰", 32 | "│", 33 | }, 34 | }, 35 | documentation = { 36 | auto_show = true, 37 | window = { 38 | border = { 39 | { "", "DiagnosticHint" }, 40 | "─", 41 | "╮", 42 | "│", 43 | "╯", 44 | "─", 45 | "╰", 46 | "│", 47 | }, 48 | }, 49 | }, 50 | }, 51 | }) 52 | end, 53 | } 54 | -------------------------------------------------------------------------------- /nvim/lua/plugins/resession.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "stevearc/resession.nvim", 3 | dependencies = { 4 | { 5 | "scottmckendry/pick-resession.nvim", 6 | dev = true, 7 | config = function() 8 | require("pick-resession").setup({ 9 | path_icons = { 10 | { match = "C:/Users/" .. vim.g.user .. "/git/", icon = " ", highlight = "Changed" }, 11 | { match = "/home/" .. vim.g.user .. "/git/", icon = " ", highlight = "Changed" }, 12 | { match = "C:/Users/" .. vim.g.user .. "/", icon = " ", highlight = "Special" }, 13 | { match = "/home/" .. vim.g.user .. "/", icon = " ", highlight = "Special" }, 14 | }, 15 | }) 16 | end, 17 | }, 18 | }, 19 | lazy = false, 20 | config = function() 21 | local resession = require("resession") 22 | resession.setup({ 23 | autosave = { 24 | enabled = true, 25 | interval = 60, 26 | notify = false, 27 | }, 28 | }) 29 | vim.api.nvim_create_autocmd("VimEnter", { 30 | callback = function() 31 | -- Only load the session if nvim was started with no args 32 | if vim.fn.argc(-1) == 0 then 33 | -- Save these to a different directory, so our manual sessions don't get polluted 34 | resession.load(vim.fn.getcwd(), { silence_errors = true }) 35 | end 36 | end, 37 | nested = true, 38 | }) 39 | vim.api.nvim_create_autocmd("VimLeavePre", { 40 | callback = function() 41 | resession.save(vim.fn.getcwd(), { notify = true }) 42 | end, 43 | }) 44 | end, 45 | } 46 | -------------------------------------------------------------------------------- /fastfetch/config.jsonc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", 3 | "logo": { 4 | "source": "ascii.txt", 5 | "type": "file", 6 | "padding": { 7 | "top": 1, 8 | "left": 3 9 | } 10 | }, 11 | "display": { 12 | "separator": "", 13 | "key": { 14 | "width": 15 15 | }, 16 | "color": { 17 | "keys": "white", 18 | "title": "cyan" 19 | } 20 | }, 21 | "modules": [ 22 | { 23 | "key": "╭───────────╮", 24 | "type": "custom" 25 | }, 26 | { 27 | "key": "│ │\u001b[11D{#36} user", 28 | "type": "title" 29 | }, 30 | { 31 | "key": "│ │\u001b[11D{#31}󰅐 uptime", 32 | "type": "uptime" 33 | }, 34 | { 35 | "key": "│ │\u001b[11D{#32} term", 36 | "type": "terminal", 37 | "format": "{5}" 38 | }, 39 | { 40 | "key": "│ │\u001b[11D{#33} shell", 41 | "type": "shell" 42 | }, 43 | { 44 | "key": "│ │\u001b[11D{#34}󰍛 cpu", 45 | "type": "cpu", 46 | "format": "{1}" 47 | }, 48 | { 49 | "key": "│ │\u001b[11D{#35} memory", 50 | "type": "memory" 51 | }, 52 | { 53 | "key": "│ │\u001b[11D{#39}󰓡 swap", 54 | "type": "swap" 55 | }, 56 | { 57 | "key": "│ │\u001b[11D{#36}󰩟 network", 58 | "type": "localip", 59 | "format": "{1} ({4})" 60 | }, 61 | { 62 | "key": "╰───────────╯", 63 | "type": "custom" 64 | } 65 | ] 66 | } 67 | -------------------------------------------------------------------------------- /nvim/lsp/ts_ls.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | init_options = { hostInfo = "neovim" }, 4 | cmd = { "typescript-language-server", "--stdio" }, 5 | filetypes = { 6 | "javascript", 7 | "javascriptreact", 8 | "javascript.jsx", 9 | "typescript", 10 | "typescriptreact", 11 | "typescript.tsx", 12 | }, 13 | root_markers = { "tsconfig.json", "jsconfig.json", "package.json", ".git" }, 14 | handlers = { 15 | -- handle rename request for certain code actions like extracting functions / types 16 | ["_typescript.rename"] = function(_, result, ctx) 17 | local client = assert(vim.lsp.get_client_by_id(ctx.client_id)) 18 | vim.lsp.util.show_document({ 19 | uri = result.textDocument.uri, 20 | range = { 21 | start = result.position, 22 | ["end"] = result.position, 23 | }, 24 | }, client.offset_encoding) 25 | vim.lsp.buf.rename() 26 | return vim.NIL 27 | end, 28 | }, 29 | on_attach = function(client) 30 | -- ts_ls provides `source.*` code actions that apply to the whole file. These only appear in 31 | -- `vim.lsp.buf.code_action()` if specified in `context.only`. 32 | vim.api.nvim_buf_create_user_command(0, "LspTypescriptSourceAction", function() 33 | local source_actions = vim.tbl_filter(function(action) 34 | return vim.startswith(action, "source.") 35 | end, client.server_capabilities.codeActionProvider.codeActionKinds) 36 | 37 | vim.lsp.buf.code_action({ 38 | --- @diagnostic disable-next-line: missing-fields 39 | context = { 40 | only = source_actions, 41 | }, 42 | }) 43 | end, {}) 44 | end, 45 | } 46 | -------------------------------------------------------------------------------- /nvim/lua/plugins/roslyn.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "seblyng/roslyn.nvim", 3 | ft = { "cs", "razor" }, 4 | dependencies = { "tris203/rzls.nvim", config = true }, 5 | init = function() 6 | vim.filetype.add({ 7 | extension = { 8 | razor = "razor", 9 | cshtml = "razor", 10 | }, 11 | }) 12 | end, 13 | config = function() 14 | require("roslyn").setup({ lock_target = true }) 15 | 16 | local function build_cmd() 17 | local log_dir = vim.fs.dirname(vim.lsp.get_log_path()) 18 | local cmd = { 19 | "roslyn", 20 | "--stdio", 21 | "--logLevel=Information", 22 | "--extensionLogDirectory=" .. log_dir, 23 | } 24 | 25 | local rzls_libexec = vim.fn.stdpath("data") .. "/mason/packages/rzls/libexec" 26 | table.insert( 27 | cmd, 28 | "--razorSourceGenerator=" .. vim.fs.joinpath(rzls_libexec, "Microsoft.CodeAnalysis.Razor.Compiler.dll") 29 | ) 30 | table.insert( 31 | cmd, 32 | "--razorDesignTimePath=" 33 | .. vim.fs.joinpath(rzls_libexec, "Targets", "Microsoft.NET.Sdk.Razor.DesignTime.targets") 34 | ) 35 | table.insert(cmd, "--extension") 36 | table.insert( 37 | cmd, 38 | vim.fs.joinpath(rzls_libexec, "RazorExtension", "Microsoft.VisualStudioCode.RazorExtension.dll") 39 | ) 40 | 41 | return cmd 42 | end 43 | 44 | local handlers = (function() 45 | local ok, h = pcall(require, "rzls.roslyn_handlers") 46 | return ok and h or nil 47 | end)() 48 | 49 | vim.lsp.config("roslyn", { 50 | cmd = build_cmd(), 51 | handlers = handlers, 52 | settings = { 53 | ["csharp|code_lens"] = { 54 | dotnet_enable_references_code_lens = true, 55 | }, 56 | }, 57 | }) 58 | 59 | vim.lsp.enable("roslyn") 60 | end, 61 | } 62 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Symlinks: Target -> Destination 4 | declare -A mappings=( 5 | ["$HOME/git/dots/.bash_profile"]=$HOME/.bash_profile 6 | ["$HOME/git/dots/.bashrc"]=$HOME/.bashrc 7 | ["$HOME/git/dots/.gitconfig"]=$HOME/.gitconfig 8 | ["$HOME/git/dots/tmux/.tmux.conf"]=$HOME/.tmux.conf 9 | ["$HOME/git/dots/alacritty"]=$HOME/.config/alacritty 10 | ["$HOME/git/dots/lazygit/"]=$HOME/.config/lazygit 11 | ["$HOME/git/dots/nvim"]=$HOME/.config/nvim 12 | ) 13 | 14 | # Dependencies 15 | deps=( 16 | "alacritty" 17 | "azure-cli-bin" 18 | "bash-completion" 19 | "bat" 20 | "bat" 21 | "bicep-bin" 22 | "eza" 23 | "fastfetch" 24 | "fuse2" 25 | "fuse2fs" 26 | "fuse3" 27 | "fzf" 28 | "github-cli" 29 | "git-delta" 30 | "go" 31 | "lazygit" 32 | "neovim-git" 33 | "nodejs" 34 | "npm" 35 | "powershell-bin" 36 | "python" 37 | "ripgrep" 38 | "screen" 39 | "starship" 40 | "tmux" 41 | "ttf-jetbrains-mono-nerd" 42 | "unzip" 43 | "wget" 44 | "zoxide" 45 | ) 46 | 47 | # Install yay if not already installed 48 | if ! command -v yay &>/dev/null; then 49 | echo "yay could not be found, installing..." 50 | sudo pacman -S --noconfirm git base-devel 51 | 52 | # Clone the yay repository 53 | git clone https://aur.archlinux.org/yay-bin 54 | cd yay-bin 55 | makepkg -si --noconfirm 56 | 57 | # Clean up 58 | cd .. 59 | rm -rf yay-bin 60 | fi 61 | yay -Syu --noconfirm 62 | 63 | # Change to the directory of this script 64 | cd "$(dirname "$0")" 65 | 66 | echo "Removing existing files/directories..." 67 | for key in "${!mappings[@]}"; do 68 | rm -rf ${mappings[$key]} 69 | done 70 | 71 | echo "Creating symbolic links..." 72 | for key in "${!mappings[@]}"; do 73 | ln -sf $key ${mappings[$key]} 74 | done 75 | 76 | echo "Installing Dependencies..." 77 | depString="" 78 | for dep in "${deps[@]}"; do 79 | depString="$depString $dep" 80 | done 81 | yay -S --noconfirm --needed $depString 82 | 83 | echo "Configuring tmux..." 84 | if [ ! -d "$HOME/.tmux/plugins/tpm" ]; then 85 | git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm 86 | fi 87 | $HOME/.tmux/plugins/tpm/bin/install_plugins 88 | ln -sf $HOME/git/dots/tmux/cyberdream.tmuxtheme $HOME/.tmux/plugins/tmux/themes/catppuccin_cyberdream.tmuxtheme 89 | 90 | # install bat themes 91 | cp -f $HOME/git/dots/bat/themes/* $HOME/.config/bat/themes/ 92 | bat cache --clear 93 | bat cache --build 94 | 95 | echo "Done!" 96 | -------------------------------------------------------------------------------- /nvim/lua/plugins/dashboard.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "nvimdev/dashboard-nvim", 3 | event = "VimEnter", 4 | dev = true, 5 | config = function() 6 | vim.cmd("highlight DashboardHeader guifg=#ffffff") 7 | require("dashboard").setup({ 8 | theme = "hyper", 9 | config = { 10 | week_header = { enable = true }, 11 | shortcut = { 12 | { 13 | icon = "󰒲 ", 14 | icon_hl = "Boolean", 15 | desc = "Update ", 16 | group = "Directory", 17 | action = "Lazy update", 18 | key = "u", 19 | }, 20 | { 21 | icon = "  ", 22 | icon_hl = "Boolean", 23 | desc = "Files ", 24 | group = "Statement", 25 | action = function() 26 | Snacks.picker.files() 27 | end, 28 | key = "f", 29 | }, 30 | { 31 | icon = "  ", 32 | icon_hl = "Boolean", 33 | desc = "Recent ", 34 | group = "String", 35 | action = function() 36 | Snacks.picker.recent() 37 | end, 38 | key = "r", 39 | }, 40 | { 41 | icon = "  ", 42 | icon_hl = "Boolean", 43 | desc = "Grep ", 44 | group = "ErrorMsg", 45 | action = function() 46 | Snacks.picker.grep() 47 | end, 48 | key = "g", 49 | }, 50 | { 51 | icon = "  ", 52 | icon_hl = "Boolean", 53 | desc = "Quit ", 54 | group = "WarningMsg", 55 | action = "qall!", 56 | key = "q", 57 | }, 58 | }, 59 | project = { enable = false }, 60 | mru = { enable = false }, 61 | footer = {}, 62 | }, 63 | }) 64 | end, 65 | } 66 | -------------------------------------------------------------------------------- /nvim/lua/plugins/mason.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "williamboman/mason.nvim", 3 | lazy = false, 4 | build = ":MasonUpdate", 5 | config = function() 6 | require("mason").setup({ 7 | ui = { 8 | border = "rounded", 9 | width = 0.8, 10 | height = 0.8, 11 | }, 12 | registries = { 13 | "github:mason-org/mason-registry", 14 | "github:Crashdummyy/mason-registry", 15 | }, 16 | }) 17 | 18 | local linux_only_pacakages = { "nil" } 19 | local ignore_on_nixos = { "nil" } 20 | local mason_packages = { 21 | "basedpyright", 22 | "bash-language-server", 23 | "bicep-lsp", 24 | "black", 25 | "copilot-language-server", 26 | "goimports-reviser", 27 | "golines", 28 | "gopls", 29 | "html-lsp", 30 | "jq", 31 | "json-lsp", 32 | "lua-language-server", 33 | "markdownlint-cli2", 34 | "ols", 35 | "powershell-editor-services", 36 | "prettier", 37 | "roslyn", 38 | "rust-analyzer", 39 | "rzls", 40 | "shfmt", 41 | "stylua", 42 | "tailwindcss-language-server", 43 | "taplo", 44 | "templ", 45 | "terraform-ls", 46 | "typescript-language-server", 47 | "yaml-language-server", 48 | } 49 | 50 | if vim.fn.has("unix") == 1 then 51 | mason_packages = vim.list_extend(mason_packages, linux_only_pacakages) 52 | local os = vim.fn.systemlist("grep ^ID= /etc/os-release | cut -d= -f2")[1] 53 | if os == "nixos" then 54 | mason_packages = vim.tbl_filter(function(p) 55 | return not vim.tbl_contains(ignore_on_nixos, p) 56 | end, mason_packages) 57 | end 58 | end 59 | 60 | local mr = require("mason-registry") 61 | local function ensure_installed() 62 | for _, tool in ipairs(mason_packages) do 63 | local p = mr.get_package(tool) 64 | if not p:is_installed() then 65 | p:install() 66 | end 67 | end 68 | end 69 | if mr.refresh then 70 | mr.refresh(ensure_installed) 71 | else 72 | ensure_installed() 73 | end 74 | end, 75 | } 76 | -------------------------------------------------------------------------------- /.bashrc: -------------------------------------------------------------------------------- 1 | # 2 | # ~/.bashrc 3 | # 4 | 5 | # start tmux 6 | if command -v tmux &>/dev/null && [ -n "$PS1" ] && [[ ! "$TERM" =~ screen ]] && [[ ! "$TERM" =~ tmux ]] && [ -z "$TMUX" ]; then 7 | exec tmux 8 | fi 9 | 10 | export BASHRC_LOADED=1 11 | # If not running interactively, don't do anything 12 | [[ $- != *i* ]] && return 13 | 14 | # Functions 15 | function lsPretty() { 16 | echo "" 17 | eza -a -l --header --icons --hyperlink --time-style relative $1 18 | echo "" 19 | } 20 | 21 | # Check for updates with yay 22 | function checkUpdates() { 23 | updates=$(yay -Qu | wc -l) 24 | if [ $updates -gt 1 ]; then 25 | sed -i "s/SOFTWARE_UPDATE_AVAILABLE=.*/SOFTWARE_UPDATE_AVAILABLE=\"\ \"/" ~/.bash_profile 26 | else 27 | sed -i "s/SOFTWARE_UPDATE_AVAILABLE=.*/SOFTWARE_UPDATE_AVAILABLE=\"\"/" ~/.bash_profile 28 | fi 29 | } 30 | 31 | # Check for updates in dotfiles 32 | function checkDotfilesUpdate() { 33 | cd ~/git/dots 34 | git fetch >/dev/null 35 | updates=$(git status | grep -q "behind" && echo "true" || echo "false") 36 | if $updates; then 37 | sed -i "s/DOTFILES_UPDATE_AVAILABLE=.*/DOTFILES_UPDATE_AVAILABLE=\"󱤜 \"/" ~/.bash_profile 38 | else 39 | sed -i "s/DOTFILES_UPDATE_AVAILABLE=.*/DOTFILES_UPDATE_AVAILABLE=\"\"/" ~/.bash_profile 40 | fi 41 | } 42 | 43 | # Update software using apt 44 | function updateSoftware() { 45 | yay -Syu --noconfirm 46 | sed -i "s/SOFTWARE_UPDATE_AVAILABLE=.*/SOFTWARE_UPDATE_AVAILABLE=\"\"/" ~/.bash_profile 47 | . ~/.bash_profile 48 | } 49 | 50 | # Pull in latest dotfile updates and run setup 51 | function updateDotfiles() { 52 | currentDir=$(pwd) 53 | cd ~/git/dots 54 | git stash 55 | git pull 56 | git stash pop 57 | ./setup.sh 58 | cd $currentDir 59 | sed -i "s/DOTFILES_UPDATE_AVAILABLE=.*/DOTFILES_UPDATE_AVAILABLE=\"\"/" ~/.bash_profile 60 | . ~/.bash_profile 61 | } 62 | 63 | # Environment variables 64 | . ~/.bash_profile 65 | 66 | # Aliases 67 | alias cd='z' 68 | alias cdi='zi' 69 | alias cat='bat' 70 | alias up='updateDotfiles' 71 | alias us='updateSoftware' 72 | alias ls=lsPretty 73 | 74 | # Enable bash completion in interactive shells 75 | if ! shopt -oq posix; then 76 | if [ -f /usr/share/bash-completion/bash_completion ]; then 77 | . /usr/share/bash-completion/bash_completion 78 | elif [ -f /etc/bash_completion ]; then 79 | . /etc/bash_completion 80 | fi 81 | fi 82 | 83 | # Load NVM 84 | [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" 85 | 86 | # Setup prompt 87 | eval "$(starship init bash)" 88 | eval "$(zoxide init bash)" 89 | 90 | (checkUpdates &) 91 | (checkDotfilesUpdate &) 92 | 93 | PROMPT_COMMAND='source ~/.bash_profile;'$PROMPT_COMMAND 94 | -------------------------------------------------------------------------------- /nvim/lua/plugins/copilot-chat.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "CopilotC-Nvim/CopilotChat.nvim", 3 | cmd = "CopilotChat", 4 | keys = { 5 | { 6 | "aa", 7 | function() 8 | return require("CopilotChat").toggle() 9 | end, 10 | desc = "Toggle", 11 | mode = { "n", "v" }, 12 | }, 13 | { 14 | "ax", 15 | function() 16 | return require("CopilotChat").reset() 17 | end, 18 | desc = "Clear", 19 | mode = { "n", "v" }, 20 | }, 21 | { 22 | "aq", 23 | function() 24 | local input = vim.fn.input("Quick Chat: ") 25 | if input ~= "" then 26 | require("CopilotChat").ask(input) 27 | end 28 | end, 29 | desc = "Quick Chat", 30 | mode = { "n", "v" }, 31 | }, 32 | { 33 | "ac", 34 | ":CopilotChatCommit", 35 | desc = "Commit", 36 | mode = { "n", "v" }, 37 | }, 38 | }, 39 | config = function() 40 | vim.api.nvim_create_autocmd("BufEnter", { 41 | pattern = "copilot-chat", 42 | callback = function() 43 | vim.opt_local.relativenumber = false 44 | vim.opt_local.number = false 45 | end, 46 | }) 47 | 48 | require("CopilotChat").setup({ 49 | model = "claude-sonnet-4", 50 | auto_insert_mode = true, 51 | chat_autocomplete = false, 52 | show_help = false, 53 | show_folds = false, 54 | headers = { 55 | user = " " .. vim.g.user:gsub("^%l", string.upper) .. " ", 56 | assistant = " Copilot ", 57 | }, 58 | window = { 59 | layout = "float", 60 | relative = "editor", 61 | row = 0, 62 | col = vim.o.columns - 80, 63 | width = 80, 64 | height = vim.o.lines - 3, 65 | border = "rounded", 66 | }, 67 | mappings = { 68 | close = { 69 | insert = "C-q", -- removes the default C-c mapping 70 | }, 71 | }, 72 | selection = function(source) 73 | local select = require("CopilotChat.select") 74 | return select.visual(source) or select.buffer(source) 75 | end, 76 | }) 77 | end, 78 | } 79 | -------------------------------------------------------------------------------- /nvim/lua/core/autocmds.lua: -------------------------------------------------------------------------------- 1 | local autocmd = vim.api.nvim_create_autocmd 2 | local augroup = vim.api.nvim_create_augroup 3 | local utils = require("core.utils") 4 | 5 | -- General Settings 6 | local general = augroup("General Settings", { clear = true }) 7 | 8 | autocmd("BufEnter", { 9 | callback = function() 10 | vim.opt.formatoptions:remove({ "c", "r", "o" }) 11 | end, 12 | group = general, 13 | desc = "Disable New Line Comment", 14 | }) 15 | 16 | -- NOTE: This is a hacky fix for bicep param files. The current behaviour causes the bicep lsp to detect 17 | -- bicepparem files as bicep files when switching buffers. This isn't an issue when initialising the lsp 18 | -- with a bicepparam file initially. 19 | -- TODO: Find a better solution, report upstream or wait for a fix. 20 | autocmd("BufEnter", { 21 | pattern = { "*.bicepparam" }, 22 | callback = function() 23 | local bicep_client = vim.lsp.get_clients({ name = "bicep" }) 24 | vim.lsp.buf_detach_client(vim.api.nvim_get_current_buf(), bicep_client[1].id) 25 | vim.lsp.buf_attach_client(vim.api.nvim_get_current_buf(), bicep_client[1].id) 26 | end, 27 | group = general, 28 | desc = "Detach and reattach bicep client for bicepparam files", 29 | }) 30 | 31 | autocmd("BufEnter", { 32 | pattern = { "*.md", "*.txt" }, 33 | callback = function() 34 | vim.opt_local.spell = true 35 | end, 36 | group = general, 37 | desc = "Enable spell checking on specific filetypes", 38 | }) 39 | 40 | autocmd("BufWinEnter", { 41 | callback = function(data) 42 | utils.open_help(data.buf) 43 | end, 44 | group = general, 45 | desc = "Redirect help to floating window", 46 | }) 47 | 48 | autocmd("FileType", { 49 | group = general, 50 | pattern = { 51 | "grug-far", 52 | "help", 53 | "checkhealth", 54 | "copilot-chat", 55 | }, 56 | callback = function(event) 57 | vim.bo[event.buf].buflisted = false 58 | vim.keymap.set("n", "q", "close", { 59 | buffer = event.buf, 60 | silent = true, 61 | desc = "Quit buffer", 62 | }) 63 | end, 64 | }) 65 | 66 | autocmd("BufEnter", { 67 | group = general, 68 | callback = function(event) 69 | local two_space_indent_types = { 70 | "nix", 71 | } 72 | if vim.tbl_contains(two_space_indent_types, vim.bo[event.buf].filetype) then 73 | vim.bo[event.buf].shiftwidth = 2 74 | vim.bo[event.buf].tabstop = 2 75 | vim.bo[event.buf].softtabstop = 2 76 | end 77 | end, 78 | }) 79 | -------------------------------------------------------------------------------- /nvim/lua/plugins/treesitter.lua: -------------------------------------------------------------------------------- 1 | return { 2 | "nvim-treesitter/nvim-treesitter", 3 | dependencies = { 4 | "nvim-treesitter/nvim-treesitter-textobjects", 5 | }, 6 | build = ":TSUpdate", 7 | event = { "BufReadPost", "BufNewFile" }, 8 | cmd = { "TSUpdateSync" }, 9 | opts = { 10 | highlight = { enable = true }, 11 | indent = { enable = true }, 12 | textobjects = { 13 | select = { 14 | enable = true, 15 | lookahead = true, 16 | keymaps = { 17 | ["af"] = "@function.outer", 18 | ["if"] = "@function.inner", 19 | ["ac"] = "@class.outer", 20 | ["ic"] = "@class.inner", 21 | ["aa"] = "@parameter.outer", 22 | ["ia"] = "@parameter.inner", 23 | ["al"] = "@loop.outer", 24 | ["il"] = "@loop.inner", 25 | ["ai"] = "@conditional.outer", 26 | ["ii"] = "@conditional.inner", 27 | ["ab"] = "@block.outer", 28 | ["ib"] = "@block.inner", 29 | }, 30 | }, 31 | move = { 32 | enable = true, 33 | set_jumps = true, 34 | goto_next_start = { 35 | ["]f"] = "@function.outer", 36 | ["]c"] = "@class.outer", 37 | }, 38 | goto_next_end = { 39 | ["]F"] = "@function.outer", 40 | ["]C"] = "@class.outer", 41 | }, 42 | goto_previous_start = { 43 | ["[f"] = "@function.outer", 44 | ["[c"] = "@class.outer", 45 | }, 46 | goto_previous_end = { 47 | ["[F"] = "@function.outer", 48 | ["[C"] = "@class.outer", 49 | }, 50 | }, 51 | }, 52 | ensure_installed = { 53 | "bash", 54 | "bicep", 55 | "css", 56 | "c_sharp", 57 | "gitignore", 58 | "go", 59 | "gomod", 60 | "gosum", 61 | "gowork", 62 | "html", 63 | "http", 64 | "json", 65 | "kdl", 66 | "lua", 67 | "luadoc", 68 | "luap", 69 | "markdown", 70 | "markdown_inline", 71 | "nix", 72 | "odin", 73 | "powershell", 74 | "python", 75 | "razor", 76 | "regex", 77 | "ron", 78 | "rust", 79 | "sql", 80 | "templ", 81 | "terraform", 82 | "toml", 83 | "typescript", 84 | "vimdoc", 85 | "yaml", 86 | }, 87 | }, 88 | config = function(_, opts) 89 | require("nvim-treesitter.configs").setup(opts) 90 | end, 91 | } 92 | -------------------------------------------------------------------------------- /k9s/skins/cyberdream.yaml: -------------------------------------------------------------------------------- 1 | k9s: 2 | body: 3 | fgColor: "#ffffff" 4 | bgColor: default 5 | logoColor: "#bd5eff" 6 | prompt: 7 | fgColor: "#ffffff" 8 | bgColor: default 9 | suggestColor: "#5ea1ff" 10 | help: 11 | fgColor: "#ffffff" 12 | bgColor: default 13 | sectionColor: "#5eff6c" 14 | keyColor: "#5ea1ff" 15 | numKeyColor: "#ff6e5e" 16 | frame: 17 | title: 18 | fgColor: "#5ef1ff" 19 | bgColor: default 20 | highlightColor: "#ff5ea0" 21 | counterColor: "#f1ff5e" 22 | filterColor: "#5eff6c" 23 | border: 24 | fgColor: "#bd5eff" 25 | focusColor: "#5ea1ff" 26 | menu: 27 | fgColor: "#ffffff" 28 | keyColor: "#5ea1ff" 29 | numKeyColor: "#ff6e5e" 30 | crumbs: 31 | fgColor: "#16181a" 32 | bgColor: default 33 | activeColor: "#ffbd5e" 34 | status: 35 | newColor: "#5ea1ff" 36 | modifyColor: "#5ea1ff" 37 | addColor: "#5eff6c" 38 | pendingColor: "#ffbd5e" 39 | errorColor: "#ff6e5e" 40 | highlightColor: "#5ef1ff" 41 | killColor: "#bd5eff" 42 | completedColor: "#7b8496" 43 | info: 44 | fgColor: "#ffbd5e" 45 | sectionColor: "#ffffff" 46 | views: 47 | table: 48 | fgColor: "#ffffff" 49 | bgColor: default 50 | cursorFgColor: "#16181a" 51 | cursorBgColor: "#3c4048" 52 | markColor: "#ff5ea0" 53 | header: 54 | fgColor: "#3c4048" 55 | bgColor: default 56 | sorterColor: "#5ef1ff" 57 | xray: 58 | fgColor: "#ffffff" 59 | bgColor: default 60 | cursorColor: "#3c4048" 61 | cursorTextColor: "#16181a" 62 | graphicColor: "#ff5ea0" 63 | charts: 64 | bgColor: default 65 | chartBgColor: default 66 | dialBgColor: default 67 | defaultDialColors: 68 | - "#5eff6c" 69 | - "#ff6e5e" 70 | defaultChartColors: 71 | - "#5eff6c" 72 | - "#ff6e5e" 73 | resourceColors: 74 | cpu: 75 | - "#bd5eff" 76 | - "#5ea1ff" 77 | mem: 78 | - "#f1ff5e" 79 | - "#ffbd5e" 80 | yaml: 81 | keyColor: "#5ea1ff" 82 | valueColor: "#ffffff" 83 | colonColor: "#7b8496" 84 | logs: 85 | fgColor: "#ffffff" 86 | bgColor: default 87 | indicator: 88 | fgColor: "#5ea1ff" 89 | bgColor: default 90 | toggleOnColor: "#5eff6c" 91 | toggleOffColor: "#7b8496" 92 | dialog: 93 | fgColor: "#f1ff5e" 94 | bgColor: default 95 | buttonFgColor: "#16181a" 96 | buttonBgColor: default 97 | buttonFocusFgColor: "#16181a" 98 | buttonFocusBgColor: "#ff5ea0" 99 | labelFgColor: "#ffbd5e" 100 | fieldFgColor: "#ffffff" 101 | -------------------------------------------------------------------------------- /nvim/lsp/copilot.lua: -------------------------------------------------------------------------------- 1 | ---@param bufnr integer, 2 | ---@param client vim.lsp.Client 3 | local function sign_in(bufnr, client) 4 | client:request( 5 | ---@diagnostic disable-next-line: param-type-mismatch 6 | "signIn", 7 | vim.empty_dict(), 8 | function(err, result) 9 | if err then 10 | vim.notify(err.message, vim.log.levels.ERROR) 11 | return 12 | end 13 | if result.command then 14 | local code = result.userCode 15 | local command = result.command 16 | vim.fn.setreg("+", code) 17 | vim.fn.setreg("*", code) 18 | local continue = vim.fn.confirm( 19 | "Copied your one-time code to clipboard.\n" .. "Open the browser to complete the sign-in process?", 20 | "&Yes\n&No" 21 | ) 22 | if continue == 1 then 23 | client:exec_cmd(command, { bufnr = bufnr }, function(cmd_err, cmd_result) 24 | if cmd_err then 25 | vim.notify(err.message, vim.log.levels.ERROR) 26 | return 27 | end 28 | if cmd_result.status == "OK" then 29 | vim.notify("Signed in as " .. cmd_result.user .. ".") 30 | end 31 | end) 32 | end 33 | end 34 | 35 | if result.status == "PromptUserDeviceFlow" then 36 | vim.notify("Enter your one-time code " .. result.userCode .. " in " .. result.verificationUri) 37 | elseif result.status == "AlreadySignedIn" then 38 | vim.notify("Already signed in as " .. result.user .. ".") 39 | end 40 | end 41 | ) 42 | end 43 | 44 | ---@param client vim.lsp.Client 45 | local function sign_out(_, client) 46 | client:request( 47 | ---@diagnostic disable-next-line: param-type-mismatch 48 | "signOut", 49 | vim.empty_dict(), 50 | function(err, result) 51 | if err then 52 | vim.notify(err.message, vim.log.levels.ERROR) 53 | return 54 | end 55 | if result.status == "NotSignedIn" then 56 | vim.notify("Not signed in.") 57 | end 58 | end 59 | ) 60 | end 61 | 62 | ---@type vim.lsp.Config 63 | return { 64 | cmd = { 65 | "copilot-language-server", 66 | "--stdio", 67 | }, 68 | root_markers = { ".git" }, 69 | init_options = { 70 | editorInfo = { 71 | name = "Neovim", 72 | version = tostring(vim.version()), 73 | }, 74 | editorPluginInfo = { 75 | name = "Neovim", 76 | version = tostring(vim.version()), 77 | }, 78 | }, 79 | settings = { 80 | telemetry = { 81 | telemetryLevel = "all", 82 | }, 83 | }, 84 | on_attach = function(client, bufnr) 85 | vim.api.nvim_buf_create_user_command(bufnr, "LspCopilotSignIn", function() 86 | sign_in(bufnr, client) 87 | end, { desc = "Sign in Copilot with GitHub" }) 88 | vim.api.nvim_buf_create_user_command(bufnr, "LspCopilotSignOut", function() 89 | sign_out(bufnr, client) 90 | end, { desc = "Sign out Copilot with GitHub" }) 91 | end, 92 | } 93 | -------------------------------------------------------------------------------- /nvim/lsp/tailwindcss.lua: -------------------------------------------------------------------------------- 1 | --- @type vim.lsp.Config 2 | return { 3 | cmd = { "tailwindcss-language-server", "--stdio" }, 4 | -- filetypes copied and adjusted from tailwindcss-intellisense 5 | filetypes = { 6 | -- html 7 | "aspnetcorerazor", 8 | "astro", 9 | "astro-markdown", 10 | "blade", 11 | "clojure", 12 | "django-html", 13 | "htmldjango", 14 | "edge", 15 | "eelixir", -- vim ft 16 | "elixir", 17 | "ejs", 18 | "erb", 19 | "eruby", -- vim ft 20 | "gohtml", 21 | "gohtmltmpl", 22 | "haml", 23 | "handlebars", 24 | "hbs", 25 | "html", 26 | "htmlangular", 27 | "html-eex", 28 | "heex", 29 | "jade", 30 | "leaf", 31 | "liquid", 32 | "markdown", 33 | "mdx", 34 | "mustache", 35 | "njk", 36 | "nunjucks", 37 | "php", 38 | "razor", 39 | "slim", 40 | "twig", 41 | -- css 42 | "css", 43 | "less", 44 | "postcss", 45 | "sass", 46 | "scss", 47 | "stylus", 48 | "sugarss", 49 | -- js 50 | "javascript", 51 | "javascriptreact", 52 | "reason", 53 | "rescript", 54 | "typescript", 55 | "typescriptreact", 56 | -- mixed 57 | "vue", 58 | "svelte", 59 | "templ", 60 | }, 61 | settings = { 62 | tailwindCSS = { 63 | validate = true, 64 | lint = { 65 | cssConflict = "warning", 66 | invalidApply = "error", 67 | invalidScreen = "error", 68 | invalidVariant = "error", 69 | invalidConfigPath = "error", 70 | invalidTailwindDirective = "error", 71 | recommendedVariantOrder = "warning", 72 | }, 73 | classAttributes = { 74 | "class", 75 | "className", 76 | "class:list", 77 | "classList", 78 | "ngClass", 79 | }, 80 | includeLanguages = { 81 | eelixir = "html-eex", 82 | eruby = "erb", 83 | templ = "html", 84 | htmlangular = "html", 85 | }, 86 | }, 87 | }, 88 | before_init = function(_, config) 89 | if not config.settings then 90 | config.settings = {} 91 | end 92 | if not config.settings.editor then 93 | config.settings.editor = {} 94 | end 95 | if not config.settings.editor.tabSize then 96 | config.settings.editor.tabSize = vim.lsp.util.get_effective_tabstop() 97 | end 98 | end, 99 | workspace_required = true, 100 | root_dir = function(bufnr, on_dir) 101 | local root_files = { 102 | "tailwind.config.js", 103 | "tailwind.config.cjs", 104 | "tailwind.config.mjs", 105 | "tailwind.config.ts", 106 | "postcss.config.js", 107 | "postcss.config.cjs", 108 | "postcss.config.mjs", 109 | "postcss.config.ts", 110 | } 111 | local fname = vim.api.nvim_buf_get_name(bufnr) 112 | on_dir(vim.fs.dirname(vim.fs.find(root_files, { path = fname, upward = true })[1])) 113 | end, 114 | } 115 | -------------------------------------------------------------------------------- /wezterm/wezterm.lua: -------------------------------------------------------------------------------- 1 | -- Initialize Configuration 2 | local wezterm = require("wezterm") 3 | local config = wezterm.config_builder() 4 | local opacity = 1 5 | local transparent_bg = "rgba(22, 24, 26, " .. opacity .. ")" 6 | 7 | --- Get the current operating system 8 | --- @return "windows"| "linux" | "macos" 9 | local function get_os() 10 | local bin_format = package.cpath:match("%p[\\|/]?%p(%a+)") 11 | if bin_format == "dll" then 12 | return "windows" 13 | elseif bin_format == "so" then 14 | return "linux" 15 | end 16 | 17 | return "macos" 18 | end 19 | 20 | local host_os = get_os() 21 | 22 | -- Font Configuration 23 | local emoji_font = "Segoe UI Emoji" 24 | config.font = wezterm.font_with_fallback({ 25 | { 26 | family = "JetBrainsMono Nerd Font", 27 | weight = "Regular", 28 | }, 29 | emoji_font, 30 | }) 31 | config.font_size = 10 32 | 33 | -- Color Configuration 34 | config.colors = require("cyberdream") 35 | config.force_reverse_video_cursor = true 36 | 37 | -- Window Configuration 38 | config.initial_rows = 45 39 | config.initial_cols = 180 40 | config.window_decorations = "RESIZE" 41 | config.window_background_opacity = opacity 42 | config.window_background_image = (os.getenv("WEZTERM_CONFIG_FILE") or ""):gsub("wezterm.lua", "bg-blurred.png") 43 | config.window_close_confirmation = "NeverPrompt" 44 | config.win32_system_backdrop = "Acrylic" 45 | 46 | -- Performance Settings 47 | config.max_fps = 144 48 | config.animation_fps = 60 49 | config.cursor_blink_rate = 250 50 | 51 | -- Tab Bar Configuration 52 | config.enable_tab_bar = true 53 | config.hide_tab_bar_if_only_one_tab = true 54 | config.show_tab_index_in_tab_bar = false 55 | config.use_fancy_tab_bar = false 56 | config.colors.tab_bar = { 57 | background = config.window_background_image and "rgba(0, 0, 0, 0)" or transparent_bg, 58 | new_tab = { fg_color = config.colors.background, bg_color = config.colors.brights[6] }, 59 | new_tab_hover = { fg_color = config.colors.background, bg_color = config.colors.foreground }, 60 | } 61 | 62 | -- Tab Formatting 63 | wezterm.on("format-tab-title", function(tab, _, _, _, hover) 64 | local background = config.colors.brights[1] 65 | local foreground = config.colors.foreground 66 | 67 | if tab.is_active then 68 | background = config.colors.brights[7] 69 | foreground = config.colors.background 70 | elseif hover then 71 | background = config.colors.brights[8] 72 | foreground = config.colors.background 73 | end 74 | 75 | local title = tostring(tab.tab_index + 1) 76 | return { 77 | { Foreground = { Color = background } }, 78 | { Text = "█" }, 79 | { Background = { Color = background } }, 80 | { Foreground = { Color = foreground } }, 81 | { Text = title }, 82 | { Foreground = { Color = background } }, 83 | { Text = "█" }, 84 | } 85 | end) 86 | 87 | -- Keybindings 88 | config.keys = { 89 | { key = "v", mods = "CTRL", action = wezterm.action({ PasteFrom = "Clipboard" }) }, 90 | } 91 | 92 | -- Default Shell Configuration 93 | config.default_prog = { "pwsh", "-NoLogo" } 94 | 95 | -- OS-Specific Overrides 96 | if host_os == "linux" then 97 | emoji_font = "Noto Color Emoji" 98 | config.default_prog = { "zsh" } 99 | config.front_end = "WebGpu" 100 | config.window_background_image = os.getenv("HOME") .. "/.config/wezterm/bg-blurred.png" 101 | config.window_decorations = nil -- use system decorations 102 | end 103 | 104 | return config 105 | -------------------------------------------------------------------------------- /nvim/lua/plugins/obsidian.lua: -------------------------------------------------------------------------------- 1 | local obsidian_path = os.getenv("OBSIDIAN_PATH") 2 | if not obsidian_path then 3 | return {} 4 | end 5 | 6 | return { 7 | "obsidian-nvim/obsidian.nvim", 8 | dependencies = { 9 | "nvim-lua/plenary.nvim", 10 | }, 11 | ft = "markdown", 12 | keys = { 13 | { "on", "Obsidian new_from_template Core", desc = "New Obsidian note" }, 14 | { "oo", "Obsidian search", desc = "Search Obsidian notes" }, 15 | { "os", "Obsidian quick_switch", desc = "Quick Switch" }, 16 | { "ob", "Obsidian backlinks", desc = "Show location list of backlinks" }, 17 | { "of", "Obsidian follow_link", desc = "Follow link under cursor" }, 18 | { "ot", "Obsidian template Core", desc = "Apply Core Template" }, 19 | 20 | -- Custom git sync job - manual trigger. Auto sync is available but off by default. 21 | -- Toggle on with to (toggle obsidian git sync) 22 | { "og", "ObsidianGitSync", desc = "Sync changes to git" }, 23 | }, 24 | opts = { 25 | 26 | attachments = { img_folder = obsidian_path .. "/Files" }, 27 | completion = { blink = true }, 28 | picker = { snacks = true }, 29 | disable_frontmatter = true, 30 | new_notes_location = "notes_subdir", 31 | notes_subdir = "Zettelkasten", 32 | templates = { folder = "Templates", date_format = "%y%m%d", time_format = "%H%M" }, 33 | workspaces = { { name = "vault", path = obsidian_path } }, 34 | 35 | note_id_func = function(title) 36 | if title ~= nil then 37 | return title 38 | else 39 | return os.date("%Y%m%d%H%M%S") 40 | end 41 | end, 42 | 43 | -- open external links in preferred browser 44 | follow_url_func = function(url) 45 | local cmd = { "xdg-open", url } 46 | if vim.fn.has("win32") == 1 then 47 | cmd = { "explorer", url } 48 | end 49 | vim.fn.jobstart(cmd) 50 | end, 51 | 52 | legacy_commands = false, 53 | }, 54 | 55 | config = function(_, opts) 56 | require("obsidian").setup(opts) 57 | local job = require("plenary.job") 58 | local update_interval_mins = 2 59 | 60 | -- check for any changes in the vault & pull them in 61 | local function pull_changes() 62 | job:new({ 63 | command = "git", 64 | args = { "pull" }, 65 | cwd = obsidian_path, 66 | }):start() 67 | end 68 | 69 | local function push_changes() 70 | vim.notify("Pushing updates...", 2, { title = "Obsidian.nvim" }) 71 | job:new({ 72 | command = "git", 73 | args = { "push" }, 74 | cwd = obsidian_path, 75 | }):start() 76 | end 77 | 78 | local function commit_changes() 79 | local timestamp = os.date("%Y-%m-%d %H:%M:%S") 80 | job:new({ 81 | command = "git", 82 | args = { "commit", "-m", "vault backup: " .. timestamp }, 83 | cwd = obsidian_path, 84 | on_exit = function() 85 | push_changes() 86 | end, 87 | on_stderr = function(_, data) 88 | vim.notify("Error committing changes: " .. data, 2, { title = "Obsidian.nvim" }) 89 | end, 90 | }):start() 91 | end 92 | 93 | local function stage_changes() 94 | vim.notify("Performing git sync...", 2, { title = "Obsidian.nvim" }) 95 | job:new({ 96 | command = "git", 97 | args = { "add", "." }, 98 | cwd = obsidian_path, 99 | on_exit = function() 100 | commit_changes() 101 | end, 102 | on_stderr = function(_, data) 103 | vim.notify("Error staging changes: " .. data, 2, { title = "Obsidian.nvim" }) 104 | end, 105 | }):start() 106 | end 107 | 108 | local function sync_changes() 109 | stage_changes() 110 | pull_changes() 111 | end 112 | 113 | local function schedule_update() 114 | if not vim.g.obsidian_git_sync then 115 | return 116 | end 117 | vim.defer_fn(function() 118 | sync_changes() 119 | schedule_update() 120 | end, update_interval_mins * 60 * 1000) 121 | end 122 | 123 | schedule_update() 124 | vim.g.obsidian_git_sync = false 125 | 126 | vim.api.nvim_create_user_command("ObsidianGitSync", function() 127 | sync_changes() 128 | end, {}) 129 | end, 130 | } 131 | -------------------------------------------------------------------------------- /nvim/lua/core/utils.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | --- Get highlight properties for a given highlight name 4 | --- @param name string The highlight group name 5 | --- @param fallback? table The fallback highlight properties 6 | --- @return table properties # the highlight group properties 7 | function M.get_hlgroup(name, fallback) 8 | if vim.fn.hlexists(name) == 1 then 9 | local group = vim.api.nvim_get_hl(0, { name = name }) 10 | 11 | local hl = { 12 | fg = group.fg == nil and "NONE" or M.parse_hex(group.fg), 13 | bg = group.bg == nil and "NONE" or M.parse_hex(group.bg), 14 | } 15 | 16 | return hl 17 | end 18 | return fallback or {} 19 | end 20 | 21 | --- Switch to the previous buffer 22 | function M.switch_to_other_buffer() 23 | -- try alternate buffer first 24 | local ok, _ = pcall(function() 25 | vim.cmd("buffer #") 26 | end) 27 | if ok then 28 | return 29 | end 30 | 31 | -- fallback to previous buffer 32 | if M.get_buffer_count() > 1 then 33 | vim.cmd("bprevious") 34 | return 35 | end 36 | 37 | vim.notify("No other buffer to switch to!", 3, { title = "Warning" }) 38 | end 39 | 40 | --- Get the number of open buffers 41 | --- @return number 42 | function M.get_buffer_count() 43 | local count = 0 44 | for _, buf in ipairs(vim.api.nvim_list_bufs()) do 45 | if vim.bo[buf].buflisted and vim.bo[buf].buftype ~= "nofile" then 46 | count = count + 1 47 | end 48 | end 49 | return count 50 | end 51 | 52 | --- Parse a given integer color to a hex value. 53 | --- @param int_color number 54 | function M.parse_hex(int_color) 55 | return string.format("#%x", int_color) 56 | end 57 | 58 | --- Open the help window in a floating window 59 | --- @param buf number The buffer number 60 | function M.open_help(buf) 61 | if buf ~= nil and vim.bo[buf].filetype == "help" and not vim.bo[buf].modifiable then 62 | local help_win = vim.api.nvim_get_current_win() 63 | local new_win = vim.api.nvim_open_win(buf, true, { 64 | relative = "editor", 65 | row = 0, 66 | col = vim.o.columns - 80, 67 | width = 80, 68 | height = vim.o.lines - 3, 69 | border = "rounded", 70 | }) 71 | 72 | -- set scroll position 73 | vim.wo[help_win].scroll = vim.wo[new_win].scroll 74 | 75 | -- close the help window 76 | vim.api.nvim_win_close(help_win, true) 77 | end 78 | end 79 | 80 | --- Write a table of lines to a file 81 | --- @param file string Path to the file 82 | --- @param lines table Table of lines to write to the file 83 | function M.write_to_file(file, lines) 84 | if not lines or #lines == 0 then 85 | return 86 | end 87 | local buf = io.open(file, "w") 88 | for _, line in ipairs(lines) do 89 | if buf ~= nil then 90 | buf:write(line .. "\n") 91 | end 92 | end 93 | 94 | if buf ~= nil then 95 | buf:close() 96 | end 97 | end 98 | 99 | function M.toggle_global_boolean(option, description) 100 | return require("snacks").toggle({ 101 | name = description, 102 | get = function() 103 | return vim.g[option] == nil or vim.g[option] 104 | end, 105 | set = function(state) 106 | vim.g[option] = state 107 | end, 108 | }) 109 | end 110 | 111 | --- Open K9s in a fullscreen interactive terminal 112 | ---@param cmd table The command to run in the terminal 113 | --- @param fullscreen? boolean Open ther terminal in a fullscreen float 114 | function M.open_terminal_toggle(cmd, fullscreen) 115 | local snacks = require("snacks") 116 | local opts = fullscreen and { win = { position = "float", width = 0.99, height = 0.99 } } or nil 117 | snacks.terminal.toggle(cmd, opts) 118 | if vim.bo.filetype == "snacks_terminal" then 119 | vim.notify("_Double press `ESC`_ to return to normal mode", 2, { title = cmd[1] }) 120 | end 121 | end 122 | 123 | --- Restart all LSP clients attached to the current buffer 124 | function M.restart_lsp() 125 | local clients = vim.lsp.get_clients({ bufnr = 0 }) 126 | if #clients == 0 then 127 | vim.notify("No LSP client attached to current buffer", vim.log.levels.WARN) 128 | return 129 | end 130 | for _, client in ipairs(clients) do 131 | local config = client.config 132 | local name = client.name 133 | client.stop(true) 134 | vim.defer_fn(function() 135 | vim.lsp.start(config) 136 | vim.notify("LSP restarted: " .. name, vim.log.levels.INFO) 137 | end, 50) 138 | end 139 | end 140 | 141 | --- Open the LSP log file in a readonly split 142 | function M.open_lsp_log() 143 | local log_path = vim.lsp.get_log_path() 144 | if vim.fn.filereadable(log_path) == 0 then 145 | vim.notify("LSP log file not found: " .. log_path, vim.log.levels.WARN) 146 | return 147 | end 148 | vim.cmd("e " .. log_path) 149 | vim.notify("Opened LSP log: " .. log_path, vim.log.levels.INFO) 150 | end 151 | 152 | return M 153 | -------------------------------------------------------------------------------- /nvim/after/syntax/log.vim: -------------------------------------------------------------------------------- 1 | " Vim syntax file" 2 | " Based on log-highlight.nvim by @fei6409 3 | " https://github.com/fei6409/log-highlight.nvim 4 | 5 | if exists("b:current_syntax") 6 | finish 7 | endif 8 | 9 | let s:cpo_save = &cpo 10 | set cpo&vim 11 | 12 | " Symbols / special characters 13 | " ------------------------------ 14 | syn match logSymbol display '[!@#$%^&*;:?]' 15 | 16 | " Separators 17 | " ------------------------------ 18 | syn match logSeparatorLine display '-\{3,}\|=\{3,}\|#\{3,}\|\*\{3,}\|<\{3,}\|>\{3,}' 19 | 20 | " Strings 21 | " ------------------------------ 22 | syn region logString start=/"/ end=/"/ end=/$/ skip=/\\./ 23 | syn region logString start=/`/ end=/`/ end=/$/ skip=/\\./ 24 | " Quoted strings, but no match on quotes like `don't`, possessive `s'` and `'s` 25 | syn region logString start=/\(s\)\@' 30 | syn match logNumberFloat display '\<\d\+\.\d\+\([eE][+-]\?\d\+\)\?\>' 31 | syn match logNumberBin display '\<0[bB][01]\+\>' 32 | syn match logNumberOctal display '\<0[oO]\o\+\>' 33 | syn match logNumberHex display '\<0[xX]\x\+\>' 34 | 35 | " Numbers in Hardware Description Languages e.g. Verilog 36 | " Note that this must come after logString to have a higher priority over it 37 | syn match logNumber display '\'d\d\+\>' 38 | syn match logNumberBin display '\'b[01]\+\>' 39 | syn match logNumberOctal display '\'o\o\+\>' 40 | syn match logNumberHex display '\'h\x\+\>' 41 | 42 | " Constants 43 | " ------------------------------ 44 | syn keyword logBool TRUE True true FALSE False false 45 | syn keyword logNull NULL Null null 46 | 47 | " Date & Time 48 | " ------------------------------ 49 | " 2023-01-01 or 2023/01/01 or 01/01/2023 or 01-Jan-2023 50 | syn match logDate display '\<\d\{4}[-\/]\(\d\d\|\a\{3}\)[-\/]\d\d\|\d\d[-\/]\(\d\d\|\a\{3}\)[-\/]\d\{4}' contains=logDateMonth 51 | " RFC3339 e.g. 2023-01-01T 52 | syn match logDate display '\<\d\{4}-\d\d-\d\dT' 53 | " YYYYMMDD starting with '20' e.g. 20230101 54 | syn match logDate display '\<20\d{6}' 55 | " Day 01-31 56 | syn match logDateDay display '0[1-9]\|[1-2]\d\|3[0-1]\>' contained 57 | 58 | " 12:34:56 or 12:34:56.700000Z or 12:34:56.700000+08:00 59 | syn match logTime display '\d\d:\d\d:\d\d\(\.\d\{2,6}\)\?' skipwhite nextgroup=logTimeZone,logTimeAMPM,logSysColumns 60 | " AM / PM 61 | syn match logTimeAMPM display '\cAM\|\cPM\>' contained skipwhite nextgroup=logSysColumns 62 | " Time zones, e.g. PST, CST etc. 63 | syn match logTimeZone display 'Z\|[+-]\d\d:\d\d\|\a\{3}\>' contained skipwhite nextgroup=logSysColumns 64 | 65 | syn keyword logDateMonth Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec nextgroup=logDateDay skipwhite 66 | syn keyword logDateWeekDay Mon Tue Wed Thu Fri Sat Sun 67 | 68 | " System info 69 | " ------------------------------ 70 | " Match letters & digits, dots, underscores and hyphens in system columns. 71 | " Usually the first column is the host name or log level keywords. 72 | syn match logSysColumns display '\<[[:alnum:]\._-]\+ [[:alnum:]\._-]\+\(\[[[:digit:]:]\+\]\)\?:' contained contains=@logLvs,logSysProcess 73 | syn match logSysProcess display '\<[[:alnum:]\._-]\+\(\[[[:digit:]:]\+\]\)\?:' contained contains=logNumber 74 | 75 | " Objects 76 | " ------------------------------ 77 | syn match logUrl display '\' 79 | syn match logIPv6 display '\<\x\{1,4}\(:\x\{1,4}\)\{7}\(\/\d\+\)\?\>' 80 | syn match logMacAddr display '\x\{2}\(:\x\{2}\)\{5}' 81 | syn match logUUID display '\<\x\{8}-\x\{4}-\x\{4}-\x\{4}-\x\{12}\>' 82 | syn match logMD5 display '\<\x\{32}\>' 83 | syn match logSHA display '\<\(\x\{40}\|\x\{56}\|\x\{64}\|\x\{96}\|\x\{128}\)\>' 84 | " File path starting with '/' , './', '../' and '~/'. 85 | " Must be start-of-line or prefixed with space 86 | syn match logPath display '\(^\|\s\)\(\.\{0,2}\|\~\)\/[[:alnum:]\/\.:_-]\+' 87 | 88 | " Log Levels 89 | " ------------------------------ 90 | syn keyword logLvFatal FATAL 91 | syn keyword logLvEmergency EMERGENCY EMERG 92 | syn keyword logLvAlert ALERT 93 | syn keyword logLvCritical CRITICAL CRIT 94 | syn keyword logLvError ERROR ERRORS ERR E error 95 | syn keyword logLvFailure FAILURE FAILED FAIL F 96 | syn keyword logLvWarning WARNING WARN W warning warn 97 | syn keyword logLvNotice NOTICE 98 | syn keyword logLvInfo INFO I info 99 | syn keyword logLvDebug DEBUG DBG D debug dbg 100 | syn keyword logLvTrace TRACE 101 | 102 | " Composite log levels e.g. *_INFO 103 | syn match logLvFatal display '\<\u\+_FATAL\>' 104 | syn match logLvEmergency display '\<\u\+_EMERG\(ENCY\)\?\>' 105 | syn match logLvAlert display '\<\u\+_ALERT\>' 106 | syn match logLvCritical display '\<\u\+_CRIT\(ICAL\)\?\>' 107 | syn match logLvError display '\<\u\+_ERR\(\OR\)\?\>' 108 | syn match logLvFailure display '\<\u\+_FAIL\(URE\)\?\>' 109 | syn match logLvWarning display '\<\u\+_WARN\(ING\)\?\>' 110 | syn match logLvNotice display '\<\u\+_NOTICE\>' 111 | syn match logLvInfo display '\<\u\+_INFO\>' 112 | syn match logLvDebug display '\<\u\+_DEBUG\>' 113 | syn match logLvTrace display '\<\u\+_TRACE\>' 114 | 115 | " spdlog pattern level: [trace] [info] ... 116 | syn match logLvCritical display '\[\zscritical\ze\]' 117 | syn match logLvError display '\[\zserror\ze\]' 118 | syn match logLvWarning display '\[\zswarning\ze\]' 119 | syn match logLvInfo display '\[\zsinfo\ze\]' 120 | syn match logLvDebug display '\[\zsdebug\ze\]' 121 | syn match logLvTrace display '\[\zstrace\ze\]' 122 | 123 | syn cluster logLvs contains=logLvFatal,logLvEmergency,logLvAlert,logLvCritical,logLvError,logLvFailure,logLvWarning,logLvNotice,logLvInfo,logLvDebug,logLvTrace 124 | 125 | " Highlight Links 126 | " ------------------------------ 127 | hi def link logNumber Number 128 | hi def link logNumberFloat Float 129 | hi def link logNumberBin Number 130 | hi def link logNumberOctal Number 131 | hi def link logNumberHex Number 132 | 133 | hi def link logSymbol Special 134 | hi def link logSeparatorLine Comment 135 | 136 | hi def link logBool Boolean 137 | hi def link logNull Constant 138 | hi def link logString String 139 | 140 | hi def link logDate Type 141 | hi def link logDateDay Type 142 | hi def link logDateMonth Type 143 | hi def link logDateWeekDay Type 144 | hi def link logTime Conditional 145 | hi def link logTimeAMPM Conditional 146 | hi def link logTimeZone Conditional 147 | 148 | hi def link logSysColumns Statement 149 | hi def link logSysProcess Function 150 | 151 | hi def link logUrl @markup.link.url 152 | hi def link logIPv4 @markup.link.url 153 | hi def link logIPv6 @markup.link.url 154 | hi def link logMacAddr Label 155 | hi def link logUUID Label 156 | hi def link logMD5 Label 157 | hi def link logSHA Label 158 | hi def link logPath String 159 | 160 | hi def link logLvFatal ErrorMsg 161 | hi def link logLvEmergency ErrorMsg 162 | hi def link logLvAlert ErrorMsg 163 | hi def link logLvCritical ErrorMsg 164 | hi def link logLvError ErrorMsg 165 | hi def link logLvFailure ErrorMsg 166 | hi def link logLvWarning WarningMsg 167 | hi def link logLvNotice Exception 168 | hi def link logLvInfo MoreMsg 169 | hi def link logLvDebug Debug 170 | hi def link logLvTrace Comment 171 | 172 | 173 | let b:current_syntax = "log" 174 | 175 | let &cpo = s:cpo_save 176 | unlet s:cpo_save 177 | -------------------------------------------------------------------------------- /nvim/spell/en.utf-8.add: -------------------------------------------------------------------------------- 1 | 3D 2 | 3DES 3 | adblock 4 | adhoc 5 | admin 6 | ajax 7 | alacritty 8 | allowlist 9 | altsnap 10 | AngularJS 11 | ansi 12 | Ansible 13 | apache 14 | API 15 | api 16 | APIM 17 | APIs 18 | app 19 | appimage 20 | apps 21 | archlinux 22 | Arduino 23 | arduino 24 | args 25 | arp 26 | ascii 27 | ASN 28 | aspx 29 | async 30 | ATmega2560 31 | augroup 32 | augroups 33 | AUR 34 | aur 35 | AUTH 36 | auth 37 | autocmd 38 | autocommand 39 | autocommands 40 | autocompletion 41 | autofill 42 | autofix 43 | autogen 44 | autogenerate 45 | autoload 46 | autoloaded 47 | autoloads 48 | autosave 49 | autosaved 50 | autosaves 51 | backend 52 | backends 53 | backtick 54 | backtrace 55 | backtraces 56 | base64 57 | bashrc 58 | Bicep 59 | Bitbucket 60 | Bitwarden 61 | blockchain 62 | blockchains 63 | blockquote 64 | blockquotes 65 | blog 66 | blogs 67 | bluetooth 68 | bool 69 | borderless 70 | Broadcom 71 | bruteforce 72 | btw 73 | buf 74 | builtin 75 | builtins 76 | C 77 | callout 78 | callouts 79 | cardholder 80 | CAs 81 | cd 82 | chad 83 | changelog 84 | changelogs 85 | changesets 86 | cheatsheet 87 | checkbox 88 | checkboxes 89 | checklist 90 | chmod 91 | choco 92 | CI 93 | CICD 94 | cicd 95 | CLI 96 | cli 97 | cmake 98 | cmd 99 | cmdline 100 | cmds 101 | codeaction 102 | codebase 103 | codeberg 104 | codelens 105 | colors 106 | colorscheme 107 | colorschemes 108 | colourschemes 109 | commandline 110 | compton 111 | COMPUSEC 112 | COMSEC 113 | conda 114 | conf 115 | config 116 | configs 117 | const 118 | CORS 119 | cpp 120 | cpu 121 | cronjob 122 | cronjobs 123 | crontab 124 | crypto 125 | csharp 126 | css 127 | csv 128 | Ctrl 129 | ctrl 130 | cuda 131 | cURL 132 | cyberdream 133 | Cython 134 | dap 135 | Datadog 136 | datasource 137 | datatype 138 | datatypes 139 | datetime 140 | DBA 141 | Debian 142 | dependabot 143 | deregister 144 | dev 145 | DevOps 146 | devs 147 | dialup 148 | dict 149 | dicts 150 | diff 151 | diffs 152 | diffstat 153 | diffstats 154 | difftool 155 | dir 156 | dirs 157 | Django 158 | DLL 159 | dmesg 160 | DNS 161 | dns 162 | dockerfile 163 | dockerfiles 164 | docstring 165 | docstrings 166 | dotfile 167 | dotfiles 168 | dpkg 169 | dropdown 170 | DSG 171 | DSP 172 | ebook 173 | Elasticsearch 174 | emacs 175 | emoji 176 | enum 177 | env 178 | envvar 179 | EOF 180 | EOL 181 | epub 182 | esc 183 | etc 184 | Ethereum 185 | ethernet 186 | exe 187 | fallback 188 | fallbacks 189 | Fastly 190 | favicon 191 | favicons 192 | Figma 193 | filename 194 | filenames 195 | filesystem 196 | filesystems 197 | filetype 198 | filetypes 199 | Firebase 200 | Firefox 201 | fmt 202 | frontend 203 | fullscreen 204 | func 205 | fzf 206 | gcc 207 | gif 208 | gitattributes 209 | gitcommit 210 | gitconfig 211 | GitHub 212 | github 213 | gitignore 214 | Gitlab 215 | gitlab 216 | gitmodules 217 | GitOps 218 | gitrevisions 219 | GitUI 220 | globbing 221 | gmail 222 | gnupg 223 | gofmt 224 | golang 225 | google 226 | goroutine 227 | Goroutines 228 | goroutines 229 | goto 230 | GPG 231 | gpg 232 | GPT 233 | GPU 234 | GPUs 235 | Gradle 236 | Grafana 237 | GraphQL 238 | graphql 239 | grep 240 | GRPC 241 | gtk 242 | gtk3 243 | gui 244 | GUIs 245 | hacky 246 | Hadoop 247 | hardcode 248 | hashtag 249 | hashtags 250 | Heroku 251 | homebrew 252 | homelab 253 | hostname 254 | https 255 | hypervisor 256 | IaC 257 | iCloud 258 | IDE 259 | IDOC 260 | IDOCs 261 | IDs 262 | iframe 263 | IIR 264 | img 265 | inbox 266 | InfluxDB 267 | ini 268 | init 269 | inline 270 | inlined 271 | int 272 | IntelliJ 273 | intellisense 274 | io 275 | IOPs 276 | iOS 277 | ios 278 | IoT 279 | IP 280 | ip 281 | IPs 282 | IPsec 283 | ipv4 284 | ipv6 285 | iterable 286 | JavaScript 287 | javascript 288 | jdk 289 | jedi 290 | jekyll 291 | JetBrains 292 | JPEG 293 | jpeg 294 | jpg 295 | jq 296 | JQuery 297 | jQuery 298 | js 299 | JSON 300 | json 301 | Jupyter 302 | jupyter 303 | K3s 304 | kanban 305 | kde 306 | KeePass 307 | keepass 308 | keepassxc 309 | Keras 310 | Kerberos 311 | keybindings 312 | keybinds 313 | keycodes 314 | keyfile 315 | keygen 316 | keymap 317 | keyrings 318 | keystore 319 | killswitch 320 | kubeconfig 321 | kubectl 322 | Kubernetes 323 | kubuntu 324 | kudo 325 | KVM 326 | KVP 327 | LANs 328 | Laravel 329 | LastPass 330 | LaTex 331 | Lazydocker 332 | Lazygit 333 | lazygit 334 | LazyVim 335 | Lazyvim 336 | len 337 | lexer 338 | lifecycle 339 | lifecycles 340 | linkedin 341 | Linksys 342 | linter 343 | linters 344 | linting 345 | linux 346 | llvm 347 | localhost 348 | lockfile 349 | lockscreen 350 | logfile 351 | Logitech 352 | lookaround 353 | lookbehind 354 | lsp 355 | LTS 356 | lua 357 | lualine 358 | LVM 359 | macbook 360 | macbooks 361 | MacOS 362 | macOS 363 | macos 364 | manpage 365 | MariaDB 366 | markup 367 | Maven 368 | md 369 | md5 370 | metadata 371 | microcontroller 372 | microservice 373 | Microservices 374 | microservices 375 | microsoft 376 | middleware 377 | Minikube 378 | mockup 379 | MongoDB 380 | monospaced 381 | motd 382 | mouseless 383 | mozilla 384 | mp3 385 | MQTT 386 | MSI 387 | multithreaded 388 | multivalue 389 | mutex 390 | MySQL 391 | namespace 392 | namespacing 393 | NAS 394 | Neovim 395 | neovim 396 | Nginx 397 | NixOS 398 | nixos 399 | noice 400 | NoSQL 401 | npm 402 | nvim 403 | OAuth 404 | OAuth2 405 | ocaml 406 | offline 407 | onboard 408 | oneline 409 | OpenAI 410 | OpenCV 411 | opentype 412 | OpenVPN 413 | org 414 | os 415 | OSI 416 | OSIRM 417 | PaaS 418 | pacman 419 | param 420 | passwd 421 | PCIe 422 | pdb 423 | pdf 424 | perf 425 | perl 426 | phishing 427 | picom 428 | PID 429 | pid 430 | pip3 431 | pipelining 432 | pkgconfig 433 | pkgs 434 | PKI 435 | placeholder 436 | plaintext 437 | playlist 438 | plugin 439 | Plugins 440 | plugins 441 | png 442 | PoC 443 | polybar 444 | polymorph 445 | POP3 446 | popup 447 | Portainer 448 | posix 449 | postgres 450 | PostgreSQL 451 | postgresql 452 | PowerShell 453 | powershell 454 | prepended 455 | proc 456 | Prometheus 457 | Proxmox 458 | ps1 459 | pylint 460 | python3 461 | PyTorch 462 | Pywal 463 | QEMU 464 | qt4 465 | qt5 466 | ReactJS 467 | readme 468 | rebase 469 | rebased 470 | rebasing 471 | reddit 472 | Redis 473 | redis 474 | redist 475 | Redux 476 | refactor 477 | refractor 478 | regex 479 | reparse 480 | reparsing 481 | REPL 482 | repo 483 | repos 484 | ripgrep 485 | routable 486 | RPC 487 | RStudio 488 | runbook 489 | runtimepath 490 | rustup 491 | screenshot 492 | screenshots 493 | scrollback 494 | semver 495 | setup 496 | SHA 497 | sha256 498 | sha512 499 | shada 500 | SharePoint 501 | sharepoint 502 | SHAs 503 | shiftwidth 504 | signedness 505 | signup 506 | SKU 507 | SKUs 508 | smartphone 509 | soundcloud 510 | sourceforge 511 | specs 512 | spinoff 513 | spotify 514 | sql 515 | SQLite 516 | SQLite3 517 | src 518 | SSD 519 | SSH 520 | ssid 521 | startup 522 | stderr 523 | stdin 524 | stdout 525 | struct 526 | structs 527 | stylix 528 | subkey 529 | subkeys 530 | sublist 531 | sublists 532 | submodule 533 | submodules 534 | subnetting 535 | subnetwork 536 | subprocess 537 | sudo 538 | superencryption 539 | swimlanes 540 | Symlink 541 | symlink 542 | symlinked 543 | symlinks 544 | systemd 545 | Talos 546 | TBD 547 | TCSEC 548 | TensorFlow 549 | Terraform 550 | texting 551 | Textmate 552 | thunar 553 | Tilux 554 | timestamp 555 | TLDR 556 | tldr 557 | TLS 558 | tmux 559 | ToC 560 | TODO 561 | todo 562 | todos 563 | toml 564 | toolchain 565 | toolset 566 | tpm 567 | Traefik 568 | treesitter 569 | TS 570 | Twilio 571 | txt 572 | TypeScript 573 | Uber 574 | Ubuntu 575 | ubuntu 576 | UI 577 | ui 578 | UIs 579 | UML 580 | uncommenting 581 | uncommit 582 | unicode 583 | unix 584 | unmarshal 585 | unstaged 586 | unstash 587 | upsert 588 | url 589 | URLs 590 | urls 591 | usb 592 | useragent 593 | userbase 594 | UTC 595 | utils 596 | uuid 597 | var 598 | virtualenv 599 | VM 600 | VMs 601 | VPS 602 | VueJS 603 | warmup 604 | wasm 605 | webhook 606 | Webpack 607 | webrtc 608 | WebSocket 609 | WebSockets 610 | Wez 611 | wezterm 612 | wget 613 | whitelist 614 | whitespace 615 | WiFi 616 | wifi 617 | wiki 618 | wildcard 619 | wildcards 620 | win32 621 | win64 622 | Windots 623 | winget 624 | WIP 625 | WireShark 626 | workflow 627 | WSL 628 | www 629 | X11 630 | X509 631 | x509 632 | x86 633 | Xamarin 634 | xml 635 | XSS 636 | xss 637 | YAML 638 | yaml 639 | YMMV 640 | youtube 641 | Zellij 642 | zig 643 | zigbee 644 | zsh 645 | -------------------------------------------------------------------------------- /nvim/lua/core/keymaps.lua: -------------------------------------------------------------------------------- 1 | local utils = require("core.utils") 2 | local snacks = require("snacks") 3 | 4 | --- Map a key combination to a command 5 | ---@param modes string|string[]: The mode(s) to map the key combination to 6 | ---@param lhs string: The key combination to map 7 | ---@param rhs string|function: The command to run when the key combination is pressed 8 | ---@param opts table: Options to pass to the keymap 9 | local map = function(modes, lhs, rhs, opts) 10 | local options = { silent = true } 11 | if opts then 12 | options = vim.tbl_extend("force", options, opts) 13 | end 14 | if type(modes) == "string" then 15 | modes = { modes } 16 | end 17 | for _, mode in ipairs(modes) do 18 | vim.keymap.set(mode, lhs, rhs, options) 19 | end 20 | end 21 | 22 | local copilot_toggle_opts = { 23 | name = "Inline (Copilot) Completions", 24 | get = function() 25 | return vim.lsp.inline_completion.is_enabled() 26 | end, 27 | set = function() 28 | vim.lsp.inline_completion.enable(not vim.lsp.inline_completion.is_enabled()) 29 | end, 30 | } 31 | 32 | --- Open a non-interactive terminal and run a command. Keeps the current window focused. 33 | ---@param cmd string: The command to run 34 | local function run_non_interactive_cmd(cmd) 35 | return function() 36 | local win = vim.api.nvim_get_current_win() 37 | snacks.terminal.toggle(cmd, { interactive = false }) 38 | vim.api.nvim_set_current_win(win) 39 | end 40 | end 41 | 42 | -- stylua: ignore start 43 | 44 | -- better up/down 45 | map({ "n", "x" }, "j", "v:count == 0 ? 'gj' : 'j'", { desc = "Down", expr = true }) 46 | map({ "n", "x" }, "", "v:count == 0 ? 'gj' : 'j'", { desc = "Down", expr = true }) 47 | map({ "n", "x" }, "k", "v:count == 0 ? 'gk' : 'k'", { desc = "Up", expr = true }) 48 | map({ "n", "x" }, "", "v:count == 0 ? 'gk' : 'k'", { desc = "Up", expr = true }) 49 | 50 | -- Move to window using the hjkl keys 51 | map("n", "", "h", { desc = "Go to Left Window", remap = true }) 52 | map("n", "", "j", { desc = "Go to Lower Window", remap = true }) 53 | map("n", "", "k", { desc = "Go to Upper Window", remap = true }) 54 | map("n", "", "l", { desc = "Go to Right Window", remap = true }) 55 | 56 | -- Resize window using arrow keys 57 | map("n", "", "resize +2", { desc = "Increase Window Height" }) 58 | map("n", "", "resize -2", { desc = "Decrease Window Height" }) 59 | map("n", "", "vertical resize -2", { desc = "Decrease Window Width" }) 60 | map("n", "", "vertical resize +2", { desc = "Increase Window Width" }) 61 | 62 | -- Move Lines 63 | map("n", "", "execute 'move .+' . v:count1==", { desc = "Move Down" }) 64 | map("n", "", "execute 'move .-' . (v:count1 + 1)==", { desc = "Move Up" }) 65 | map("i", "", "m .+1==gi", { desc = "Move Down" }) 66 | map("i", "", "m .-2==gi", { desc = "Move Up" }) 67 | map("v", "", ":execute \"'<,'>move '>+\" . v:count1gv=gv", { desc = "Move Down" }) 68 | map("v", "", ":execute \"'<,'>move '<-\" . (v:count1 + 1)gv=gv", { desc = "Move Up" }) 69 | 70 | -- Buffers 71 | map("n", "bb", function() utils.switch_to_other_buffer() end, { desc = "Switch to Other Buffer" }) 72 | map("n", "bd", function() snacks.bufdelete({ wipe = true }) end, { desc = "Delete buffer" }) 73 | map("n", "L", ":bnext", { desc = "Next buffer" }) 74 | map("n", "H", ":bprevious", { desc = "Previous buffer" }) 75 | 76 | -- lazy 77 | map("n", "l", ":Lazy", { desc = "Lazy" }) 78 | 79 | -- Snacks Picker 80 | map("n", "", function() snacks.picker.smart() end, { desc = "Smart Fuzzy Find" }) 81 | map("n", "ff", function() snacks.picker.files({ hidden = true }) end, { desc = "Fuzzy find files" }) 82 | map("n", "fr", function() snacks.picker.recent() end, { desc = "Fuzzy find recent files" }) 83 | map("n", "fs", function() snacks.picker.grep() end, { desc = "Find string in CWD" }) 84 | map("n", "fc", function() snacks.picker.grep_word() end, { desc = "Find word under cursor in CWD" }) 85 | map("n", "fb", function() snacks.picker.buffers({ layout = { preset = "select" }}) end, { desc = "Fuzzy find buffers" }) 86 | map("n", "ft", function() snacks.picker() end, { desc = "Other pickers..." }) 87 | map("n", "fh", function() snacks.picker.help() end, { desc = "Find help tags" }) 88 | map("n", "fS", function() require("pick-resession").pick() end, { desc = "Find Session" }) 89 | 90 | -- toggle options 91 | utils.toggle_global_boolean("autoformat", "Autoformat"):map("ta") 92 | utils.toggle_global_boolean("obsidian_git_sync", "Obsidian Git Sync"):map("to") 93 | snacks.toggle(copilot_toggle_opts):map("tc") 94 | snacks.toggle.option("spell", { name = "Spelling" }):map("ts") 95 | snacks.toggle.option("wrap", { name = "Wrap" }):map("tw") 96 | snacks.toggle.option("relativenumber", { name = "Relative Number" }):map("tL") 97 | snacks.toggle.diagnostics():map("td") 98 | snacks.toggle.line_number():map("tl") 99 | snacks.toggle.option("conceallevel", { off = 0, on = vim.o.conceallevel > 0 and vim.o.conceallevel or 2 }):map("tC") 100 | snacks.toggle.treesitter():map("tT") 101 | if vim.lsp.inlay_hint then snacks.toggle.inlay_hints():map("th") end 102 | 103 | -- browse to git repo 104 | map("n", "gb", function() snacks.gitbrowse() end, { desc = "Git Browse" }) 105 | 106 | -- Clear search with 107 | map("n", "", ":noh", { desc = "Escape and clear hlsearch" }) 108 | 109 | -- https://github.com/mhinz/vim-galore#saner-behavior-of-n-and-n 110 | map("n", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next search result" }) 111 | map("x", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next search result" }) 112 | map("o", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next search result" }) 113 | map("n", "N", "'nN'[v:searchforward]", { expr = true, desc = "Prev search result" }) 114 | map("x", "N", "'nN'[v:searchforward]", { expr = true, desc = "Prev search result" }) 115 | map("o", "N", "'nN'[v:searchforward]", { expr = true, desc = "Prev search result" }) 116 | 117 | -- quit 118 | map("n", "qq", ":qa", { desc = "Quit all" }) 119 | 120 | -- windows 121 | map("n", "ww", "p", { desc = "Other window", remap = true }) 122 | map("n", "wd", "c", { desc = "Delete window", remap = true }) 123 | map("n", "w-", "s", { desc = "Split window below", remap = true }) 124 | map("n", "w|", "v", { desc = "Split window right", remap = true }) 125 | map("n", "-", "s", { desc = "Split window below", remap = true }) 126 | map("n", "|", "v", { desc = "Split window right", remap = true }) 127 | map("n", "wz", function() snacks.zen() end, { desc = "Zen mode" }) 128 | 129 | -- tabs 130 | map("n", "", ":tabnew", { desc = "New Tab" }) 131 | map("n", "l", ":tabnext", { desc = "Next Tab" }) 132 | map("n", "d", ":tabclose", { desc = "Close Tab" }) 133 | map("n", "h", ":tabprevious", { desc = "Previous Tab" }) 134 | 135 | -- Code/LSP 136 | map("n", "ca", vim.lsp.buf.code_action, { desc = "Code Action" }) 137 | map("n", "cd", function() vim.diagnostic.open_float({border = 'rounded'}) end, { desc = "Line Diagnostics" }) 138 | map("n", "cli", ":check lsp", { desc = "LSP Info" }) 139 | map("n", "cr", vim.lsp.buf.rename, { desc = "Rename" }) 140 | map("n", "clr", utils.restart_lsp, { desc = "Restart LSP" }) 141 | map("n", "cll", utils.open_lsp_log, { desc = "Open LSP Log" }) 142 | map("i", "", function() vim.lsp.inline_completion.get() end, { desc = "Accept Inline Completion" }) 143 | map("n", "K", function() return vim.lsp.buf.hover() end, { desc = "Hover" }) 144 | map("n", "gD", vim.lsp.buf.declaration, { desc = "Goto Declaration" }) 145 | map("n", "gK", vim.lsp.buf.signature_help, { desc = "Signature Help" }) 146 | map("n", "gr", function() snacks.picker.lsp_references() end, { desc = "Goto References" }) 147 | map("n", "gI", function() snacks.picker.lsp_implementations() end, { desc = "Goto Implementations" }) 148 | map("n", "gd", function() snacks.picker.lsp_definitions() end, { desc = "Goto Definitions" }) 149 | map("n", "gy", function() snacks.picker.lsp_type_definitions() end, { desc = "Goto Type Definitions" }) 150 | 151 | -- Terminal/Run... 152 | map({"n", "t"}, "", function() snacks.terminal() end, { desc = "Toggle Terminal" }) 153 | map("n", "gg", function() snacks.lazygit() end, { desc = "Lazygit" }) 154 | map("n", "kk", function() utils.open_terminal_toggle({ "k9s" }, true) end, { desc = "K9s" }) 155 | map("n", "ao", function() utils.open_terminal_toggle({ "opencode", "." }) end, { desc = "Opencode" }) 156 | map("n", "rlf", ":luafile %", { desc = "Run Current Lua File" }) 157 | map("n", "rlt", ":PlenaryBustedFile %", { desc = "Run Lua Test File" }) 158 | map("n", "rss", run_non_interactive_cmd(vim.fn.expand("%:p")), { desc = "Run shell script" }) 159 | map("n", "rm", run_non_interactive_cmd("make"), { desc = "Run make" }) 160 | map("n", "rt", run_non_interactive_cmd("task"), { desc = "Run task" }) 161 | -- stylua: ignore end 162 | -------------------------------------------------------------------------------- /nvim/lua/core/statusline.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | -- Mode mappings 4 | local mode_map = { 5 | ["n"] = "NORMAL", 6 | ["no"] = "NORMAL", 7 | ["v"] = "VISUAL", 8 | ["V"] = "V-LINE", 9 | ["\22"] = "V-BLOCK", 10 | ["i"] = "INSERT", 11 | ["c"] = "COMMAND", 12 | ["r"] = "REPLACE", 13 | ["r?"] = "CONFIRM", 14 | ["!"] = "SHELL", 15 | ["t"] = "TERMINAL", 16 | ["nt"] = "TERMINAL", 17 | } 18 | 19 | local mode_hl_map = { 20 | ["NORMAL"] = "Directory", 21 | ["VISUAL"] = "Number", 22 | ["V-LINE"] = "Number", 23 | ["V-BLOCK"] = "Number", 24 | ["INSERT"] = "String", 25 | ["COMMAND"] = "Keyword", 26 | ["TERMINAL"] = "Keyword", 27 | } 28 | 29 | -- Helper functions 30 | --- Global function for statusline component rendering. Can be called directly from the statusline 31 | --- @param name string The name of the component to render 32 | --- @param hl string The highlight group to use for the component 33 | --- @return string 34 | function _G._statusline_component(name, hl) 35 | return M[name](hl) 36 | end 37 | 38 | --- Format a given component value with a highlight group in the format expected by the statusline 39 | --- @param val string The value to format 40 | --- @param hl string|nil The highlight group to use 41 | --- @param l_sep string|nil The left separator to use 42 | --- @param r_sep string|nil The right separator to use 43 | --- @return string 44 | local function format_component(val, hl, l_sep, r_sep) 45 | l_sep = l_sep or " " 46 | r_sep = r_sep or " " 47 | hl = hl or "Comment" 48 | return l_sep .. "%#" .. hl .. "#" .. val .. "%*" .. r_sep 49 | end 50 | 51 | --- Generate a statusline component with optional highlight group 52 | --- @param val string The value to render 53 | --- @param hl string|nil The highlight group to use 54 | --- @return string 55 | local function component(val, hl) 56 | if val == nil or val == "" then 57 | return "" 58 | end 59 | 60 | if hl == nil then 61 | return "%{%v:lua._statusline_component('" .. val .. "')%}" 62 | end 63 | return "%{%v:lua._statusline_component('" .. val .. "', '" .. hl .. "')%}" 64 | end 65 | 66 | --- Get the count of diagnostics for a given severity 67 | --- @param severity "ERROR"|"WARN"|"HINT"|"INFO" 68 | --- @return number 69 | local function get_diagnostic_count(severity) 70 | return #vim.diagnostic.get(0, { severity = vim.diagnostic.severity[severity] }) 71 | end 72 | 73 | --- Get the corresponding highlight group and statusline value for the current vim mode 74 | --- @return string, string 75 | local function get_mode_info() 76 | local mode = vim.api.nvim_get_mode().mode 77 | local val = mode_map[mode] 78 | return val, mode_hl_map[val] 79 | end 80 | 81 | -- Components 82 | --- Mode component with dynamic highlights 83 | --- @return string 84 | M.mode = function() 85 | local val, hl = get_mode_info() 86 | if not val then 87 | return "" 88 | end 89 | return format_component(" " .. string.lower(val), hl) 90 | end 91 | 92 | --- Git branch component based on CWD - depends on gitsigns.nvim 93 | --- @param hl string The highlight group to use 94 | --- @return string 95 | M.git_branch = function(hl) 96 | local branch = vim.g.gitsigns_head 97 | if not branch then 98 | return "" 99 | end 100 | return format_component(" " .. branch, hl) 101 | end 102 | 103 | --- Git diff component - current buffer, depends on gitsigns.nvim 104 | --- @param hl string The highlight group to use 105 | --- @return string 106 | M.git_diff = function(hl) 107 | local summary = vim.b.gitsigns_status 108 | if not summary or summary == "" then 109 | return "" 110 | end 111 | 112 | summary = summary:gsub("+", " ") 113 | summary = summary:gsub("-", " ") 114 | summary = summary:gsub("~", " ") 115 | 116 | return format_component(summary, hl) 117 | end 118 | 119 | --- Buffer diagnostics component 120 | --- @return string 121 | M.diagnostics = function() 122 | local errors = get_diagnostic_count("ERROR") 123 | local warnings = get_diagnostic_count("WARN") 124 | local hints = get_diagnostic_count("HINT") 125 | local info = get_diagnostic_count("INFO") 126 | 127 | if errors + warnings + hints + info == 0 then 128 | return "" 129 | end 130 | 131 | local components = { 132 | errors > 0 and format_component(" " .. errors, "DiagnosticError", "") or "", 133 | warnings > 0 and format_component(" " .. warnings, "DiagnosticWarn", "") or "", 134 | hints > 0 and format_component(" " .. hints, "DiagnosticHint", "") or "", 135 | info > 0 and format_component("󰝶 " .. info, "DiagnosticInfo", "") or "", 136 | } 137 | 138 | return " " .. table.concat(components, "") .. " " 139 | end 140 | 141 | --- Buffer location component - dependes on nvim-navic 142 | --- @param hl string The highlight group to use 143 | M.navic = function(hl) 144 | if package.loaded["nvim-navic"] and require("nvim-navic").is_available() then 145 | return format_component(require("nvim-navic").get_location(), hl) 146 | end 147 | return "" 148 | end 149 | 150 | --- Status messages component. Shows @recording meesages. Depends on noice.nvim 151 | --- @param hl string|nil The highlight group to use 152 | --- @return string 153 | M.status_messages = function(hl) 154 | local ignore = { 155 | "-- INSERT --", 156 | "-- TERMINAL --", 157 | "-- VISUAL --", 158 | "-- VISUAL LINE --", 159 | "-- VISUAL BLOCK --", 160 | } 161 | --- @diagnostic disable: undefined-field 162 | local mode = require("noice").api.status.mode.get() 163 | if require("noice").api.status.mode.has() and not vim.tbl_contains(ignore, mode) then 164 | return format_component(mode, hl) 165 | end 166 | --- @diagnostic enable: undefined-field 167 | return "" 168 | end 169 | 170 | --- Lazy updates component - show pending lazy.nvim updates 171 | --- @param hl string The highlight group to use 172 | M.lazy_updates = function(hl) 173 | local updates = require("lazy.status").updates() 174 | if type(updates) == "string" then 175 | return format_component(updates, hl) 176 | end 177 | return "" 178 | end 179 | 180 | --- Copilot status component - depends on copilot.lua 181 | --- @return string 182 | M.copilot_status = function() 183 | local ok, clients = pcall(vim.lsp.get_clients, { name = "copilot", bufnr = 0 }) 184 | if not (ok and #clients > 0) then 185 | return "" 186 | end 187 | 188 | local status = require("sidekick.status").get() 189 | if not status then 190 | return "" 191 | end 192 | 193 | local hl = "Comment" 194 | if status.kind == "Error" then 195 | hl = "DiagnosticError" 196 | elseif status.busy then 197 | hl = "DiagnosticWarn" 198 | end 199 | 200 | return format_component(" ", hl) 201 | end 202 | 203 | --- Search count component - show current and total search matches when searching a buffer 204 | --- @param hl string|nil The highlight group to use 205 | --- @return string 206 | M.search_count = function(hl) 207 | if vim.v.hlsearch == 0 then 208 | return "" 209 | end 210 | 211 | local ok, s_count = pcall(vim.fn.searchcount, { recompute = true }) 212 | if not ok or s_count.current == nil or s_count.total == 0 then 213 | return "" 214 | end 215 | 216 | if s_count.incomplete == 1 then 217 | return format_component("?/?", hl) 218 | end 219 | 220 | return format_component(s_count.current .. "/" .. s_count.total, hl) 221 | end 222 | 223 | --- File name component - show the current buffer's file name and coloured icon. Depends on mini.icons. 224 | --- @param hl string The highlight group to use 225 | M.file_name = function(hl) 226 | local ft_overrides = { 227 | ["copilot-chat"] = { name = "copilot", icon = "󰚩", icon_hl = "MiniIconsAzure" }, 228 | ["grug-far"] = { name = "grug-far", icon = "", icon_hl = "DiagnosticWarn" }, 229 | ["lazy"] = { name = "lazy.nvim", icon = "󰒲", icon_hl = "Directory" }, 230 | ["mason"] = { name = "mason", icon = "󱌣", icon_hl = "MiniIconsAzure" }, 231 | ["minifiles"] = { name = "files", icon = "󰝰", icon_hl = "Directory" }, 232 | ["snacks_picker_input"] = { name = "picker", icon = "󰦨", icon_hl = "Changed" }, 233 | } 234 | 235 | local fn_overrides = { 236 | ["k9s"] = { icon = "󱃾", icon_hl = "Directory" }, 237 | ["lazygit"] = { icon = "", icon_hl = "Changed" }, 238 | } 239 | 240 | local ft = vim.bo.filetype 241 | if ft_overrides[ft] then 242 | return format_component(ft_overrides[ft].icon, ft_overrides[ft].icon_hl, " ", "") 243 | .. format_component(ft_overrides[ft].name, hl) 244 | end 245 | 246 | local filename = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(0), ":t") 247 | if filename == "" then 248 | return "" 249 | end 250 | 251 | local icon, icon_hl = require("mini.icons").get("file", filename) 252 | 253 | -- Override or set custom icons 254 | if fn_overrides[filename] then 255 | icon = fn_overrides[filename].icon 256 | icon_hl = fn_overrides[filename].icon_hl 257 | end 258 | 259 | return format_component(icon, icon_hl, " ", "") .. format_component(filename, hl) 260 | end 261 | 262 | --- Buffer count component - show the number of other open buffers 263 | --- @param hl string The highlight group to use 264 | M.other_buffers = function(hl) 265 | local other_bufs = require("core.utils").get_buffer_count() - 1 266 | if other_bufs < 1 then 267 | return "" 268 | end 269 | return format_component("+" .. other_bufs .. " ", hl, "", " ") 270 | end 271 | 272 | --- Progress component - show percentage of buffer scrolled 273 | --- @param hl string|nil The highlight group to use 274 | M.progress = function(hl) 275 | return format_component("%2p%%", hl) 276 | end 277 | 278 | --- Clock component - show current time 279 | --- @param hl string|nil The highlight group to use 280 | M.location = function(hl) 281 | return format_component("%l:%c", hl) 282 | end 283 | 284 | --- Clock component - show current time 285 | --- @param hl string|nil The highlight group to use 286 | M.clock = function(hl) 287 | --- @diagnostic disable-next-line: param-type-mismatch 288 | return format_component(os.date("%I:%M %p"):gsub("^0", ""), hl) 289 | end 290 | 291 | -- Statusline components 292 | local components = { 293 | component("mode"), 294 | component("git_branch", "Changed"), 295 | component("git_diff", "Type"), 296 | component("diagnostics"), 297 | "%<", -- mark general truncate point 298 | component("navic", "Comment"), 299 | "%=", -- mark end of left alignment 300 | component("status_messages"), 301 | component("lazy_updates", "String"), 302 | component("copilot_status"), 303 | component("search_count", "Directory"), 304 | component("file_name", "Normal"), 305 | component("other_buffers", "Comment"), 306 | component("progress", "Special"), 307 | component("location", "Changed"), 308 | component("clock", "Conceal"), 309 | } 310 | 311 | --- Return the statusline as a concatenated string - use with vim.opt.statusline to set 312 | --- @type string 313 | M.statusline = table.concat(components, "") 314 | 315 | return M 316 | -------------------------------------------------------------------------------- /nvim/lua/plugins/mini.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { 3 | "echasnovski/mini.pairs", 4 | event = "InsertEnter", 5 | config = function() 6 | require("mini.pairs").setup() 7 | end, 8 | }, 9 | { 10 | "echasnovski/mini.icons", 11 | specs = { 12 | { "nvim-tree/nvim-web-devicons", enabled = false, optional = true }, 13 | }, 14 | config = function() 15 | require("mini.icons").setup() 16 | require("mini.icons").mock_nvim_web_devicons() 17 | end, 18 | }, 19 | { 20 | "echasnovski/mini.indentscope", 21 | event = { "BufReadPre", "BufNewFile" }, 22 | opts = { 23 | symbol = "│", 24 | options = { try_as_border = true }, 25 | }, 26 | init = function() 27 | vim.api.nvim_create_autocmd("FileType", { 28 | pattern = { 29 | "Trouble", 30 | "alpha", 31 | "copilot-chat", 32 | "dashboard", 33 | "help", 34 | "lazy", 35 | "mason", 36 | "neotree", 37 | "notify", 38 | "snacks_terminal", 39 | }, 40 | callback = function() 41 | vim.b.miniindentscope_disable = true 42 | end, 43 | }) 44 | end, 45 | }, 46 | { 47 | "echasnovski/mini.files", 48 | dependencies = { "echasnovski/mini.icons" }, 49 | keys = { 50 | { 51 | "ee", 52 | function() 53 | local path = vim.bo.buftype ~= "nofile" and vim.api.nvim_buf_get_name(0) or nil 54 | local ok = pcall(require("mini.files").open, path) 55 | if not ok then 56 | require("mini.files").open() 57 | end 58 | end, 59 | desc = "Open mini.files (cwd)", 60 | }, 61 | }, 62 | config = function() 63 | require("mini.files").setup({ 64 | windows = { 65 | width_focus = 40, 66 | width_nofocus = 40, 67 | }, 68 | }) 69 | 70 | -- All config below is to render git status in mini.files 71 | -- See gist for more details: https://gist.github.com/bassamsdata/eec0a3065152226581f8d4244cce9051 72 | local nsMiniFiles = vim.api.nvim_create_namespace("mini_files_git") 73 | local autocmd = vim.api.nvim_create_autocmd 74 | local _, MiniFiles = pcall(require, "mini.files") 75 | 76 | -- Cache for git status 77 | local gitStatusCache = {} 78 | local cacheTimeout = 2000 -- in milliseconds 79 | local uv = vim.uv or vim.loop 80 | 81 | local function isSymlink(path) 82 | local stat = uv.fs_lstat(path) 83 | return stat and stat.type == "link" 84 | end 85 | 86 | ---@type table 87 | ---@param status string 88 | ---@return string symbol, string hlGroup 89 | local function mapSymbols(status, is_symlink) 90 | local statusMap = { 91 | [" M"] = { symbol = "", hlGroup = "MiniDiffSignChange" }, -- Modified in the working directory 92 | ["M "] = { symbol = "", hlGroup = "MiniDiffSignAdd" }, -- modified in index 93 | ["MM"] = { symbol = "", hlGroup = "MiniDiffSignChange" }, -- modified in both working tree and index 94 | ["A "] = { symbol = "", hlGroup = "MiniDiffSignAdd" }, -- Added to the staging area, new file 95 | ["AA"] = { symbol = "≈", hlGroup = "MiniDiffSignAdd" }, -- file is added in both working tree and index 96 | ["D "] = { symbol = "-", hlGroup = "MiniDiffSignDelete" }, -- Deleted from the staging area 97 | ["AM"] = { symbol = "⊕", hlGroup = "MiniDiffSignChange" }, -- added in working tree, modified in index 98 | ["AD"] = { symbol = "-•", hlGroup = "MiniDiffSignChange" }, -- Added in the index and deleted in the working directory 99 | ["R "] = { symbol = "→", hlGroup = "MiniDiffSignChange" }, -- Renamed in the index 100 | ["U "] = { symbol = "‖", hlGroup = "MiniDiffSignChange" }, -- Unmerged path 101 | ["UU"] = { symbol = "⇄", hlGroup = "MiniDiffSignAdd" }, -- file is unmerged 102 | ["UA"] = { symbol = "⊕", hlGroup = "MiniDiffSignAdd" }, -- file is unmerged and added in working tree 103 | ["??"] = { symbol = "", hlGroup = "MiniDiffSignDelete" }, -- Untracked files 104 | ["!!"] = { symbol = "", hlGroup = "MiniDiffSignChange" }, -- Ignored files 105 | } 106 | 107 | local result = statusMap[status] or { symbol = "?", hlGroup = "NonText" } 108 | local gitSymbol = result.symbol 109 | local gitHlGroup = result.hlGroup 110 | 111 | local symlinkSymbol = is_symlink and "↩" or "" 112 | 113 | -- Combine symlink symbol with Git status if both exist 114 | local combinedSymbol = (symlinkSymbol .. gitSymbol):gsub("^%s+", ""):gsub("%s+$", "") 115 | -- Change the color of the symlink icon from "MiniDiffSignDelete" to something else 116 | local combinedHlGroup = is_symlink and "MiniDiffSignDelete" or gitHlGroup 117 | 118 | return combinedSymbol, combinedHlGroup 119 | end 120 | 121 | ---@param cwd string 122 | ---@param callback function 123 | ---@return nil 124 | local function fetchGitStatus(cwd, callback) 125 | local clean_cwd = cwd:gsub("^minifiles://%d+/", "") 126 | ---@param content table 127 | local function on_exit(content) 128 | if content.code == 0 then 129 | callback(content.stdout) 130 | -- vim.g.content = content.stdout 131 | end 132 | end 133 | ---@see vim.system 134 | vim.system({ "git", "status", "--ignored", "--porcelain" }, { text = true, cwd = clean_cwd }, on_exit) 135 | end 136 | 137 | ---@param buf_id integer 138 | ---@param gitStatusMap table 139 | ---@return nil 140 | local function updateMiniWithGit(buf_id, gitStatusMap) 141 | vim.schedule(function() 142 | local nlines = vim.api.nvim_buf_line_count(buf_id) 143 | local cwd = vim.fs.root(buf_id, ".git") 144 | local escapedcwd = cwd and vim.pesc(cwd) 145 | if not escapedcwd then 146 | return 147 | end 148 | escapedcwd = vim.fs.normalize(escapedcwd) 149 | 150 | for i = 1, nlines do 151 | local entry = MiniFiles.get_fs_entry(buf_id, i) 152 | if not entry then 153 | break 154 | end 155 | local relativePath = entry.path:gsub("^" .. escapedcwd .. "/", "") 156 | local status = gitStatusMap[relativePath] 157 | 158 | if status then 159 | local symbol, hlGroup = mapSymbols(status, isSymlink(entry.path)) 160 | vim.api.nvim_buf_set_extmark(buf_id, nsMiniFiles, i - 1, 0, { 161 | sign_text = symbol, 162 | sign_hl_group = hlGroup, 163 | priority = 2, 164 | }) 165 | -- This below code is responsible for coloring the text of the items. comment it out if you don't want that 166 | local line = vim.api.nvim_buf_get_lines(buf_id, i - 1, i, false)[1] 167 | -- Find the name position accounting for potential icons 168 | local nameStartCol = line:find(vim.pesc(entry.name)) or 0 169 | 170 | if nameStartCol > 0 then 171 | vim.api.nvim_buf_set_extmark(buf_id, nsMiniFiles, i - 1, nameStartCol - 1, { 172 | end_col = nameStartCol + #entry.name - 1, 173 | hl_group = hlGroup, 174 | }) 175 | end 176 | else 177 | end 178 | end 179 | end) 180 | end 181 | 182 | -- Thanks for the idea of gettings https://github.com/refractalize/oil-git-status.nvim signs for dirs 183 | ---@param content string 184 | ---@return table 185 | local function parseGitStatus(content) 186 | local gitStatusMap = {} 187 | -- lua match is faster than vim.split (in my experience ) 188 | for line in content:gmatch("[^\r\n]+") do 189 | local status, filePath = string.match(line, "^(..)%s+(.*)") 190 | -- Split the file path into parts 191 | local parts = {} 192 | for part in filePath:gmatch("[^/]+") do 193 | table.insert(parts, part) 194 | end 195 | -- Start with the root directory 196 | local currentKey = "" 197 | for i, part in ipairs(parts) do 198 | if i > 1 then 199 | -- Concatenate parts with a separator to create a unique key 200 | currentKey = currentKey .. "/" .. part 201 | else 202 | currentKey = part 203 | end 204 | -- If it's the last part, it's a file, so add it with its status 205 | if i == #parts then 206 | gitStatusMap[currentKey] = status 207 | else 208 | -- If it's not the last part, it's a directory. Check if it exists, if not, add it. 209 | if not gitStatusMap[currentKey] then 210 | gitStatusMap[currentKey] = status 211 | end 212 | end 213 | end 214 | end 215 | return gitStatusMap 216 | end 217 | 218 | ---@param buf_id integer 219 | ---@return nil 220 | local function updateGitStatus(buf_id) 221 | if not vim.fs.root(buf_id, ".git") then 222 | return 223 | end 224 | local cwd = vim.fs.root(buf_id, ".git") 225 | -- local cwd = vim.fn.expand("%:p:h") 226 | if not cwd then 227 | return 228 | end 229 | local currentTime = os.time() 230 | 231 | if gitStatusCache[cwd] and currentTime - gitStatusCache[cwd].time < cacheTimeout then 232 | updateMiniWithGit(buf_id, gitStatusCache[cwd].statusMap) 233 | else 234 | fetchGitStatus(cwd, function(content) 235 | local gitStatusMap = parseGitStatus(content) 236 | gitStatusCache[cwd] = { 237 | time = currentTime, 238 | statusMap = gitStatusMap, 239 | } 240 | updateMiniWithGit(buf_id, gitStatusMap) 241 | end) 242 | end 243 | end 244 | 245 | ---@return nil 246 | local function clearCache() 247 | gitStatusCache = {} 248 | end 249 | 250 | local function augroup(name) 251 | return vim.api.nvim_create_augroup("MiniFiles_" .. name, { clear = true }) 252 | end 253 | 254 | autocmd("User", { 255 | group = augroup("start"), 256 | pattern = "MiniFilesExplorerOpen", 257 | callback = function() 258 | local bufnr = vim.api.nvim_get_current_buf() 259 | updateGitStatus(bufnr) 260 | end, 261 | }) 262 | 263 | autocmd("User", { 264 | group = augroup("close"), 265 | pattern = "MiniFilesExplorerClose", 266 | callback = function() 267 | clearCache() 268 | end, 269 | }) 270 | 271 | autocmd("User", { 272 | group = augroup("update"), 273 | pattern = "MiniFilesBufferUpdate", 274 | callback = function(args) 275 | local bufnr = args.data.buf_id 276 | local cwd = vim.fs.root(bufnr, ".git") 277 | if gitStatusCache[cwd] then 278 | updateMiniWithGit(bufnr, gitStatusCache[cwd].statusMap) 279 | end 280 | end, 281 | }) 282 | end, 283 | }, 284 | } 285 | -------------------------------------------------------------------------------- /bat/themes/cyberdream.tmTheme: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | name 6 | Cyberdream 7 | settings 8 | 9 | 10 | settings 11 | 12 | background 13 | #16181a 14 | caret 15 | #ffffff 16 | block_caret 17 | #7b8496 18 | foreground 19 | #ffffff 20 | invisibles 21 | #16181a 22 | lineHighlight 23 | #3c4048 24 | selection 25 | #3c4048 26 | findHighlight 27 | #5ef1ff 28 | findHighlightForeground 29 | #1e2124 30 | selectionBorder 31 | #16181a 32 | activeGuide 33 | #ffbd5e 34 | bracketsForeground 35 | #ff5ea0 36 | bracketsOptions 37 | underline 38 | bracketContentsForeground 39 | #ffffff 40 | bracketContentsOptions 41 | underline 42 | tagsOptions 43 | stippled_underline 44 | 45 | 46 | 47 | name 48 | Comment 49 | scope 50 | comment 51 | settings 52 | 53 | foreground 54 | #7b8496 55 | fontStyle 56 | 57 | 58 | 59 | 60 | name 61 | String 62 | scope 63 | string 64 | settings 65 | 66 | foreground 67 | #5eff6c 68 | 69 | 70 | 71 | name 72 | Number 73 | scope 74 | constant.numeric 75 | settings 76 | 77 | foreground 78 | #ffffff 79 | 80 | 81 | 82 | name 83 | Built-in constant 84 | scope 85 | constant.language 86 | settings 87 | 88 | foreground 89 | #ffffff 90 | 91 | 92 | 93 | name 94 | User-defined constant 95 | scope 96 | constant.character, constant.other 97 | settings 98 | 99 | foreground 100 | #ffffff 101 | 102 | 103 | 104 | name 105 | Variable 106 | scope 107 | variable 108 | settings 109 | 110 | fontStyle 111 | 112 | 113 | 114 | 115 | name 116 | Ruby's @variable 117 | scope 118 | variable.other.readwrite.instance 119 | settings 120 | 121 | fontStyle 122 | 123 | foreground 124 | #ffbd5e 125 | 126 | 127 | 128 | name 129 | String interpolation 130 | scope 131 | constant.character.escaped, constant.character.escape, string source, string source.ruby 132 | settings 133 | 134 | fontStyle 135 | 136 | foreground 137 | #ff5ef1 138 | 139 | 140 | 141 | name 142 | Ruby Regexp 143 | scope 144 | source.ruby string.regexp.classic.ruby,source.ruby string.regexp.mod-r.ruby 145 | settings 146 | 147 | fontStyle 148 | 149 | foreground 150 | #ff6e5e 151 | 152 | 153 | 154 | name 155 | Keyword 156 | scope 157 | keyword 158 | settings 159 | 160 | foreground 161 | #ffbd5e 162 | 163 | 164 | 165 | name 166 | Keyword Operator 167 | scope 168 | keyword.operator 169 | settings 170 | 171 | foreground 172 | #bd5eff 173 | 174 | 175 | 176 | name 177 | Storage 178 | scope 179 | storage 180 | settings 181 | 182 | fontStyle 183 | 184 | foreground 185 | #ff5ea0 186 | 187 | 188 | 189 | name 190 | Storage type 191 | scope 192 | storage.type 193 | settings 194 | 195 | fontStyle 196 | italic 197 | foreground 198 | #5ef1ff 199 | 200 | 201 | 202 | name 203 | Storage Type Namespace 204 | scope 205 | storage.type.namespace 206 | settings 207 | 208 | fontStyle 209 | italic 210 | foreground 211 | #bd5eff 212 | 213 | 214 | 215 | name 216 | Storage Type Class 217 | scope 218 | storage.type.class 219 | settings 220 | 221 | fontStyle 222 | italic 223 | foreground 224 | #bd5eff 225 | 226 | 227 | 228 | name 229 | Class name 230 | scope 231 | entity.name.class 232 | settings 233 | 234 | fontStyle 235 | underline 236 | foreground 237 | #bd5eff 238 | 239 | 240 | 241 | name 242 | Meta Path 243 | scope 244 | meta.path 245 | settings 246 | 247 | fontStyle 248 | underline 249 | foreground 250 | #5ef1ff 251 | 252 | 253 | 254 | name 255 | Inherited class 256 | scope 257 | entity.other.inherited-class 258 | settings 259 | 260 | fontStyle 261 | italic underline 262 | foreground 263 | #bd5eff 264 | 265 | 266 | 267 | name 268 | Function name 269 | scope 270 | entity.name.function 271 | settings 272 | 273 | fontStyle 274 | 275 | foreground 276 | #5ea1ff 277 | 278 | 279 | 280 | name 281 | Function argument 282 | scope 283 | variable.parameter 284 | settings 285 | 286 | fontStyle 287 | italic 288 | foreground 289 | #bd5eff 290 | 291 | 292 | 293 | name 294 | Tag name 295 | scope 296 | entity.name.tag 297 | settings 298 | 299 | fontStyle 300 | 301 | foreground 302 | #5ef1ff 303 | 304 | 305 | 306 | name 307 | Tag attribute 308 | scope 309 | entity.other.attribute-name 310 | settings 311 | 312 | fontStyle 313 | 314 | foreground 315 | #5ef1ff 316 | 317 | 318 | 319 | name 320 | Library function 321 | scope 322 | support.function 323 | settings 324 | 325 | fontStyle 326 | 327 | foreground 328 | #5ea1ff 329 | 330 | 331 | 332 | name 333 | Library constant 334 | scope 335 | support.constant 336 | settings 337 | 338 | fontStyle 339 | 340 | foreground 341 | #ffffff 342 | 343 | 344 | 345 | name 346 | Library class/type 347 | scope 348 | support.type, support.class 349 | settings 350 | 351 | fontStyle 352 | italic 353 | foreground 354 | #bd5eff 355 | 356 | 357 | 358 | name 359 | Library variable 360 | scope 361 | support.other.variable 362 | settings 363 | 364 | fontStyle 365 | 366 | 367 | 368 | 369 | name 370 | Support Other Namespace 371 | scope 372 | support.other.namespace 373 | settings 374 | 375 | fontStyle 376 | italic 377 | foreground 378 | #bd5eff 379 | 380 | 381 | 382 | name 383 | Invalid 384 | scope 385 | invalid 386 | settings 387 | 388 | background 389 | #ff5ea0 390 | fontStyle 391 | 392 | foreground 393 | #ffffff 394 | 395 | 396 | 397 | name 398 | Invalid deprecated 399 | scope 400 | invalid.deprecated 401 | settings 402 | 403 | background 404 | #bd5eff 405 | foreground 406 | #ffffff 407 | 408 | 409 | 410 | name 411 | JSON String 412 | scope 413 | meta.structure.dictionary.json string.quoted.double.json 414 | settings 415 | 416 | foreground 417 | #ffffff 418 | 419 | 420 | 421 | name 422 | diff.header 423 | scope 424 | meta.diff, meta.diff.header 425 | settings 426 | 427 | foreground 428 | #7b8496 429 | 430 | 431 | 432 | name 433 | diff.deleted 434 | scope 435 | markup.deleted 436 | settings 437 | 438 | foreground 439 | #ff6e5e 440 | 441 | 442 | 443 | name 444 | diff.inserted 445 | scope 446 | markup.inserted 447 | settings 448 | 449 | foreground 450 | #5eff6c 451 | 452 | 453 | 454 | name 455 | diff.changed 456 | scope 457 | markup.changed 458 | settings 459 | 460 | foreground 461 | #5ef1ff 462 | 463 | 464 | 465 | scope 466 | constant.numeric.line-number.find-in-files - match 467 | settings 468 | 469 | foreground 470 | #ff5ef1 471 | 472 | 473 | 474 | scope 475 | entity.name.filename 476 | settings 477 | 478 | foreground 479 | #5eff6c 480 | 481 | 482 | 483 | scope 484 | message.error 485 | settings 486 | 487 | foreground 488 | #ff6e5e 489 | 490 | 491 | 492 | name 493 | JSON Punctuation 494 | scope 495 | punctuation.definition.string.begin.json - meta.structure.dictionary.value.json, punctuation.definition.string.end.json - meta.structure.dictionary.value.json 496 | settings 497 | 498 | foreground 499 | #ffffff 500 | 501 | 502 | 503 | name 504 | JSON Structure 505 | scope 506 | meta.structure.dictionary.json string.quoted.double.json 507 | settings 508 | 509 | foreground 510 | #ffffff 511 | 512 | 513 | 514 | name 515 | JSON String 516 | scope 517 | meta.structure.dictionary.value.json string.quoted.double.json 518 | settings 519 | 520 | foreground 521 | #ffffff 522 | 523 | 524 | 525 | name 526 | JSON: 6 deep 527 | scope 528 | meta meta meta meta meta meta meta.structure.dictionary.value string 529 | settings 530 | 531 | foreground 532 | #ff5ea0 533 | 534 | 535 | 536 | name 537 | JSON: 5 deep 538 | scope 539 | meta meta meta meta meta meta.structure.dictionary.value string 540 | settings 541 | 542 | foreground 543 | #ff5ef1 544 | 545 | 546 | 547 | name 548 | JSON: 4 deep 549 | scope 550 | meta meta meta meta meta.structure.dictionary.value string 551 | settings 552 | 553 | foreground 554 | #bd5eff 555 | 556 | 557 | 558 | name 559 | JSON: 3 deep 560 | scope 561 | meta meta meta meta.structure.dictionary.value string 562 | settings 563 | 564 | foreground 565 | #5ea1ff 566 | 567 | 568 | 569 | name 570 | JSON: 2 deep 571 | scope 572 | meta meta meta.structure.dictionary.value string 573 | settings 574 | 575 | foreground 576 | #5ef1ff 577 | 578 | 579 | 580 | name 581 | JSON: 1 deep 582 | scope 583 | meta meta.structure.dictionary.value string 584 | settings 585 | 586 | foreground 587 | #ffbd5e 588 | 589 | 590 | 591 | 592 | 593 | name 594 | Markup: strike 595 | scope 596 | markup.strike 597 | settings 598 | 599 | fontStyle 600 | italic 601 | foreground 602 | #ffbd5e 603 | 604 | 605 | 606 | name 607 | Markup: bold 608 | scope 609 | markup.bold 610 | settings 611 | 612 | fontStyle 613 | bold 614 | foreground 615 | #ffbd5e 616 | 617 | 618 | 619 | name 620 | Markup: italic 621 | scope 622 | markup.italic 623 | settings 624 | 625 | fontStyle 626 | italic 627 | foreground 628 | #ffbd5e 629 | 630 | 631 | 632 | name 633 | Markdown: heading 634 | scope 635 | markup.heading 636 | settings 637 | 638 | foreground 639 | #ffbd5e 640 | 641 | 642 | 643 | name 644 | Markdown: List Items Punctuation 645 | scope 646 | punctuation.definition.list_item.markdown 647 | settings 648 | 649 | foreground 650 | #ff5ea0 651 | 652 | 653 | 654 | name 655 | Markdown: Blockquote 656 | scope 657 | markup.quote 658 | settings 659 | 660 | fontStyle 661 | italic 662 | foreground 663 | #ffffff 664 | 665 | 666 | 667 | name 668 | Markdown: Blockquote Punctuation 669 | scope 670 | punctuation.definition.blockquote.markdown 671 | settings 672 | 673 | fontStyle 674 | italic 675 | foreground 676 | #ffffff 677 | 678 | 679 | 680 | name 681 | Markdown: Separator 682 | scope 683 | meta.separator 684 | settings 685 | 686 | foreground 687 | #7b8496 688 | 689 | 690 | 691 | name 692 | Markup: raw inline 693 | scope 694 | text.html.markdown markup.raw.inline 695 | settings 696 | 697 | foreground 698 | #5eff6c 699 | 700 | 701 | 702 | name 703 | Markup: underline 704 | scope 705 | markup.underline 706 | settings 707 | 708 | fontStyle 709 | underline 710 | foreground 711 | #bd5eff 712 | 713 | 714 | 715 | name 716 | Markup: Raw block 717 | scope 718 | markup.raw.block 719 | settings 720 | 721 | foreground 722 | #ffffff 723 | 724 | 725 | 726 | name 727 | Markdown: Raw Block fenced source 728 | scope 729 | markup.raw.block.fenced.markdown source 730 | settings 731 | 732 | foreground 733 | #ffffff 734 | 735 | 736 | 737 | name 738 | Markdown: Fenced Bode Block 739 | scope 740 | punctuation.definition.fenced.markdown, variable.language.fenced.markdown 741 | settings 742 | 743 | fontStyle 744 | italic 745 | foreground 746 | #7b8496 747 | 748 | 749 | 750 | name 751 | Markdown: Fenced Language 752 | scope 753 | variable.language.fenced.markdown 754 | settings 755 | 756 | fontStyle 757 | italic 758 | foreground 759 | #7b8496 760 | 761 | 762 | 763 | name 764 | Punctuation Accessor 765 | scope 766 | punctuation.accessor 767 | settings 768 | 769 | foreground 770 | #ff5ea0 771 | 772 | 773 | 774 | name 775 | Meta Function Return Type 776 | scope 777 | meta.function.return-type 778 | settings 779 | 780 | foreground 781 | #bd5eff 782 | 783 | 784 | 785 | name 786 | Punctuation Section Block Begin 787 | scope 788 | punctuation.section.block.begin 789 | settings 790 | 791 | foreground 792 | #ffffff 793 | 794 | 795 | 796 | name 797 | Punctuation Section Block End 798 | scope 799 | punctuation.section.block.end 800 | settings 801 | 802 | foreground 803 | #ffffff 804 | 805 | 806 | 807 | name 808 | Punctuation Section Embedded Begin 809 | scope 810 | punctuation.section.embedded.begin 811 | settings 812 | 813 | foreground 814 | #ff5ea0 815 | 816 | 817 | 818 | name 819 | Punctuation Section Embedded End 820 | scope 821 | punctuation.section.embedded.end 822 | settings 823 | 824 | foreground 825 | #ff5ea0 826 | 827 | 828 | 829 | name 830 | Punctuation Separator Namespace 831 | scope 832 | punctuation.separator.namespace 833 | settings 834 | 835 | foreground 836 | #ff5ea0 837 | 838 | 839 | 840 | name 841 | Variable Function 842 | scope 843 | variable.function 844 | settings 845 | 846 | foreground 847 | #5ea1ff 848 | 849 | 850 | 851 | name 852 | Variable Other 853 | scope 854 | variable.other 855 | settings 856 | 857 | foreground 858 | #ffffff 859 | 860 | 861 | 862 | name 863 | Variable Language 864 | scope 865 | variable.language 866 | settings 867 | 868 | foreground 869 | #bd5eff 870 | 871 | 872 | 873 | name 874 | Entity Name Module Ruby 875 | scope 876 | entity.name.module.ruby 877 | settings 878 | 879 | foreground 880 | #5ef1ff 881 | 882 | 883 | 884 | name 885 | Entity Name Constant Ruby 886 | scope 887 | entity.name.constant.ruby 888 | settings 889 | 890 | foreground 891 | #5ea1ff 892 | 893 | 894 | 895 | name 896 | Support Function Builtin Ruby 897 | scope 898 | support.function.builtin.ruby 899 | settings 900 | 901 | foreground 902 | #ffffff 903 | 904 | 905 | 906 | name 907 | Storage Type Namespace CS 908 | scope 909 | storage.type.namespace.cs 910 | settings 911 | 912 | foreground 913 | #ff5ea0 914 | 915 | 916 | 917 | name 918 | Entity Name Namespace CS 919 | scope 920 | entity.name.namespace.cs 921 | settings 922 | 923 | foreground 924 | #5ef1ff 925 | 926 | 927 | 928 | uuid 929 | 68394a4e-1404-4971-bdfc-81dd7f9d29f6 930 | colorSpaceName 931 | sRGB 932 | semanticClass 933 | theme.cyberdream 934 | author 935 | Scott McKendry 936 | 937 | 938 | --------------------------------------------------------------------------------