tenseleyflow/ndotfiles / 76a2ea1

Browse files

neovim

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
76a2ea1a3f3b326de5800206315dea5aff884fdd
Parents
f20affe
Tree
81330ea

2 changed files

StatusFile+-
M notes/neovim.md 168 105
A nvim/init.lua 267 0
notes/neovim.mdmodified
@@ -1,105 +1,168 @@
1
-# Neovim Keybind Guide for Modern Usage
1
+# Neovim Modern Workflow & Plugin Guide
2
-
2
+
3
-This guide provides a concise reference for keybindings in Neovim (version 0.7 or later), focusing on quick navigation, jumping between words and lines, and handling multiple cursors or selections. Master these to enhance your productivity in this powerful text editor.
3
+This guide extends the default Neovim keybinds with **modern workflows** (LSP, Telescope, Treesitter, Git, terminals) for Neovim ≥ 0.8. Designed for productivity on Wayland/Hyprland with lazy.nvim config.
4
-
4
+
5
-## Neovim Modes Overview
5
+---
6
-
6
+
7
-Neovim operates in distinct modes, each serving specific purposes. Understanding these is essential for effective editing.
7
+## Modes Overview
8
-
8
+
9
-| Mode            | Description                                      | How to Enter                     |
9
+| Mode            | Description                                   | Enter From            |
10
-|-----------------|--------------------------------------------------|----------------------------------|
10
+|-----------------|-----------------------------------------------|-----------------------|
11
-| **Normal Mode** | Default mode for navigation and commands        | Press `Esc` from other modes     |
11
+| **Normal**      | Navigation, commands                         | `Esc`                 |
12
-| **Insert Mode** | For typing and inserting text                   | Press `i`, `a`, `o`, etc. from Normal Mode |
12
+| **Insert**      | Insert/typing                                | `i`, `a`, `o`, `O`    |
13
-| **Visual Mode** | For selecting text (line, block, or character)  | Press `v`, `V`, or `Ctrl+v` from Normal Mode |
13
+| **Visual**      | Select text (char, line, block)              | `v`, `V`, `Ctrl+v`    |
14
-| **Command Mode**| For entering Ex commands (e.g., saving, quitting)| Press `:` from Normal Mode       |
14
+| **Command**     | Ex commands (`:w`, `:q`)                     | `:`                   |
15
-
15
+| **Terminal**    | Interactive terminal buffer                  | `:term`, `<C-`>`      |
16
-## Navigation Keybindings
16
+
17
-
17
+---
18
-These keybindings are primarily for **Normal Mode** and help you move around your editor efficiently.
18
+
19
-
19
+## Navigation Keybindings (Default)
20
-### Basic Movement
20
+
21
-| Keybind       | Action                            |
21
+| Keybind    | Action                               |
22
-|---------------|-----------------------------------|
22
+|------------|--------------------------------------|
23
-| `h`           | Move left one character          |
23
+| `h`/`l`    | Left / right one character           |
24
-| `j`           | Move down one line               |
24
+| `j`/`k`    | Down / up one line                   |
25
-| `k`           | Move up one line                 |
25
+| `w`/`e`/`b`| Next word / end word / back a word   |
26
-| `l`           | Move right one character         |
26
+| `0` / `$`  | Start / end of line                  |
27
-| `w`           | Jump to start of next word       |
27
+| `gg` / `G` | First / last line of file            |
28
-| `b`           | Jump to start of previous word   |
28
+| `{n}G`     | Jump to line n                       |
29
-| `e`           | Jump to end of current/next word |
29
+| `Ctrl+u/d` | Scroll half screen up/down           |
30
-| `0`           | Jump to start of line            |
30
+| `Ctrl+b/f` | Scroll full screen up/down           |
31
-| `$`           | Jump to end of line              |
31
+| `%`        | Match brackets/parentheses           |
32
-| `gg`          | Jump to first line of file       |
32
+| `/text`    | Search forward (n/N = next/prev)     |
33
-| `G`           | Jump to last line of file        |
33
+| `?text`    | Search backward (n/N = next/prev)    |
34
-| `{number}G`   | Jump to specific line number (e.g., `5G` for line 5) |
34
+| `*` / `#`  | Next/prev word under cursor          |
35
-
35
+
36
-### Scrolling and Larger Jumps
36
+---
37
-| Keybind       | Action                            |
37
+
38
-|---------------|-----------------------------------|
38
+## Editing Essentials
39
-| `Ctrl+u`      | Scroll up half a screen          |
39
+
40
-| `Ctrl+d`      | Scroll down half a screen        |
40
+| Keybind | Action                                   |
41
-| `Ctrl+b`      | Scroll up a full screen (backward)|
41
+|---------|------------------------------------------|
42
-| `Ctrl+f`      | Scroll down a full screen (forward)|
42
+| `i`/`a` | Insert before / after cursor             |
43
-| `%`           | Jump to matching bracket/parenthesis |
43
+| `o`/`O` | New line below / above                   |
44
-
44
+| `x`     | Delete character                         |
45
-### Search-Based Navigation
45
+| `dd`    | Delete line                              |
46
-| Keybind       | Action                            |
46
+| `yy`    | Yank (copy) line                         |
47
-|---------------|-----------------------------------|
47
+| `p`/`P` | Paste after / before cursor              |
48
-| `/` + `text` + `Enter` | Search forward for text; use `n` for next, `N` for previous |
48
+| `.`     | Repeat last command                      |
49
-| `?` + `text` + `Enter` | Search backward for text; use `n` for next, `N` for previous |
49
+| `{n}{op}` | Repeat operation n times (`5dd`)       |
50
-| `*`           | Jump to next occurrence of word under cursor |
50
+
51
-| `#`           | Jump to previous occurrence of word under cursor |
51
+### Visual Mode Tricks
52
-
52
+- `v`/`V`/`Ctrl+v` → char/line/block selections
53
-## Editing and Multi-Cursor Techniques
53
+- Block mode (`Ctrl+v` + `j/k`):
54
-
54
+  - `I` insert before selection (applies to all lines)
55
-Neovim lacks native multi-cursor support, but Visual Mode and other features provide powerful alternatives. These are mostly **Normal Mode** commands unless noted.
55
+  - `A` append after selection
56
-
56
+
57
-### Basic Editing
57
+---
58
-| Keybind       | Action                            |
58
+
59
-|---------------|-----------------------------------|
59
+## Custom Workflow Keymaps (from lazy config)
60
-| `i`           | Enter Insert Mode before cursor   |
60
+
61
-| `a`           | Enter Insert Mode after cursor    |
61
+| Keybind     | Action                              |
62
-| `o`           | Open new line below, enter Insert Mode |
62
+|-------------|-------------------------------------|
63
-| `O`           | Open new line above, enter Insert Mode |
63
+| `<C-s>`     | Save (normal/insert/visual)         |
64
-| `x`           | Delete character under cursor     |
64
+| `<leader>q` | Quit                                |
65
-| `dd`          | Delete current line               |
65
+| `<leader>sv`| Vertical split                      |
66
-| `yy`          | Yank (copy) current line          |
66
+| `<leader>sh`| Horizontal split                    |
67
-| `p`           | Paste after cursor                |
67
+| `<leader>to`| New tab                             |
68
-| `P`           | Paste before cursor               |
68
+| `<leader>ff`| Telescope: find files               |
69
-
69
+| `<leader>fg`| Telescope: live grep                |
70
-### Visual Mode for Selections (Multi-Cursor Alternative)
70
+| `<leader>fb`| Telescope: buffers                  |
71
-| Keybind       | Action                            |
71
+| `<leader>fh`| Telescope: help tags                |
72
-|---------------|-----------------------------------|
72
+| `-`         | Oil file manager float              |
73
-| `v`           | Start character-wise Visual Mode  |
73
+| `<C-`>`     | Toggle floating terminal            |
74
-| `V`           | Start line-wise Visual Mode       |
74
+| `<leader>tr`| Run task (Overseer)                 |
75
-| `Ctrl+v`      | Start block-wise Visual Mode (for columnar edits) |
75
+| `<leader>tt`| Task list toggle                    |
76
-| After selection, `I` | Insert at start of each selected line/block (block mode) |
76
+| `<leader>f` | Format buffer/file (Conform)        |
77
-| After selection, `A` | Append at end of each selected line/block (block mode) |
77
+
78
-
78
+---
79
-**Note:** For block edits, select with `Ctrl+v`, move with `j`/`k`, then use `I` or `A` to edit multiple lines at once. Press `Esc` to apply changes.
79
+
80
-
80
+## LSP Workflow (Language Server Protocol)
81
-### Repeating Commands for Efficient Edits
81
+
82
-| Keybind       | Action                            |
82
+Requires `mason.nvim` + `nvim-lspconfig`.
83
-|---------------|-----------------------------------|
83
+
84
-| `.`           | Repeat the last command          |
84
+| Keybind     | Action                               |
85
-| `{number}{command}` | Repeat command a specific number of times (e.g., `5dd` deletes 5 lines) |
85
+|-------------|--------------------------------------|
86
-
86
+| `gd`        | Goto definition                      |
87
-## Plugin for True Multi-Cursor Support
87
+| `gD`        | Goto declaration                     |
88
-
88
+| `gi`        | Goto implementation                  |
89
-For a modern multi-cursor experience (like VS Code), install the `vim-visual-multi` plugin.
89
+| `gr`        | List references                      |
90
-
90
+| `K`         | Hover docs                           |
91
-| Plugin        | Keybind       | Action                            |
91
+| `<leader>rn`| Rename symbol                        |
92
-|---------------|---------------|-----------------------------------|
92
+| `<leader>ca`| Code action                          |
93
-| `vim-visual-multi` | `Ctrl+n` | Start multi-cursor or add cursor at next word occurrence |
93
+| `<leader>fd`| Format buffer (LSP/formatter)        |
94
-| `vim-visual-multi` | `Ctrl+p` | Add cursor at previous occurrence |
94
+
95
-| `vim-visual-multi` | `Ctrl+x` | Skip an occurrence               |
95
+---
96
-
96
+
97
-**Installation:** Add via plugin manager, e.g., `Plug 'mg979/vim-visual-multi'` with vim-plug.
97
+## Git Integration
98
-
98
+
99
-## Quick Tips for Efficiency
99
+- **Gitsigns.nvim**  
100
--  **Practice Normal Mode:** Use it for navigation to minimize mode-switching.
100
+  - Shows inline git diff signs, hunk navigation (`]c` / `[c`), staging hunks (`:Gitsigns stage_hunk`).
101
--  **Leverage `.` for Repetition:** Repeat edits quickly with the dot operator.
101
+
102
--  **Combine Commands:** Use motions with actions, e.g., `d2w` (delete 2 words) or `c$` (change to end of line).
102
+- **LazyGit.nvim**  
103
--  **Use `:help`:** Type `:help key-notation` or `:help motion` in Neovim for detailed docs.
103
+  - `:LazyGit` launches interactive TUI for Git inside Neovim.
104
-
104
+
105
-This tabulated guide focuses on default Neovim keybindings and practical workflows. For customizations or plugin setup help, let me know!
105
+---
106
+
107
+## Telescope (Fuzzy Finder)
108
+
109
+- `<leader>ff` → Files
110
+- `<leader>fg` → Live grep
111
+- `<leader>fb` → Buffers
112
+- `<leader>fh` → Help tags
113
+
114
+Extra: type `/` inside Telescope for fuzzy-in-list filtering.
115
+
116
+---
117
+
118
+## Treesitter (Syntax Engine)
119
+
120
+- Auto-installs parsers for `bash`, `c/cpp`, `lua`, `python`, `rust`, `json`, `yaml`, `toml`, `html/css/js/ts`, `markdown`, `fish`, **fortran**.
121
+- Provides better highlighting + indenting.
122
+
123
+---
124
+
125
+## Formatting (Conform.nvim)
126
+
127
+| Language     | Formatter(s)                         |
128
+|--------------|--------------------------------------|
129
+| Lua          | stylua                               |
130
+| Python       | ruff_format, black                   |
131
+| Shell/Fish   | shfmt, fish_indent                   |
132
+| C/C++        | clang-format                         |
133
+| JS/TS/HTML   | prettier                             |
134
+| JSON/YAML    | jq / prettier                        |
135
+| TOML         | taplo                                |
136
+| Markdown     | prettier                             |
137
+| Fortran      | fprettify                            |
138
+
139
+---
140
+
141
+## Debugging (nvim-dap + dap-ui)
142
+
143
+- `:DapToggleBreakpoint` → set/clear breakpoint
144
+- `:DapContinue` → run/start
145
+- `:DapStepOver` / `:DapStepInto` / `:DapStepOut`
146
+- DAP UI auto-opens on session start.
147
+
148
+---
149
+
150
+## Bonus: Multi-Cursor
151
+
152
+- Native block selections: `Ctrl+v` + `I`/`A`
153
+- True multi-cursor: install **vim-visual-multi**
154
+  - `Ctrl+n` → add cursor to next occurrence
155
+  - `Ctrl+p` → add cursor to prev
156
+  - `Ctrl+x` → skip
157
+
158
+---
159
+
160
+## Quick Efficiency Tips
161
+- Use `.` to repeat edits, `:noh` to clear highlights
162
+- Combine motions: `d2w` (delete 2 words), `c$` (change to end of line)
163
+- Use **Overseer** for project build/run/test integration
164
+- Map `-` (Oil) for directory browsing like a mini file manager
165
+- Use `<C-`>` as a popup shell without leaving Neovim
166
+- Keep `<leader>` easy (`<Space>` in this config) for speed
167
+
168
+---
nvim/init.luaadded
@@ -0,0 +1,267 @@
1
+-- smooth editing, LSP, Treesitter, Telescope, formatting, Git, terminals, and a few QoL boosts.
2
+
3
+---------------------------------------------------------------
4
+-- 0) Bootstrap lazy.nvim (plugin manager)
5
+---------------------------------------------------------------
6
+local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
7
+if not vim.loop.fs_stat(lazypath) then
8
+  vim.fn.system({
9
+    "git", "clone", "--filter=blob:none",
10
+    "https://github.com/folke/lazy.nvim.git", "--branch=stable", lazypath,
11
+  })
12
+end
13
+vim.opt.rtp:prepend(lazypath)
14
+
15
+---------------------------------------------------------------
16
+-- 1) Core settings (Wayland-safe clipboard, sensible defaults)
17
+---------------------------------------------------------------
18
+vim.g.mapleader = " "
19
+vim.g.maplocalleader = ","
20
+
21
+local opt = vim.opt
22
+opt.number = true
23
+opt.relativenumber = true
24
+opt.signcolumn = "yes"
25
+opt.termguicolors = true
26
+opt.cursorline = true
27
+opt.wrap = false
28
+opt.scrolloff = 5
29
+opt.sidescrolloff = 8
30
+opt.expandtab = true
31
+opt.shiftwidth = 2
32
+opt.tabstop = 2
33
+opt.smartindent = true
34
+opt.ignorecase = true
35
+opt.smartcase = true
36
+opt.incsearch = true
37
+opt.splitbelow = true
38
+opt.splitright = true
39
+opt.updatetime = 300
40
+opt.timeoutlen = 400
41
+opt.undofile = true
42
+opt.clipboard = "unnamedplus"   -- uses wl-clipboard on Wayland if installed
43
+
44
+---------------------------------------------------------------
45
+-- 2) Plugins via lazy.nvim
46
+---------------------------------------------------------------
47
+require("lazy").setup({
48
+  -- UI + UX ---------------------------------------------------
49
+  { "folke/tokyonight.nvim", lazy = false, priority = 1000, opts = { style = "night" } },
50
+  { "nvim-lualine/lualine.nvim", dependencies = { "nvim-tree/nvim-web-devicons" },
51
+    opts = { options = { theme = "auto", globalstatus = true } } },
52
+  { "folke/which-key.nvim", event = "VeryLazy", opts = {} },
53
+  { "stevearc/dressing.nvim", event = "VeryLazy", opts = {} },
54
+  { "rcarriga/nvim-notify", opts = { timeout = 2000 } },
55
+  { "folke/noice.nvim", event = "VeryLazy", dependencies = { "MunifTanjim/nui.nvim", "rcarriga/nvim-notify" },
56
+    opts = { presets = { command_palette = true, long_message_to_split = true } } },
57
+  { "lukas-reineke/indent-blankline.nvim", main = "ibl", opts = {} },
58
+  { "numToStr/Comment.nvim", opts = {} },
59
+  { "kylechui/nvim-surround", event = "VeryLazy", opts = {} },
60
+
61
+  -- Files, search, projects ----------------------------------
62
+  { "nvim-telescope/telescope.nvim", dependencies = { "nvim-lua/plenary.nvim" } },
63
+  { "nvim-telescope/telescope-fzf-native.nvim", build = "make", cond = function() return vim.fn.executable("make") == 1 end },
64
+  { "ahmedkhalf/project.nvim", opts = { detection_methods = { "pattern", "lsp" }, patterns = { ".git", "pyproject.toml", "package.json", "Makefile" } } },
65
+  { "stevearc/oil.nvim", opts = { view_options = { show_hidden = true } } },
66
+
67
+  -- Git -------------------------------------------------------
68
+  { "lewis6991/gitsigns.nvim", opts = {} },
69
+  { "kdheepak/lazygit.nvim", cmd = { "LazyGit" } },
70
+
71
+  -- Terminal & task runner -----------------------------------
72
+  { "akinsho/toggleterm.nvim", version = "*", opts = { open_mapping = [[<C-`>]], direction = "float" } },
73
+  { "stevearc/overseer.nvim", opts = {} },
74
+
75
+  -- Treesitter ------------------------------------------------
76
+  { "nvim-treesitter/nvim-treesitter", build = ":TSUpdate", opts = {
77
+      ensure_installed = {
78
+        "bash", "c", "cpp", "lua", "python", "rust", "json", "yaml", "toml",
79
+        "html", "css", "javascript", "typescript", "markdown", "markdown_inline",
80
+        "make", "fish", "fortran"
81
+      },
82
+      highlight = { enable = true },
83
+      indent = { enable = true },
84
+    }
85
+  },
86
+
87
+  -- LSP, format, lint ----------------------------------------
88
+  { "williamboman/mason.nvim", opts = { ui = { border = "rounded" } } },
89
+  { "williamboman/mason-lspconfig.nvim" },
90
+  { "neovim/nvim-lspconfig" },
91
+  { "stevearc/conform.nvim", opts = {
92
+      notify_on_error = false,
93
+      format_on_save = function(buf)
94
+        -- Disable on big files
95
+        local ok, stats = pcall(vim.loop.fs_stat, vim.api.nvim_buf_get_name(buf))
96
+        if ok and stats and stats.size > 512 * 1024 then return end
97
+        return { timeout_ms = 2000, lsp_fallback = true }
98
+      end,
99
+      formatters_by_ft = {
100
+        lua = { "stylua" },
101
+        python = { "ruff_format", "black" },
102
+        sh = { "shfmt" }, bash = { "shfmt" }, zsh = { "shfmt" }, fish = { "fish_indent" },
103
+        c = { "clang_format" }, cpp = { "clang_format" },
104
+        javascript = { "prettier" }, typescript = { "prettier" },
105
+        json = { "jq", "prettier" }, yaml = { "prettier" }, toml = { "taplo" },
106
+        html = { "prettier" }, css = { "prettier" }, markdown = { "prettier" },
107
+        fortran = { "fprettify" },
108
+      },
109
+    }
110
+  },
111
+
112
+  -- Debugging (optional, light defaults) ---------------------
113
+  { "mfussenegger/nvim-dap" },
114
+  { "rcarriga/nvim-dap-ui", dependencies = { "mfussenegger/nvim-dap" } },
115
+}, {
116
+  install = { colorscheme = { "tokyonight" } },
117
+  change_detection = { notify = false },
118
+})
119
+
120
+---------------------------------------------------------------
121
+-- 3) Post-plugin config (LSP, Telescope, keymaps, etc.)
122
+---------------------------------------------------------------
123
+-- Colorscheme
124
+vim.cmd.colorscheme("tokyonight")
125
+
126
+-- Lualine
127
+require("lualine").setup({})
128
+
129
+-- Telescope
130
+local telescope = require("telescope")
131
+telescope.setup({ defaults = { mappings = { i = { ["<C-j>"] = "move_selection_next", ["<C-k>"] = "move_selection_previous" } } } })
132
+pcall(telescope.load_extension, "fzf")
133
+
134
+-- Oil: simple file manager toggle
135
+vim.keymap.set("n", "-", function() require("oil").toggle_float() end, { desc = "Oil file manager" })
136
+
137
+-- ToggleTerm: float terminal with <C-`>
138
+-- (Already mapped via opts. Add extra terminals if desired.)
139
+
140
+-- Overseer: tasks (build, run, test)
141
+vim.keymap.set("n", "<leader>tt", ":OverseerToggle<CR>", { desc = "Toggle task list" })
142
+vim.keymap.set("n", "<leader>tr", ":OverseerRun<CR>",    { desc = "Run a task" })
143
+
144
+-- Gitsigns
145
+require("gitsigns").setup()
146
+
147
+-- Treesitter
148
+require("nvim-treesitter.configs").setup({})
149
+
150
+-- Mason + LSPConfig
151
+require("mason").setup()
152
+local mlsp = require("mason-lspconfig")
153
+mlsp.setup({ ensure_installed = {
154
+  "pyright", "ruff_lsp", "lua_ls", "clangd", "rust_analyzer", "bashls",
155
+  "jsonls", "yamlls", "html", "cssls", "ts_ls", "marksman", "taplo", "fortls"
156
+}})
157
+
158
+local lspconfig = require("lspconfig")
159
+local capabilities = vim.lsp.protocol.make_client_capabilities()
160
+local ok_cmp, cmp_lsp = pcall(require, "cmp_nvim_lsp")
161
+if ok_cmp then capabilities = cmp_lsp.default_capabilities(capabilities) end
162
+
163
+-- Pretty borders
164
+local handlers = {
165
+  ["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { border = "rounded" }),
166
+  ["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, { border = "rounded" }),
167
+}
168
+
169
+-- on_attach: buffer-local mappings
170
+local on_attach = function(_, bufnr)
171
+  local nmap = function(keys, func, desc)
172
+    vim.keymap.set("n", keys, func, { buffer = bufnr, desc = desc })
173
+  end
174
+  nmap("gd", vim.lsp.buf.definition, "Goto Definition")
175
+  nmap("gr", vim.lsp.buf.references, "References")
176
+  nmap("gD", vim.lsp.buf.declaration, "Goto Declaration")
177
+  nmap("gi", vim.lsp.buf.implementation, "Goto Implementation")
178
+  nmap("K",  vim.lsp.buf.hover, "Hover")
179
+  nmap("<leader>rn", vim.lsp.buf.rename, "Rename symbol")
180
+  nmap("<leader>ca", vim.lsp.buf.code_action, "Code Action")
181
+  nmap("<leader>fd", function() vim.lsp.buf.format({ async = true }) end, "Format buffer")
182
+end
183
+
184
+mlsp.setup_handlers({ function(server)
185
+  lspconfig[server].setup({ capabilities = capabilities, on_attach = on_attach, handlers = handlers })
186
+end })
187
+
188
+-- Lua LS: tuned for Neovim config dev
189
+lspconfig.lua_ls.setup({
190
+  capabilities = capabilities,
191
+  on_attach = on_attach,
192
+  settings = { Lua = { diagnostics = { globals = { "vim" } }, workspace = { checkThirdParty = false } } }
193
+})
194
+
195
+-- Ruff: prefer as linter + fixer with Pyright for types
196
+lspconfig.ruff_lsp.setup({ capabilities = capabilities, on_attach = on_attach })
197
+
198
+-- DAP minimal sugar
199
+local dap_ok, dapui = pcall(require, "dapui")
200
+if dap_ok then
201
+  dapui.setup()
202
+  local dap = require("dap")
203
+  dap.listeners.after.event_initialized["dapui_config"] = function() dapui.open() end
204
+  dap.listeners.before.event_terminated["dapui_config"] = function() dapui.close() end
205
+  dap.listeners.before.event_exited["dapui_config"]      = function() dapui.close() end
206
+end
207
+
208
+---------------------------------------------------------------
209
+-- 4) Keymaps you’ll actually use (and remember)
210
+---------------------------------------------------------------
211
+local map = vim.keymap.set
212
+-- Save, quit
213
+map({"n","i","v"}, "<C-s>", function() vim.cmd("silent w") end, { desc = "Save" })
214
+map("n", "<leader>q", ":q<CR>", { desc = "Quit" })
215
+
216
+-- Windows and tabs
217
+map("n", "<leader>sv", ":vsplit<CR>", { desc = "Split vertical" })
218
+map("n", "<leader>sh", ":split<CR>",  { desc = "Split horizontal" })
219
+map("n", "<leader>to", ":tabnew<CR>",  { desc = "New tab" })
220
+
221
+-- Telescope
222
+map("n", "<leader>ff", function() require("telescope.builtin").find_files() end, { desc = "Find files" })
223
+map("n", "<leader>fg", function() require("telescope.builtin").live_grep()  end, { desc = "Live grep" })
224
+map("n", "<leader>fb", function() require("telescope.builtin").buffers()    end, { desc = "Buffers" })
225
+map("n", "<leader>fh", function() require("telescope.builtin").help_tags()  end, { desc = "Help tags" })
226
+
227
+-- Move lines (visual)
228
+map("v", "J", ":m '>+1<CR>gv=gv")
229
+map("v", "K", ":m '<-2<CR>gv=gv")
230
+
231
+-- Clear search
232
+map("n", "<Esc>", ":noh<CR>", { silent = true })
233
+
234
+-- Format
235
+map("n", "<leader>f", function() require("conform").format({ lsp_fallback = true }) end, { desc = "Format file" })
236
+
237
+---------------------------------------------------------------
238
+-- 5) Small QoL autocommands
239
+---------------------------------------------------------------
240
+-- Restore cursor to last position
241
+vim.api.nvim_create_autocmd("BufReadPost", {
242
+  callback = function()
243
+    local mark = vim.api.nvim_buf_get_mark(0, '"')
244
+    local lcount = vim.api.nvim_buf_line_count(0)
245
+    if mark[1] > 0 and mark[1] <= lcount then
246
+      pcall(vim.api.nvim_win_set_cursor, 0, mark)
247
+    end
248
+  end
249
+})
250
+
251
+-- Highlight on yank
252
+vim.api.nvim_create_autocmd("TextYankPost", {
253
+  callback = function() vim.highlight.on_yank({ higroup = "IncSearch", timeout = 120 }) end
254
+})
255
+
256
+-- Wayland clipboard fix hint (if clipboard missing)
257
+if vim.env.WAYLAND_DISPLAY and vim.o.clipboard ~= "unnamedplus" then
258
+  vim.notify("Tip: install 'wl-clipboard' and set clipboard=unnamedplus for system clipboard.", vim.log.levels.INFO)
259
+end
260
+
261
+---------------------------------------------------------------
262
+-- 6) Add language tools via Mason: :Mason
263
+--    Choose servers/formatters: pyright, ruff, lua_ls, clangd, rust_analyzer, bashls,
264
+--    jsonls, yamlls, html, cssls, tsserver/ts_ls, marksman, taplo, fortls, etc.
265
+--    Then enjoy: <leader>ff (files), <leader>fg (grep), <C-`> (terminal), - (Oil),
266
+--    <leader>f (format), gd/gr/K, and :OverseerRun for project tasks.
267
+---------------------------------------------------------------