commit a184f14af251a926227167d39e3d37cac8c1cf58 Author: huyjaky Date: Tue Jul 23 12:55:49 2024 +0700 astro-nvim-v3 - archive v3 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6fd0a37 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# Compiled Lua sources +luac.out + +# luarocks build files +*.src.rock +*.zip +*.tar.gz + +# Object files +*.o +*.os +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo +*.def +*.exp + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + diff --git a/.neoconf.json b/.neoconf.json new file mode 100644 index 0000000..4da33ca --- /dev/null +++ b/.neoconf.json @@ -0,0 +1,20 @@ +{ + "neodev": { + "library": { + "enabled": true, + "plugins": true + } + }, + "neoconf": { + "plugins": { + "lua_ls": { + "enabled": true + } + } + }, + "lspconfig": { + "lua_ls": { + "Lua.format.enable": false + } + } +} diff --git a/.stylua.toml b/.stylua.toml new file mode 100644 index 0000000..bfcffff --- /dev/null +++ b/.stylua.toml @@ -0,0 +1,7 @@ +column_width = 120 +line_endings = "Unix" +indent_type = "Spaces" +indent_width = 2 +quote_style = "AutoPreferDouble" +call_parentheses = "None" +collapse_simple_statement = "Always" diff --git a/README.md b/README.md new file mode 100644 index 0000000..0f44983 --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +# nvim-config + +My personal neovim config + +## Installation + +- Windows + + ```powershell + Rename-Item -Path $env:LOCALAPPDATA\nvim -NewName $env:LOCALAPPDATA\nvim.bak + Rename-Item -Path $env:LOCALAPPDATA\nvim-data -NewName $env:LOCALAPPDATA\nvim-data.bak + git clone https://github.com/Penguin-jpg/nvim-config $env:LOCALAPPDATA\nvim + nvim + ``` + +- Unix + + ```shell + mv ~/.config/nvim ~/.config/nvim.bak + mv ~/.local/share/nvim ~/.local/share/nvim.bak + git clone https://github.com/Penguin-jpg/nvim-config ~/.config/nvim + nvim + ``` + +## Dependency + +- Python + + ```shell + sudo apt-get install python3-dev python3-pip python3-venv + pip install pynvim + ``` + +- Node + + ```shell + npm install -g neovim + ``` + +- Cargo + ```shell + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + rustup update + cargo install --locked yazi-fm yazi-cli + ``` +- Optional + - [ripgrep (for live grep)](https://github.com/BurntSushi/ripgrep) + - [wezterm](https://wezfurlong.org/wezterm/index.html) diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..425b155 --- /dev/null +++ b/init.lua @@ -0,0 +1,19 @@ +-- This file simply bootstraps the installation of Lazy.nvim and then calls other files for execution +-- This file doesn't necessarily need to be touched, BE CAUTIOUS editing this file and proceed at your own risk. +local lazypath = vim.env.LAZY or vim.fn.stdpath "data" .. "/lazy/lazy.nvim" +if not (vim.env.LAZY or (vim.uv or vim.loop).fs_stat(lazypath)) then + -- stylua: ignore + vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", "--branch=stable", lazypath }) +end +vim.opt.rtp:prepend(lazypath) + +-- validate that lazy is available +if not pcall(require, "lazy") then + -- stylua: ignore + vim.api.nvim_echo({ { ("Unable to load lazy from: %s\n"):format(lazypath), "ErrorMsg" }, { "Press any key to exit...", "MoreMs" } }, true, {}) + vim.fn.getchar() + vim.cmd.quit() +end + +require "lazy_setup" +require "polish" diff --git a/lazy-lock.json b/lazy-lock.json new file mode 100644 index 0000000..f5524fd --- /dev/null +++ b/lazy-lock.json @@ -0,0 +1,84 @@ +{ + "AstroNvim": { "branch": "main", "commit": "7d7e3f124d7789233f3faf200980a6ca36f11174" }, + "Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" }, + "LuaSnip": { "branch": "master", "commit": "03c8e67eb7293c404845b3982db895d59c0d1538" }, + "SmoothCursor.nvim": { "branch": "main", "commit": "c082e1e943acec28d95aa05325097426e612047f" }, + "aerial.nvim": { "branch": "master", "commit": "7e2615991cf110f6688112abcb45cf338248d1f6" }, + "alpha-nvim": { "branch": "main", "commit": "41283fb402713fc8b327e60907f74e46166f4cfd" }, + "astrocommunity": { "branch": "main", "commit": "110e75863a4b7d88bf9e198cde83598c90cc833a" }, + "astrocore": { "branch": "main", "commit": "e659ec1f23dd070fa9a68a78eab0675b7bf3e97d" }, + "astrolsp": { "branch": "main", "commit": "366a8edfddb90bfcd7b710b95a3d6b685efaa4db" }, + "astrotheme": { "branch": "main", "commit": "c52dad31bb0000524ca4003222c9ed0f4e8c3058" }, + "astroui": { "branch": "main", "commit": "a96ee08273f8050025c9e5b40776b0f2808313fa" }, + "auto-save.nvim": { "branch": "main", "commit": "5fe9ab0c42f0457f2a973e814a6352b8eeb04730" }, + "better-escape.nvim": { "branch": "master", "commit": "92b3d7d06ac3405178def49853f81118a12ea051" }, + "catppuccin": { "branch": "main", "commit": "0b5df9c9e641b1212b21a0762ccad4434fd41322" }, + "clangd_extensions.nvim": { "branch": "main", "commit": "a8500531c4ed3a207e744a374ea038744a0f93eb" }, + "cmp-buffer": { "branch": "main", "commit": "3022dbc9166796b644a841a02de8dd1cc1d311fa" }, + "cmp-dap": { "branch": "master", "commit": "ea92773e84c0ad3288c3bc5e452ac91559669087" }, + "cmp-nvim-lsp": { "branch": "main", "commit": "39e2eda76828d88b773cc27a3f61d2ad782c922d" }, + "cmp-path": { "branch": "main", "commit": "91ff86cd9c29299a64f968ebb45846c485725f23" }, + "cmp_luasnip": { "branch": "master", "commit": "05a9ab28b53f71d1aece421ef32fee2cb857a843" }, + "code_runner.nvim": { "branch": "main", "commit": "6c5bfe44a6c7523350cd706e6b3b8101166eed99" }, + "cyberdream.nvim": { "branch": "main", "commit": "bb3011a38b94ac4f13c107f5f1b3464c1c03ced1" }, + "dressing.nvim": { "branch": "master", "commit": "71349f24c6e07b39f33600985843c289ca735308" }, + "duplicate.nvim": { "branch": "main", "commit": "ab057af7872c44e6fbd48df9b03983c8e67c50a7" }, + "flash.nvim": { "branch": "main", "commit": "34c7be146a91fec3555c33fe89c7d643f6ef5cf1" }, + "friendly-snippets": { "branch": "main", "commit": "00ebcaa159e817150bd83bfe2d51fa3b3377d5c4" }, + "gitsigns.nvim": { "branch": "main", "commit": "0b04035bb7b3c83e999b9676e2fb46fd0aa9f910" }, + "grapple.nvim": { "branch": "main", "commit": "7aedc261b05a6c030397c4bc26416efbe746ebf1" }, + "grug-far.nvim": { "branch": "main", "commit": "0fb9cb0f96acbd75f524312c8587bef2a0e20181" }, + "guess-indent.nvim": { "branch": "main", "commit": "6cd61f7a600bb756e558627cd2e740302c58e32d" }, + "heirline.nvim": { "branch": "master", "commit": "0d797435e54645a5f98bad7ad6046aac1ef95c1e" }, + "hlchunk.nvim": { "branch": "main", "commit": "d49b06762b51209b41577a84dc2925b4969e3954" }, + "kanagawa.nvim": { "branch": "master", "commit": "e5f7b8a804360f0a48e40d0083a97193ee4fcc87" }, + "lazy.nvim": { "branch": "main", "commit": "839f9e78e78dc935b1188fb16583365991739c51" }, + "lazydev.nvim": { "branch": "main", "commit": "399299ca570aa82c13ee4fb1bd1304ce6baf7f05" }, + "lsp_signature.nvim": { "branch": "master", "commit": "a38da0a61c172bb59e34befc12efe48359884793" }, + "lspkind.nvim": { "branch": "master", "commit": "1735dd5a5054c1fb7feaf8e8658dbab925f4f0cf" }, + "luvit-meta": { "branch": "main", "commit": "ce76f6f6cdc9201523a5875a4471dcfe0186eb60" }, + "markview.nvim": { "branch": "main", "commit": "316cafc79490f8b79c288bbe6638838d6d68e227" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "9ae570e206360e47d30b4c35a4550c165f4ea7b7" }, + "mason-null-ls.nvim": { "branch": "main", "commit": "2b8433f76598397fcc97318d410e0c4f7a4bea6a" }, + "mason-nvim-dap.nvim": { "branch": "main", "commit": "4ba55f9755ebe8297d92c419b90a946123292ae6" }, + "mason.nvim": { "branch": "main", "commit": "c43eeb5614a09dc17c03a7fb49de2e05de203924" }, + "mini.ai": { "branch": "main", "commit": "45587078f323eaf41b9f701bbc04f8d1ab008979" }, + "mini.bufremove": { "branch": "main", "commit": "e6044aa28e61d4dd9ec86194d6f81743eced0c1c" }, + "mini.icons": { "branch": "main", "commit": "352a25dce86c41ab9fe854dd37f60c36ea7048df" }, + "mini.move": { "branch": "main", "commit": "cde3747eec9bb3941296e6fa1d874e0da5a10256" }, + "mini.surround": { "branch": "main", "commit": "57caca9525cec0ea771a67326b0ee637d056078a" }, + "multiple-cursors.nvim": { "branch": "main", "commit": "2f5e786c43aa9c0fc34b295cfcc9bfbacef8e926" }, + "neo-tree.nvim": { "branch": "main", "commit": "8c75e8a2949cd6cd35525799200a8d34471ee9eb" }, + "neoconf.nvim": { "branch": "main", "commit": "5be1c783a4bf9fab531b71376a6955beb933fcfb" }, + "noice.nvim": { "branch": "main", "commit": "dd7363eae290ecdb9d6a2db6e0f59527df79edd6" }, + "none-ls.nvim": { "branch": "main", "commit": "2cde745aadc2c36f6860a77a556494870675771a" }, + "nui.nvim": { "branch": "main", "commit": "a0fd35fcbb4cb479366f1dc5f20145fd718a3733" }, + "nvim-autopairs": { "branch": "master", "commit": "78a4507bb9ffc9b00f11ae0ac48243d00cb9194d" }, + "nvim-cmp": { "branch": "main", "commit": "d818fd0624205b34e14888358037fb6f5dc51234" }, + "nvim-dap": { "branch": "master", "commit": "bc03b83c94d0375145ff5ac6a6dcf28c1241e06f" }, + "nvim-dap-ui": { "branch": "master", "commit": "a5606bc5958db86f8d92803bea7400ee26a8d7e4" }, + "nvim-highlight-colors": { "branch": "main", "commit": "a8f6952cb1ff7bde864a34c502f1a42c360a6662" }, + "nvim-lspconfig": { "branch": "master", "commit": "fa6c2a64100c6f692bbec29bbbc8ec2663c9e869" }, + "nvim-nio": { "branch": "master", "commit": "a428f309119086dc78dd4b19306d2d67be884eee" }, + "nvim-notify": { "branch": "master", "commit": "d333b6f167900f6d9d42a59005d82919830626bf" }, + "nvim-spider": { "branch": "main", "commit": "508b3504a350fb9a93bd0b7c0d41b8b5fc732b5e" }, + "nvim-treesitter": { "branch": "master", "commit": "debf5816eee21b7d51025ef17ba0647386226cb5" }, + "nvim-treesitter-textobjects": { "branch": "master", "commit": "34867c69838078df7d6919b130c0541c0b400c47" }, + "nvim-ts-autotag": { "branch": "main", "commit": "1624866a1379fc1861797f0ed05899a9c1d2ff61" }, + "nvim-ts-context-commentstring": { "branch": "main", "commit": "6b5f95aa4d24f2c629a74f2c935c702b08dbde62" }, + "nvim-ufo": { "branch": "main", "commit": "a5390706f510d39951dd581f6d2a972741b3fa26" }, + "plenary.nvim": { "branch": "master", "commit": "a3e3bc82a3f95c5ed0d7201546d5d2c19b20d683" }, + "promise-async": { "branch": "main", "commit": "38a4575da9497326badd3995e768b4ccf0bb153e" }, + "resession.nvim": { "branch": "master", "commit": "cc819b0489938d03e4f3532a583354f0287c015b" }, + "smart-splits.nvim": { "branch": "master", "commit": "66fda3a601a5b4c679656f15eb6ddd613c8d3216" }, + "telescope-fzf-native.nvim": { "branch": "main", "commit": "cf48d4dfce44e0b9a2e19a008d6ec6ea6f01a83b" }, + "telescope.nvim": { "branch": "master", "commit": "a0bbec21143c7bc5f8bb02e0005fa0b982edc026" }, + "todo-comments.nvim": { "branch": "main", "commit": "313b04e5b02d29ab9275c9295ff5e2b73921b0eb" }, + "transparent.nvim": { "branch": "main", "commit": "fd35a46f4b7c1b244249266bdcb2da3814f01724" }, + "treesj": { "branch": "main", "commit": "275f83c81a5a1f5ae23c1eac30c4ac28beebbca2" }, + "trouble.nvim": { "branch": "main", "commit": "6efc446226679fda0547c0fd6a7892fd5f5b15d8" }, + "ultimate-autopair.nvim": { "branch": "v0.6", "commit": "035d92eab05ac1390afef7204e3fcad9a50fa443" }, + "vim-illuminate": { "branch": "master", "commit": "5eeb7951fc630682c322e88a9bbdae5c224ff0aa" }, + "vim-visual-multi": { "branch": "master", "commit": "38b0e8d94a5499ccc17d6159763d32c79f53417b" }, + "which-key.nvim": { "branch": "main", "commit": "48cdaaab93a4c85cac8eb271bb48307ed337787f" } +} diff --git a/lua/community.lua b/lua/community.lua new file mode 100644 index 0000000..b8ee4b8 --- /dev/null +++ b/lua/community.lua @@ -0,0 +1,14 @@ +-- AstroCommunity: import any community modules here +-- We import this file in `lazy_setup.lua` before the `plugins/` folder. +-- This guarantees that the specs are processed before any user plugins. + +---@type LazySpec +return { + "AstroNvim/astrocommunity", + { import = "astrocommunity.pack.lua" }, + { import = "astrocommunity.pack.json" }, + { import = "astrocommunity.pack.markdown" }, + { import = "astrocommunity.color.nvim-highlight-colors" }, + { import = "astrocommunity.diagnostics.trouble-nvim" }, + { import = "astrocommunity.neovim-lua-development.lazydev-nvim" }, +} diff --git a/lua/core/autocmds.lua b/lua/core/autocmds.lua new file mode 100644 index 0000000..b5cb277 --- /dev/null +++ b/lua/core/autocmds.lua @@ -0,0 +1,34 @@ +-- Some commands that I want to execute in specific timing +vim.api.nvim_create_augroup("disable_comment_newline", { clear = true }) +vim.api.nvim_create_augroup("auto_wrap", { clear = true }) +vim.api.nvim_create_augroup("disable_suspend_with_c_z", { clear = true }) +vim.api.nvim_create_augroup("clear_last_search", { clear = true }) + +vim.api.nvim_create_autocmd("BufEnter", { + desc = "Disable auto insert comment newline", + group = "disable_comment_newline", + command = "set formatoptions-=cro", +}) + +vim.api.nvim_create_autocmd("FileType", { + desc = "Enable wrap and spell for text like documents", + group = "auto_wrap", + pattern = { "gitcommit", "markdown", "text", "plaintext" }, + callback = function() + vim.opt_local.wrap = true + vim.opt_local.spell = true + end, +}) + +vim.api.nvim_create_autocmd("BufEnter", { + desc = "Remap to nothing so that it doesn't suspend terminal", + group = "disable_suspend_with_c_z", + command = "nnoremap ", +}) + +vim.api.nvim_create_autocmd("BufWinEnter", { + desc = "Clear last search pattern", + group = "clear_last_search", + pattern = "*", + command = "let @/ = ''", +}) diff --git a/lua/core/mappings.lua b/lua/core/mappings.lua new file mode 100644 index 0000000..a20ff09 --- /dev/null +++ b/lua/core/mappings.lua @@ -0,0 +1,55 @@ +-- Mapping data with "desc" stored directly by vim.keymap.set(). +-- +-- Please use this mappings table to set keyboard mapping since this is the +-- lower level configuration and more robust one. (which-key will +-- automatically pick-up stored data by this setting.) + +return function() + local mappings = require("astrocore").empty_map_table() + + ------------------------------------------- + ------- Disable default mappings ---------- + ------------------------------------------- + mappings.n[""] = false + mappings.n[""] = false + mappings.n[""] = false + mappings.n[""] = false + mappings.n[""] = false + mappings.n[""] = false + mappings.n[""] = false + mappings.n[""] = false + + ------------------------------------------- + ----------- Utility functions ------------- + ------------------------------------------- + mappings.n[""] = { "u", desc = "Undo" } + mappings.i[""] = { "u", desc = "Undo" } + mappings.i[""] = { "dw", desc = "Delete a word backward" } + mappings.i[""] = { "w!", desc = "Save file" } + mappings.i[""] = { "", desc = "Unindent line" } + mappings.v[""] = { ">gv", desc = "Indent line" } + mappings.v[""] = { ""] = { "ggVG", desc = "Select all lines" } + + return mappings +end diff --git a/lua/core/options.lua b/lua/core/options.lua new file mode 100644 index 0000000..afdf9d4 --- /dev/null +++ b/lua/core/options.lua @@ -0,0 +1,33 @@ +return { + -- vim.opt. + opt = { + number = true, -- show line number + relativenumber = true, -- show relative line number + spell = false, -- disable spell check + wrap = false, -- disable auto wrap lines + signcolumn = "yes", -- show changes of file + foldcolumn = "1", -- show foldcolumn + foldenable = true, -- enable fold for nvim-ufo + foldlevel = 99, -- set high foldlevel for nvim-ufo + foldlevelstart = 99, -- start with all code unfolded + guicursor = "n-v-c-sm:block,i-ci-ve:ver25,r-cr-o:hor20", -- default cursor setting + clipboard = "unnamedplus", -- enable system clipboard + termguicolors = true, -- true color support + mouse = "a", -- enable mouse + mousemoveevent = true, -- enable mousemove event + laststatus = 3, -- only show one statusline + swapfile = false, -- don't use swapfile + shiftwidth = 4, -- number of space inserted for indentation; when zero the 'tabstop' value will be used + tabstop = 2, -- set the number of space in a tab to 4 + softtabstop = 4, -- can be differnt from tabstop + showtabline = 2, -- always show tabline + expandtab = true, -- use spaces instead of tab + undofile = true, -- enable persistent undo + }, + -- vim.g. + g = { + -- configure global vim variables (vim.g) + -- NOTE: `mapleader` and `maplocalleader` must be set in the AstroNvim opts or before `lazy.setup` + -- This can be found in the `lua/lazy_setup.lua` file + }, +} diff --git a/lua/lazy_setup.lua b/lua/lazy_setup.lua new file mode 100644 index 0000000..cca2306 --- /dev/null +++ b/lua/lazy_setup.lua @@ -0,0 +1,31 @@ +require("lazy").setup({ + { + "AstroNvim/AstroNvim", + version = "^4", -- Remove version tracking to elect for nighly AstroNvim + import = "astronvim.plugins", + opts = { -- AstroNvim options must be set here with the `import` key + mapleader = " ", -- This ensures the leader key must be configured before Lazy is set up + maplocalleader = ",", -- This ensures the localleader key must be configured before Lazy is set up + icons_enabled = true, -- Set to false to disable icons (if no Nerd Font is available) + pin_plugins = nil, -- Default will pin plugins when tracking `version` of AstroNvim, set to true/false to override + }, + }, + { import = "community" }, + { import = "plugins" }, +} --[[@as LazySpec]], { + -- Configure any other `lazy.nvim` configuration options here + install = { colorscheme = { "astrodark", "habamax" } }, + ui = { backdrop = 100 }, + performance = { + rtp = { + -- disable some rtp plugins, add more to your liking + disabled_plugins = { + "gzip", + "netrwPlugin", + "tarPlugin", + "tohtml", + "zipPlugin", + }, + }, + }, +} --[[@as LazyConfig]]) diff --git a/lua/plugins/astrocore.lua b/lua/plugins/astrocore.lua new file mode 100644 index 0000000..ffc2eeb --- /dev/null +++ b/lua/plugins/astrocore.lua @@ -0,0 +1,46 @@ +-- AstroCore provides a central place to modify mappings, vim options, autocommands, and more! +-- Configuration documentation can be found with `:h astrocore` +-- NOTE: We highly recommend setting up the Lua Language Server (`:LspInstall lua_ls`) +-- as this provides autocomplete and documentation while editing + +---@type LazySpec +return { + "AstroNvim/astrocore", + ---@type AstroCoreOpts + opts = { + -- Configure core features of AstroNvim + features = { + large_buf = { size = 1024 * 500, lines = 10000 }, -- set global limits for large files for disabling features like treesitter + autopairs = true, -- enable autopairs at start + cmp = true, -- enable completion at start + diagnostics_mode = 3, -- diagnostic mode on start (0 = off, 1 = no signs/virtual text, 2 = no virtual text, 3 = on) + highlighturl = true, -- highlight URLs at start + notifications = true, -- enable notifications at start + }, + -- Diagnostics configuration (for vim.diagnostics.config({...})) when diagnostics are on + diagnostics = { + virtual_text = true, + underline = true, + update_in_insert = false, + }, + -- Configuration table of session options for AstroNvim's session management powered by Resession + sessions = { + -- Configure auto saving + autosave = { + last = true, -- auto save last session + cwd = true, -- auto save session for each working directory + }, + -- Patterns to ignore when saving sessions + ignore = { + dirs = {}, -- working directories to ignore sessions in + filetypes = { "gitcommit", "gitrebase" }, -- filetypes to ignore sessions + buftypes = {}, -- buffer types to ignore sessions + }, + }, + -- vim options can be configured here + options = require "core.options", + -- Mappings can be configured through AstroCore as well. + -- NOTE: keycodes follow the casing in the vimdocs. For example, `` must be capitalized + mappings = require "core.mappings"(), + }, +} diff --git a/lua/plugins/astrolsp.lua b/lua/plugins/astrolsp.lua new file mode 100644 index 0000000..e9c53f9 --- /dev/null +++ b/lua/plugins/astrolsp.lua @@ -0,0 +1,115 @@ +-- Configuration documentation can be found with `:h astrolsp` +-- NOTE: We highly recommend setting up the Lua Language Server (`:LspInstall lua_ls`) +-- as this provides autocomplete and documentation while editing + +---@type LazySpec +return { + "AstroNvim/astrolsp", + ---@type AstroLSPOpts + opts = { + -- Configuration table of features provided by AstroLSP + features = { + autoformat = true, -- enable or disable auto formatting on start + codelens = true, -- enable/disable codelens refresh on start + inlay_hints = true, -- enable/disable inlay hints on start + semantic_tokens = true, -- enable/disable semantic token highlighting + }, + -- customize lsp formatting options + formatting = require "plugins.configs.lsp.formatting", + -- enable servers that you already have installed without mason + servers = {}, + -- customize language server configuration options passed to `lspconfig` + ---@diagnostic disable: missing-fields + config = { + clangd = require "plugins.configs.lsp.config.clangd", + basedpyright = require "plugins.configs.lsp.config.basedpyright", + }, + -- customize how language servers are attached + handlers = { + -- a function without a key is simply the default handler, functions take two parameters, the server name and the configured options table for that server + -- function(server, opts) require("lspconfig")[server].setup(opts) end + + -- the key is the server that is being setup with `lspconfig` + -- rust_analyzer = false, -- setting a handler to false will disable the set up of that language server + -- pyright = function(_, opts) require("lspconfig").pyright.setup(opts) end -- or a custom handler function can be passed + }, + -- Configure buffer local auto commands to add when attaching a language server + autocmds = { + -- first key is the `augroup` to add the auto commands to (:h augroup) + lsp_document_highlight = { + -- Optional condition to create/delete auto command group + -- can either be a string of a client capability or a function of `fun(client, bufnr): boolean` + -- condition will be resolved for each client on each execution and if it ever fails for all clients, + -- the auto commands will be deleted for that buffer + cond = "textDocument/documentHighlight", + -- cond = function(client, bufnr) return client.name == "lua_ls" end, + -- list of auto commands to set + { + -- events to trigger + event = { "CursorHold", "CursorHoldI" }, + -- the rest of the autocmd options (:h nvim_create_autocmd) + desc = "Document Highlighting", + callback = function() vim.lsp.buf.document_highlight() end, + }, + { + event = { "CursorMoved", "CursorMovedI", "BufLeave" }, + desc = "Document Highlighting Clear", + callback = function() vim.lsp.buf.clear_references() end, + }, + }, + -- disable inlay hints in insert mode + disable_inlay_hints_on_insert = { + -- only create for language servers that support inlay hints + -- (and only if vim.lsp.inlay_hint is available) + cond = vim.lsp.inlay_hint and "textDocument/inlayHint" or false, + { + -- when going into insert mode + event = "InsertEnter", + desc = "disable inlay hints on insert", + callback = function(args) + local filter = { bufnr = args.buf } + -- if the inlay hints are currently enabled + if vim.lsp.inlay_hint.is_enabled(filter) then + -- disable the inlay hints + vim.lsp.inlay_hint.enable(false, filter) + -- create a single use autocommand to turn the inlay hints back on + -- when leaving insert mode + vim.api.nvim_create_autocmd("InsertLeave", { + buffer = args.buf, + once = true, + callback = function() vim.lsp.inlay_hint.enable(true, filter) end, + }) + end + end, + }, + }, + }, + -- mappings to be set up on attaching of a language server + mappings = { + n = { + gh = { function() vim.lsp.buf.hover() end, desc = "Hover symbol details", cond = "textDocument/hover" }, + gl = { function() vim.diagnostic.open_float() end, desc = "Hover diagnostics" }, + -- a `cond` key can provided as the string of a server capability to be required to attach, or a function with `client` and `bufnr` parameters from the `on_attach` that returns a boolean + gD = { + function() vim.lsp.buf.declaration() end, + desc = "Declaration of current symbol", + cond = "textDocument/declaration", + }, + ["uY"] = { + function() require("astrolsp.toggles").buffer_semantic_tokens() end, + desc = "Toggle LSP semantic highlight (buffer)", + cond = function(client) return client.server_capabilities.semanticTokensProvider and vim.lsp.semantic_tokens end, + }, + }, + }, + -- A custom `on_attach` function to be run after the default `on_attach` function + -- takes two parameters `client` and `bufnr` (`:h lspconfig-setup`) + on_attach = function(client, bufnr) + -- this would disable semanticTokensProvider for all clients + -- client.server_capabilities.semanticTokensProvider = nil + + -- Disable ruff_lsp hover in favor of pyright + if client.name == "ruff_lsp" then client.server_capabilities.hoverProvider = false end + end, + }, +} diff --git a/lua/plugins/astroui.lua b/lua/plugins/astroui.lua new file mode 100644 index 0000000..cdfbcac --- /dev/null +++ b/lua/plugins/astroui.lua @@ -0,0 +1,19 @@ +-- AstroUI provides the basis for configuring the AstroNvim User Interface +-- Configuration documentation can be found with `:h astroui` +-- NOTE: We highly recommend setting up the Lua Language Server (`:LspInstall lua_ls`) +-- as this provides autocomplete and documentation while editing + +---@type LazySpec +return { + "AstroNvim/astroui", + ---@type AstroUIOpts + opts = { + -- change colorscheme + colorscheme = "cyberdream", + -- AstroUI allows you to easily modify highlight groups easily for any and all colorschemes + highlights = require "plugins.configs.ui.highlights", + -- Icons can be configured throughout the interface + icons = require "plugins.configs.ui.icons", + status = require "plugins.configs.ui.status", + }, +} diff --git a/lua/plugins/auto-save.lua b/lua/plugins/auto-save.lua new file mode 100644 index 0000000..c737bfe --- /dev/null +++ b/lua/plugins/auto-save.lua @@ -0,0 +1,40 @@ +return { + "okuuva/auto-save.nvim", + cmd = "ASToggle", -- optional for lazy loading on command + event = { "InsertLeave", "TextChanged" }, -- optional for lazy loading on trigger events + opts = { + -- your config goes here + -- or just leave it empty :) + enabled = true, -- start auto-save when the plugin is loaded (i.e. when your package manager loads it) + execution_message = { + enabled = false, + message = function() -- message to print on save + return ("AutoSave: saved at " .. vim.fn.strftime "%H:%M:%S") + end, + dim = 0.18, -- dim the color of `message` + cleaning_interval = 1250, -- (milliseconds) automatically clean MsgArea after displaying `message`. See :h MsgArea + }, + trigger_events = { -- See :h events + immediate_save = { "BufLeave", "FocusLost" }, -- vim events that trigger an immediate save + defer_save = { "InsertLeave", "TextChanged" }, -- vim events that trigger a deferred save (saves after `debounce_delay`) + cancel_defered_save = { "InsertEnter" }, -- vim events that cancel a pending deferred save + }, + -- function that takes the buffer handle and determines whether to save the current buffer or not + -- return true: if buffer is ok to be saved + -- return false: if it's not ok to be saved + -- if set to `nil` then no specific condition is applied + -- + condition = function(buf) + -- Check if vim-visual-multi is active + local visual_multi_active = vim.g.VM_is_active or false + if visual_multi_active then return false end + -- Additional conditions can be added here if needed + return true + end, + + write_all_buffers = false, -- write all buffers when the current one meets `condition` + noautocmd = false, -- do not execute autocmds when saving + lockmarks = false, -- lock marks when saving, see `:h lockmarks` for more details + debounce_delay = 500, -- delay after which a pending save is executed + }, +} diff --git a/lua/plugins/cmp.lua b/lua/plugins/cmp.lua new file mode 100644 index 0000000..ec00ca4 --- /dev/null +++ b/lua/plugins/cmp.lua @@ -0,0 +1,74 @@ +return { + { + "onsails/lspkind.nvim", + opts = { + symbol_map = require "plugins.configs.ui.lspkind", + }, + }, + { + "hrsh7th/nvim-cmp", + opts = function(_, opts) + local cmp = require "cmp" + local luasnip = require "luasnip" + + local function has_words_before() + local line, col = (unpack or table.unpack)(vim.api.nvim_win_get_cursor(0)) + return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match "%s" == nil + end + + return require("astrocore").extend_tbl(opts, { + -- Configure window style + window = { + completion = { + winhighlight = "Normal:Pmenu,CursorLine:PmenuSel,Search:None", + border = "none", + side_padding = 0, + }, + }, + formatting = { + -- Show icon at the beginning and menu at the end + fields = { "kind", "abbr", "menu" }, + format = function(entry, vim_item) + local kind = require("lspkind").cmp_format { mode = "symbol_text", maxwidth = 50 }(entry, vim_item) + local strings = vim.split(kind.kind, "%s", { trimetry = true }) + kind.kind = " " .. (strings[1] or "") .. " " + kind.menu = " [" .. (strings[2] or "") .. "]" + return kind + end, + }, + -- Always select the first option + completion = { + completeopt = "menu,menuone,noinsert", + }, + -- Custom mapping + mapping = { + -- Esc to close completion menu + [""] = cmp.mapping { i = cmp.mapping.abort(), c = cmp.mapping.close() }, + -- Tab to select completion + [""] = cmp.mapping(function(fallback) + if cmp.visible() and has_words_before() then + cmp.confirm { select = true } + else + fallback() + end + end, { "i", "s" }), + -- Use and to select luasnip + [""] = cmp.mapping(function(fallback) + if luasnip.jumpable(1) then + luasnip.jump(1) + else + fallback() + end + end, { "i", "s" }), + [""] = cmp.mapping(function(fallback) + if luasnip.jumpable(-1) then + luasnip.jump(-1) + else + fallback() + end + end, { "i", "s" }), + }, + }) + end, + }, +} diff --git a/lua/plugins/code-runner.lua b/lua/plugins/code-runner.lua new file mode 100644 index 0000000..39e3bb6 --- /dev/null +++ b/lua/plugins/code-runner.lua @@ -0,0 +1,31 @@ +return { + "CRAG666/code_runner.nvim", + opts = { + filetype = { + java = { + "cd $dir &&", + "javac $fileName &&", + "java $fileNameWithoutExt", + }, + python = { + "cd $dir &&", + "python3 -u $fileName", + }, + rust = { + "cd $dir &&", + "rustc $fileName &&", + "$dir/$fileNameWithoutExt", + }, + }, + }, + keys = { + + { "r", ":RunCode", mode = "n", noremap = true, silent = false, desc = "Run code" }, + { "rf", ":RunFile", mode = "n", noremap = true, silent = false, desc = "Run file" }, + { "rft", ":RunFile tab", mode = "n", noremap = true, silent = false, desc = "Run file in new tab" }, + { "rp", ":RunProject", mode = "n", noremap = true, silent = false, desc = "Run project" }, + { "rc", ":RunClose", mode = "n", noremap = true, silent = false, desc = "Close run" }, + { "crf", ":CRFiletype", mode = "n", noremap = true, silent = false, desc = "Change run filetype" }, + { "crp", ":CRProjects", mode = "n", noremap = true, silent = false, desc = "Change run projects" }, + }, +} diff --git a/lua/plugins/colorscheme.lua b/lua/plugins/colorscheme.lua new file mode 100644 index 0000000..eae29da --- /dev/null +++ b/lua/plugins/colorscheme.lua @@ -0,0 +1,64 @@ +return { + { + "catppuccin/nvim", + name = "catppuccin", + opts = { + flavour = "mocha", -- latte, frappe, macchiato, mocha + background = { -- :h background + light = "latte", + dark = "mocha", + }, + color_overrides = { + mocha = { + rosewater = "#efc9c2", + flamingo = "#ebb2b2", + pink = "#f2a7de", + mauve = "#b889f4", + red = "#ea7183", + maroon = "#ea838c", + peach = "#f39967", + yellow = "#eaca89", + green = "#96d382", + teal = "#78cec1", + sky = "#91d7e3", + sapphire = "#68bae0", + blue = "#739df2", + lavender = "#a0a8f6", + text = "#b5c1f1", + subtext1 = "#a6b0d8", + subtext0 = "#959ec2", + overlay2 = "#848cad", + overlay1 = "#717997", + overlay0 = "#63677f", + surface2 = "#505469", + surface1 = "#3e4255", + surface0 = "#2c2f40", + base = "#1a1c2a", + mantle = "#141620", + crust = "#0e0f16", + }, + }, + integrations = { + aerial = true, + alpha = true, + cmp = true, + dap = true, + dap_ui = true, + gitsigns = true, + illuminate = true, + markdown = true, + mason = true, + native_lsp = true, + neotree = true, + notify = true, + semantic_tokens = true, + symbols_outline = true, + telescope = true, + treesitter = true, + ts_rainbow = false, + which_key = true, + window_picker = true, + }, + }, + }, +} diff --git a/lua/plugins/configs/lsp/config/basedpyright.lua b/lua/plugins/configs/lsp/config/basedpyright.lua new file mode 100644 index 0000000..38c8b92 --- /dev/null +++ b/lua/plugins/configs/lsp/config/basedpyright.lua @@ -0,0 +1,34 @@ +return { + before_init = function(_, c) + if not c.settings then c.settings = {} end + if not c.settings.python then c.settings.python = {} end + c.settings.python.pythonPath = vim.fn.exepath "python" + end, + settings = { + basedpyright = { + analysis = { + -- diagnosticMode = "workspace", + diagnosticMode = "openFilesOnly", + typeCheckingMode = "basic", + autoImportCompletions = true, + autoSearchPath = true, + inlayHints = { + variableTypes = true, + functionReturnTypes = true, + callArgumentNames = true, + pytestParameters = true, + }, + useLibraryCodeForTypes = true, + diagnosticSeverityOverrides = { + reportUnusedImport = "information", + reportUnusedFunction = "information", + reportUnusedVariable = "information", + -- reportGeneralTypeIssues = "none", + -- reportOptionalMemberAccess = "none", + -- reportOptionalSubscript = "none", + -- reportPrivateImportUsage = "none", + }, + }, + }, + }, +} diff --git a/lua/plugins/configs/lsp/config/clangd.lua b/lua/plugins/configs/lsp/config/clangd.lua new file mode 100644 index 0000000..93ba604 --- /dev/null +++ b/lua/plugins/configs/lsp/config/clangd.lua @@ -0,0 +1,19 @@ +return { + capabilities = { + offsetEncoding = "utf-8", + }, + cmd = { + "clangd", + "--background-index", + "--clang-tidy", + "--all-scopes-completion", + "--header-insertion=iwyu", + "--completion-style=detailed", + "--fallback-style=Microsoft", + }, + init_options = { + clangdFileStatus = true, + usePlaceholders = false, + completeUnimported = true, + }, +} diff --git a/lua/plugins/configs/lsp/formatting.lua b/lua/plugins/configs/lsp/formatting.lua new file mode 100644 index 0000000..be08b7b --- /dev/null +++ b/lua/plugins/configs/lsp/formatting.lua @@ -0,0 +1,20 @@ +-- Customize lsp formatting options +return { -- control auto formatting on save + format_on_save = { + enabled = false, -- enable or disable format on save globally + allow_filetypes = { -- enable format on save for specified filetypes only + -- "go", + }, + ignore_filetypes = { -- disable format on save for specified filetypes + -- "lua", + }, + }, + disabled = { -- disable formatting capabilities for the listed language servers + -- disable lua_ls formatting capability if you want to use StyLua to format your lua code + -- "lua_ls", + }, + timeout_ms = 1000, -- default format timeout + -- filter = function(client) -- fully override the default formatting function + -- return true + -- end +} diff --git a/lua/plugins/configs/ui/alpha.lua b/lua/plugins/configs/ui/alpha.lua new file mode 100644 index 0000000..665bf2a --- /dev/null +++ b/lua/plugins/configs/ui/alpha.lua @@ -0,0 +1,182 @@ +-- Store alpha themes + +local banners = { + [1] = { + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣤⣤⣶⣶⣶⣶⣶⣦⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠸⣿⣿⣿⣿⠿⠿⠿⢿⣿⣿⣿⠿⠿⠿⣿⣿⣿⣿⣿⣿⣿⡿⠿⠿⢿⣿⣿⣿⡿⠿⠿⢿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⡄⠀⠀⠸⢿⣿⠟⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠘⢿⣿⡿⠁⠀⠀⣾⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⢀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀⠀⢀⣠⣾⣿⣿⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣷⣾⣿⣿⣿⣿⣿⣿⠟⢹⠛⢿⣿⣿⣿⣿⣿⣿⣶⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⣸⡀⠀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣠⣼⣿⣷⣤⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠉⠉⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠈⠉⠁⠈⠉⠁⠉⠉⠀⠉⠉⠈⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + }, + [2] = { + " ", + " ", + " ", + " ⣴⣶⣤⡤⠦⣤⣀⣤⠆ ⣈⣭⣿⣶⣿⣦⣼⣆ ", + " ⠉⠻⢿⣿⠿⣿⣿⣶⣦⠤⠄⡠⢾⣿⣿⡿⠋⠉⠉⠻⣿⣿⡛⣦ ", + " ⠈⢿⣿⣟⠦ ⣾⣿⣿⣷ ⠻⠿⢿⣿⣧⣄ ", + " ⣸⣿⣿⢧ ⢻⠻⣿⣿⣷⣄⣀⠄⠢⣀⡀⠈⠙⠿⠄ ", + " ⢠⣿⣿⣿⠈ ⣻⣿⣿⣿⣿⣿⣿⣿⣛⣳⣤⣀⣀ ", + " ⢠⣧⣶⣥⡤⢄ ⣸⣿⣿⠘ ⢀⣴⣿⣿⡿⠛⣿⣿⣧⠈⢿⠿⠟⠛⠻⠿⠄ ", + " ⣰⣿⣿⠛⠻⣿⣿⡦⢹⣿⣷ ⢊⣿⣿⡏ ⢸⣿⣿⡇ ⢀⣠⣄⣾⠄ ", + " ⣠⣿⠿⠛ ⢀⣿⣿⣷⠘⢿⣿⣦⡀ ⢸⢿⣿⣿⣄ ⣸⣿⣿⡇⣪⣿⡿⠿⣿⣷⡄ ", + " ⠙⠃ ⣼⣿⡟ ⠈⠻⣿⣿⣦⣌⡇⠻⣿⣿⣷⣿⣿⣿ ⣿⣿⡇ ⠛⠻⢷⣄ ", + " ⢻⣿⣿⣄ ⠈⠻⣿⣿⣿⣷⣿⣿⣿⣿⣿⡟ ⠫⢿⣿⡆ ", + " ⠻⣿⣿⣿⣿⣶⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⡟⢀⣀⣤⣾⡿⠃ ", + " ", + }, + [3] = { + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⢀⢄⠀⠀⡴⠁⠈⡆⠀⢀⡤⡀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠢⣄⠀⠀⡇⠀⡕⠀⢸⠀⢠⠃⠀⢮⠀⠹⠀⠀⣠⢾⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⣞⠀⢀⠇⠀⡇⠀⡸⠀⠈⣆⠀⡸⠀⢰⠀⠀⡇⣸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⠘⢶⣯⣊⣄⡨⠟⡡⠁⠐⢌⠫⢅⣢⣑⣵⠶⠁⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⠀⠀⠀⠀⠀⣼⣀⠀⢀⠒⠒⠂⠉⠀⠀⠀⠀⠁⠐⠒⠂⡀⠀⣸⣄⠀⠀⠀⠀⠀⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⢮⣵⣶⣦⡩⡲⣄⠀⠀⣿⣿⣽⠲⠭⣥⣖⣂⣀⣀⣀⣀⣐⣢⡭⠵⠖⣿⣿⢫⠀⠀⣠⣖⣯⣶⣶⣮⡷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⢸⡟⢉⣉⠙⣿⣿⣦⠀⣿⣿⣿⣿⣷⣲⠶⠤⠭⣭⡭⠭⠴⠶⣖⣾⣿⣿⡿⢸⢀⣼⣿⡿⠋⣉⠉⢳⠁⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠮⣳⣴⣫⠂⠘⣿⣿⣇⢷⢻⣿⣿⣿⣿⣿⣷⣶⣶⣶⣶⣿⣿⣿⣿⣿⢿⢃⡟⣼⣿⣿⠁⠸⣘⣢⣚⠜⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⠈⢧⢻ ⣿⣿⣟⠻⣿⣿⣿⣿⠛⣩⣿⣿ ⢟⡞⢀⣿⣿⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣒⣒⣦⣄⣿⣿⣿⢀⡬⣟⣯ ⣿⢷⣼⡟⢿⣿⡿⣿⣿ ⡻⣤⡀⣿⣿⣸⡠⢔⣒⡒⢤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⠀⠀⠀⠀⠀⠀⠀⢾⣟⣅⠉⢎⣽⣿⣿⡏⡟⣤⣮⣿⣿ ⡏⣿⠀⠀⣿⢡⣷ ⣿⣟⢎⣷⢻⣿⣿⣾⡟⠉⣽⡇⡇⠀⠀⠀⠀⠀⠀⠀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⡴⣫⣭⣭⣍⡲⢄⠀⠀⠀⠀⠈⠻⠋⣠⡮⣻⣿⣿⠃⠳⣏⣼⣿⣿⣿⣿⡇⣿⣴⣴⣿⣾⣿⣿⣿⡿⣄⣩⠏⢸⣿⣿⣿⣧⡀⠛⠞⠁⠀⠀⠀⢀⣤⣺⣭⣭⣭⡝⢦⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⢸⢹⡟⠁⠀⠉⢫⡳⣵⣄⠀⠀⢀⠴⢊⣿⣾⣿⣿⣿⠀⠀⠀⠻⣬⣽⣿⣿⣿⣿ ⣿⣿⣿⣿⣯⣵⠏⠀⠀⢸⣿⣿⣿⣿⣿⣗⢤⡀⠀⠀⣠⣿⢟⠟⠉⠀⠈⢻⢸⡆⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠘⢏⢧⣤⡀⠀⠀⣇⢻⣿⣆⢔⢕⣵⠟⣏⣿⣿⣿⠋⣵⠚⠄⣾⣿⣿⣿⡿⠟⣛⣛⣛⣛⠻⣿⣿⣿⣿⣧⢰⠓⣏⠻⣿⣿⣿⢹⠻⣿⣿⢦⣸⣿⡏⡾⠀⠀⢠⣤⠎⡼⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠈⠑⠂⠁⠀⠀⣿⠸⣿⢏⢂⣾⠇⠀⣿⣿⣿⡇⡆⠹⢷⣴⣿⡿⠟⠉⣐⡀⠄⣠⡄⡠⣁⡠⠙⠻⢿⣿⣴⡾⠃⢠⢹⣿⣿⢸⠀⢹⣿⣷⢹⣿⢃⡇⠀⠀⠈⠒⠋⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⡀⣿⢀⣿⣿⡀⠀⢫⣿⣿⣷⣙⠒⠀⠄⠐⠂⣼⠾⣵⠾⠟⣛⣛⠺⢷⣮⠷⣢⠐⠂⠀⠀⠒⣣⣾⣿⡿⡎⠀⢠⣿⣿⡄⣿⣸⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣟⣿⢸⣿⣿⣷⣄⡈⣾⣿⣿⣿⣿⣿⠻⡷⢺⠃⠠⠁⠈⠋⠀⠀⠉⠁⠙⡀⠘⡗⣾⠿⣿⣿⣿⣿⣿⡿⢀⣴⣿⣿⡿⢃⣯⣽⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣿⡆⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣵⡞⠀⠁⠐⢁⠎⠄⣠⠀⠀⡄⠀⢳⠈⠆⠈⠈⢳⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⣸⡷⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⣌⠛⢿⣿⣿⣿⣿⣿⣿⠿⠋⣠⣢⠂⠀⢂⠌⠀⠃⠀⠀⠘⠀⢢⡑⠀⠰⣵⡀⠻⢿⣿⣿⣿⣿⣿⣿⡿⠋⣰⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠳⣤⣭⢛⣻⠿⣿⣷⣶⢞⡟⡁⢀⢄⠎⠀⠀⠀⠀⠀⡀⠁⠀⠳⢠⠀⢈⢿⢳⣶⣾⣿⠿⣟⣛⣅⡴⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠙⠛⠻⠿⠿⡟⢜⠔⡠⢊⠔⠀⡆⠀⡆⠀⠀⢡⢰⢠⠀⢢⠱⣌⢂⠃⢿⠿⠿⠟⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢤⣊⡰⠵⢺⠉⠸⠀⢰⢃⠀⠀⠀⠀⠀⠸⢸⠀⠀⡇⡞⡑⠬⢆⣑⢤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠁⠀⠀⠀⠘⣾⡸⢀⡜⡾⡀⡇⠀⠀⡴⢠⢻⢦⠀⢃⡿⠀⠀⠀⠀⠈⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⡎⠀⠱⡡⠐⠀⠠⠃⢢⠋⠀⢧⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢤⡀⢀⠔⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠱⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + }, + [4] = { + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣤⣤⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣾⣿⣿⠿⠿⠿⠿⢿⣿⣿⣷⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⠟⠋⠀⠀⠀⠀⠀⠀⠀⠙⢿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⣶⣾⣿⣿⠀⣿⣿⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣿⣿⠀⣿⣿⣷⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣾⣿⡿⠟⠛⠉⠉⠀⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⠀⠉⠉⠛⠻⢿⣿⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⡿⠋⠀⠀⠀⠀⠀⠀⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⠀⠀⠀⠀⠀⠀⠙⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⠃⠀⠀⣠⣶⣾⣿⠀⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⠀⣿⣷⣦⣄⠀⠀⠸⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⠀⢀⣾⣿⡿⠛⠉⠀⣿⣿⡇⠀⠀⣀⣀⠀⠀⠀⠀⠀⣀⣀⠀⠀⢸⣿⣿⠀⠉⠛⢿⣿⣷⡀⠀⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣆⢸⣿⣿⠀⠀⠀⠀⣿⣿⡇⠀⢾⣿⣿⡇⠀⠀⠀⢾⣿⣿⡇⠀⢸⣿⣿⠀⠀⠀⠈⣿⣿⡇⣼⣿⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣄⠀⠀⠀⣿⣿⡇⠀⠈⠙⠋⠀⠀⠀⠀⠈⠙⠋⠀⠀⢸⣿⣿⠀⠀⠀⣰⣿⣿⣿⣿⡿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⢿⣿⣿⣿⣷⣶⣶⣿⣿⣿⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣿⣿⣿⣶⣶⣿⣿⣿⣿⡿⠛⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠛⠛⠛⠛⠛⠛⠛⠛⢻⣿⣿⠛⣿⣿⣿⢻⣿⣿⠛⠛⠛⠛⠛⠛⠛⠛⠛⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⣿⣿⣿⣿⣿⣿⠀⢸⣿⣿⠀⣿⣿⣿⢸⣿⣿⠀⠀⣿⣿⣿⣿⣿⣿⣿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣈⣉⣉⣉⣉⡉⢹⣿⣿⠀⢸⣿⣿⠀⣿⣿⣿⢸⣿⣿⠀⠀⣿⣿⡏⢉⣉⣉⣉⣉⣁⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⣿⣿⣿⡇⢸⣿⣿⠀⢸⣿⣿⠀⣿⣿⣿⢸⣿⣿⠀⠀⣿⣿⡇⢸⣿⣿⣿⣿⣿⣿⣿⣿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⡇⢸⣿⣿⠀⢸⣿⣿⠀⣿⣿⣿⢸⣿⣿⠀⠀⣿⣿⡇⢸⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⡇⢸⣿⣿⠀⢸⣿⣿⠀⣿⣿⣿⢸⣿⣿⠀⠀⣿⣿⡇⢸⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⡇⢸⣿⣿⣄⣼⣿⣿⠀⣿⣿⣿⠸⣿⣿⣆⣠⣿⣿⡇⢸⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣿⣿⣄⠻⢿⣿⣿⠿⢋⣴⣿⣿⣿⣦⡙⠿⣿⣿⡿⠛⣠⣿⣿⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⢿⣿⣷⣶⣤⣴⣶⣿⣿⠿⠙⢿⣿⣿⣶⣦⣴⣶⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⠿⠿⠛⠋⠁⠀⠀⠀⠈⠙⠛⠿⠿⠛⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + }, + [5] = { + [[ ██████ ]], + [[ ████▒▒▒▒▒▒████ ]], + [[ ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒██ ]], + [[ ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██ ]], + [[ ██▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ]], + [[ ██▒▒▒▒▒▒ ▒▒▓▓▒▒▒▒▒▒ ▓▓▓▓ ]], + [[ ██▒▒▒▒▒▒ ▒▒▓▓▒▒▒▒▒▒ ▒▒▓▓ ]], + [[ ██▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ██ ]], + [[ ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██ ]], + [[ ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██ ]], + [[ ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██ ]], + [[ ██▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██ ]], + [[ ██▒▒██▒▒▒▒▒▒██▒▒▒▒▒▒▒▒██▒▒▒▒██ ]], + [[ ████ ██▒▒██ ██▒▒▒▒██ ██▒▒██ ]], + [[ ██ ██ ████ ████ ]], + }, + [6] = { + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣤⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣤⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣤⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⣠⣶⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀⠀⠀⣠⣶⣿⣿⣿⣿⣿⣿⣿⣿⣶⣄⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⣿⣿⣿⡆⠀⠀⠀⢸⣿⣿⠿⠿⢿⣿⣿⣿⣿⡿⠿⠿⣿⣿⡇⠀⠀⠀⣾⣿⣿⡿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀", + "⠀⠀⠀⠀⢿⣿⠿⠿⠿⠿⣿⣿⣿⡏⠀⠀⠀⢹⣿⡇⠀⠀⠀⢸⣿⢱⣶⣴⣶⢹⣿⣿⡏⣶⣦⣶⡎⣿⡇⠀⠀⠀⢿⣿⠁⠀⠀⠈⣿⣿⣿⡿⠟⣋⣽⣿⣿⠇⠀⠀⠀⠀", + "⠀⠀⠀⠀⠘⣿⣧⣄⣀⣴⣿⣿⣿⣷⣄⣀⣠⣾⣟⠀⠀⠀⠀⠈⣿⣦⣙⣛⣡⣾⡿⢿⣷⣌⣛⣋⣴⣿⠁⠀⠀⠀⠘⣿⣦⣄⣀⣴⣿⣿⣿⣿⣶⣶⣤⣿⡟⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣏⣼⣌⣿⣿⣿⣿⣿⡟⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣰⣆⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠈⢿⣿⣿⣿⣿⣏⣼⣌⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠉⠉⢿⣿⣿⣿⣿⣿⣿⡏⠉⠁⠀⠀⠀⠀⠀⠀⠀⠉⠉⢹⣿⣿⣿⣿⣿⣿⡏⠉⠉⠀⠀⠀⠀⠀⠀⠀⠉⠉⣿⣿⣿⣿⣿⣿⣿⡏⠉⠁⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠁⠁⠁⠉⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠁⠉⠉⠈⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠁⠁⠁⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀", + }, + [7] = { + "⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⣀⣤⣴⣶⣾⣿⣿⣿⣶⣶⣦⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣶⣶⣿⣿⣿⣿⣶⣶⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣶⣶⣿⣿⣿⣷⣶⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⢿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡿⠿⠛⠻⠿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠟⠛⠿⢿⣿⣿⣿⡇⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣿⣿⣿⡟⠁⠀⠀⠀⠈⢻⣿⣿⣿⠀⠀⠀⠀⠀⠀⢸⣿⣿⠏⣠⣤⡄⣠⣤⡌⢿⣿⣿⣿⣿⡿⢁⣤⣄⢀⣤⣄⠹⣿⣿⡇⠀⠀⠀⠀⠀⢺⣿⣿⡿⠋⠀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠛⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⠛⠛⠛⠛⠛⠛⢛⣿⣮⣿⣿⣿⠀⠀⠀⠀⠀⠀⢈⣿⣿⡟⠀⠀⠀⠀⠀⠀⠸⣿⣿⠀⢿⣿⣿⣿⣿⡟⢸⣿⣿⣿⣿⡇⠸⣿⣿⣿⣿⡿⠀⣿⣿⠇⠀⠀⠀⠀⠀⢸⣿⣿⡇⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⠋⠁⠠⢴⣾⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠸⣿⣿⣧⡀⠀⠀⠀⢀⣼⣿⣿⣿⣿⣿⣧⡀⠀⠀⠀⢀⣼⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⢻⣿⣆⠀⠙⠿⠟⠋⢀⣾⣿⣿⣿⣿⣷⡀⠈⠻⡿⠋⠁⣰⣿⡟⠀⠀⠀⠀⠀⠀⠀⢿⣿⣷⣄⠀⠀⠀⢀⣰⣿⣿⣿⣿⣿⣿⣷⣶⣦⣤⣄⣼⣿⣿⡏⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣶⣿⣿⣿⣿⠟⠉⠻⣿⣿⣿⣿⣶⣿⣿⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣶⣶⣶⣾⣿⣿⡿⠋⠙⢿⣿⣿⣷⣶⣶⣶⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣷⣾⣿⣿⣿⡟⢻⠙⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣠⣷⡀⢹⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⢁⣴⣧⡀⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⢀⣼⣆⢘⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⠋⠛⠋⠛⠙⠛⠙⠛⠙⠛⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠛⠙⠛⠙⠛⠛⠋⠛⠋⠛⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠛⠙⠛⠛⠋⠛⠋⠛⠋⠛⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + }, + [8] = { + "⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⣀⣤⣴⣶⣾⣿⣿⣿⣶⣶⣦⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⢿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀ ", + "⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣿⣿⣿⡟⠁⠀⠀⠀⠈⢻⣿⣿⣿⠀⠀⠀⠀⠀⠀ ", + "⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⠛⠛⠛⠛⠛⠛⢛⣿⣮⣿⣿⣿⠀⠀⠀⠀⠀⠀⢈⣿⣿⡟⠀⠀⠀⠀⠀⠀ ", + "⠀⠀⠀⠀⠀⠀⠀⠸⣿⣿⣧⡀⠀⠀⠀⢀⣼⣿⣿⣿⣿⣿⣧⡀⠀⠀⠀⢀⣼⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣶⣿⣿⣿⣿⠟⠉⠻⣿⣿⣿⣿⣶⣿⣿⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣠⣷⡀⢹⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠛⠋⠛⠋⠛⠙⠛⠙⠛⠙⠛⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + }, + [9] = { + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣶⣶⣿⣿⣿⣿⣶⣶⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⠀ ", + "⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⡿⠿⠛⠻⠿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠟⠛⠿⢿⣿⣿⣿⡇⠀⠀⠀⠀⠀ ", + "⠀⠀⠀⠀⠀⠀⢸⣿⣿⠏⣠⣤⡄⣠⣤⡌⢿⣿⣿⣿⣿⡿⢁⣤⣄⢀⣤⣄⠹⣿⣿⡇⠀⠀⠀⠀⠀ ", + "⠀⠀⠀⠀⠀⠀⠸⣿⣿⠀⢿⣿⣿⣿⣿⡟⢸⣿⣿⣿⣿⡇⠸⣿⣿⣿⣿⡿⠀⣿⣿⠇⠀⠀⠀⠀⠀ ", + "⠀⠀⠀⠀⠀⠀⠀⢻⣿⣆⠀⠙⠿⠟⠋⢀⣾⣿⣿⣿⣿⣷⡀⠈⠻⡿⠋⠁⣰⣿⡟⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣶⣶⣶⣾⣿⣿⡿⠋⠙⢿⣿⣿⣷⣶⣶⣶⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⢁⣴⣧⡀⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠙⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠋⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠛⠙⠛⠙⠛⠛⠋⠛⠋⠛⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀", + }, + [10] = { + [[ __ ]], + [[ ___ ___ ___ __ __ /\_\ ___ ___ ]], + [[ / _ `\ / __`\ / __`\/\ \/\ \\/\ \ / __` __`\ ]], + [[/\ \/\ \/\ __//\ \_\ \ \ \_/ |\ \ \/\ \/\ \/\ \ ]], + [[\ \_\ \_\ \____\ \____/\ \___/ \ \_\ \_\ \_\ \_\]], + [[ \/_/\/_/\/____/\/___/ \/__/ \/_/\/_/\/_/\/_/]], + }, +} + +return banners diff --git a/lua/plugins/configs/ui/heirline.lua b/lua/plugins/configs/ui/heirline.lua new file mode 100644 index 0000000..018a29a --- /dev/null +++ b/lua/plugins/configs/ui/heirline.lua @@ -0,0 +1,215 @@ +local M = {} + +local status = require "astroui.status" +local get_icon = require("astroui").get_icon +local is_available = require("astrocore").is_available +local path_func = status.provider.filename { modify = ":.:h", fallback = "" } + +-- custom statusline +M.statusline = { + hl = { fg = "fg", bg = "bg" }, + -- Show mode text + status.component.mode { + -- enable mode text with padding as well as an icon before it + mode_text = { + icon = { kind = "Mode", padding = { left = 0, right = 1 } }, + }, + -- surround the component with a separators + surround = { + separator = "left", + }, + }, + status.component.file_info { + file_icon = { padding = { left = 0, right = 1 } }, + filename = { fallback = "Empty" }, + filetype = false, + file_modified = false, + surround = { + separator = "none", + color = "bg", + }, + }, + status.component.git_branch { + padding = { left = 2, right = 1 }, + surround = { + separator = "none", + color = "bg", + }, + }, + -- Add a icon to represent diagnostic and git git diff + status.component.builder { + provider = function() return get_icon "Diagnostic" .. "/" .. get_icon "Github" end, + hl = { fg = "black" }, + surround = { + separator = { " ", "" }, + color = "#81ab9e", + }, + }, + status.component.diagnostics { + surround = { + separator = "none", + color = "bg", + }, + }, + status.component.git_diff { + padding = { left = 1 }, + surround = { + separator = "none", + color = "bg", + }, + }, + status.component.fill(), + -- Show search counts and results + { + condition = function(self) + local query = vim.fn.getreg "/" + if query == "" then return false end + query = query:gsub([[^\V]], "") + query = query:gsub([[\<]], ""):gsub([[\>]], "") + + local search_count = vim.fn.searchcount { recompute = 1, maxcount = -1 } + if search_count.total == 0 then return false end + + self.query = query + self.count = search_count + return true + end, + status.component.builder { + provider = function(self) + return status.utils.stylize(" " .. self.query .. " " .. self.count.current .. "/" .. self.count.total, { + icon = { kind = "Search" }, + }) + end, + hl = { fg = "black" }, + surround = { + separator = "left", + color = "search_bg", + }, + }, + }, + -- Show file encoding + status.component.builder { + provider = function() + return status.utils.stylize(string.upper(vim.bo.fileencoding), { + icon = { kind = "FileEncoding", padding = { right = 1 } }, + }) + end, + hl = { fg = "text_fg" }, + padding = { right = 1 }, + }, + -- Show tab width + status.component.builder { + provider = function() + return status.utils.stylize(tostring(vim.bo.tabstop), { + icon = { kind = "TabWidth", padding = { right = 1 } }, + }) + end, + hl = { fg = "text_fg" }, + padding = { right = 1 }, + }, + -- Show Grapple tag + status.component.builder { + condition = function() + if status.condition.is_file and is_available "grapple.nvim" then return true end + return false + end, + provider = function() + local tag = tostring(require("grapple").name_or_index()) + if tag == "nil" then tag = "NO" end + return status.utils.stylize(tag, { + icon = { kind = "Grapple", padding = { right = 1 } }, + }) + end, + + hl = { fg = "text_fg" }, + padding = { right = 1 }, + }, + -- Show Codeium status + status.component.builder { + condition = function() + if status.condition.lsp_attached and is_available "neocodeium" then return true end + return false + end, + provider = function() + local codeium_status = "OFF" + if require("neocodeium.options").options.enabled == true then codeium_status = "ON" end + return status.utils.stylize(codeium_status, { + icon = { kind = "Codeium", padding = { right = 1 } }, + }) + end, + hl = { fg = "text_fg" }, + padding = { right = 1 }, + }, + status.component.lsp { + lsp_client_names = { + icon = { kind = "ActiveLSP", padding = { right = 1 } }, + }, + surround = { separator = "left" }, + }, + { + status.component.builder { + { provider = get_icon "ScrollText" }, + padding = { right = 1 }, + hl = { fg = "black" }, + surround = { + separator = { " ", "" }, + color = { main = "nav_icon_bg", left = "bg" }, + }, + }, + status.component.nav { + percentage = { padding = { left = 0 } }, + ruler = false, + scrollbar = false, + surround = { separator = { "", "" } }, + }, + }, +} + +-- custom winbar +M.winbar = { + -- store the current buffer number + init = function(self) self.bufnr = vim.api.nvim_get_current_buf() end, + fallthrough = false, -- pick the correct winbar based on condition + -- inactive winbar + { + condition = function() return not status.condition.is_active() end, + -- show the path to the file relative to the working directory + status.component.separated_path { path_func = path_func }, + -- add the file name and icon + status.component.file_info { + file_icon = { hl = status.hl.file_icon "winbar", padding = { left = 0 } }, + filename = {}, + filetype = false, + file_modified = false, + file_read_only = false, + hl = status.hl.get_attributes("winbarnc", true), + surround = false, + update = "BufEnter", + }, + }, + -- active winbar + { + -- show the path to the file relative to the working directory + status.component.separated_path { path_func = path_func }, + -- add the file name and icon + status.component.file_info { -- add file_info to breadcrumbs + file_icon = { hl = status.hl.filetype_color, padding = { left = 0 } }, + filename = {}, + filetype = false, + file_modified = false, + file_read_only = false, + hl = status.hl.get_attributes("winbar", true), + surround = false, + update = "BufEnter", + }, + -- show the breadcrumbs + status.component.breadcrumbs { + icon = { hl = true }, + hl = status.hl.get_attributes("winbar", true), + prefix = true, + padding = { left = 0 }, + }, + }, +} + +return M diff --git a/lua/plugins/configs/ui/highlights.lua b/lua/plugins/configs/ui/highlights.lua new file mode 100644 index 0000000..3609ec2 --- /dev/null +++ b/lua/plugins/configs/ui/highlights.lua @@ -0,0 +1,41 @@ +return { + init = function() -- this table overrides highlights in all themes + local get_hlgroup = require("astroui").get_hlgroup + local ui = require "astroui" + local utils = require "astrocore" + + local hl = { + -- remove background of virtual texts + DiagnosticVirtualTextError = { fg = get_hlgroup("DiagnosticError").fg, bg = "none" }, + DiagnosticVirtualTextHint = { fg = get_hlgroup("DiagnosticHint").fg, bg = "none" }, + DiagnosticVirtualTextInfo = { fg = get_hlgroup("DiagnosticInfo").fg, bg = "none" }, + DiagnosticVirtualTextWarn = { fg = get_hlgroup("DiagnosticWarn").fg, bg = "none" }, + + -- remove background of inlay hints + LspInlayHint = { fg = get_hlgroup("LspInlayHint").fg, bg = "none" }, + } + + if utils.is_available "kanagawa.nvim" and ui.config.colorscheme == "kanagawa" then + local colors = require("kanagawa.colors").setup() + local theme = colors.theme + hl = utils.extend_tbl(hl, { + Pmenu = { fg = theme.ui.shade0, bg = theme.ui.bg_p1 }, -- add `blend = vim.o.pumblend` to enable transparency + PmenuSel = { fg = "NONE", bg = theme.ui.bg_p2 }, + PmenuSbar = { bg = theme.ui.bg_m1 }, + PmenuThumb = { bg = theme.ui.bg_p2 }, + TelescopeTitle = { fg = theme.ui.special, bold = true }, + TelescopePromptNormal = { bg = theme.ui.bg_p1 }, + TelescopePromptBorder = { fg = theme.ui.bg_p1, bg = theme.ui.bg_p1 }, + TelescopeResultsNormal = { fg = theme.ui.fg_dim, bg = theme.ui.bg_m1 }, + TelescopeResultsBorder = { fg = theme.ui.bg_m1, bg = theme.ui.bg_m1 }, + TelescopePreviewNormal = { bg = theme.ui.bg_dim }, + TelescopePromptNormalopePreviewBorder = { bg = theme.ui.bg_dim, fg = theme.ui.bg_dim }, + }) + end + + return hl + end, + astrotheme = { -- a table of overrides/changes when applying the astrotheme theme + -- Normal = { bg = "#000000" }, + }, +} diff --git a/lua/plugins/configs/ui/icons.lua b/lua/plugins/configs/ui/icons.lua new file mode 100644 index 0000000..c54e4b7 --- /dev/null +++ b/lua/plugins/configs/ui/icons.lua @@ -0,0 +1,59 @@ +return { + -- LSP + ActiveLSP = "", + ActiveTS = "", + LSPLoaded = "", + LSPLoading1 = "⠋", + LSPLoading2 = "⠙", + LSPLoading3 = "⠹", + LSPLoading4 = "⠸", + LSPLoading5 = "⠼", + LSPLoading6 = "⠴", + LSPLoading7 = "⠦", + LSPLoading8 = "⠧", + LSPLoading9 = "⠇", + LSPLoading10 = "⠏", + -- Git + Github = "", + GitAdd = "", + GitBranch = "", + GitChange = "", + GitConflict = "", + GitDelete = "", + GitIgnored = "", + GitRenamed = "", + GitStaged = "✓", + GitUnstaged = "✗", + GitUntracked = "★", + Neogit = "", + -- Files + Ellipsis = "", + DefaultFile = "", + FileModified = "", + FileReadOnly = "", + FoldClosed = "", + FoldOpened = "", + FolderClosed = "", + FolderEmpty = "", + FolderOpen = "", + -- DAP + DapBreakpoint = "", + DapBreakpointCondition = "", + DapBreakpointRejected = "", + DapLogPoint = "", + DapStopped = "", + -- Diagnostics + Diagnostic = "󰒡", + DiagnosticError = "", + DiagnosticHint = "", + DiagnosticInfo = "󰋼", + DiagnosticWarn = "", + -- Misc + Mode = "󰊠   ", + FileEncoding = "", + ScrollText = "", + TabWidth = "", + Search = "", + Grapple = "󰓹", + Codeium = "󱚝", +} diff --git a/lua/plugins/configs/ui/lspkind.lua b/lua/plugins/configs/ui/lspkind.lua new file mode 100644 index 0000000..01f3d74 --- /dev/null +++ b/lua/plugins/configs/ui/lspkind.lua @@ -0,0 +1,38 @@ +-- LSP kind symbol map +return { + Array = "", + Boolean = "", + Class = "", + Color = "", + Constant = "", + Constructor = "", + Enum = "", + EnumMember = "", + Event = "", + Field = "", + File = "", + Folder = "", + Function = "", + Interface = "", + Key = "", + Keyword = "󰌋", + Method = "", + Module = "", + Namespace = "", + Null = "", + Number = "", + Object = "", + Operator = "", + Package = " ", + Property = "", + Reference = "", + Snippet = "󰗀", + String = "", + Struct = "", + Text = "󰉿", + TypeParameter = "", + Unit = "ﱦ", + Value = "", + Variable = "", +} + diff --git a/lua/plugins/configs/ui/status.lua b/lua/plugins/configs/ui/status.lua new file mode 100644 index 0000000..e5a7385 --- /dev/null +++ b/lua/plugins/configs/ui/status.lua @@ -0,0 +1,38 @@ +return { + separators = { + left = { " ", " " }, -- separator for the left side of the statusline + right = { " ", "" }, -- separator for the right side of the statusline + -- tab = { "", "" }, + }, + colors = function(hl) + local get_hlgroup = require("astroui").get_hlgroup + -- use helper function to get highlight group properties + hl.text_fg = "#60b2a7" + hl.insert = "#a9b665" + hl.visual = "#e8b142" + hl.replace = "#ea6962" + hl.terminal = "#a89984" + hl.file_info_fg = hl.text_fg + hl.file_info_bg = "#bac2de" + hl.git_branch_fg = "#bd81b6" + hl.git_branch_bg = "#f5c2e7" + hl.lsp_fg = "black" + hl.lsp_bg = "#7fb4ca" + hl.search_bg = "#c8c093" + hl.grapple_bg = "#eba0ac" + hl.file_encoding_bg = "#f7768e" + hl.tab_width_bg = "#ff966c" + hl.nav_fg = "black" + hl.nav_bg = get_hlgroup("String").fg + hl.nav_icon_bg = hl.nav_bg + return hl + end, + attributes = { + mode = { bold = true }, + file_info = { bold = false }, + git_branch = { bold = false }, + diagnostics = { bold = false }, + git_diff = { bold = false }, + lsp = { bold = false }, + }, +} diff --git a/lua/plugins/configs/ui/transparent.lua b/lua/plugins/configs/ui/transparent.lua new file mode 100644 index 0000000..ccf79ab --- /dev/null +++ b/lua/plugins/configs/ui/transparent.lua @@ -0,0 +1,39 @@ +return function(opts) + return require("astrocore").extend_tbl(opts, { + -- table: default groups + groups = { + "Normal", + "NormalNC", + "Comment", + "Constant", + "Special", + "Identifier", + "Statement", + "PreProc", + "Type", + "Underlined", + "Todo", + "String", + "Function", + "Conditional", + "Repeat", + "Operator", + "Structure", + "LineNr", + "NonText", + "SignColumn", + "CursorLineNr", + "EndOfBuffer", + }, + -- table: additional groups that should be cleared + extra_groups = { + "NormalFloat", + "NvimTreeNormal", + "NeoTreeNormal", + "NeoTreeFloatBorder", + "NeoTreeNormalNC", + }, + -- table: groups you don't want to clear + exclude_groups = {}, + }) +end diff --git a/lua/plugins/cyber-dream.lua b/lua/plugins/cyber-dream.lua new file mode 100644 index 0000000..3d4ecd7 --- /dev/null +++ b/lua/plugins/cyber-dream.lua @@ -0,0 +1,10 @@ +return { + "scottmckendry/cyberdream.nvim", + opts = { + transparent = true, + italic_comments = true, + hide_fillchars = true, + borderless_telescope = true, + terminal_colors = true, + }, +} diff --git a/lua/plugins/disabled.lua b/lua/plugins/disabled.lua new file mode 100644 index 0000000..4220625 --- /dev/null +++ b/lua/plugins/disabled.lua @@ -0,0 +1,14 @@ +-- Plugins to disable +return { + { "nvim-neo-tree/neo-tree.nvim", enabled = true }, + { "lukas-reineke/indent-blankline.nvim", enabled = false }, + { "s1n7ax/nvim-window-picker", enabled = false }, + { "akinsho/toggleterm.nvim", enabled = false }, + { "NvChad/nvim-colorizer.lua", enabled = false }, + { "catppuccin/nvim", name = "catppuccin", enabled = false}, + + { "rebelot/kanagawa.nvim", enabled = false }, + { "folke/tokyonight.nvim", enabled = false }, + { "f4z3r/gruvbox-material.nvim", name = "gruvbox-material", enabled = false }, + { "b0o/SchemaStore.nvim", enabled = false }, +} diff --git a/lua/plugins/editor.lua b/lua/plugins/editor.lua new file mode 100644 index 0000000..51fc842 --- /dev/null +++ b/lua/plugins/editor.lua @@ -0,0 +1,251 @@ +-- Plugins that enhance editor experience +return { + { + "numToStr/Comment.nvim", + opts = { + -- Ignore empty line + ignore = "^$", + }, + keys = { + { + "", + function() require("Comment.api").toggle.linewise.count(vim.v.count > 0 and vim.v.count or 1) end, + mode = { "n", "i" }, + desc = "Comment line", + }, + { + "", + "lua require('Comment.api').toggle.linewise(vim.fn.visualmode())", + mode = { "v" }, + desc = "Comment block", + }, + }, + }, + -- Built-in terminal support + { + "akinsho/toggleterm.nvim", + opts = function(_, opts) + -- Use powershell for toggleterm on windows + if vim.fn.has "win32" then opts.shell = "pwsh.exe" end + end, + }, + -- File tagging and navigation + { + "cbochs/grapple.nvim", + dependencies = { + "nvim-lua/plenary.nvim", + { + "AstroNvim/astrocore", + opts = function(_, opts) + opts.mappings.n[""] = { desc = require("astroui").get_icon("Grapple", 1, true) .. "Grapple" } + end, + }, + }, + opts = { + scope = "git_branch", + }, + cmd = { "Grapple" }, + keys = { + { "a", "Grapple tag", desc = "Add tag to file" }, + { "d", "Grapple untag", desc = "Delete tag from file" }, + { "e", "Grapple toggle_tags", desc = "Select from tags" }, + { "s", "Grapple toggle_scopes", desc = "Select a project scope" }, + { "x", "Grapple reset", desc = "Clear tags" }, + { "", "Grapple cycle forward", desc = "Select next tag" }, + { "", "Grapple cycle backward", desc = "Select previous tag" }, + }, + }, + -- Better escape support + -- { + -- "max397574/better-escape.nvim", + -- opts = { + -- mapping = { "jj", "kk", "jk" }, + -- }, + -- }, + -- Better indent blankline + { + "shellRaining/hlchunk.nvim", + event = { "BufReadPre", "BufNewFile" }, + config = function(_, opts) + require("hlchunk").setup(require("astrocore").extend_tbl(opts, { + chunk = { + enable = true, + notify = false, + chars = { + horizontal_line = "━", + vertical_line = "┃", + left_top = "┏", + left_bottom = "┗", + right_arrow = "➤", + }, + style = "#cba6f7", + delay = 100, + }, + indent = { + enable = true, + chars = { "┃" }, + }, + blank = { + enable = false, + }, + line_num = { + enable = true, + }, + })) + end, + }, + -- AI code completion + -- { + -- "monkoose/neocodeium", + -- event = "LspAttach", + -- config = function() + -- local neocodeium = require "neocodeium" + -- neocodeium.setup() + -- vim.keymap.set("n", ";", function() require("neocodeium.commands").toggle() end) + -- vim.keymap.set("i", "", function() require("neocodeium").accept() end) + -- vim.keymap.set("i", "", function() require("neocodeium").accept_word() end) + -- vim.keymap.set("i", "", function() require("neocodeium").accept_line() end) + -- vim.keymap.set("i", "", function() require("neocodeium").cycle_or_complete() end) + -- vim.keymap.set("i", "", function() require("neocodeium").cycle_or_complete(-1) end) + -- vim.keymap.set("i", "", function() require("neocodeium").clear() end) + -- end, + -- }, + -- Multi-cursors support + { + "brenton-leighton/multiple-cursors.nvim", + version = "*", + opts = {}, + keys = { + { "", "MultipleCursorsAddDown", mode = { "n", "i", "x" } }, + { "", "MultipleCursorsAddUp", mode = { "n", "i", "x" } }, + { "", "MultipleCursorsMouseAddDelete", mode = { "n", "i" } }, + { "a", "MultipleCursorsAddMatches", mode = { "n", "x" } }, + { "", "MultipleCursorsAddJumpNextMatch", mode = { "n", "x" } }, + }, + }, + -- Better code folding + { + "kevinhwang91/nvim-ufo", + opts = { + -- Add virtual text to show how many lines are folded + fold_virt_text_handler = function(virtText, lnum, endLnum, width, truncate) + local newVirtText = {} + local suffix = (" 󰁂 %d "):format(endLnum - lnum) + local sufWidth = vim.fn.strdisplaywidth(suffix) + local targetWidth = width - sufWidth + local curWidth = 0 + for _, chunk in ipairs(virtText) do + local chunkText = chunk[1] + local chunkWidth = vim.fn.strdisplaywidth(chunkText) + if targetWidth > curWidth + chunkWidth then + table.insert(newVirtText, chunk) + else + chunkText = truncate(chunkText, targetWidth - curWidth) + local hlGroup = chunk[2] + table.insert(newVirtText, { chunkText, hlGroup }) + chunkWidth = vim.fn.strdisplaywidth(chunkText) + -- str width returned from truncate() may less than 2nd argument, need padding + if curWidth + chunkWidth < targetWidth then + suffix = suffix .. (" "):rep(targetWidth - curWidth - chunkWidth) + end + break + end + curWidth = curWidth + chunkWidth + end + table.insert(newVirtText, { suffix, "MoreMsg" }) + return newVirtText + end, + }, + }, + -- Better split navigation and resize + { + "mrjones2014/smart-splits.nvim", + event = "VeryLazy", -- load on very lazy for mux detection + opts = function(_, opts) + opts.ignored_filetypes = { "nofile", "quickfix", "qf", "prompt" } + opts.ignored_buftypes = { "nofile" } + end, + keys = { + { + "", + function() require("smart-splits").move_cursor_left() end, + mode = { "n" }, + desc = "Move to left split", + }, + { + "", + function() require("smart-splits").move_cursor_right() end, + mode = { "n", "t" }, + desc = "Move to right split", + }, + { + "", + function() require("smart-splits").move_cursor_up() end, + mode = { "n" }, + desc = "Move to above split", + }, + { + "", + function() require("smart-splits").move_cursor_down() end, + mode = { "n" }, + desc = "Move to below split", + }, + { + "", + function() require("smart-splits").resize_left() end, + mode = { "n" }, + desc = "Resize split left", + }, + { + "", + function() require("smart-splits").resize_right() end, + mode = { "n" }, + desc = "Resize split right", + }, + { + "", + function() require("smart-splits").resize_up() end, + mode = { "n" }, + desc = "Resize split up", + }, + { + "", + function() require("smart-splits").resize_down() end, + mode = { "n" }, + desc = "Resize split down", + }, + }, + }, + -- Find and replace + { + "MagicDuck/grug-far.nvim", + cmd = "GrugFar", + config = function() + require("grug-far").setup { + windowCreationCommand = "tabnew", + } + end, + keys = { + { + "R", + function() require("grug-far").grug_far { prefills = { search = vim.fn.expand "" } } end, + mode = { "n" }, + desc = "Open GrugFar", + }, + }, + }, + -- Markdown preview support + { + "OXY2DEV/markview.nvim", + dependencies = { + { + "nvim-treesitter/nvim-treesitter", + opts = function(_, opts) + opts.ensure_installed = + require("astrocore").list_insert_unique(opts.ensure_installed, { "markdown", "markdown_inline" }) + end, + }, + }, + ft = { "markdown" }, + }, +} diff --git a/lua/plugins/lsp-features.lua b/lua/plugins/lsp-features.lua new file mode 100644 index 0000000..120251b --- /dev/null +++ b/lua/plugins/lsp-features.lua @@ -0,0 +1,36 @@ +-- Plugins to add additional functionality for LSP +return { + -- Signature help + { + "ray-x/lsp_signature.nvim", + event = "User AstroFile", + config = function() + require("lsp_signature").setup { bind = true, handler_opts = { border = "rounded" }, hint_enable = false } + end, + }, + -- Additional features for Clangd + { + "p00f/clangd_extensions.nvim", + lazy = true, + ft = { "c", "cpp" }, + dependencies = { + "AstroNvim/astrocore", + opts = { + autocmds = { + clangd_extensions = { + { + event = "LspAttach", + desc = "Load clangd_extensions with clangd", + callback = function(args) + if assert(vim.lsp.get_client_by_id(args.data.client_id)).name == "clangd" then + require "clangd_extensions" + vim.api.nvim_del_augroup_by_name "clangd_extensions" + end + end, + }, + }, + }, + }, + }, + }, +} diff --git a/lua/plugins/mason.lua b/lua/plugins/mason.lua new file mode 100644 index 0000000..3ca38ec --- /dev/null +++ b/lua/plugins/mason.lua @@ -0,0 +1,46 @@ +-- Customize Mason plugins + +---@type LazySpec +return { + -- use mason-lspconfig to configure LSP installations + { + "williamboman/mason-lspconfig.nvim", + -- overrides `require("mason-lspconfig").setup(...)` + opts = function(_, opts) + -- add more things to the ensure_installed table protecting against community packs modifying it + opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, { + "lua_ls", + "clangd", + "basedpyright", + "ruff", + }) + end, + }, + -- use mason-null-ls to configure Formatters/Linter installation for null-ls sources + { + "jay-babu/mason-null-ls.nvim", + -- overrides `require("mason-null-ls").setup(...)` + opts = function(_, opts) + -- add more things to the ensure_installed table protecting against community packs modifying it + opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, { + "stylua", + "clang-format", + "black", + "prettier", + }) + end, + }, + { + "jay-babu/mason-nvim-dap.nvim", + -- add this to lazy load dap-related plugins + init = function() end, + -- overrides `require("mason-nvim-dap").setup(...)` + opts = function(_, opts) + -- add more things to the ensure_installed table protecting against community packs modifying it + opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, { + "codelldb", + "python", + }) + end, + }, +} diff --git a/lua/plugins/motion.lua b/lua/plugins/motion.lua new file mode 100644 index 0000000..54770c5 --- /dev/null +++ b/lua/plugins/motion.lua @@ -0,0 +1,145 @@ +-- Plugins related to motion +return { + -- Move lines up/down/left/right + { + "echasnovski/mini.move", + opts = {}, + keys = { + { "", mode = { "n", "x" }, desc = "Move line/block left" }, + { "", mode = { "n", "x" }, desc = "Move line/block right" }, + { "", mode = { "n", "x" }, desc = "Move line/block down" }, + { "", mode = { "n", "x" }, desc = "Move line/block up" }, + }, + }, + -- Faster change/delete/replace delimiter pairs + { + "echasnovski/mini.surround", + opts = { n_lines = 200 }, + keys = { + { "sa", mode = { "n", "x" }, desc = "Add surrounding" }, + { "sd", mode = { "n", "x" }, desc = "Delete surrounding" }, + { "sr", mode = { "n", "x" }, desc = "Replace surrounding" }, + { "sf", mode = { "n", "x" }, desc = "Find right surrounding" }, + { "sF", mode = { "n", "x" }, desc = "Find left surrounding" }, + { "sh", mode = { "n", "x" }, desc = "Highlight surrounding" }, + { "sn", mode = { "n", "x" }, desc = "Update `MiniSurround.config.n_lines`" }, + }, + }, + -- Brackets splitjoin + { + "Wansmer/treesj", + cmd = { "TSJToggle", "TSJSplit", "TSJJoin" }, + opts = { + use_default_keymaps = false, + max_join_length = 150, + }, + keys = { + { "gs", "TSJToggle", mode = { "n" }, desc = "Toggle splitjoin" }, + }, + }, + { + "echasnovski/mini.ai", + event = "User AstroFile", + opts = function() + -- Register to which-key + local i = { + [" "] = "Whitespace", + ["?"] = "User Prompt", + _ = "Underscore", + a = "Argument", + b = "Paired ), ], }", + c = "Class", + d = "Digit(s)", + e = "Word in CamelCase & snake_case", + f = "Function", + g = "Entire file", + o = "Block, conditional, loop", + q = "Quote `, \", '", + t = "Tag", + u = "Use/call function & method", + U = "Use/call without dot in name", + } + local a = vim.deepcopy(i) + for k, v in pairs(a) do + a[k] = v:gsub(" including.*", "") + end + + local ic = vim.deepcopy(i) + local ac = vim.deepcopy(a) + for key, name in pairs { n = "Next", l = "Last" } do + i[key] = vim.tbl_extend("force", { name = "Inside " .. name .. " textobject" }, ic) + a[key] = vim.tbl_extend("force", { name = "Around " .. name .. " textobject" }, ac) + end + require("which-key").register { + mode = { "o", "x" }, + i = i, + a = a, + } + + -- define custom textobjects + local ai = require "mini.ai" + return { + n_lines = 500, + custom_textobjects = { + o = ai.gen_spec.treesitter { -- code block + a = { "@block.outer", "@conditional.outer", "@loop.outer" }, + i = { "@block.inner", "@conditional.inner", "@loop.inner" }, + }, + f = ai.gen_spec.treesitter { a = "@function.outer", i = "@function.inner" }, -- function + c = ai.gen_spec.treesitter { a = "@class.outer", i = "@class.inner" }, -- class + t = { "<([%p%w]-)%f[^<%w][^<>]->.-", "^<.->().*()$" }, -- tags + d = { "%f[%d]%d+" }, -- digits + e = { -- Word with case + { "%u[%l%d]+%f[^%l%d]", "%f[%S][%l%d]+%f[^%l%d]", "%f[%P][%l%d]+%f[^%l%d]", "^[%l%d]+%f[^%l%d]" }, + "^().*()$", + }, + u = ai.gen_spec.function_call(), -- u for "Usage" + U = ai.gen_spec.function_call { name_pattern = "[%w_]" }, -- without dot in function name + }, + } + end, + }, + -- Better move by word + { + "chrisgrieser/nvim-spider", + opts = {}, + keys = { + { "w", "lua require('spider').motion('w')", mode = { "n", "o", "x" }, desc = "Spider-w" }, + { "e", "lua require('spider').motion('e')", mode = { "n", "o", "x" }, desc = "Spider-e" }, + { "b", "lua require('spider').motion('b')", mode = { "n", "o", "x" }, desc = "Spider-b" }, + { "ge", "lua require('spider').motion('ge')", mode = { "n", "o", "x" }, desc = "Spider-ge" }, + }, + }, + -- Duplicate line/block up/down + { + "hinell/duplicate.nvim", + keys = { + { "", "LineDuplicate -1", mode = { "n" }, desc = "Duplicate line up" }, + { "", "LineDuplicate +1", mode = { "n" }, desc = "Duplicate line down" }, + { "", "VisualDuplicate -1", mode = { "x" }, desc = "Duplicate block up" }, + { "", "VisualDuplicate +1", mode = { "x" }, desc = "Duplicate block down" }, + }, + }, + -- Better character motion + { + "folke/flash.nvim", + event = "VeryLazy", + opts = {}, + keys = { + { "gj", function() require("flash").jump() end, mode = { "n", "x", "o" }, desc = "Flash" }, + { + "gJ", + function() require("flash").treesitter() end, + mode = { "n", "x", "o" }, + desc = "Flash Treesitter", + }, + { "r", function() require("flash").remote() end, mode = "o", desc = "Remote Flash" }, + { + "R", + function() require("flash").treesitter_search() end, + mode = { "x", "o" }, + desc = "Treesitter Search", + }, + }, + }, +} diff --git a/lua/plugins/multiple-cursor.lua b/lua/plugins/multiple-cursor.lua new file mode 100644 index 0000000..2226b00 --- /dev/null +++ b/lua/plugins/multiple-cursor.lua @@ -0,0 +1,40 @@ +return { + "brenton-leighton/multiple-cursors.nvim", + event = 'VimEnter', + cmd = { + "MultipleCursorsAddDown", + "MultipleCursorsAddUp", + "MultipleCursorsMouseAddDelete", + "MultipleCursorsAddMatches", + "MultipleCursorsAddMatchesV", + "MultipleCursorsAddJumpNextMatch", + "MultipleCursorsJumpNextMatch", + "MultipleCursorsLock", + }, + dependencies = { + "AstroNvim/astrocore", + opts = function(_, opts) + local maps = opts.mappings + for lhs, map in pairs { + [""] = { "MultipleCursorsAddDown", desc = "Add cursor down" }, + [""] = { "MultipleCursorsAddUp", desc = "Add cursor up" }, + [""] = { "MultipleCursorsMouseAddDelete", desc = "Add cursor with mouse" }, + } do + maps.n[lhs] = map + maps.i[lhs] = map + end + local prefix = "c" + for lhs, map in pairs { + [prefix .. "a"] = { "MultipleCursorsAddMatches", desc = "Add cursor matches" }, + [prefix .. "A"] = { "MultipleCursorsAddMatchesV", desc = "Add cursor matches in previous visual area" }, + [prefix .. "j"] = { "MultipleCursorsAddJumpNextMatch", desc = "Add cursor and jump to next match" }, + [prefix .. "J"] = { "MultipleCursorsJumpNextMatch", desc = "Move cursor to next match" }, + [prefix .. "l"] = { "MultipleCursorsLock", desc = "Lock virtual cursors" }, + } do + maps.n[lhs] = map + maps.x[lhs] = map + end + end, + }, + opts = {}, +} diff --git a/lua/plugins/multiple-visual.lua b/lua/plugins/multiple-visual.lua new file mode 100644 index 0000000..ab1b1e3 --- /dev/null +++ b/lua/plugins/multiple-visual.lua @@ -0,0 +1,4 @@ +return { + "mg979/vim-visual-multi", + event = "VeryLazy", +} diff --git a/lua/plugins/neotree.lua b/lua/plugins/neotree.lua new file mode 100644 index 0000000..684289d --- /dev/null +++ b/lua/plugins/neotree.lua @@ -0,0 +1,27 @@ +-- NOTE: always show hidden files and dot files +return { + "nvim-neo-tree/neo-tree.nvim", + opts = { + sources = { + "filesystem", + }, + + filesystem = { + filtered_items = { + visible = true, + show_hidden_count = true, + hide_dotfiles = true, + hide_gitignored = true, + hide_by_name = { + -- '.git', + -- '.DS_Store', + -- 'thumbs.db', + }, + never_show = {}, + }, + }, + enable_git_status = false, + enable_diagnostics = false, + git_status_async = false, + }, +} diff --git a/lua/plugins/noice.lua b/lua/plugins/noice.lua new file mode 100644 index 0000000..d0af8ca --- /dev/null +++ b/lua/plugins/noice.lua @@ -0,0 +1,203 @@ +return { + "folke/noice.nvim", + event = "VeryLazy", + dependencies = { "MunifTanjim/nui.nvim" }, + + config = function() + require("noice").setup { + -- Configuration here, or leave empty to use defaults + views = { + cmdline_popup = { + position = { + row = "50%", + col = "50%", + }, + size = { + width = 60, + height = "auto", + }, + }, + popupmenu = { + relative = "editor", + position = { + row = 8, + col = "50%", + }, + size = { + width = 60, + height = 10, + }, + border = { + style = "rounded", + padding = { 0, 1 }, + }, + win_options = { + winhighlight = { Normal = "Normal", FloatBorder = "DiagnosticInfo" }, + }, + }, + }, + messages = { + enabled = false, -- disables the Noice messages UI + }, + notify = { + enabled = false, -- disables Noice notifications + }, + lsp = { + progress = { + enabled = false, + }, + hover = { + enabled = false, -- disables Noice LSP hover + }, + signature = { + enabled = false, -- disables Noice LSP signature help + }, + message = { + enabled = false, + }, + }, + presets = { + bottom_search = true, -- use a classic bottom cmdline for search + command_palette = true, -- position the cmdline and popupmenu together + long_message_to_split = false, -- long messages will be sent to a split + inc_rename = false, -- enables an input dialog for inc-rename.nvim + lsp_doc_border = false, -- add a border to hover docs and signature help + }, + + routes = { + -- disable "written" notification + { + filter = { event = "msg_show", kind = "", find = "written" }, + opts = { skip = true }, + }, + -- disable paste/undo notification + { + filter = { event = "msg_show", find = "^%d+ more lines" }, + opts = { skip = true }, + }, + -- disable delete/undo notification + { + filter = { event = "msg_show", find = "^%d+ fewer lines" }, + opts = { skip = true }, + }, + -- disable yank notification + { + filter = { event = "msg_show", find = "^%d+ lines yanked$" }, + opts = { skip = true }, + }, + -- disable move notification + { + filter = { event = "msg_show", find = "^%d+ lines moved$" }, + }, + }, + } + end, + opts = function(_, opts) + local utils = require "astrocore" + return utils.extend_tbl(opts, { + lsp = { + progress = { + enabled = false, + }, + hover = { + enabled = false, -- disables Noice LSP hover + }, + signature = { + enabled = false, -- disables Noice LSP signature help + }, + message = { + enabled = false, + }, + }, + presets = { + bottom_search = true, -- use a classic bottom cmdline for search + command_palette = true, -- position the cmdline and popupmenu together + long_message_to_split = false, -- long messages will be sent to a split + inc_rename = false, -- enables an input dialog for inc-rename.nvim + lsp_doc_border = false, -- add a border to hover docs and signature help + }, + messages = { + enabled = false, -- disables the Noice messages UI + }, + notify = { + enabled = false, -- disables Noice notifications + }, + + routes = { + -- disable "written" notification + { + filter = { event = "msg_show", kind = "", find = "written" }, + opts = { skip = true }, + }, + -- disable paste/undo notification + { + filter = { event = "msg_show", find = "^%d+ more lines" }, + opts = { skip = true }, + }, + -- disable delete/undo notification + { + filter = { event = "msg_show", find = "^%d+ fewer lines" }, + opts = { skip = true }, + }, + -- disable yank notification + { + filter = { event = "msg_show", find = "^%d+ lines yanked$" }, + opts = { skip = true }, + }, + -- disable move notification + { + filter = { event = "msg_show", find = "^%d+ lines moved$" }, + }, + }, + }) + end, + specs = { + { + "nvim-treesitter/nvim-treesitter", + opts = function(_, opts) + if opts.ensure_installed ~= "all" then + opts.ensure_installed = require("astrocore").list_insert_unique( + opts.ensure_installed, + { "bash", "markdown", "markdown_inline", "regex", "vim" } + ) + end + end, + }, + { + "AstroNvim/astrolsp", + optional = true, + ---@param opts AstroLSPOpts + opts = function(_, opts) + -- No need to manage lsp_handlers as noice is not handling them now + end, + }, + { + "heirline.nvim", + optional = true, + opts = function(_, opts) + local noice_opts = require("astrocore").plugin_opts "noice.nvim" + if vim.tbl_get(noice_opts, "lsp", "progress", "enabled") ~= false then -- check if lsp progress is enabled + opts.statusline[9] = require("astroui.status").component.lsp { lsp_progress = false } + end + end, + }, + { + "folke/edgy.nvim", + optional = true, + opts = function(_, opts) + if not opts.bottom then opts.bottom = {} end + table.insert(opts.bottom, { + ft = "noice", + size = { height = 0.4 }, + filter = function(_, win) return vim.api.nvim_win_get_config(win).relative == "" end, + }) + end, + }, + { + "catppuccin", + optional = true, + ---@type CatppuccinOptions + opts = { integrations = { noice = true } }, + }, + }, +} diff --git a/lua/plugins/none-ls.lua b/lua/plugins/none-ls.lua new file mode 100644 index 0000000..4228102 --- /dev/null +++ b/lua/plugins/none-ls.lua @@ -0,0 +1,22 @@ +-- Customize None-ls sources + +---@type LazySpec +return { + "nvimtools/none-ls.nvim", + opts = function(_, opts) + -- config variable is the default configuration table for the setup function call + local null_ls = require "null-ls" + + -- Check supported formatters and linters + -- https://github.com/nvimtools/none-ls.nvim/tree/main/lua/null-ls/builtins/formatting + -- https://github.com/nvimtools/none-ls.nvim/tree/main/lua/null-ls/builtins/diagnostics + opts.sources = { + -- Set a formatter + null_ls.builtins.formatting.stylua, + null_ls.builtins.formatting.clang_format, + null_ls.builtins.formatting.black, + null_ls.builtins.formatting.prettier, + } + return opts + end, +} diff --git a/lua/plugins/smooth-cursor.lua b/lua/plugins/smooth-cursor.lua new file mode 100644 index 0000000..aa6ef32 --- /dev/null +++ b/lua/plugins/smooth-cursor.lua @@ -0,0 +1,75 @@ +return { + "gen740/SmoothCursor.nvim", + config = function() + require("smoothcursor").setup { + type = "default", -- Cursor movement calculation method, choose "default", "exp" (exponential) or "matrix". + + cursor = "", -- Cursor shape (requires Nerd Font). Disabled in fancy mode. + texthl = "SmoothCursor", -- Highlight group. Default is { bg = nil, fg = "#FFD400" }. Disabled in fancy mode. + linehl = nil, -- Highlights the line under the cursor, similar to 'cursorline'. "CursorLine" is recommended. Disabled in fancy mode. + + fancy = { + enable = true, -- enable fancy mode + head = { cursor = "▷", texthl = "SmoothCursor", linehl = nil }, -- false to disable fancy head + body = { + { cursor = "󰝥", texthl = "SmoothCursorRed" }, + { cursor = "󰝥", texthl = "SmoothCursorOrange" }, + { cursor = "●", texthl = "SmoothCursorYellow" }, + { cursor = "●", texthl = "SmoothCursorGreen" }, + { cursor = "•", texthl = "SmoothCursorAqua" }, + { cursor = ".", texthl = "SmoothCursorBlue" }, + { cursor = ".", texthl = "SmoothCursorPurple" }, + }, + tail = { cursor = nil, texthl = "SmoothCursor" }, -- false to disable fancy tail + }, + + matrix = { -- Loaded when 'type' is set to "matrix" + head = { + -- Picks a random character from this list for the cursor text + cursor = require "smoothcursor.matrix_chars", + -- Picks a random highlight from this list for the cursor text + texthl = { + "SmoothCursor", + }, + linehl = nil, -- No line highlight for the head + }, + body = { + length = 6, -- Specifies the length of the cursor body + -- Picks a random character from this list for the cursor body text + cursor = require "smoothcursor.matrix_chars", + -- Picks a random highlight from this list for each segment of the cursor body + texthl = { + "SmoothCursorGreen", + }, + }, + tail = { + -- Picks a random character from this list for the cursor tail (if any) + cursor = nil, + -- Picks a random highlight from this list for the cursor tail + texthl = { + "SmoothCursor", + }, + }, + unstop = false, -- Determines if the cursor should stop or not (false means it will stop) + }, + + autostart = true, -- Automatically start SmoothCursor + always_redraw = true, -- Redraw the screen on each update + flyin_effect = nil, -- Choose "bottom" or "top" for flying effect + speed = 25, -- Max speed is 100 to stick with your current position + intervals = 35, -- Update intervals in milliseconds + priority = 10, -- Set marker priority + timeout = 3000, -- Timeout for animations in milliseconds + threshold = 3, -- Animate only if cursor moves more than this many lines + max_threshold = nil, -- If you move more than this many lines, don't animate (if `nil`, deactivate check) + disable_float_win = false, -- Disable in floating windows + enabled_filetypes = nil, -- Enable only for specific file types, e.g., { "lua", "vim" } + disabled_filetypes = nil, -- Disable for these file types, ignored if enabled_filetypes is set. e.g., { "TelescopePrompt", "NvimTree" } + -- Show the position of the latest input mode positions. + -- A value of "enter" means the position will be updated when entering the mode. + -- A value of "leave" means the position will be updated when leaving the mode. + -- `nil` = disabled + show_last_positions = nil, + } + end, +} diff --git a/lua/plugins/treesitter.lua b/lua/plugins/treesitter.lua new file mode 100644 index 0000000..26272b3 --- /dev/null +++ b/lua/plugins/treesitter.lua @@ -0,0 +1,16 @@ +-- Customize Treesitter + +---@type LazySpec +return { + "nvim-treesitter/nvim-treesitter", + opts = function(_, opts) + -- add more things to the ensure_installed table protecting against community packs modifying it + opts.ensure_installed = require("astrocore").list_insert_unique(opts.ensure_installed, { + "lua", + "c", + "cpp", + "python", + -- "javascript", + }) + end, +} diff --git a/lua/plugins/ui.lua b/lua/plugins/ui.lua new file mode 100644 index 0000000..9838091 --- /dev/null +++ b/lua/plugins/ui.lua @@ -0,0 +1,51 @@ +-- Plugins related to UI +return { + { + "goolord/alpha-nvim", + opts = function(_, opts) + -- customize the dashboard header + opts.section.header.val = require("plugins.configs.ui.alpha")[3] + opts.section.buttons.val = {} + end, + }, + { + "rebelot/heirline.nvim", + opts = function(_, opts) + opts.statusline = require("plugins.configs.ui.heirline").statusline + opts.winbar = require("plugins.configs.ui.heirline").winbar + end, + }, + { + "rcarriga/nvim-notify", + opts = function(_, opts) + -- Do this to prevent the warning + opts.background_colour = "#000000" + end, + }, + -- Icons support + { + "echasnovski/mini.icons", + opts = function(_, opts) + if vim.g.icons_enabled == false then opts.style = "ascii" end + end, + lazy = true, + specs = { + { "nvim-tree/nvim-web-devicons", enabled = false, optional = true }, + }, + init = function() + package.preload["nvim-web-devicons"] = function() + require("mini.icons").mock_nvim_web_devicons() + return package.loaded["nvim-web-devicons"] + end + end, + }, + -- Transparent background + { + "xiyaowong/transparent.nvim", + lazy = false, + opts = function(_, opts) opts = require "plugins.configs.ui.transparent"(opts) end, + keys = { + { "uT", "TransparentToggle", desc = "Toggle transparent" }, + }, + }, +} diff --git a/lua/plugins/ultimate-autopair.lua b/lua/plugins/ultimate-autopair.lua new file mode 100644 index 0000000..2751c7e --- /dev/null +++ b/lua/plugins/ultimate-autopair.lua @@ -0,0 +1,63 @@ +return { + "altermo/ultimate-autopair.nvim", + event = "InsertEnter", + branch = "v0.6", --recommended as each new version will have breaking changes + opts = { + -- disable autopair in the command line: https://github.com/altermo/ultimate-autopair.nvim/issues/8 + cmap = false, + extensions = { + cond = { + -- disable in comments + -- https://github.com/altermo/ultimate-autopair.nvim/blob/6fd0d6aa976a97dd6f1bed4d46be1b437613a52f/Q%26A.md?plain=1#L26 + cond = { + function(fn) return not fn.in_node "comment" end, + }, + }, + -- get fly mode working on strings: + -- https://github.com/altermo/ultimate-autopair.nvim/issues/33 + fly = { + nofilter = true, + }, + }, + config_internal_pairs = { + { '"', '"', fly = true }, + { "'", "'", fly = true }, + { "[", "]", fly = true }, + { "{", "}", fly = true }, + { "(", ")", fly = true }, + }, + }, + dependencies = { + { + "AstroNvim/astrocore", + opts = { + mappings = { + n = { + ["ua"] = { + desc = "Toggle Ultimate Autopair", + function() + local notify = require("astrocore").notify + local function bool2str(bool) return bool and "on" or "off" end + local ok, ultimate_autopair = pcall(require, "ultimate-autopair") + if ok then + ultimate_autopair.toggle() + vim.g.ultimate_autopair_enabled = require("ultimate-autopair.core").disable + notify(string.format("ultimate-autopair %s", bool2str(not vim.g.ultimate_autopair_enabled))) + else + notify "ultimate-autopair not available" + end + end, + }, + }, + }, + }, + }, + }, + specs = { + { + "windwp/nvim-autopairs", + optional = true, + enabled = false, + }, + }, +} diff --git a/lua/polish.lua b/lua/polish.lua new file mode 100644 index 0000000..a9bca36 --- /dev/null +++ b/lua/polish.lua @@ -0,0 +1,6 @@ +-- This will run last in the setup process and is a good place to configure +-- things like custom filetypes. This just pure lua so anything that doesn't +-- fit in the normal config locations above can go here + +-- Run autocommands +require("core.autocmds") \ No newline at end of file diff --git a/neovim.yml b/neovim.yml new file mode 100644 index 0000000..b9235ab --- /dev/null +++ b/neovim.yml @@ -0,0 +1,6 @@ +--- +base: lua51 + +globals: + vim: + any: true diff --git a/selene.toml b/selene.toml new file mode 100644 index 0000000..e7005c3 --- /dev/null +++ b/selene.toml @@ -0,0 +1,8 @@ +std = "neovim" + +[rules] +global_usage = "allow" +if_same_then_else = "allow" +incorrect_standard_library_use = "allow" +mixed_table = "allow" +multiple_statements = "allow"