diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000000..221e424175f --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,80 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +Kickstart-based Neovim config using lazy.nvim as the plugin manager. Single `init.lua` + modular custom plugins under `lua/custom/plugins/`. + +## Plugin Manager + +lazy.nvim — plugins defined as lazy specs (`return { "owner/repo", ... }`). + +Update plugins: `:Lazy update` +Check status: `:Lazy` +Install/manage LSP tools: `:Mason` + +## Structure + +``` +init.lua — Sections 1–9: foundation → plugins +lua/custom/plugins/init.lua — Auto-loads all *.lua files in same dir +lua/custom/plugins/*.lua — User-added plugins (no merge conflicts from upstream) +lua/kickstart/plugins/*.lua — Optional kickstart examples (indent_line, lint, gitsigns) +lazy-lock.json — Lockfile (commit this) +``` + +`init.lua` is organized into `do...end` blocks by section: +1. Foundation (options, keymaps, autocmds) +2. lazy.nvim bootstrap + setup +3. UI/UX (gitsigns, which-key, mini.nvim, todo-comments) +4. Search/Navigation (Telescope) +5. LSP (mason, nvim-lspconfig, fidget) +6. Formatting (conform.nvim) +7. Autocomplete & Snippets (blink.cmp + LuaSnip) +8. Treesitter +9. Optional examples + +## Custom Plugins + +| File | Purpose | +|------|---------| +| `claude.lua` | claudecode.nvim — `a*` keymaps; depends on snacks.nvim | +| `lsp.lua` | dbt language server config for SQL/YAML files | +| `markdown.lua` | live-preview.nvim | +| `notebook.lua` | molten-nvim (Jupyter), image.nvim (magick_cli), wezterm.nvim | +| `oil.lua` | oil.nvim file manager via mini.icons | +| `themes.lua` | gruvbox-medium (active), tokyonight (installed) | +| `toggle-term.lua` | toggleterm.nvim terminal toggle | + +## LSP + +Servers are configured in `init.lua:670` via `vim.lsp.config(name, server)` + `vim.lsp.enable(name)`. +Custom dbt server lives in `lua/custom/plugins/lsp.lua` — requires `dbt-language-server` in `$PATH`. +Lua formatting disabled in `lua_ls`; formatting delegated to `stylua` via conform.nvim. + +## Key Bindings (leader = ``) + +- `s*` — Telescope search +- `f` — format buffer (conform) +- `a*` — Claude Code integration +- `h*` — gitsigns hunk operations +- `t*` — toggles (inlay hints, blame, word diff) +- `gr*` — LSP actions (rename, code action, references, definitions) + +## Adding Plugins + +Drop a `.lua` file in `lua/custom/plugins/` — auto-required on next start. Use the lazy spec pattern: + +```lua +return { + "owner/repo", + opts = {}, +} +``` + +## Formatting & Linting + +- **Formatter**: conform.nvim — `f` to format; auto-format on save disabled by default (opt-in per filetype in `init.lua:760`) +- **Linter**: nvim-lint — runs on `BufEnter`/`BufWritePost`/`InsertLeave`; markdownlint for markdown +- **Treesitter**: auto-installs parsers on `FileType` event diff --git a/TEST b/TEST new file mode 100644 index 00000000000..12d9ac99501 --- /dev/null +++ b/TEST @@ -0,0 +1,24 @@ + 1. Move the cursor to this line. + + 2. Press [v](v) and move the cursor to the fifth item below. Notice that the + text is highlighted. + + 3. Press the `:`{normal} character. At the bottom of the screen + + `:'<,'>`{vim} + + will appear. + + 4. Type + + `w TEST`{vim} + + where TEST is a filename that does not exist yet. Verify that you see + + `:'<,'>w TEST`{vim} + + before you press ``{normal}. + + 5. Neovim will write the selected lines to the file TEST. Use `:!{unix:(ls),win:(dir)}`{vim} to see it. + Do not remove it yet! We will use it in the next lesson. + diff --git a/config/lazy.lua b/config/lazy.lua new file mode 100644 index 00000000000..594c38a1173 --- /dev/null +++ b/config/lazy.lua @@ -0,0 +1,35 @@ +-- Bootstrap lazy.nvim +local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim' +if not (vim.uv or vim.loop).fs_stat(lazypath) then + local lazyrepo = 'https://github.com/folke/lazy.nvim.git' + local out = vim.fn.system { 'git', 'clone', '--filter=blob:none', '--branch=stable', lazyrepo, lazypath } + if vim.v.shell_error ~= 0 then + vim.api.nvim_echo({ + { 'Failed to clone lazy.nvim:\n', 'ErrorMsg' }, + { out, 'WarningMsg' }, + { '\nPress any key to exit...' }, + }, true, {}) + vim.fn.getchar() + os.exit(1) + end +end +vim.opt.rtp:prepend(lazypath) + +-- Make sure to setup `mapleader` and `maplocalleader` before +-- loading lazy.nvim so that mappings are correct. +-- This is also a good place to setup other settings (vim.opt) +vim.g.mapleader = ' ' +vim.g.maplocalleader = '\\' + +-- Setup lazy.nvim +require('lazy').setup { + spec = { + -- import your plugins + { import = 'plugins' }, + }, + -- Configure any other settings here. See the documentation for more details. + -- colorscheme that will be used when installing plugins. + install = { colorscheme = { 'habamax' } }, + -- automatically check for plugin updates + checker = { enabled = true }, +} diff --git a/init.lua b/init.lua index aff5250e921..77f14504e64 100644 --- a/init.lua +++ b/init.lua @@ -85,7 +85,7 @@ P.S. You can delete this when you're done too. It's your config now! :) --]] -- ============================================================ --- SECTION 1: OPTIONS +-- SECTION 1: FOUNDATION -- Core Neovim settings, leaders, options, basic keymaps, basic autocmds -- ============================================================ do @@ -99,7 +99,7 @@ do vim.g.maplocalleader = ' ' -- Set to true if you have a Nerd Font installed and selected in the terminal - vim.g.have_nerd_font = false + vim.g.have_nerd_font = true -- [[ Setting options ]] -- See `:help vim.o` @@ -171,13 +171,7 @@ do -- instead raise a dialog asking if you wish to save the current file(s) -- See `:help 'confirm'` vim.o.confirm = true -end --- ============================================================ --- SECTION 2: KEYMAPS --- basic keymaps --- ============================================================ -do -- [[ Basic Keymaps ]] -- See `:help vim.keymap.set()` @@ -220,10 +214,10 @@ do vim.keymap.set('t', '', '', { desc = 'Exit terminal mode' }) -- TIP: Disable arrow keys in normal mode - -- vim.keymap.set('n', '', 'echo "Use h to move!!"') - -- vim.keymap.set('n', '', 'echo "Use l to move!!"') - -- vim.keymap.set('n', '', 'echo "Use k to move!!"') - -- vim.keymap.set('n', '', 'echo "Use j to move!!"') + vim.keymap.set('n', '', 'echo "Use h to move!!"') + vim.keymap.set('n', '', 'echo "Use l to move!!"') + vim.keymap.set('n', '', 'echo "Use k to move!!"') + vim.keymap.set('n', '', 'echo "Use j to move!!"') -- Keybinds to make split navigation easier. -- Use CTRL+ to switch between windows @@ -254,730 +248,414 @@ do end -- ============================================================ --- SECTION 3: PLUGIN MANAGER INTRO --- vim.pack intro, build hooks +-- SECTION 2: PLUGIN MANAGER (lazy.nvim) +-- Bootstrap, install, and configure all plugins -- ============================================================ -do - -- [[ Intro to `vim.pack` ]] - -- `vim.pack` is a new plugin manager built into Neovim, - -- which provides a Lua interface for installing and managing plugins. - -- - -- See `:help vim.pack`, `:help vim.pack-examples` or the - -- excellent blog post from the creator of vim.pack and mini.nvim: - -- https://echasnovski.com/blog/2026-03-13-a-guide-to-vim-pack - -- - -- To inspect plugin state and pending updates, run - -- :lua vim.pack.update(nil, { offline = true }) - -- - -- To update plugins, run - -- :lua vim.pack.update() - -- - -- - -- Throughout the rest of the config there will be examples - -- of how to install and configure plugins using `vim.pack`. - -- - -- In this section we set up some autocommands to run build - -- steps for certain plugins after they are installed or updated. - - local function run_build(name, cmd, cwd) - local result = vim.system(cmd, { cwd = cwd }):wait() - if result.code ~= 0 then - local stderr = result.stderr or '' - local stdout = result.stdout or '' - local output = stderr ~= '' and stderr or stdout - if output == '' then output = 'No output from build command.' end - vim.notify(('Build failed for %s:\n%s'):format(name, output), vim.log.levels.ERROR) - end - end - -- This autocommand runs after a plugin is installed or updated and - -- runs the appropriate build command for that plugin if necessary. - -- - -- See `:help vim.pack-events` - vim.api.nvim_create_autocmd('PackChanged', { - callback = function(ev) - local name = ev.data.spec.name - local kind = ev.data.kind - if kind ~= 'install' and kind ~= 'update' then return end - - if name == 'telescope-fzf-native.nvim' and vim.fn.executable 'make' == 1 then - run_build(name, { 'make' }, ev.data.path) - return - end - - if name == 'LuaSnip' then - if vim.fn.has 'win32' ~= 1 and vim.fn.executable 'make' == 1 then run_build(name, { 'make', 'install_jsregexp' }, ev.data.path) end - return - end - - if name == 'nvim-treesitter' then - if not ev.data.active then vim.cmd.packadd 'nvim-treesitter' end - vim.cmd 'TSUpdate' - return - end - end, - }) +-- Bootstrap lazy.nvim +local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim' +if not (vim.uv or vim.loop).fs_stat(lazypath) then + local out = vim.fn.system { + 'git', + 'clone', + '--filter=blob:none', + '--branch=stable', + 'https://github.com/folke/lazy.nvim.git', + lazypath, + } + if vim.v.shell_error ~= 0 then + vim.api.nvim_echo({ { 'Failed to clone lazy.nvim:\n', 'ErrorMsg' }, { out, 'WarningMsg' }, { '\nPress any key to exit...' } }, true, {}) + vim.fn.getchar() + os.exit(1) + end end +vim.opt.rtp:prepend(lazypath) ----Because most plugins are hosted on GitHub, you can use the helper ----function to have less repetition in the following sections. ----@param repo string ----@return string -local function gh(repo) return 'https://github.com/' .. repo end +require('lazy').setup { + spec = { + -- ============================================================ + -- SECTION 3: UI / CORE UX PLUGINS + -- ============================================================ --- ============================================================ --- SECTION 4: UI / CORE UX PLUGINS --- guess-indent, gitsigns, which-key, colorscheme, todo-comments, mini modules --- ============================================================ -do - -- [[ Installing and Configuring Plugins ]] - -- - -- To install a plugin simply call `vim.pack.add` with its git url. - -- This will download the default branch of the plugin, which will usually be `main` or `master` - -- You can also have more advanced specs, which we will talk about later. - -- - -- For most plugins its not enough to install them, you also need to call their `.setup()` to start them. - -- - -- For example, lets say we want to install `guess-indent.nvim` - a plugin for - -- automatically detecting and setting the indentation. - -- - -- We first install it from https://github.com/NMAC427/guess-indent.nvim - -- and then call its `setup()` function to start it with default settings. - vim.pack.add { gh 'NMAC427/guess-indent.nvim' } - require('guess-indent').setup {} + { 'NMAC427/guess-indent.nvim', opts = {} }, - -- Here is a more advanced configuration example that passes options to `gitsigns.nvim` - -- - -- See `:help gitsigns` to understand what each configuration key does. - -- Adds git related signs to the gutter, as well as utilities for managing changes - vim.pack.add { gh 'lewis6991/gitsigns.nvim' } - require('gitsigns').setup { - signs = { - add = { text = '+' }, ---@diagnostic disable-line: missing-fields - change = { text = '~' }, ---@diagnostic disable-line: missing-fields - delete = { text = '_' }, ---@diagnostic disable-line: missing-fields - topdelete = { text = '‾' }, ---@diagnostic disable-line: missing-fields - changedelete = { text = '~' }, ---@diagnostic disable-line: missing-fields + { + 'nvim-tree/nvim-web-devicons', + cond = vim.g.have_nerd_font, }, - } - -- Useful plugin to show you pending keybinds. - vim.pack.add { gh 'folke/which-key.nvim' } - require('which-key').setup { - -- Delay between pressing a key and opening which-key (milliseconds) - delay = 0, - icons = { mappings = vim.g.have_nerd_font }, - -- Document existing key chains - spec = { - { 's', group = '[S]earch', mode = { 'n', 'v' } }, - { 't', group = '[T]oggle' }, - { 'h', group = 'Git [H]unk', mode = { 'n', 'v' } }, -- Enable gitsigns recommended keymaps first - { 'gr', group = 'LSP Actions', mode = { 'n' } }, + { + 'lewis6991/gitsigns.nvim', + opts = { + signs = { + add = { text = '+' }, + change = { text = '~' }, + delete = { text = '_' }, + topdelete = { text = '‾' }, + changedelete = { text = '~' }, + }, + }, }, - } - -- [[ Colorscheme ]] - -- You can easily change to a different colorscheme. - -- Change the name of the colorscheme plugin below, and then - -- change the command under that to load whatever the name of that colorscheme is. - -- - -- If you want to see what colorschemes are already installed, you can use `:Telescope colorscheme`. - vim.pack.add { gh 'folke/tokyonight.nvim' } - ---@diagnostic disable-next-line: missing-fields - require('tokyonight').setup { - styles = { - comments = { italic = false }, -- Disable italics in comments + { + 'folke/which-key.nvim', + event = 'VimEnter', + opts = { + delay = 0, + icons = { mappings = vim.g.have_nerd_font }, + spec = { + { 's', group = '[S]earch', mode = { 'n', 'v' } }, + { 't', group = '[T]oggle' }, + { 'h', group = 'Git [H]unk', mode = { 'n', 'v' } }, + { 'gr', group = 'LSP Actions', mode = { 'n' } }, + }, + }, }, - } - - -- Load the colorscheme here. - -- Like many other themes, this one has different styles, and you could load - -- any other, such as 'tokyonight-storm', 'tokyonight-moon', or 'tokyonight-day'. - vim.cmd.colorscheme 'tokyonight-night' - - -- Highlight todo, notes, etc in comments - vim.pack.add { gh 'folke/todo-comments.nvim' } - require('todo-comments').setup { signs = false } - - -- [[ mini.nvim ]] - -- A collection of various small independent plugins/modules - vim.pack.add { gh 'nvim-mini/mini.nvim' } - -- If a nerd font is available, load the icons module for pretty icons in various plugins. - if vim.g.have_nerd_font then - require('mini.icons').setup() - -- Used for backwards compatibility with plugins that require `nvim-web-devicons` (e.g. telescope.nvim) - MiniIcons.mock_nvim_web_devicons() - end + { 'folke/todo-comments.nvim', opts = { signs = false } }, - -- Better Around/Inside textobjects - -- - -- Examples: - -- - va) - [V]isually select [A]round [)]paren - -- - yiiq - [Y]ank [I]nside [I]+1 [Q]uote - -- - ci' - [C]hange [I]nside [']quote - require('mini.ai').setup { - -- NOTE: Avoid conflicts with the built-in incremental selection mappings on Neovim>=0.12 (see `:help treesitter-incremental-selection`) - mappings = { - around_next = 'aa', - inside_next = 'ii', + { + 'nvim-mini/mini.nvim', + config = function() + require('mini.ai').setup { + mappings = { around_next = 'aa', inside_next = 'ii' }, + n_lines = 500, + } + require('mini.surround').setup() + local statusline = require 'mini.statusline' + statusline.setup { use_icons = vim.g.have_nerd_font } + ---@diagnostic disable-next-line: duplicate-set-field + statusline.section_location = function() return '%2l:%-2v' end + end, }, - n_lines = 500, - } - -- Add/delete/replace surroundings (brackets, quotes, etc.) - -- - -- - saiw) - [S]urround [A]dd [I]nner [W]ord [)]Paren - -- - sd' - [S]urround [D]elete [']quotes - -- - sr)' - [S]urround [R]eplace [)] ['] - require('mini.surround').setup() - - -- Simple and easy statusline. - -- You could remove this setup call if you don't like it, - -- and try some other statusline plugin - local statusline = require 'mini.statusline' - -- Set `use_icons` to true if you have a Nerd Font - statusline.setup { use_icons = vim.g.have_nerd_font } - - -- You can configure sections in the statusline by overriding their - -- default behavior. For example, here we set the section for - -- cursor location to LINE:COLUMN - ---@diagnostic disable-next-line: duplicate-set-field - statusline.section_location = function() return '%2l:%-2v' end - - -- ... and there is more! - -- Check out: https://github.com/nvim-mini/mini.nvim -end + -- ============================================================ + -- SECTION 4: SEARCH & NAVIGATION + -- ============================================================ + + { 'nvim-lua/plenary.nvim' }, + + { + 'nvim-telescope/telescope.nvim', + event = 'VimEnter', + dependencies = { + 'nvim-lua/plenary.nvim', + 'nvim-telescope/telescope-ui-select.nvim', + { + 'nvim-telescope/telescope-fzf-native.nvim', + build = 'make', + cond = vim.fn.executable 'make' == 1, + }, + }, + config = function() + require('telescope').setup { + extensions = { + ['ui-select'] = { require('telescope.themes').get_dropdown() }, + }, + } + pcall(require('telescope').load_extension, 'fzf') + pcall(require('telescope').load_extension, 'ui-select') + + local builtin = require 'telescope.builtin' + vim.keymap.set('n', 'sh', builtin.help_tags, { desc = '[S]earch [H]elp' }) + vim.keymap.set('n', 'sk', builtin.keymaps, { desc = '[S]earch [K]eymaps' }) + vim.keymap.set('n', 'sf', builtin.find_files, { desc = '[S]earch [F]iles' }) + vim.keymap.set('n', 'ss', builtin.builtin, { desc = '[S]earch [S]elect Telescope' }) + vim.keymap.set({ 'n', 'v' }, 'sw', builtin.grep_string, { desc = '[S]earch current [W]ord' }) + vim.keymap.set('n', 'sg', builtin.live_grep, { desc = '[S]earch by [G]rep' }) + vim.keymap.set('n', 'sd', builtin.diagnostics, { desc = '[S]earch [D]iagnostics' }) + vim.keymap.set('n', 'sr', builtin.resume, { desc = '[S]earch [R]esume' }) + vim.keymap.set('n', 's.', builtin.oldfiles, { desc = '[S]earch Recent Files ("." for repeat)' }) + vim.keymap.set('n', 'sc', builtin.commands, { desc = '[S]earch [C]ommands' }) + vim.keymap.set('n', '', builtin.buffers, { desc = '[ ] Find existing buffers' }) + + vim.api.nvim_create_autocmd('LspAttach', { + group = vim.api.nvim_create_augroup('telescope-lsp-attach', { clear = true }), + callback = function(event) + local buf = event.buf + vim.keymap.set('n', 'grr', builtin.lsp_references, { buffer = buf, desc = '[G]oto [R]eferences' }) + vim.keymap.set('n', 'gri', builtin.lsp_implementations, { buffer = buf, desc = '[G]oto [I]mplementation' }) + vim.keymap.set('n', 'grd', builtin.lsp_definitions, { buffer = buf, desc = '[G]oto [D]efinition' }) + vim.keymap.set('n', 'gO', builtin.lsp_document_symbols, { buffer = buf, desc = 'Open Document Symbols' }) + vim.keymap.set('n', 'gW', builtin.lsp_dynamic_workspace_symbols, { buffer = buf, desc = 'Open Workspace Symbols' }) + vim.keymap.set('n', 'grt', builtin.lsp_type_definitions, { buffer = buf, desc = '[G]oto [T]ype Definition' }) + end, + }) --- ============================================================ --- SECTION 5: SEARCH & NAVIGATION --- Telescope setup, keymaps, LSP picker mappings --- ============================================================ -do - -- [[ Fuzzy Finder (files, lsp, etc) ]] - -- - -- Telescope is a fuzzy finder that comes with a lot of different things that - -- it can fuzzy find! It's more than just a "file finder", it can search - -- many different aspects of Neovim, your workspace, LSP, and more! - -- - -- There are lots of other alternative pickers (like snacks.picker, or fzf-lua) - -- so feel free to experiment and see what you like! - -- - -- The easiest way to use Telescope, is to start by doing something like: - -- :Telescope help_tags - -- - -- After running this command, a window will open up and you're able to - -- type in the prompt window. You'll see a list of `help_tags` options and - -- a corresponding preview of the help. - -- - -- Two important keymaps to use while in Telescope are: - -- - Insert mode: - -- - Normal mode: ? - -- - -- This opens a window that shows you all of the keymaps for the current - -- Telescope picker. This is really useful to discover what Telescope can - -- do as well as how to actually do it! - - ---@type (string|vim.pack.Spec)[] - local telescope_plugins = { - gh 'nvim-lua/plenary.nvim', - gh 'nvim-telescope/telescope.nvim', - gh 'nvim-telescope/telescope-ui-select.nvim', - } - if vim.fn.executable 'make' == 1 then table.insert(telescope_plugins, gh 'nvim-telescope/telescope-fzf-native.nvim') end - - -- NOTE: You can install multiple plugins at once - vim.pack.add(telescope_plugins) - - -- See `:help telescope` and `:help telescope.setup()` - require('telescope').setup { - -- You can put your default mappings / updates / etc. in here - -- All the info you're looking for is in `:help telescope.setup()` - -- - -- defaults = { - -- mappings = { - -- i = { [''] = 'to_fuzzy_refine' }, - -- }, - -- }, - -- pickers = {} - extensions = { - ['ui-select'] = { require('telescope.themes').get_dropdown() }, + vim.keymap.set( + 'n', + '/', + function() builtin.current_buffer_fuzzy_find(require('telescope.themes').get_dropdown { winblend = 10, previewer = false }) end, + { desc = '[/] Fuzzily search in current buffer' } + ) + + vim.keymap.set( + 'n', + 's/', + function() builtin.live_grep { grep_open_files = true, prompt_title = 'Live Grep in Open Files' } end, + { desc = '[S]earch [/] in Open Files' } + ) + + vim.keymap.set('n', 'sn', function() builtin.find_files { cwd = vim.fn.stdpath 'config' } end, { desc = '[S]earch [N]eovim files' }) + end, }, - } - -- Enable Telescope extensions if they are installed - pcall(require('telescope').load_extension, 'fzf') - pcall(require('telescope').load_extension, 'ui-select') - - -- See `:help telescope.builtin` - local builtin = require 'telescope.builtin' - vim.keymap.set('n', 'sh', builtin.help_tags, { desc = '[S]earch [H]elp' }) - vim.keymap.set('n', 'sk', builtin.keymaps, { desc = '[S]earch [K]eymaps' }) - vim.keymap.set('n', 'sf', builtin.find_files, { desc = '[S]earch [F]iles' }) - vim.keymap.set('n', 'ss', builtin.builtin, { desc = '[S]earch [S]elect Telescope' }) - vim.keymap.set({ 'n', 'v' }, 'sw', builtin.grep_string, { desc = '[S]earch current [W]ord' }) - vim.keymap.set('n', 'sg', builtin.live_grep, { desc = '[S]earch by [G]rep' }) - vim.keymap.set('n', 'sd', builtin.diagnostics, { desc = '[S]earch [D]iagnostics' }) - vim.keymap.set('n', 'sr', builtin.resume, { desc = '[S]earch [R]esume' }) - vim.keymap.set('n', 's.', builtin.oldfiles, { desc = '[S]earch Recent Files ("." for repeat)' }) - vim.keymap.set('n', 'sc', builtin.commands, { desc = '[S]earch [C]ommands' }) - vim.keymap.set('n', '', builtin.buffers, { desc = '[ ] Find existing buffers' }) - - -- Add Telescope-based LSP pickers when an LSP attaches to a buffer. - -- If you later switch picker plugins, this is where to update these mappings. - vim.api.nvim_create_autocmd('LspAttach', { - group = vim.api.nvim_create_augroup('telescope-lsp-attach', { clear = true }), - callback = function(event) - local buf = event.buf - - -- Find references for the word under your cursor. - vim.keymap.set('n', 'grr', builtin.lsp_references, { buffer = buf, desc = '[G]oto [R]eferences' }) - - -- Jump to the implementation of the word under your cursor. - -- Useful when your language has ways of declaring types without an actual implementation. - vim.keymap.set('n', 'gri', builtin.lsp_implementations, { buffer = buf, desc = '[G]oto [I]mplementation' }) - - -- Jump to the definition of the word under your cursor. - -- This is where a variable was first declared, or where a function is defined, etc. - -- To jump back, press . - vim.keymap.set('n', 'grd', builtin.lsp_definitions, { buffer = buf, desc = '[G]oto [D]efinition' }) - - -- Fuzzy find all the symbols in your current document. - -- Symbols are things like variables, functions, types, etc. - vim.keymap.set('n', 'gO', builtin.lsp_document_symbols, { buffer = buf, desc = 'Open Document Symbols' }) - - -- Fuzzy find all the symbols in your current workspace. - -- Similar to document symbols, except searches over your entire project. - vim.keymap.set('n', 'gW', builtin.lsp_dynamic_workspace_symbols, { buffer = buf, desc = 'Open Workspace Symbols' }) - - -- Jump to the type of the word under your cursor. - -- Useful when you're not sure what type a variable is and you want to see - -- the definition of its *type*, not where it was *defined*. - vim.keymap.set('n', 'grt', builtin.lsp_type_definitions, { buffer = buf, desc = '[G]oto [T]ype Definition' }) - end, - }) + -- ============================================================ + -- SECTION 5: LSP + -- ============================================================ - -- Override default behavior and theme when searching - vim.keymap.set('n', '/', function() - -- You can pass additional configuration to Telescope to change the theme, layout, etc. - builtin.current_buffer_fuzzy_find(require('telescope.themes').get_dropdown { - winblend = 10, - previewer = false, - }) - end, { desc = '[/] Fuzzily search in current buffer' }) - - -- It's also possible to pass additional configuration options. - -- See `:help telescope.builtin.live_grep()` for information about particular keys - vim.keymap.set( - 'n', - 's/', - function() - builtin.live_grep { - grep_open_files = true, - prompt_title = 'Live Grep in Open Files', - } - end, - { desc = '[S]earch [/] in Open Files' } - ) - - -- Shortcut for searching your Neovim configuration files - vim.keymap.set('n', 'sn', function() builtin.find_files { cwd = vim.fn.stdpath 'config', follow = true } end, { desc = '[S]earch [N]eovim files' }) -end + { 'j-hui/fidget.nvim', opts = {} }, --- ============================================================ --- SECTION 6: LSP --- LSP keymaps, server configuration, Mason tools installations --- ============================================================ -do - -- [[ LSP Configuration ]] - -- Brief aside: **What is LSP?** - -- - -- LSP is an initialism you've probably heard, but might not understand what it is. - -- - -- LSP stands for Language Server Protocol. It's a protocol that helps editors - -- and language tooling communicate in a standardized fashion. - -- - -- In general, you have a "server" which is some tool built to understand a particular - -- language (such as `gopls`, `lua_ls`, `rust_analyzer`, etc.). These Language Servers - -- (sometimes called LSP servers, but that's kind of like ATM Machine) are standalone - -- processes that communicate with some "client" - in this case, Neovim! - -- - -- LSP provides Neovim with features like: - -- - Go to definition - -- - Find references - -- - Autocompletion - -- - Symbol Search - -- - and more! - -- - -- Thus, Language Servers are external tools that must be installed separately from - -- Neovim. This is where `mason` and related plugins come into play. - -- - -- If you're wondering about lsp vs treesitter, you can check out the wonderfully - -- and elegantly composed help section, `:help lsp-vs-treesitter` - - -- Useful status updates for LSP. - vim.pack.add { gh 'j-hui/fidget.nvim' } - require('fidget').setup {} - - -- This function gets run when an LSP attaches to a particular buffer. - -- That is to say, every time a new file is opened that is associated with - -- an lsp (for example, opening `main.rs` is associated with `rust_analyzer`) this - -- function will be executed to configure the current buffer - vim.api.nvim_create_autocmd('LspAttach', { - group = vim.api.nvim_create_augroup('kickstart-lsp-attach', { clear = true }), - callback = function(event) - -- NOTE: Remember that Lua is a real programming language, and as such it is possible - -- to define small helper and utility functions so you don't have to repeat yourself. - -- - -- In this case, we create a function that lets us more easily define mappings specific - -- for LSP related items. It sets the mode, buffer and description for us each time. - local map = function(keys, func, desc, mode) - mode = mode or 'n' - vim.keymap.set(mode, keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc }) - end - - -- Rename the variable under your cursor. - -- Most Language Servers support renaming across files, etc. - map('grn', vim.lsp.buf.rename, '[R]e[n]ame') - - -- Execute a code action, usually your cursor needs to be on top of an error - -- or a suggestion from your LSP for this to activate. - map('gra', vim.lsp.buf.code_action, '[G]oto Code [A]ction', { 'n', 'x' }) - - -- WARN: This is not Goto Definition, this is Goto Declaration. - -- For example, in C this would take you to the header. - map('grD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') - - -- The following two autocommands are used to highlight references of the - -- word under your cursor when your cursor rests there for a little while. - -- See `:help CursorHold` for information about when this is executed - -- - -- When you move your cursor, the highlights will be cleared (the second autocommand). - local client = vim.lsp.get_client_by_id(event.data.client_id) - if client and client:supports_method('textDocument/documentHighlight', event.buf) then - local highlight_augroup = vim.api.nvim_create_augroup('kickstart-lsp-highlight', { clear = false }) - vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, { - buffer = event.buf, - group = highlight_augroup, - callback = vim.lsp.buf.document_highlight, + { + 'neovim/nvim-lspconfig', + dependencies = { + 'mason-org/mason.nvim', + 'mason-org/mason-lspconfig.nvim', + 'WhoIsSethDaniel/mason-tool-installer.nvim', + }, + config = function() + vim.api.nvim_create_autocmd('LspAttach', { + group = vim.api.nvim_create_augroup('kickstart-lsp-attach', { clear = true }), + callback = function(event) + local map = function(keys, func, desc, mode) + mode = mode or 'n' + vim.keymap.set(mode, keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc }) + end + + map('grn', vim.lsp.buf.rename, '[R]e[n]ame') + map('gra', vim.lsp.buf.code_action, '[G]oto Code [A]ction', { 'n', 'x' }) + map('grD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') + + local client = vim.lsp.get_client_by_id(event.data.client_id) + if client and client:supports_method('textDocument/documentHighlight', event.buf) then + local highlight_augroup = vim.api.nvim_create_augroup('kickstart-lsp-highlight', { clear = false }) + vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, { + buffer = event.buf, + group = highlight_augroup, + callback = vim.lsp.buf.document_highlight, + }) + vim.api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI' }, { + buffer = event.buf, + group = highlight_augroup, + callback = vim.lsp.buf.clear_references, + }) + vim.api.nvim_create_autocmd('LspDetach', { + group = vim.api.nvim_create_augroup('kickstart-lsp-detach', { clear = true }), + callback = function(event2) + vim.lsp.buf.clear_references() + vim.api.nvim_clear_autocmds { group = 'kickstart-lsp-highlight', buffer = event2.buf } + end, + }) + end + + if client and client:supports_method('textDocument/inlayHint', event.buf) then + map('th', function() vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled { bufnr = event.buf }) end, '[T]oggle Inlay [H]ints') + end + end, }) - vim.api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI' }, { - buffer = event.buf, - group = highlight_augroup, - callback = vim.lsp.buf.clear_references, - }) + ---@type table + local servers = { + -- clangd = {}, + -- gopls = {}, + -- pyright = {}, + -- rust_analyzer = {}, + -- ts_ls = {}, + + stylua = {}, + + lua_ls = { + on_init = function(client) + client.server_capabilities.documentFormattingProvider = false + + if client.workspace_folders then + local path = client.workspace_folders[1].name + if path ~= vim.fn.stdpath 'config' and (vim.uv.fs_stat(path .. '/.luarc.json') or vim.uv.fs_stat(path .. '/.luarc.jsonc')) then return end + end + + client.config.settings.Lua = vim.tbl_deep_extend('force', client.config.settings.Lua, { + runtime = { + version = 'LuaJIT', + path = { 'lua/?.lua', 'lua/?/init.lua' }, + }, + workspace = { + checkThirdParty = false, + library = vim.tbl_extend('force', vim.api.nvim_get_runtime_file('', true), { + '${3rd}/luv/library', + '${3rd}/busted/library', + }), + }, + }) + end, + ---@type lspconfig.settings.lua_ls + settings = { + Lua = { format = { enable = false } }, + }, + }, + } - vim.api.nvim_create_autocmd('LspDetach', { - group = vim.api.nvim_create_augroup('kickstart-lsp-detach', { clear = true }), - callback = function(event2) - vim.lsp.buf.clear_references() - vim.api.nvim_clear_autocmds { group = 'kickstart-lsp-highlight', buffer = event2.buf } - end, + require('mason').setup {} + + local ensure_installed = vim.tbl_keys(servers or {}) + vim.list_extend(ensure_installed, { + -- Add extra Mason tools here }) - end - - -- The following code creates a keymap to toggle inlay hints in your - -- code, if the language server you are using supports them - -- - -- This may be unwanted, since they displace some of your code - if client and client:supports_method('textDocument/inlayHint', event.buf) then - map('th', function() vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled { bufnr = event.buf }) end, '[T]oggle Inlay [H]ints') - end - end, - }) + require('mason-tool-installer').setup { ensure_installed = ensure_installed } - -- Enable the following language servers - -- Feel free to add/remove any LSPs that you want here. They will automatically be installed. - -- See `:help lsp-config` for information about keys and how to configure - ---@type table - local servers = { - -- clangd = {}, - -- gopls = {}, - -- pyright = {}, - -- rust_analyzer = {}, - -- - -- Some languages (like typescript) have entire language plugins that can be useful: - -- https://github.com/pmizio/typescript-tools.nvim - -- - -- But for many setups, the LSP (`ts_ls`) will work just fine - -- ts_ls = {}, - - stylua = {}, -- Used to format Lua code - - -- Special Lua Config, as recommended by neovim help docs - lua_ls = { - on_init = function(client) - client.server_capabilities.documentFormattingProvider = false -- Disable formatting (formatting is done by stylua) - - if client.workspace_folders then - local path = client.workspace_folders[1].name - if path ~= vim.fn.stdpath 'config' and (vim.uv.fs_stat(path .. '/.luarc.json') or vim.uv.fs_stat(path .. '/.luarc.jsonc')) then return end + for name, server in pairs(servers) do + vim.lsp.config(name, server) + vim.lsp.enable(name) end - - client.config.settings.Lua = vim.tbl_deep_extend('force', client.config.settings.Lua, { - runtime = { - version = 'LuaJIT', - path = { 'lua/?.lua', 'lua/?/init.lua' }, - }, - workspace = { - checkThirdParty = false, - -- NOTE: this is a lot slower and will cause issues when working on your own configuration. - -- See https://github.com/neovim/nvim-lspconfig/issues/3189 - library = vim.tbl_extend('force', vim.api.nvim_get_runtime_file('', true), { - '${3rd}/luv/library', - '${3rd}/busted/library', - }), - }, - }) end, - ---@type lspconfig.settings.lua_ls - settings = { - Lua = { - format = { enable = false }, -- Disable formatting (formatting is done by stylua) - }, - }, }, - } - - vim.pack.add { - gh 'neovim/nvim-lspconfig', - gh 'mason-org/mason.nvim', - gh 'mason-org/mason-lspconfig.nvim', - gh 'WhoIsSethDaniel/mason-tool-installer.nvim', - } - -- Automatically install LSPs and related tools to stdpath for Neovim - require('mason').setup {} - - -- Ensure the servers and tools above are installed - -- - -- To check the current status of installed tools and/or manually install - -- other tools, you can run - -- :Mason - -- - -- You can press `g?` for help in this menu. - local ensure_installed = vim.tbl_keys(servers or {}) - vim.list_extend(ensure_installed, { - -- You can add other tools here that you want Mason to install - }) - - require('mason-tool-installer').setup { ensure_installed = ensure_installed } - - for name, server in pairs(servers) do - vim.lsp.config(name, server) - vim.lsp.enable(name) - end -end + -- ============================================================ + -- SECTION 6: FORMATTING + -- ============================================================ + + { + 'stevearc/conform.nvim', + config = function() + local prettier_ft = { + 'javascript', + 'javascriptreact', + 'typescript', + 'typescriptreact', + 'vue', + 'css', + 'scss', + 'less', + 'html', + 'json', + 'jsonc', + 'yaml', + 'markdown', + 'graphql', + } + local formatters_by_ft = {} + for _, ft in ipairs(prettier_ft) do + formatters_by_ft[ft] = { 'prettierd', 'prettier', stop_after_first = true } + end --- ============================================================ --- SECTION 7: FORMATTING --- conform.nvim setup and keymap --- ============================================================ -do - -- [[ Formatting ]] - vim.pack.add { gh 'stevearc/conform.nvim' } - require('conform').setup { - notify_on_error = false, - format_on_save = function(bufnr) - -- You can specify filetypes to autoformat on save here: - local enabled_filetypes = { - -- lua = true, - -- python = true, - } - if enabled_filetypes[vim.bo[bufnr].filetype] then - return { timeout_ms = 500 } - else - return nil - end - end, - default_format_opts = { - lsp_format = 'fallback', -- Use external formatters if configured below, otherwise use LSP formatting. Set to `false` to disable LSP formatting entirely. - }, - -- You can also specify external formatters in here. - formatters_by_ft = { - -- rust = { 'rustfmt' }, - -- Conform can also run multiple formatters sequentially - -- python = { "isort", "black" }, - -- - -- You can use 'stop_after_first' to run the first available formatter from the list - -- javascript = { "prettierd", "prettier", stop_after_first = true }, + require('conform').setup { + notify_on_error = false, + format_on_save = function(bufnr) + if formatters_by_ft[vim.bo[bufnr].filetype] then return { timeout_ms = 500, lsp_format = 'fallback' } end + return nil + end, + default_format_opts = { + lsp_format = 'fallback', + }, + formatters_by_ft = formatters_by_ft, + } + vim.keymap.set({ 'n', 'v' }, 'f', function() require('conform').format { async = true } end, { desc = '[F]ormat buffer' }) + end, }, - } - - vim.keymap.set({ 'n', 'v' }, 'f', function() require('conform').format { async = true } end, { desc = '[F]ormat buffer' }) -end - --- ============================================================ --- SECTION 8: AUTOCOMPLETE & SNIPPETS --- blink.cmp and luasnip setup --- ============================================================ -do - -- [[ Snippet Engine ]] - - -- NOTE: You can also specify plugin using a version range for its git tag. - -- See `:help vim.version.range()` for more info - vim.pack.add { { src = gh 'L3MON4D3/LuaSnip', version = vim.version.range '2.*' } } - require('luasnip').setup {} - -- `friendly-snippets` contains a variety of premade snippets. - -- See the README about individual language/framework/plugin snippets: - -- https://github.com/rafamadriz/friendly-snippets - -- - -- vim.pack.add { gh 'rafamadriz/friendly-snippets' } - -- require('luasnip.loaders.from_vscode').lazy_load() - - -- [[ Autocomplete Engine ]] - vim.pack.add { { src = gh 'saghen/blink.cmp', version = vim.version.range '1.*' } } - require('blink.cmp').setup { - keymap = { - -- 'default' (recommended) for mappings similar to built-in completions - -- to accept ([y]es) the completion. - -- This will auto-import if your LSP supports it. - -- This will expand snippets if the LSP sent a snippet. - -- 'super-tab' for tab to accept - -- 'enter' for enter to accept - -- 'none' for no mappings - -- - -- For an understanding of why the 'default' preset is recommended, - -- you will need to read `:help ins-completion` - -- - -- No, but seriously. Please read `:help ins-completion`, it is really good! - -- - -- All presets have the following mappings: - -- /: move to right/left of your snippet expansion - -- : Open menu or open docs if already open - -- / or /: Select next/previous item - -- : Hide menu - -- : Toggle signature help - -- - -- See `:help blink-cmp-config-keymap` for defining your own keymap - preset = 'default', - - -- For more advanced Luasnip keymaps (e.g. selecting choice nodes, expansion) see: - -- https://github.com/L3MON4D3/LuaSnip?tab=readme-ov-file#keymaps + -- ============================================================ + -- SECTION 7: AUTOCOMPLETE & SNIPPETS + -- ============================================================ + + { + 'L3MON4D3/LuaSnip', + version = '2.*', + build = (vim.fn.has 'win32' ~= 1 and vim.fn.executable 'make' == 1) and 'make install_jsregexp' or nil, + config = function() + require('luasnip').setup {} + -- vim.pack.add { gh 'rafamadriz/friendly-snippets' } + -- require('luasnip.loaders.from_vscode').lazy_load() + end, }, - appearance = { - -- 'mono' (default) for 'Nerd Font Mono' or 'normal' for 'Nerd Font' - -- Adjusts spacing to ensure icons are aligned - nerd_font_variant = 'mono', + { + 'saghen/blink.cmp', + version = '1.*', + dependencies = { 'L3MON4D3/LuaSnip' }, + opts = { + keymap = { preset = 'default' }, + appearance = { nerd_font_variant = 'mono' }, + completion = { + documentation = { auto_show = false, auto_show_delay_ms = 500 }, + }, + sources = { default = { 'lsp', 'path', 'snippets' } }, + snippets = { preset = 'luasnip' }, + fuzzy = { implementation = 'lua' }, + signature = { enabled = true }, + }, }, - completion = { - -- By default, you may press `` to show the documentation. - -- Optionally, set `auto_show = true` to show the documentation after a delay. - documentation = { auto_show = false, auto_show_delay_ms = 500 }, - }, + -- ============================================================ + -- SECTION 8: TREESITTER + -- ============================================================ + + { + 'nvim-treesitter/nvim-treesitter', + branch = 'main', + build = ':TSUpdate', + config = function() + local parsers = { 'bash', 'c', 'diff', 'html', 'lua', 'luadoc', 'markdown', 'markdown_inline', 'python', 'query', 'sql', 'vim', 'vimdoc' } + require('nvim-treesitter').install(parsers, function(lang, success) + if success then + vim.notify('treesitter: installed ' .. lang, vim.log.levels.INFO) + else + vim.notify('treesitter: failed to install ' .. lang, vim.log.levels.WARN) + end + end) + + ---@param buf integer + ---@param language string + local function treesitter_try_attach(buf, language) + if not vim.treesitter.language.add(language) then return end + vim.treesitter.start(buf, language) + -- vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()' + -- vim.wo.foldmethod = 'expr' + local has_indent_query = vim.treesitter.query.get(language, 'indents') ~= nil + if has_indent_query then vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" end + end - sources = { - default = { 'lsp', 'path', 'snippets' }, + local available_parsers = require('nvim-treesitter').get_available() + vim.api.nvim_create_autocmd('FileType', { + callback = function(args) + local buf, filetype = args.buf, args.match + local language = vim.treesitter.language.get_lang(filetype) + if not language then return end + local installed_parsers = require('nvim-treesitter').get_installed 'parsers' + if vim.tbl_contains(installed_parsers, language) then + treesitter_try_attach(buf, language) + elseif vim.tbl_contains(available_parsers, language) then + require('nvim-treesitter').install(language):await(function() treesitter_try_attach(buf, language) end) + else + treesitter_try_attach(buf, language) + end + end, + }) + end, }, - snippets = { preset = 'luasnip' }, + -- ============================================================ + -- SECTION 9: KICKSTART OPTIONAL PLUGINS + -- ============================================================ - -- Blink.cmp includes an optional, recommended rust fuzzy matcher, - -- which automatically downloads a prebuilt binary when enabled. - -- - -- By default, we use the Lua implementation instead, but you may enable - -- the rust implementation via `'prefer_rust_with_warning'` - -- - -- See `:help blink-cmp-config-fuzzy` for more information - fuzzy = { implementation = 'lua' }, + { import = 'kickstart.plugins.indent_line' }, + { import = 'kickstart.plugins.lint' }, + -- { import = 'kickstart.plugins.debug' }, + -- { import = 'kickstart.plugins.autopairs' }, + -- { import = 'kickstart.plugins.neo-tree' }, + { import = 'kickstart.plugins.gitsigns' }, - -- Shows a signature help window while you type arguments for a function - signature = { enabled = true }, - } -end + -- ============================================================ + -- CUSTOM PLUGINS + -- ============================================================ --- ============================================================ --- SECTION 9: TREESITTER --- Parser installation, syntax highlighting, folds, indentation --- ============================================================ -do - -- [[ Configure Treesitter ]] - -- Used to highlight, edit, and navigate code - -- - -- See `:help nvim-treesitter-intro` - - -- NOTE: You can also specify a branch or a specific commit - vim.pack.add { { src = gh 'nvim-treesitter/nvim-treesitter', version = 'main' } } - - -- Ensure basic parsers are installed - local parsers = { 'bash', 'c', 'diff', 'html', 'lua', 'luadoc', 'markdown', 'markdown_inline', 'query', 'vim', 'vimdoc' } - require('nvim-treesitter').install(parsers) - - ---@param buf integer - ---@param language string - local function treesitter_try_attach(buf, language) - -- Check if a parser exists and load it - if not vim.treesitter.language.add(language) then return end - -- Enable syntax highlighting and other treesitter features - vim.treesitter.start(buf, language) - - -- Enable treesitter based folds - -- For more info on folds see `:help folds` - -- vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()' - -- vim.wo.foldmethod = 'expr' - - -- Check if treesitter indentation is available for this language, and if so enable it - -- in case there is no indent query, the indentexpr will fallback to the vim's built in one - local has_indent_query = vim.treesitter.query.get(language, 'indents') ~= nil - - -- Enable treesitter based indentation - if has_indent_query then vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" end - end + { import = 'custom.plugins' }, + }, - local available_parsers = require('nvim-treesitter').get_available() - vim.api.nvim_create_autocmd('FileType', { - callback = function(args) - local buf, filetype = args.buf, args.match - - local language = vim.treesitter.language.get_lang(filetype) - if not language then return end - - local installed_parsers = require('nvim-treesitter').get_installed 'parsers' - - if vim.tbl_contains(installed_parsers, language) then - -- Enable the parser if it is already installed - treesitter_try_attach(buf, language) - elseif vim.tbl_contains(available_parsers, language) then - -- If a parser is available in `nvim-treesitter`, auto-install it and enable it after the installation is done - require('nvim-treesitter').install(language):await(function() treesitter_try_attach(buf, language) end) - else - -- Try to enable treesitter features in case the parser exists but is not available from `nvim-treesitter` - treesitter_try_attach(buf, language) - end - end, - }) -end + install = { colorscheme = { 'gruvbox-medium', 'habamax' } }, + checker = { enabled = false }, +} --- ============================================================ --- SECTION 10: OPTIONAL EXAMPLES / NEXT STEPS --- kickstart.plugins.* examples --- ============================================================ -do - -- The following comments only work if you have downloaded the kickstart repo, not just copy pasted the - -- init.lua. If you want these files, they are in the repository, so you can just download them and - -- place them in the correct locations. - - -- NOTE: Next step on your Neovim journey: Add/Configure additional plugins for Kickstart - -- - -- Here are some example plugins that I've included in the Kickstart repository. - -- Uncomment any of the lines below to enable them (you will need to restart nvim). - -- - -- require 'kickstart.plugins.debug' - -- require 'kickstart.plugins.indent_line' - -- require 'kickstart.plugins.lint' - -- require 'kickstart.plugins.autopairs' - -- require 'kickstart.plugins.neo-tree' - -- require 'kickstart.plugins.gitsigns' -- adds gitsigns recommended keymaps - - -- NOTE: You can add your own plugins, configuration, etc from `lua/custom/plugins/*.lua` - -- - -- Uncomment the following line and add your plugins to `lua/custom/plugins/*.lua` to get going. - -- require 'custom.plugins' -end +-- Open Oil in a floating window +vim.keymap.set('n', 'of', 'Oil --float', { desc = 'Open Oil float' }) -- The line beneath this is called `modeline`. See `:help modeline` -- vim: ts=2 sts=2 sw=2 et diff --git a/lazy-lock.json b/lazy-lock.json new file mode 100644 index 00000000000..c6d163a9df3 --- /dev/null +++ b/lazy-lock.json @@ -0,0 +1,39 @@ +{ + "LuaSnip": { "branch": "master", "commit": "642b0c595e11608b4c18219e93b88d7637af27bc" }, + "blink.cmp": { "branch": "main", "commit": "78336bc89ee5365633bcf754d93df01678b5c08f" }, + "claudecode.nvim": { "branch": "main", "commit": "102d835c964069c9c5e37abaf05ae4f9c3ee6f00" }, + "conform.nvim": { "branch": "master", "commit": "619363c30309d29ffa631e67c8183f2a72caa373" }, + "fidget.nvim": { "branch": "main", "commit": "82404b196e73a00b1727a91903beef5ddc319d22" }, + "fzf-lua": { "branch": "main", "commit": "fea9eedc6894c44d44cbb772a5cd11c93b82d7a1" }, + "gitsigns.nvim": { "branch": "main", "commit": "dd3f588bacbeb041be6facf1742e42097f62165d" }, + "gruvbox.nvim": { "branch": "main", "commit": "c14c475585494c592ef48064ad338424f15f8bad" }, + "guess-indent.nvim": { "branch": "main", "commit": "84a4987ff36798c2fc1169cbaff67960aed9776f" }, + "image.nvim": { "branch": "master", "commit": "44e07129cd0ea0c60afa7a1991d35b5765b51a6b" }, + "indent-blankline.nvim": { "branch": "master", "commit": "d28a3f70721c79e3c5f6693057ae929f3d9c0a03" }, + "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, + "live-preview.nvim": { "branch": "main", "commit": "c1fcf75c5f9c9c01dd392852de44204b60f1b5b1" }, + "lsp_lines.nvim": { "branch": "main", "commit": "3b57922d2d79762e6baedaf9d66d8ba71f822816" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "7b01e2974a47d489bb92f47a41e4c0088ea8f86e" }, + "mason-tool-installer.nvim": { "branch": "main", "commit": "443f1ef8b5e6bf47045cb2217b6f748a223cf7dc" }, + "mason.nvim": { "branch": "main", "commit": "bb639d4bf385a4d89f478b83af4d770be05ab7eb" }, + "mini.nvim": { "branch": "main", "commit": "44657837c7338e52727facc85c1d95bec1f6bd7c" }, + "mini.pick": { "branch": "main", "commit": "4522d9ab65224675df2cf1ede8c12f0410aae2be" }, + "molten-nvim": { "branch": "main", "commit": "a286aa914d9a154bc359131aab788b5a077a5a99" }, + "nvim-lint": { "branch": "master", "commit": "d48f3a76189d03b2239f6df1b2f7e3fa8353743b" }, + "nvim-lspconfig": { "branch": "master", "commit": "6f76a3eeadc2ee235d74cd7d5319e95a261084af" }, + "nvim-treesitter": { "branch": "main", "commit": "4916d6592ede8c07973490d9322f187e07dfefac" }, + "nvim-web-devicons": { "branch": "master", "commit": "dfbfaa967a6f7ec50789bead7ef87e336c1fa63c" }, + "oil.nvim": { "branch": "master", "commit": "0fcc83805ad11cf714a949c98c605ed717e0b83e" }, + "plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" }, + "snacks.nvim": { "branch": "main", "commit": "882c996cf28183f4d63640de0b4c02ec886d01f2" }, + "telescope-fzf-native.nvim": { "branch": "main", "commit": "b25b749b9db64d375d782094e2b9dce53ad53a40" }, + "telescope-ui-select.nvim": { "branch": "master", "commit": "6e51d7da30bd139a6950adf2a47fda6df9fa06d2" }, + "telescope.nvim": { "branch": "master", "commit": "7d324792b7943e4aa16ad007212e6acc6f9fe335" }, + "todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" }, + "toggleterm.nvim": { "branch": "main", "commit": "50ea089fc548917cc3cc16b46a8211833b9e3c7c" }, + "tokyonight.nvim": { "branch": "main", "commit": "cdc07ac78467a233fd62c493de29a17e0cf2b2b6" }, + "trouble.nvim": { "branch": "main", "commit": "bd67efe408d4816e25e8491cc5ad4088e708a69a" }, + "vim-fugitive": { "branch": "master", "commit": "3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0" }, + "wezterm.nvim": { "branch": "main", "commit": "032c33b621b96cc7228955b4352b48141c482098" }, + "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" } +} diff --git a/lua/custom/plugins/claude.lua b/lua/custom/plugins/claude.lua new file mode 100644 index 00000000000..9948796842b --- /dev/null +++ b/lua/custom/plugins/claude.lua @@ -0,0 +1,24 @@ +return { + 'coder/claudecode.nvim', + dependencies = { 'folke/snacks.nvim' }, + config = true, + keys = { + { 'a', nil, desc = 'AI/Claude Code' }, + { 'ac', 'ClaudeCode', desc = 'Toggle Claude' }, + { 'af', 'ClaudeCodeFocus', desc = 'Focus Claude' }, + { 'ar', 'ClaudeCode --resume', desc = 'Resume Claude' }, + { 'aC', 'ClaudeCode --continue', desc = 'Continue Claude' }, + { 'am', 'ClaudeCodeSelectModel', desc = 'Select Claude model' }, + { 'ab', 'ClaudeCodeAdd %', desc = 'Add current buffer' }, + { 'as', 'ClaudeCodeSend', mode = 'v', desc = 'Send to Claude' }, + { + 'as', + 'ClaudeCodeTreeAdd', + desc = 'Add file', + ft = { 'NvimTree', 'neo-tree', 'oil', 'minifiles', 'netrw' }, + }, + -- Diff management + { 'aa', 'ClaudeCodeDiffAccept', desc = 'Accept diff' }, + { 'ad', 'ClaudeCodeDiffDeny', desc = 'Deny diff' }, + }, +} diff --git a/lua/custom/plugins/fugitive.lua b/lua/custom/plugins/fugitive.lua new file mode 100644 index 00000000000..b6b4c97bc32 --- /dev/null +++ b/lua/custom/plugins/fugitive.lua @@ -0,0 +1,3 @@ +return { + 'tpope/vim-fugitive', +} diff --git a/lua/custom/plugins/init.lua b/lua/custom/plugins/init.lua index 01e91722fb0..8f7c2a8b1f7 100644 --- a/lua/custom/plugins/init.lua +++ b/lua/custom/plugins/init.lua @@ -1,13 +1,3 @@ --- You can add your own plugins here or in other files in this directory! --- I promise not to create any merge conflicts in this directory :) --- --- See the kickstart.nvim README for more information - --- Iterate over all Lua files in the plugins directory and load them -local plugins_dir = vim.fs.joinpath(vim.fn.stdpath 'config', 'lua', 'custom', 'plugins') -for file_name, type in vim.fs.dir(plugins_dir, { follow = true }) do - if (type == 'file' or type == 'link') and file_name:match '%.lua$' and file_name ~= 'init.lua' then - local module = file_name:gsub('%.lua$', '') - require('custom.plugins.' .. module) - end -end +-- Lazy auto-discovers all *.lua files in this directory. +-- This file is intentionally empty (lazy imports the other files directly). +return {} diff --git a/lua/custom/plugins/lsp.lua b/lua/custom/plugins/lsp.lua new file mode 100644 index 00000000000..efa8b90124e --- /dev/null +++ b/lua/custom/plugins/lsp.lua @@ -0,0 +1,11 @@ +-- dbt language server (requires dbt-language-server in $PATH) +-- Uses native Neovim LSP APIs — no extra plugin needed. +vim.lsp.config('dbt', { + cmd = { 'dbt-language-server' }, + filetypes = { 'sql', 'yaml' }, + root_markers = { 'dbt_project.yml' }, + settings = {}, +}) +vim.lsp.enable 'dbt' + +return {} diff --git a/lua/custom/plugins/lsp_lines.lua b/lua/custom/plugins/lsp_lines.lua new file mode 100644 index 00000000000..bc2592f5152 --- /dev/null +++ b/lua/custom/plugins/lsp_lines.lua @@ -0,0 +1,19 @@ +return { + 'ErichDonGubler/lsp_lines.nvim', + config = function() + require('lsp_lines').setup() + + -- Disable default virtual text to prevent overlapping/duplicate diagnostic lines + vim.diagnostic.config { + virtual_text = false, + } + end, + -- Keymap to toggle lsp_lines + keys = { + { + 'll', + function() require('lsp_lines').toggle() end, + desc = 'Toggle lsp_lines', + }, + }, +} diff --git a/lua/custom/plugins/markdown.lua b/lua/custom/plugins/markdown.lua new file mode 100644 index 00000000000..c2ee8ee7268 --- /dev/null +++ b/lua/custom/plugins/markdown.lua @@ -0,0 +1,10 @@ +return { + 'brianhuster/live-preview.nvim', + dependencies = { + -- You can choose one of the following pickers + 'nvim-telescope/telescope.nvim', + 'ibhagwan/fzf-lua', + 'echasnovski/mini.pick', + 'folke/snacks.nvim', + }, +} diff --git a/lua/custom/plugins/notebook.lua b/lua/custom/plugins/notebook.lua new file mode 100644 index 00000000000..273c95ed69c --- /dev/null +++ b/lua/custom/plugins/notebook.lua @@ -0,0 +1,26 @@ +return { + { + 'benlubas/molten-nvim', + version = '^1.0.0', -- use version <2.0.0 to avoid breaking changes + dependencies = { '3rd/image.nvim' }, + build = ':UpdateRemotePlugins', + init = function() + -- these are examples, not defaults. Please see the readme + vim.g.molten_image_provider = 'image.nvim' + vim.g.molten_output_win_max_height = 20 + end, + }, + { + 'willothy/wezterm.nvim', + cond = vim.fn.executable 'wezterm' == 1, + config = true, + }, + + { + '3rd/image.nvim', + build = false, -- so that it doesn't build the rock https://github.com/3rd/image.nvim/issues/91#issuecomment-2453430239 + opts = { + processor = 'magick_cli', + }, + }, +} diff --git a/lua/custom/plugins/oil.lua b/lua/custom/plugins/oil.lua new file mode 100644 index 00000000000..34f7ce6e088 --- /dev/null +++ b/lua/custom/plugins/oil.lua @@ -0,0 +1,31 @@ +return { + 'stevearc/oil.nvim', + dependencies = { 'nvim-mini/mini.nvim' }, + config = function() + require('mini.icons').setup() + require('oil').setup { + float = { + border = 'rounded', + title = ' Oil ', + title_pos = 'center', + }, + view_options = { + show_hidden = false, + is_hidden_file = function(name, bufnr) return vim.startswith(name, '.') end, + is_always_hidden = function(name, bufnr) return false end, + natural_order = false, + sort = { + { 'type', 'asc' }, + { 'name', 'asc' }, + }, + }, + keymaps = { + ['th'] = { + callback = function() require('oil').toggle_hidden() end, + desc = 'Toggle hidden files', + mode = 'n', + }, + }, + } + end, +} diff --git a/lua/custom/plugins/themes.lua b/lua/custom/plugins/themes.lua new file mode 100644 index 00000000000..89037260cea --- /dev/null +++ b/lua/custom/plugins/themes.lua @@ -0,0 +1,19 @@ +return { + { + 'folke/tokyonight.nvim', + opts = { + styles = { + comments = { italic = false }, + }, + }, + }, + { + 'motaz-shokry/gruvbox.nvim', + url = 'https://gitlab.com/motaz-shokry/gruvbox.nvim', + priority = 1000, + config = function() + require('gruvbox').setup() + vim.cmd 'colorscheme gruvbox-medium' + end, + }, +} diff --git a/lua/custom/plugins/toggle-term.lua b/lua/custom/plugins/toggle-term.lua new file mode 100644 index 00000000000..b5356f93cc3 --- /dev/null +++ b/lua/custom/plugins/toggle-term.lua @@ -0,0 +1,18 @@ +return { + 'akinsho/toggleterm.nvim', + version = '*', + opts = { + open_mapping = [[tt]], + }, + config = function(_, opts) + require('toggleterm').setup(opts) + vim.keymap.set('t', '', [[]], { desc = 'Exit terminal mode' }) + + local lazygit = require('toggleterm.terminal').Terminal:new { + cmd = 'lazygit', + direction = 'float', + hidden = true, + } + vim.keymap.set('n', 'tg', function() lazygit:toggle() end, { desc = 'Toggle lazygit' }) + end, +} diff --git a/lua/custom/plugins/trouble.lua b/lua/custom/plugins/trouble.lua new file mode 100644 index 00000000000..d0578c9f404 --- /dev/null +++ b/lua/custom/plugins/trouble.lua @@ -0,0 +1,37 @@ +return { + 'folke/trouble.nvim', + opts = {}, -- for default options, refer to the configuration section for custom setup. + cmd = 'Trouble', + keys = { + { + 'xx', + 'Trouble diagnostics toggle', + desc = 'Diagnostics (Trouble)', + }, + { + 'xX', + 'Trouble diagnostics toggle filter.buf=0', + desc = 'Buffer Diagnostics (Trouble)', + }, + { + 'cs', + 'Trouble symbols toggle focus=false', + desc = 'Symbols (Trouble)', + }, + { + 'cl', + 'Trouble lsp toggle focus=false win.position=right', + desc = 'LSP Definitions / references / ... (Trouble)', + }, + { + 'xL', + 'Trouble loclist toggle', + desc = 'Location List (Trouble)', + }, + { + 'xQ', + 'Trouble qflist toggle', + desc = 'Quickfix List (Trouble)', + }, + }, +} diff --git a/lua/kickstart/plugins/gitsigns.lua b/lua/kickstart/plugins/gitsigns.lua index b7e40a87cfc..5701160afd1 100644 --- a/lua/kickstart/plugins/gitsigns.lua +++ b/lua/kickstart/plugins/gitsigns.lua @@ -2,56 +2,56 @@ -- NOTE: gitsigns is already included in init.lua but contains only the base -- config. This will add also the recommended keymaps. -vim.pack.add { 'https://github.com/lewis6991/gitsigns.nvim' } +return { + 'lewis6991/gitsigns.nvim', + opts = { + on_attach = function(bufnr) + local gitsigns = require 'gitsigns' -require('gitsigns').setup { - on_attach = function(bufnr) - local gitsigns = require 'gitsigns' - - local function map(mode, l, r, opts) - opts = opts or {} - opts.buffer = bufnr - vim.keymap.set(mode, l, r, opts) - end - - -- Navigation - map('n', ']c', function() - if vim.wo.diff then - vim.cmd.normal { ']c', bang = true } - else - gitsigns.nav_hunk 'next' + local function map(mode, l, r, opts) + opts = opts or {} + opts.buffer = bufnr + vim.keymap.set(mode, l, r, opts) end - end, { desc = 'Jump to next git [c]hange' }) - map('n', '[c', function() - if vim.wo.diff then - vim.cmd.normal { '[c', bang = true } - else - gitsigns.nav_hunk 'prev' - end - end, { desc = 'Jump to previous git [c]hange' }) + -- Navigation + map('n', ']c', function() + if vim.wo.diff then + vim.cmd.normal { ']c', bang = true } + else + gitsigns.nav_hunk 'next' + end + end, { desc = 'Jump to next git [c]hange' }) + + map('n', '[c', function() + if vim.wo.diff then + vim.cmd.normal { '[c', bang = true } + else + gitsigns.nav_hunk 'prev' + end + end, { desc = 'Jump to previous git [c]hange' }) - -- Actions - -- visual mode - map('v', 'hs', function() gitsigns.stage_hunk { vim.fn.line '.', vim.fn.line 'v' } end, { desc = 'git [s]tage hunk' }) - map('v', 'hr', function() gitsigns.reset_hunk { vim.fn.line '.', vim.fn.line 'v' } end, { desc = 'git [r]eset hunk' }) - -- normal mode - map('n', 'hs', gitsigns.stage_hunk, { desc = 'git [s]tage hunk' }) - map('n', 'hr', gitsigns.reset_hunk, { desc = 'git [r]eset hunk' }) - map('n', 'hS', gitsigns.stage_buffer, { desc = 'git [S]tage buffer' }) - map('n', 'hR', gitsigns.reset_buffer, { desc = 'git [R]eset buffer' }) - map('n', 'hp', gitsigns.preview_hunk, { desc = 'git [p]review hunk' }) - map('n', 'hi', gitsigns.preview_hunk_inline, { desc = 'git preview hunk [i]nline' }) - map('n', 'hb', function() gitsigns.blame_line { full = true } end, { desc = 'git [b]lame line' }) - map('n', 'hd', gitsigns.diffthis, { desc = 'git [d]iff against index' }) - map('n', 'hD', function() gitsigns.diffthis '@' end, { desc = 'git [D]iff against last commit' }) - map('n', 'hQ', function() gitsigns.setqflist 'all' end, { desc = 'git hunk [Q]uickfix list (all files in repo)' }) - map('n', 'hq', gitsigns.setqflist, { desc = 'git hunk [q]uickfix list (all changes in this file)' }) - -- Toggles - map('n', 'tb', gitsigns.toggle_current_line_blame, { desc = '[T]oggle git show [b]lame line' }) - map('n', 'tw', gitsigns.toggle_word_diff, { desc = '[T]oggle git intra-line [w]ord diff' }) + -- Actions (visual mode) + map('v', 'hs', function() gitsigns.stage_hunk { vim.fn.line '.', vim.fn.line 'v' } end, { desc = 'git [s]tage hunk' }) + map('v', 'hr', function() gitsigns.reset_hunk { vim.fn.line '.', vim.fn.line 'v' } end, { desc = 'git [r]eset hunk' }) + -- Actions (normal mode) + map('n', 'hs', gitsigns.stage_hunk, { desc = 'git [s]tage hunk' }) + map('n', 'hr', gitsigns.reset_hunk, { desc = 'git [r]eset hunk' }) + map('n', 'hS', gitsigns.stage_buffer, { desc = 'git [S]tage buffer' }) + map('n', 'hR', gitsigns.reset_buffer, { desc = 'git [R]eset buffer' }) + map('n', 'hp', gitsigns.preview_hunk, { desc = 'git [p]review hunk' }) + map('n', 'hi', gitsigns.preview_hunk_inline, { desc = 'git preview hunk [i]nline' }) + map('n', 'hb', function() gitsigns.blame_line { full = true } end, { desc = 'git [b]lame line' }) + map('n', 'hd', gitsigns.diffthis, { desc = 'git [d]iff against index' }) + map('n', 'hD', function() gitsigns.diffthis '@' end, { desc = 'git [D]iff against last commit' }) + map('n', 'hQ', function() gitsigns.setqflist 'all' end, { desc = 'git hunk [Q]uickfix list (all files in repo)' }) + map('n', 'hq', gitsigns.setqflist, { desc = 'git hunk [q]uickfix list (all changes in this file)' }) + -- Toggles + map('n', 'tb', gitsigns.toggle_current_line_blame, { desc = '[T]oggle git show [b]lame line' }) + map('n', 'tw', gitsigns.toggle_word_diff, { desc = '[T]oggle git intra-line [w]ord diff' }) - -- Text object - map({ 'o', 'x' }, 'ih', gitsigns.select_hunk) - end, + -- Text object + map({ 'o', 'x' }, 'ih', gitsigns.select_hunk) + end, + }, } diff --git a/lua/kickstart/plugins/indent_line.lua b/lua/kickstart/plugins/indent_line.lua index 7187365656e..e445b2897ad 100644 --- a/lua/kickstart/plugins/indent_line.lua +++ b/lua/kickstart/plugins/indent_line.lua @@ -1,6 +1,5 @@ --- Add indentation guides even on blank lines - --- Enable `lukas-reineke/indent-blankline.nvim` --- See `:help ibl` -vim.pack.add { 'https://github.com/lukas-reineke/indent-blankline.nvim' } -require('ibl').setup {} +return { + 'lukas-reineke/indent-blankline.nvim', + main = 'ibl', + opts = {}, +} diff --git a/lua/kickstart/plugins/lint.lua b/lua/kickstart/plugins/lint.lua index d63054452fd..fe8bdf10340 100644 --- a/lua/kickstart/plugins/lint.lua +++ b/lua/kickstart/plugins/lint.lua @@ -1,53 +1,16 @@ --- Linting - -vim.pack.add { 'https://github.com/mfussenegger/nvim-lint' } - -local lint = require 'lint' -lint.linters_by_ft = { - markdown = { 'markdownlint' }, -- Make sure to install `markdownlint` via mason / npm -} - --- To allow other plugins to add linters to require('lint').linters_by_ft, --- instead set linters_by_ft like this: --- lint.linters_by_ft = lint.linters_by_ft or {} --- lint.linters_by_ft['markdown'] = { 'markdownlint' } --- --- However, note that this will enable a set of default linters, --- which will cause errors unless these tools are available: --- { --- clojure = { "clj-kondo" }, --- dockerfile = { "hadolint" }, --- inko = { "inko" }, --- janet = { "janet" }, --- json = { "jsonlint" }, --- markdown = { "vale" }, --- rst = { "vale" }, --- ruby = { "ruby" }, --- terraform = { "tflint" }, --- text = { "vale" } --- } --- --- You can disable the default linters by setting their filetypes to nil: --- lint.linters_by_ft['clojure'] = nil --- lint.linters_by_ft['dockerfile'] = nil --- lint.linters_by_ft['inko'] = nil --- lint.linters_by_ft['janet'] = nil --- lint.linters_by_ft['json'] = nil --- lint.linters_by_ft['markdown'] = nil --- lint.linters_by_ft['rst'] = nil --- lint.linters_by_ft['ruby'] = nil --- lint.linters_by_ft['terraform'] = nil --- lint.linters_by_ft['text'] = nil - --- Create autocommand which carries out the actual linting --- on the specified events. -local lint_augroup = vim.api.nvim_create_augroup('lint', { clear = true }) -vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost', 'InsertLeave' }, { - group = lint_augroup, - callback = function() - -- Only run the linter in buffers that you can modify in order to - -- avoid superfluous noise, notably within the handy LSP pop-ups that - -- describe the hovered symbol using Markdown. - if vim.bo.modifiable then lint.try_lint() end +return { + 'mfussenegger/nvim-lint', + config = function() + local lint = require 'lint' + lint.linters_by_ft = { + markdown = { 'markdownlint' }, + } + local lint_augroup = vim.api.nvim_create_augroup('lint', { clear = true }) + vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost', 'InsertLeave' }, { + group = lint_augroup, + callback = function() + if vim.bo.modifiable then lint.try_lint() end + end, + }) end, -}) +}