feat: improve portability and add Grug-far QoL improvements
- Refactor terminal title logic in lua/options.lua with Kitty detection and OSC 2 fallback. - Set mapleader and maplocalleader explicitly at the top of lua/options.lua. - Add <leader>sr mapping for Grug-far search and replace in lua/keymaps.lua. - Add autocommand to close Grug-far window with 'q'. - Update README.md with system dependencies (Debian/Arch) and new keymaps. - Highlight portability features (terminal titles, root detection) in README.md.
This commit is contained in:
@@ -13,6 +13,7 @@ A modern, modular, and high-performance Neovim configuration built from scratch
|
|||||||
- **High Performance**: Featuring **blink.cmp** (Rust-based completion) and optimized **Snacks.nvim** components.
|
- **High Performance**: Featuring **blink.cmp** (Rust-based completion) and optimized **Snacks.nvim** components.
|
||||||
- **AI-Powered**: Native integration with the **GitHub Copilot Language Server**.
|
- **AI-Powered**: Native integration with the **GitHub Copilot Language Server**.
|
||||||
- **User-Centric QoL**: Hybrid line numbers, autosave-on-edit, and seamless system clipboard integration.
|
- **User-Centric QoL**: Hybrid line numbers, autosave-on-edit, and seamless system clipboard integration.
|
||||||
|
- **Resilient & Portable**: Intelligent terminal title management (Kitty + Fallback) and automatic project root detection.
|
||||||
|
|
||||||
## 📁 Architecture
|
## 📁 Architecture
|
||||||
|
|
||||||
@@ -20,20 +21,43 @@ The configuration is strictly modular:
|
|||||||
|
|
||||||
- `init.lua`: Entry point and global state initialization.
|
- `init.lua`: Entry point and global state initialization.
|
||||||
- `lua/lazyload.lua`: Logic for async and phased plugin loading.
|
- `lua/lazyload.lua`: Logic for async and phased plugin loading.
|
||||||
- `lua/options.lua`: Global Vim settings and non-plugin autocommands.
|
- `lua/options.lua`: Global Vim settings, root management, and terminal title logic.
|
||||||
- `lua/plugins.lua`: Plugin declarations and detailed registry-based configurations.
|
- `lua/plugins.lua`: Plugin declarations and detailed registry-based configurations.
|
||||||
- `lua/keymaps.lua`: Centralized user-facing keybindings.
|
- `lua/keymaps.lua`: Centralized user-facing keybindings.
|
||||||
- `lua/const.lua`: Stores constant values for reference in the configuration.
|
- `lua/const.lua`: Stores constant values (like dashboard headers) for the configuration.
|
||||||
|
|
||||||
|
## 🛠️ System Dependencies
|
||||||
|
|
||||||
|
To ensure all features (pickers, formatters, and LSPs) work correctly, the following packages are required:
|
||||||
|
|
||||||
|
### Essential Tools
|
||||||
|
- `git`, `curl`, `unzip`, `build-essential` (or `base-devel`)
|
||||||
|
- `ripgrep` (Grep support)
|
||||||
|
- `fd` (Fast file finding)
|
||||||
|
- `fzf` (Fuzzy finder fallback)
|
||||||
|
- `lazygit` (Git TUI)
|
||||||
|
- `gh` (GitHub CLI integration)
|
||||||
|
- `xclip` / `xsel` (X11) or `wl-copy` (Wayland) for clipboard sync.
|
||||||
|
|
||||||
|
### Runtime Environments
|
||||||
|
- `Node.js` & `npm` (Copilot and various LSPs)
|
||||||
|
- `Python3` & `pip` (Python LSPs)
|
||||||
|
- `Cargo` (Rust toolchain, required for building `blink.cmp`)
|
||||||
|
|
||||||
|
### Installation Commands
|
||||||
|
|
||||||
|
**Debian / Ubuntu:**
|
||||||
|
```bash
|
||||||
|
sudo apt install git ripgrep fd-find fzf lazygit gh xclip nodejs npm build-essential curl unzip
|
||||||
|
```
|
||||||
|
|
||||||
|
**Arch Linux:**
|
||||||
|
```bash
|
||||||
|
sudo pacman -S git ripgrep fd fzf lazygit github-cli xclip nodejs npm base-devel curl unzip
|
||||||
|
```
|
||||||
|
|
||||||
## 🚀 Getting Started
|
## 🚀 Getting Started
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
- **Neovim 0.10+**
|
|
||||||
- **Nerd Font** (Mono variant recommended for optimal UI alignment)
|
|
||||||
- **Cargo** (Required for building `blink.cmp` fuzzy matching library)
|
|
||||||
- **Node.js** (Required for various LSPs and Copilot)
|
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -44,24 +68,27 @@ nvim
|
|||||||
### Post-Install
|
### Post-Install
|
||||||
|
|
||||||
1. **Build Blink**: If completion isn't working, run `cargo build --release` inside `~/.local/share/nvim/site/pack/core/opt/blink.cmp`.
|
1. **Build Blink**: If completion isn't working, run `cargo build --release` inside `~/.local/share/nvim/site/pack/core/opt/blink.cmp`.
|
||||||
2. **LSP Servers**: Run `:Mason` to monitor the installation of Language Servers (Lua, C, Rust, Python, etc.).
|
2. **LSP Servers**: Run `:Mason` to monitor the installation of Language Servers.
|
||||||
3. **Copilot**: Run `:LspCopilotSignIn` to authenticate with GitHub.
|
3. **Copilot**: Run `:LspCopilotSignIn` to authenticate.
|
||||||
|
|
||||||
## ⌨️ Key Features & Mappings
|
## ⌨️ Key Features & Mappings
|
||||||
|
|
||||||
| Key | Description |
|
| Key | Description |
|
||||||
| :--- | :--- |
|
| :--- | :--- |
|
||||||
| `<leader><space>` | Smart Find Files (Snacks) |
|
| `<leader><space>` | Smart Find Files (Snacks) |
|
||||||
| `<leader>e` | File Explorer |
|
| `<leader>e` | File Explorer (Snacks) |
|
||||||
| `<leader>ff` | Find Files |
|
| `<leader>sr` | Search and Replace (Grug-far) |
|
||||||
| `<leader>sg` | Project-wide Grep |
|
| `<leader>gg` | Open Lazygit |
|
||||||
| `gd` / `gr` | Go to Definition / References |
|
| `<leader>qs` | Restore Last Session (Persistence) |
|
||||||
|
| `<leader>cf` | Format Buffer (Conform) |
|
||||||
|
| `<leader>uu` | Toggle Undo Tree |
|
||||||
|
| `<leader>z` | Toggle Zen Mode |
|
||||||
|
| `gd` / `gr` | Goto Definition / References |
|
||||||
| `K` | Hover Documentation |
|
| `K` | Hover Documentation |
|
||||||
| `s` / `S` | Leap Motion (Normal/Window) |
|
| `s` / `S` | Leap Motion (Normal/Window) |
|
||||||
| `ys` / `ds` | Mini.surround (Add/Delete) |
|
| `ys` / `ds` / `cs` | Surround (Add/Delete/Change) |
|
||||||
| `:Q` | Forced Write-All and Quit |
|
| `:Q` | Forced Write-All and Quit |
|
||||||
|
|
||||||
## 📜 License
|
## 📜 License
|
||||||
|
|
||||||
Distributed under the **GPLv3 or later** License. See `LICENSE` for more information.
|
Distributed under the **GPLv3 or later** License. See `LICENSE` for more information.
|
||||||
|
|
||||||
|
|||||||
+252
-95
@@ -20,17 +20,17 @@
|
|||||||
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
-- System Clipboard Integration
|
-- System Clipboard Integration
|
||||||
-- This makes 'y' and 'p' (and all other yank/paste operations)
|
-- This makes 'y' and 'p' (and all other yank/paste operations)
|
||||||
-- use the system clipboard by default.
|
-- use the system clipboard by default.
|
||||||
vim.opt.clipboard = 'unnamedplus'
|
vim.opt.clipboard = "unnamedplus"
|
||||||
|
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
|
|
||||||
-- Redirect 'delete' and 'change' operations to the 'd' register
|
-- Redirect 'delete' and 'change' operations to the 'd' register
|
||||||
-- This keeps your system clipboard (unnamedplus) clean
|
-- This keeps your system clipboard (unnamedplus) clean
|
||||||
local delete_keys = { 'd', 'D', 'c', 'C', 'x', 'X' }
|
local delete_keys = { "d", "D", "c", "C", "x", "X" }
|
||||||
for _, key in ipairs(delete_keys) do
|
for _, key in ipairs(delete_keys) do
|
||||||
vim.keymap.set({ 'n', 'v' }, key, '"d' .. key, { noremap = true, silent = true })
|
vim.keymap.set({ "n", "v" }, key, '"d' .. key, { noremap = true, silent = true })
|
||||||
end
|
end
|
||||||
|
|
||||||
-- If you ever need to paste what you just deleted:
|
-- If you ever need to paste what you just deleted:
|
||||||
@@ -40,130 +40,279 @@ end
|
|||||||
|
|
||||||
-- Quit and Save All with :Q
|
-- Quit and Save All with :Q
|
||||||
-- Replaces safety-checked :xa with a forced write-all-and-quit.
|
-- Replaces safety-checked :xa with a forced write-all-and-quit.
|
||||||
vim.api.nvim_create_user_command('Q', 'xa!', { desc = 'Write all and quit (forced)' })
|
vim.api.nvim_create_user_command("Q", "xa!", { desc = "Write all and quit (forced)" })
|
||||||
|
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
|
|
||||||
|
-- Search and Replace (Grug-far)
|
||||||
|
vim.keymap.set("n", "<leader>sr", function()
|
||||||
|
require("grug-far").open({
|
||||||
|
prefills = {
|
||||||
|
search = vim.fn.expand("<cword>"),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end, { desc = "Search and Replace" })
|
||||||
|
|
||||||
-- Snacks Keymaps
|
-- Snacks Keymaps
|
||||||
-- Top Pickers & Explorer
|
-- Top Pickers & Explorer
|
||||||
vim.keymap.set("n", "<leader><space>", function() Snacks.picker.smart() end, { desc = "Smart Find Files" })
|
vim.keymap.set("n", "<leader><space>", function()
|
||||||
vim.keymap.set("n", "<leader>,", function() Snacks.picker.buffers() end, { desc = "Buffers" })
|
Snacks.picker.smart()
|
||||||
vim.keymap.set("n", "<leader>/", function() Snacks.picker.grep() end, { desc = "Grep" })
|
end, { desc = "Smart Find Files" })
|
||||||
vim.keymap.set("n", "<leader>:", function() Snacks.picker.command_history() end, { desc = "Command History" })
|
vim.keymap.set("n", "<leader>,", function()
|
||||||
vim.keymap.set("n", "<leader>n", function() Snacks.picker.notifications() end, { desc = "Notification History" })
|
Snacks.picker.buffers()
|
||||||
vim.keymap.set("n", "<leader>e", function() Snacks.explorer() end, { desc = "File Explorer" })
|
end, { desc = "Buffers" })
|
||||||
|
vim.keymap.set("n", "<leader>/", function()
|
||||||
|
Snacks.picker.grep()
|
||||||
|
end, { desc = "Grep" })
|
||||||
|
vim.keymap.set("n", "<leader>:", function()
|
||||||
|
Snacks.picker.command_history()
|
||||||
|
end, { desc = "Command History" })
|
||||||
|
vim.keymap.set("n", "<leader>n", function()
|
||||||
|
Snacks.picker.notifications()
|
||||||
|
end, { desc = "Notification History" })
|
||||||
|
vim.keymap.set("n", "<leader>e", function()
|
||||||
|
Snacks.explorer()
|
||||||
|
end, { desc = "File Explorer" })
|
||||||
|
|
||||||
-- Find
|
-- Find
|
||||||
vim.keymap.set("n", "<leader>fb", function() Snacks.picker.buffers() end, { desc = "Buffers" })
|
vim.keymap.set("n", "<leader>fb", function()
|
||||||
vim.keymap.set("n", "<leader>fc", function() Snacks.picker.files({ cwd = vim.fn.stdpath("config") }) end, { desc = "Find Config File" })
|
Snacks.picker.buffers()
|
||||||
vim.keymap.set("n", "<leader>ff", function() Snacks.picker.files() end, { desc = "Find Files" })
|
end, { desc = "Buffers" })
|
||||||
vim.keymap.set("n", "<leader>fg", function() Snacks.picker.git_files() end, { desc = "Find Git Files" })
|
vim.keymap.set("n", "<leader>fc", function()
|
||||||
vim.keymap.set("n", "<leader>fp", function() Snacks.picker.projects() end, { desc = "Projects" })
|
Snacks.picker.files({ cwd = vim.fn.stdpath("config") })
|
||||||
vim.keymap.set("n", "<leader>fr", function() Snacks.picker.recent() end, { desc = "Recent" })
|
end, { desc = "Find Config File" })
|
||||||
|
vim.keymap.set("n", "<leader>ff", function()
|
||||||
|
Snacks.picker.files()
|
||||||
|
end, { desc = "Find Files" })
|
||||||
|
vim.keymap.set("n", "<leader>fg", function()
|
||||||
|
Snacks.picker.git_files()
|
||||||
|
end, { desc = "Find Git Files" })
|
||||||
|
vim.keymap.set("n", "<leader>fp", function()
|
||||||
|
Snacks.picker.projects()
|
||||||
|
end, { desc = "Projects" })
|
||||||
|
vim.keymap.set("n", "<leader>fr", function()
|
||||||
|
Snacks.picker.recent()
|
||||||
|
end, { desc = "Recent" })
|
||||||
|
|
||||||
-- Git
|
-- Git
|
||||||
vim.keymap.set("n", "<leader>gb", function() Snacks.picker.git_branches() end, { desc = "Git Branches" })
|
vim.keymap.set("n", "<leader>gb", function()
|
||||||
vim.keymap.set("n", "<leader>gl", function() Snacks.picker.git_log() end, { desc = "Git Log" })
|
Snacks.picker.git_branches()
|
||||||
vim.keymap.set("n", "<leader>gL", function() Snacks.picker.git_log_line() end, { desc = "Git Log Line" })
|
end, { desc = "Git Branches" })
|
||||||
vim.keymap.set("n", "<leader>gs", function() Snacks.picker.git_status() end, { desc = "Git Status" })
|
vim.keymap.set("n", "<leader>gl", function()
|
||||||
vim.keymap.set("n", "<leader>gS", function() Snacks.picker.git_stash() end, { desc = "Git Stash" })
|
Snacks.picker.git_log()
|
||||||
vim.keymap.set("n", "<leader>gd", function() Snacks.picker.git_diff() end, { desc = "Git Diff (Hunks)" })
|
end, { desc = "Git Log" })
|
||||||
vim.keymap.set("n", "<leader>gf", function() Snacks.picker.git_log_file() end, { desc = "Git Log File" })
|
vim.keymap.set("n", "<leader>gL", function()
|
||||||
|
Snacks.picker.git_log_line()
|
||||||
|
end, { desc = "Git Log Line" })
|
||||||
|
vim.keymap.set("n", "<leader>gs", function()
|
||||||
|
Snacks.picker.git_status()
|
||||||
|
end, { desc = "Git Status" })
|
||||||
|
vim.keymap.set("n", "<leader>gS", function()
|
||||||
|
Snacks.picker.git_stash()
|
||||||
|
end, { desc = "Git Stash" })
|
||||||
|
vim.keymap.set("n", "<leader>gd", function()
|
||||||
|
Snacks.picker.git_diff()
|
||||||
|
end, { desc = "Git Diff (Hunks)" })
|
||||||
|
vim.keymap.set("n", "<leader>gf", function()
|
||||||
|
Snacks.picker.git_log_file()
|
||||||
|
end, { desc = "Git Log File" })
|
||||||
|
|
||||||
-- GH
|
-- GH
|
||||||
vim.keymap.set("n", "<leader>gi", function() Snacks.picker.gh_issue() end, { desc = "GitHub Issues (open)" })
|
vim.keymap.set("n", "<leader>gi", function()
|
||||||
vim.keymap.set("n", "<leader>gI", function() Snacks.picker.gh_issue({ state = "all" }) end, { desc = "GitHub Issues (all)" })
|
Snacks.picker.gh_issue()
|
||||||
vim.keymap.set("n", "<leader>gp", function() Snacks.picker.gh_pr() end, { desc = "GitHub Pull Requests (open)" })
|
end, { desc = "GitHub Issues (open)" })
|
||||||
vim.keymap.set("n", "<leader>gP", function() Snacks.picker.gh_pr({ state = "all" }) end, { desc = "GitHub Pull Requests (all)" })
|
vim.keymap.set("n", "<leader>gI", function()
|
||||||
|
Snacks.picker.gh_issue({ state = "all" })
|
||||||
|
end, { desc = "GitHub Issues (all)" })
|
||||||
|
vim.keymap.set("n", "<leader>gp", function()
|
||||||
|
Snacks.picker.gh_pr()
|
||||||
|
end, { desc = "GitHub Pull Requests (open)" })
|
||||||
|
vim.keymap.set("n", "<leader>gP", function()
|
||||||
|
Snacks.picker.gh_pr({ state = "all" })
|
||||||
|
end, { desc = "GitHub Pull Requests (all)" })
|
||||||
|
|
||||||
-- Grep
|
-- Grep
|
||||||
vim.keymap.set("n", "<leader>sb", function() Snacks.picker.lines() end, { desc = "Buffer Lines" })
|
vim.keymap.set("n", "<leader>sb", function()
|
||||||
vim.keymap.set("n", "<leader>sB", function() Snacks.picker.grep_buffers() end, { desc = "Grep Open Buffers" })
|
Snacks.picker.lines()
|
||||||
vim.keymap.set("n", "<leader>sg", function() Snacks.picker.grep() end, { desc = "Grep" })
|
end, { desc = "Buffer Lines" })
|
||||||
vim.keymap.set({ "n", "x" }, "<leader>sw", function() Snacks.picker.grep_word() end, { desc = "Visual selection or word" })
|
vim.keymap.set("n", "<leader>sB", function()
|
||||||
|
Snacks.picker.grep_buffers()
|
||||||
|
end, { desc = "Grep Open Buffers" })
|
||||||
|
vim.keymap.set("n", "<leader>sg", function()
|
||||||
|
Snacks.picker.grep()
|
||||||
|
end, { desc = "Grep" })
|
||||||
|
vim.keymap.set({ "n", "x" }, "<leader>sw", function()
|
||||||
|
Snacks.picker.grep_word()
|
||||||
|
end, { desc = "Visual selection or word" })
|
||||||
|
|
||||||
-- Search
|
-- Search
|
||||||
vim.keymap.set("n", '<leader>s"', function() Snacks.picker.registers() end, { desc = "Registers" })
|
vim.keymap.set("n", '<leader>s"', function()
|
||||||
vim.keymap.set("n", '<leader>s/', function() Snacks.picker.search_history() end, { desc = "Search History" })
|
Snacks.picker.registers()
|
||||||
vim.keymap.set("n", "<leader>sa", function() Snacks.picker.autocmds() end, { desc = "Autocmds" })
|
end, { desc = "Registers" })
|
||||||
vim.keymap.set("n", "<leader>sc", function() Snacks.picker.command_history() end, { desc = "Command History" })
|
vim.keymap.set("n", "<leader>s/", function()
|
||||||
vim.keymap.set("n", "<leader>sC", function() Snacks.picker.commands() end, { desc = "Commands" })
|
Snacks.picker.search_history()
|
||||||
vim.keymap.set("n", "<leader>sd", function() Snacks.picker.diagnostics() end, { desc = "Diagnostics" })
|
end, { desc = "Search History" })
|
||||||
vim.keymap.set("n", "<leader>sD", function() Snacks.picker.diagnostics_buffer() end, { desc = "Buffer Diagnostics" })
|
vim.keymap.set("n", "<leader>sa", function()
|
||||||
vim.keymap.set("n", "<leader>sh", function() Snacks.picker.help() end, { desc = "Help Pages" })
|
Snacks.picker.autocmds()
|
||||||
vim.keymap.set("n", "<leader>sH", function() Snacks.picker.highlights() end, { desc = "Highlights" })
|
end, { desc = "Autocmds" })
|
||||||
vim.keymap.set("n", "<leader>si", function() Snacks.picker.icons() end, { desc = "Icons" })
|
vim.keymap.set("n", "<leader>sc", function()
|
||||||
vim.keymap.set("n", "<leader>sj", function() Snacks.picker.jumps() end, { desc = "Jumps" })
|
Snacks.picker.command_history()
|
||||||
vim.keymap.set("n", "<leader>sk", function() Snacks.picker.keymaps() end, { desc = "Keymaps" })
|
end, { desc = "Command History" })
|
||||||
vim.keymap.set("n", "<leader>sl", function() Snacks.picker.loclist() end, { desc = "Location List" })
|
vim.keymap.set("n", "<leader>sC", function()
|
||||||
vim.keymap.set("n", "<leader>sm", function() Snacks.picker.marks() end, { desc = "Marks" })
|
Snacks.picker.commands()
|
||||||
vim.keymap.set("n", "<leader>sM", function() Snacks.picker.man() end, { desc = "Man Pages" })
|
end, { desc = "Commands" })
|
||||||
vim.keymap.set("n", "<leader>sp", function() Snacks.picker.lazy() end, { desc = "Search for Plugin Spec" })
|
vim.keymap.set("n", "<leader>sd", function()
|
||||||
vim.keymap.set("n", "<leader>sq", function() Snacks.picker.qflist() end, { desc = "Quickfix List" })
|
Snacks.picker.diagnostics()
|
||||||
vim.keymap.set("n", "<leader>sR", function() Snacks.picker.resume() end, { desc = "Resume" })
|
end, { desc = "Diagnostics" })
|
||||||
vim.keymap.set("n", "<leader>su", function() Snacks.picker.undo() end, { desc = "Undo History" })
|
vim.keymap.set("n", "<leader>sD", function()
|
||||||
vim.keymap.set("n", "<leader>uC", function() Snacks.picker.colorschemes() end, { desc = "Colorschemes" })
|
Snacks.picker.diagnostics_buffer()
|
||||||
|
end, { desc = "Buffer Diagnostics" })
|
||||||
|
vim.keymap.set("n", "<leader>sh", function()
|
||||||
|
Snacks.picker.help()
|
||||||
|
end, { desc = "Help Pages" })
|
||||||
|
vim.keymap.set("n", "<leader>sH", function()
|
||||||
|
Snacks.picker.highlights()
|
||||||
|
end, { desc = "Highlights" })
|
||||||
|
vim.keymap.set("n", "<leader>si", function()
|
||||||
|
Snacks.picker.icons()
|
||||||
|
end, { desc = "Icons" })
|
||||||
|
vim.keymap.set("n", "<leader>sj", function()
|
||||||
|
Snacks.picker.jumps()
|
||||||
|
end, { desc = "Jumps" })
|
||||||
|
vim.keymap.set("n", "<leader>sk", function()
|
||||||
|
Snacks.picker.keymaps()
|
||||||
|
end, { desc = "Keymaps" })
|
||||||
|
vim.keymap.set("n", "<leader>sl", function()
|
||||||
|
Snacks.picker.loclist()
|
||||||
|
end, { desc = "Location List" })
|
||||||
|
vim.keymap.set("n", "<leader>sm", function()
|
||||||
|
Snacks.picker.marks()
|
||||||
|
end, { desc = "Marks" })
|
||||||
|
vim.keymap.set("n", "<leader>sM", function()
|
||||||
|
Snacks.picker.man()
|
||||||
|
end, { desc = "Man Pages" })
|
||||||
|
vim.keymap.set("n", "<leader>sp", function()
|
||||||
|
Snacks.picker.lazy()
|
||||||
|
end, { desc = "Search for Plugin Spec" })
|
||||||
|
vim.keymap.set("n", "<leader>sq", function()
|
||||||
|
Snacks.picker.qflist()
|
||||||
|
end, { desc = "Quickfix List" })
|
||||||
|
vim.keymap.set("n", "<leader>sR", function()
|
||||||
|
Snacks.picker.resume()
|
||||||
|
end, { desc = "Resume" })
|
||||||
|
vim.keymap.set("n", "<leader>su", function()
|
||||||
|
Snacks.picker.undo()
|
||||||
|
end, { desc = "Undo History" })
|
||||||
|
vim.keymap.set("n", "<leader>uC", function()
|
||||||
|
Snacks.picker.colorschemes()
|
||||||
|
end, { desc = "Colorschemes" })
|
||||||
|
|
||||||
-- LSP
|
-- LSP
|
||||||
vim.keymap.set("n", "gd", function() Snacks.picker.lsp_definitions() end, { desc = "Goto Definition" })
|
vim.keymap.set("n", "gd", function()
|
||||||
vim.keymap.set("n", "gD", function() Snacks.picker.lsp_declarations() end, { desc = "Goto Declaration" })
|
Snacks.picker.lsp_definitions()
|
||||||
vim.keymap.set("n", "gr", function() Snacks.picker.lsp_references() end, { nowait = true, desc = "References" })
|
end, { desc = "Goto Definition" })
|
||||||
vim.keymap.set("n", "gI", function() Snacks.picker.lsp_implementations() end, { desc = "Goto Implementation" })
|
vim.keymap.set("n", "gD", function()
|
||||||
vim.keymap.set("n", "gy", function() Snacks.picker.lsp_type_definitions() end, { desc = "Goto T[y]pe Definition" })
|
Snacks.picker.lsp_declarations()
|
||||||
vim.keymap.set("n", "gai", function() Snacks.picker.lsp_incoming_calls() end, { desc = "C[a]lls Incoming" })
|
end, { desc = "Goto Declaration" })
|
||||||
vim.keymap.set("n", "gao", function() Snacks.picker.lsp_outgoing_calls() end, { desc = "C[a]lls Outgoing" })
|
vim.keymap.set("n", "gr", function()
|
||||||
vim.keymap.set("n", "<leader>ss", function() Snacks.picker.lsp_symbols() end, { desc = "LSP Symbols" })
|
Snacks.picker.lsp_references()
|
||||||
vim.keymap.set("n", "<leader>sS", function() Snacks.picker.lsp_workspace_symbols() end, { desc = "LSP Workspace Symbols" })
|
end, { nowait = true, desc = "References" })
|
||||||
|
vim.keymap.set("n", "gI", function()
|
||||||
|
Snacks.picker.lsp_implementations()
|
||||||
|
end, { desc = "Goto Implementation" })
|
||||||
|
vim.keymap.set("n", "gy", function()
|
||||||
|
Snacks.picker.lsp_type_definitions()
|
||||||
|
end, { desc = "Goto T[y]pe Definition" })
|
||||||
|
vim.keymap.set("n", "gai", function()
|
||||||
|
Snacks.picker.lsp_incoming_calls()
|
||||||
|
end, { desc = "C[a]lls Incoming" })
|
||||||
|
vim.keymap.set("n", "gao", function()
|
||||||
|
Snacks.picker.lsp_outgoing_calls()
|
||||||
|
end, { desc = "C[a]lls Outgoing" })
|
||||||
|
vim.keymap.set("n", "<leader>ss", function()
|
||||||
|
Snacks.picker.lsp_symbols()
|
||||||
|
end, { desc = "LSP Symbols" })
|
||||||
|
vim.keymap.set("n", "<leader>sS", function()
|
||||||
|
Snacks.picker.lsp_workspace_symbols()
|
||||||
|
end, { desc = "LSP Workspace Symbols" })
|
||||||
|
|
||||||
-- Standard LSP
|
-- Standard LSP
|
||||||
vim.keymap.set("n", "K", vim.lsp.buf.hover, { desc = "Hover Documentation" })
|
vim.keymap.set("n", "K", vim.lsp.buf.hover, { desc = "Hover Documentation" })
|
||||||
vim.keymap.set("n", "<leader>ca", vim.lsp.buf.code_action, { desc = "Code Action" })
|
vim.keymap.set("n", "<leader>ca", vim.lsp.buf.code_action, { desc = "Code Action" })
|
||||||
vim.keymap.set("n", "<leader>cr", function()
|
vim.keymap.set("n", "<leader>cr", function()
|
||||||
return ":" .. require("inc_rename").config.cmd_name .. " " .. vim.fn.expand("<cword>")
|
return ":" .. require("inc_rename").config.cmd_name .. " " .. vim.fn.expand("<cword>")
|
||||||
end, { expr = true, desc = "Rename Symbol" })
|
end, { expr = true, desc = "Rename Symbol" })
|
||||||
|
|
||||||
-- Other
|
-- Other
|
||||||
vim.keymap.set("n", "<leader>sq", "<cmd>nohlsearch<cr>", { desc = "Clear Search Highlights" })
|
vim.keymap.set("n", "<leader>sq", "<cmd>nohlsearch<cr>", { desc = "Clear Search Highlights" })
|
||||||
vim.keymap.set("n", "<leader>z", function() Snacks.zen() end, { desc = "Toggle Zen Mode" })
|
vim.keymap.set("n", "<leader>z", function()
|
||||||
vim.keymap.set("n", "<leader>Z", function() Snacks.zen.zoom() end, { desc = "Toggle Zoom" })
|
Snacks.zen()
|
||||||
vim.keymap.set("n", "<leader>.", function() Snacks.scratch() end, { desc = "Toggle Scratch Buffer" })
|
end, { desc = "Toggle Zen Mode" })
|
||||||
vim.keymap.set("n", "<leader>S", function() Snacks.scratch.select() end, { desc = "Select Scratch Buffer" })
|
vim.keymap.set("n", "<leader>Z", function()
|
||||||
vim.keymap.set("n", "<leader>n", function() Snacks.notifier.show_history() end, { desc = "Notification History" })
|
Snacks.zen.zoom()
|
||||||
vim.keymap.set("n", "<leader>bd", function() Snacks.bufdelete() end, { desc = "Delete Buffer" })
|
end, { desc = "Toggle Zoom" })
|
||||||
vim.keymap.set("n", "<leader>cR", function() Snacks.rename.rename_file() end, { desc = "Rename File" })
|
vim.keymap.set("n", "<leader>.", function()
|
||||||
vim.keymap.set({ "n", "v" }, "<leader>gB", function() Snacks.gitbrowse() end, { desc = "Git Browse" })
|
Snacks.scratch()
|
||||||
vim.keymap.set("n", "<leader>gg", function() Snacks.lazygit() end, { desc = "Lazygit" })
|
end, { desc = "Toggle Scratch Buffer" })
|
||||||
vim.keymap.set("n", "<leader>un", function() Snacks.notifier.hide() end, { desc = "Dismiss All Notifications" })
|
vim.keymap.set("n", "<leader>S", function()
|
||||||
vim.keymap.set({ "n", "t" }, "<c-/>", function() Snacks.terminal() end, { desc = "Toggle Terminal" })
|
Snacks.scratch.select()
|
||||||
vim.keymap.set({ "n", "t" }, "<c-_>", function() Snacks.terminal() end, { desc = "which_key_ignore" })
|
end, { desc = "Select Scratch Buffer" })
|
||||||
vim.keymap.set({ "n", "t" }, "]]", function() Snacks.words.jump(vim.v.count1) end, { desc = "Next Reference" })
|
vim.keymap.set("n", "<leader>n", function()
|
||||||
vim.keymap.set({ "n", "t" }, "[[", function() Snacks.words.jump(-vim.v.count1) end, { desc = "Prev Reference" })
|
Snacks.notifier.show_history()
|
||||||
|
end, { desc = "Notification History" })
|
||||||
|
vim.keymap.set("n", "<leader>bd", function()
|
||||||
|
Snacks.bufdelete()
|
||||||
|
end, { desc = "Delete Buffer" })
|
||||||
|
vim.keymap.set("n", "<leader>cR", function()
|
||||||
|
Snacks.rename.rename_file()
|
||||||
|
end, { desc = "Rename File" })
|
||||||
|
vim.keymap.set({ "n", "v" }, "<leader>gB", function()
|
||||||
|
Snacks.gitbrowse()
|
||||||
|
end, { desc = "Git Browse" })
|
||||||
|
vim.keymap.set("n", "<leader>gg", function()
|
||||||
|
Snacks.lazygit()
|
||||||
|
end, { desc = "Lazygit" })
|
||||||
|
vim.keymap.set("n", "<leader>un", function()
|
||||||
|
Snacks.notifier.hide()
|
||||||
|
end, { desc = "Dismiss All Notifications" })
|
||||||
|
vim.keymap.set({ "n", "t" }, "<c-/>", function()
|
||||||
|
Snacks.terminal()
|
||||||
|
end, { desc = "Toggle Terminal" })
|
||||||
|
vim.keymap.set({ "n", "t" }, "<c-_>", function()
|
||||||
|
Snacks.terminal()
|
||||||
|
end, { desc = "which_key_ignore" })
|
||||||
|
vim.keymap.set({ "n", "t" }, "]]", function()
|
||||||
|
Snacks.words.jump(vim.v.count1)
|
||||||
|
end, { desc = "Next Reference" })
|
||||||
|
vim.keymap.set({ "n", "t" }, "[[", function()
|
||||||
|
Snacks.words.jump(-vim.v.count1)
|
||||||
|
end, { desc = "Prev Reference" })
|
||||||
vim.keymap.set("n", "<leader>N", function()
|
vim.keymap.set("n", "<leader>N", function()
|
||||||
Snacks.win({
|
Snacks.win({
|
||||||
file = vim.api.nvim_get_runtime_file("doc/news.txt", false)[1],
|
file = vim.api.nvim_get_runtime_file("doc/news.txt", false)[1],
|
||||||
width = 0.6,
|
width = 0.6,
|
||||||
height = 0.6,
|
height = 0.6,
|
||||||
wo = {
|
wo = {
|
||||||
spell = false,
|
spell = false,
|
||||||
wrap = false,
|
wrap = false,
|
||||||
signcolumn = "yes",
|
signcolumn = "yes",
|
||||||
statuscolumn = " ",
|
statuscolumn = " ",
|
||||||
conceallevel = 3,
|
conceallevel = 3,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
end, { desc = "Neovim News" })
|
end, { desc = "Neovim News" })
|
||||||
|
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
|
|
||||||
-- Leap Keymaps
|
-- Leap Keymaps
|
||||||
vim.keymap.set({ 'n', 'x', 'o' }, '<CR>', '<Plug>(leap)')
|
vim.keymap.set({ "n", "x", "o" }, "<CR>", "<Plug>(leap)")
|
||||||
vim.keymap.set('n', 'S', '<Plug>(leap-from-window)')
|
vim.keymap.set("n", "S", "<Plug>(leap-from-window)")
|
||||||
|
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
|
|
||||||
-- Conform Keymaps
|
-- Conform Keymaps
|
||||||
vim.keymap.set({ "n", "v" }, "<leader>cf", function()
|
vim.keymap.set({ "n", "v" }, "<leader>cf", function()
|
||||||
require("conform").format({ lsp_format = "fallback" })
|
require("conform").format({ lsp_format = "fallback" })
|
||||||
end, { desc = "Format Buffer" })
|
end, { desc = "Format Buffer" })
|
||||||
|
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
@@ -174,7 +323,15 @@ vim.keymap.set("n", "<leader>uu", "<cmd>UndotreeToggle<cr>", { desc = "Toggle Un
|
|||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
|
|
||||||
-- Persistence Keymaps
|
-- Persistence Keymaps
|
||||||
vim.keymap.set("n", "<leader>qs", function() require("persistence").load() end, { desc = "Restore Session" })
|
vim.keymap.set("n", "<leader>qs", function()
|
||||||
vim.keymap.set("n", "<leader>qS", function() require("persistence").select() end, { desc = "Select Session" })
|
require("persistence").load()
|
||||||
vim.keymap.set("n", "<leader>ql", function() require("persistence").load({ last = true }) end, { desc = "Restore Last Session" })
|
end, { desc = "Restore Session" })
|
||||||
vim.keymap.set("n", "<leader>qd", function() require("persistence").stop() end, { desc = "Don't Save Current Session" })
|
vim.keymap.set("n", "<leader>qS", function()
|
||||||
|
require("persistence").select()
|
||||||
|
end, { desc = "Select Session" })
|
||||||
|
vim.keymap.set("n", "<leader>ql", function()
|
||||||
|
require("persistence").load({ last = true })
|
||||||
|
end, { desc = "Restore Last Session" })
|
||||||
|
vim.keymap.set("n", "<leader>qd", function()
|
||||||
|
require("persistence").stop()
|
||||||
|
end, { desc = "Don't Save Current Session" })
|
||||||
|
|||||||
+108
@@ -4,6 +4,10 @@
|
|||||||
└────────────────────────────────────────────────────────────────┘
|
└────────────────────────────────────────────────────────────────┘
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
|
-- Set leader keys before any other configuration
|
||||||
|
vim.g.mapleader = " "
|
||||||
|
vim.g.maplocalleader = "\\"
|
||||||
|
|
||||||
-- Copyright (C) 2026 rootiest
|
-- Copyright (C) 2026 rootiest
|
||||||
--
|
--
|
||||||
-- This program is free software: you can redistribute it and/or modify
|
-- This program is free software: you can redistribute it and/or modify
|
||||||
@@ -66,3 +70,107 @@ vim.api.nvim_create_user_command("Format", function(args)
|
|||||||
end
|
end
|
||||||
require("conform").format({ async = true, lsp_format = "fallback", range = range })
|
require("conform").format({ async = true, lsp_format = "fallback", range = range })
|
||||||
end, { range = true })
|
end, { range = true })
|
||||||
|
|
||||||
|
--[[
|
||||||
|
┌────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Root Management │
|
||||||
|
└────────────────────────────────────────────────────────────────┘
|
||||||
|
--]]
|
||||||
|
|
||||||
|
-- Automatically change the working directory to the project root.
|
||||||
|
-- This ensures that plugins like Snacks.picker and GrugFar work
|
||||||
|
-- relative to the file or project you are currently editing.
|
||||||
|
vim.api.nvim_create_autocmd("BufEnter", {
|
||||||
|
group = vim.api.nvim_create_augroup("rootiest_auto_cd", { clear = true }),
|
||||||
|
callback = function()
|
||||||
|
local path = vim.api.nvim_buf_get_name(0)
|
||||||
|
if path == "" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Skip special buffers, but allow directory buffers (for explorer support)
|
||||||
|
if vim.bo.buftype ~= "" and vim.bo.filetype ~= "snacks_explorer_tree" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get the directory (handle both files and directory paths)
|
||||||
|
local dir = vim.fn.isdirectory(path) == 1 and path or vim.fn.fnamemodify(path, ":p:h")
|
||||||
|
|
||||||
|
-- Find the project root using common markers, fallback to the directory itself
|
||||||
|
local root = vim.fs.root(dir, { ".git", "lua", "package.json", "go.mod", "Cargo.toml", "Makefile" }) or dir
|
||||||
|
|
||||||
|
-- Change directory if it's different and valid
|
||||||
|
if root and vim.fn.isdirectory(root) == 1 and root ~= vim.fn.getcwd() then
|
||||||
|
vim.fn.chdir(root)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Grug-far QoL: Close with 'q'
|
||||||
|
vim.api.nvim_create_autocmd("FileType", {
|
||||||
|
group = vim.api.nvim_create_augroup("grug_far_q_to_close", { clear = true }),
|
||||||
|
pattern = "grug-far",
|
||||||
|
callback = function(args)
|
||||||
|
vim.keymap.set("n", "q", "<cmd>close<cr>", { buffer = args.buf, silent = true, desc = "Close Grug-far" })
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
--[[
|
||||||
|
┌────────────────────────────────────────────────────────────────┐
|
||||||
|
│ Shell Interaction │
|
||||||
|
└────────────────────────────────────────────────────────────────┘
|
||||||
|
--]]
|
||||||
|
|
||||||
|
-- Detect terminal environment
|
||||||
|
local is_kitty = os.getenv("KITTY_PID") ~= nil
|
||||||
|
local current_shell = os.getenv("SHELL") or "/bin/sh"
|
||||||
|
local shell_name = current_shell:match("([^/]+)$") or "sh"
|
||||||
|
|
||||||
|
-- Helper function to update the terminal title
|
||||||
|
local function set_terminal_title(title)
|
||||||
|
-- If in Kitty, we use the direct escape sequence as it's reliable
|
||||||
|
if is_kitty then
|
||||||
|
io.stdout:write("\27]2;" .. title .. "\7")
|
||||||
|
-- Fallback: Use Neovim's built-in title management for other terminals
|
||||||
|
-- (Standard OSC 2 sequences are supported by most, but opt.title is safer)
|
||||||
|
elseif os.getenv("TERM") ~= "linux" then
|
||||||
|
vim.opt.title = true
|
||||||
|
vim.opt.titlestring = title
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Create the Autocommand Group
|
||||||
|
local title_group = vim.api.nvim_create_augroup("TerminalTitle", { clear = true })
|
||||||
|
|
||||||
|
vim.api.nvim_create_autocmd({ "BufEnter", "BufWinEnter" }, {
|
||||||
|
group = title_group,
|
||||||
|
callback = function()
|
||||||
|
local buftype = vim.bo.buftype
|
||||||
|
local filetype = vim.bo.filetype
|
||||||
|
local filename = vim.fn.expand("%:t")
|
||||||
|
|
||||||
|
-- 1. Specifically catch Snacks Terminal or standard Terminals
|
||||||
|
if filetype == "snacks_terminal" or buftype == "terminal" then
|
||||||
|
set_terminal_title("NVIM: Terminal")
|
||||||
|
|
||||||
|
-- 2. Handle normal files (buftype is empty)
|
||||||
|
elseif buftype == "" and filename ~= "" then
|
||||||
|
set_terminal_title("NVIM: " .. filename)
|
||||||
|
|
||||||
|
-- 3. Handle the empty start screen
|
||||||
|
elseif filename == "" and buftype == "" then
|
||||||
|
set_terminal_title("Neovim")
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
-- Reset the title back to the shell name when you quit Neovim
|
||||||
|
vim.api.nvim_create_autocmd("VimLeave", {
|
||||||
|
group = title_group,
|
||||||
|
callback = function()
|
||||||
|
-- On leave, direct stdout is more reliable than setting an option
|
||||||
|
if is_kitty or os.getenv("TERM") ~= "linux" then
|
||||||
|
io.stdout:write("\27]2;" .. shell_name .. "\7")
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user