Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
aa04326
Update configuration
ffewster Oct 1, 2025
bbda49d
Upate Mason Config
ffewster Oct 1, 2025
ba8725e
Add copilot chat and other nice things
ffewster Oct 2, 2025
812c1e9
Update theme
ffewster Nov 13, 2025
38f5f2c
Enable copilot by default
ffewster Feb 16, 2026
1868d1b
Install avante
ffewster Feb 16, 2026
b35f282
Update markdown config
ffewster Apr 6, 2026
b1b3ccd
Merge remote-tracking branch 'upstream/master'
ffewster Apr 8, 2026
043b503
Update kickstart 08 08 2026 (#8)
ffewster Apr 8, 2026
1132190
Merge branch 'master' of github.com:ffewster/nvim-config
ffewster Apr 8, 2026
bd755b8
Add stability fixes
ffewster Apr 8, 2026
c9f38ea
Add snacks
ffewster Apr 8, 2026
3892cc8
Update default model usage for chat
ffewster Apr 14, 2026
b15f438
Update goto
ffewster Apr 23, 2026
cf45a5c
Add claude code
ffewster Apr 23, 2026
c993452
Fix helm lsp
ffewster May 12, 2026
1c9abab
General updates to theme
ffewster Jun 5, 2026
a708f57
Install gruvbox theme
ffewster Jun 5, 2026
e2bf4cb
add nix flake
ffewster Jul 4, 2026
4a2b090
Update flakefile
ffewster Jul 4, 2026
eca3983
Add kotlin support
ffewster Aug 13, 2026
8599dfb
Update neotree config for empty dirs
ffewster Aug 28, 2026
5078e23
Merge upstream/master: migrate from lazy.nvim to vim.pack
ffewster Sep 9, 2026
55b5d43
Pin custom plugin versions and track the vim.pack lockfile
ffewster Sep 9, 2026
cebe25b
Add instructions.md for managing plugins under vim.pack
ffewster Sep 9, 2026
28cdd67
Consolidate custom plugin vim.pack.add calls into one file
ffewster Sep 9, 2026
5d91d2a
Drop needless commit pins from custom plugins, match core style
ffewster Sep 9, 2026
320652e
Mirror vim.notify into :messages when snacks notifier is enabled
ffewster Oct 16, 2026
77c7735
Mirror notifications via notifier.filter instead of patching notify
ffewster Oct 16, 2026
253c387
Check if the buffer is valid when trying to attach TS
ollien Sep 8, 2026
9d3cfe8
Install the language first
ollien Sep 8, 2026
9557523
Small formatting fixes
oriori1703 Sep 14, 2026
5101480
Check buffer validity before loading Treesitter parser
TyceHerrman Sep 30, 2026
9298d8f
Fix invalid neo-tree window position
ffewster Oct 16, 2026
888ca59
Switch colorscheme to koda-dark
ffewster Oct 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ nvim

spell/

# In your personal fork, you likely want to comment this, since it's recommended to track
# nvim-pack-lock.json in version control - see :help vim.pack-lockfile
# For the official `nvim-lua/kickstart.nvim` git repository, we leave it ignored to avoid unneeded
# merge conflicts.
nvim-pack-lock.json
# Tracked in this personal fork (recommended - see :help vim.pack-lockfile).
# Only the official `nvim-lua/kickstart.nvim` repo ignores it, to avoid unneeded merge conflicts.
# nvim-pack-lock.json

.DS_Store
14 changes: 14 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
description = "Neovim config";

inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};

outputs = { self, nixpkgs }: {
# This exposes your repo as a plain source tree
lib = {
path = self;
};
};
}
106 changes: 70 additions & 36 deletions init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand All @@ -110,7 +110,7 @@ do
vim.o.number = true
-- You can also add relative line numbers, to help with jumping.
-- Experiment for yourself to see if you like it!
-- vim.o.relativenumber = true
vim.o.relativenumber = true

-- Enable mouse mode, can be useful for resizing splits for example!
vim.o.mouse = 'a'
Expand Down Expand Up @@ -305,6 +305,11 @@ do
return
end

if name == 'CopilotChat.nvim' and vim.fn.executable 'make' == 1 then
run_build(name, { 'make', 'tiktoken' }, 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
Expand All @@ -319,8 +324,8 @@ do
})
end

---Because most plugins are hosted on GitHub, you can use the helper
---function to have less repetition in the following sections.
--- 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
Expand Down Expand Up @@ -423,18 +428,21 @@ do
-- 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
},
}

-- 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'
--
-- NOTE: Colorscheme is managed in lua/custom/plugins/theme.lua instead, so the
-- default tokyonight install/setup/colorscheme below is disabled.
-- vim.pack.add { gh 'folke/tokyonight.nvim' }
-- ---@diagnostic disable-next-line: missing-fields
-- require('tokyonight').setup {
-- styles = {
-- comments = { italic = false }, -- Disable italics in comments
-- },
-- }
--
-- -- 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' }
Expand Down Expand Up @@ -519,7 +527,7 @@ do
-- 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)[]
---@type (string | vim.pack.Spec)[]
local telescope_plugins = {
gh 'nvim-lua/plenary.nvim',
gh 'nvim-telescope/telescope.nvim',
Expand All @@ -532,17 +540,9 @@ do

-- 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 = { ['<c-enter>'] = 'to_fuzzy_refine' },
-- },
-- },
-- pickers = {}
defaults = require('telescope.themes').get_ivy(),
extensions = {
['ui-select'] = { require('telescope.themes').get_dropdown() },
['ui-select'] = { require('telescope.themes').get_ivy() },
},
}

Expand Down Expand Up @@ -581,7 +581,7 @@ do
-- 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 <C-t>.
vim.keymap.set('n', 'grd', builtin.lsp_definitions, { buffer = buf, desc = '[G]oto [D]efinition' })
vim.keymap.set('n', 'gd', 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.
Expand Down Expand Up @@ -677,9 +677,10 @@ do
vim.keymap.set(mode, keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc })
end

-- Rename the variable under your cursor.
map('K', vim.lsp.buf.hover, 'Hover Documentation')

-- Most Language Servers support renaming across files, etc.
map('grn', vim.lsp.buf.rename, '[R]e[n]ame')
map('rn', 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.
Expand Down Expand Up @@ -746,6 +747,23 @@ do

stylua = {}, -- Used to format Lua code

kotlin_lsp = {},

yamlls = {
filetypes = { 'yaml', 'yaml.docker-compose' },
},

helm_ls = {
filetypes = { 'helm' },
settings = {
['helm-ls'] = {
yamlls = {
path = 'yaml-language-server',
},
},
},
},

-- Special Lua Config, as recommended by neovim help docs
lua_ls = {
on_init = function(client)
Expand Down Expand Up @@ -803,15 +821,24 @@ do
-- 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
'ts_ls',
'biome',
'docker_compose_language_service',
'dockerls',
'graphql',
'jsonls',
'eslint',
'bashls',
})

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

-- Enable all servers (both those with custom config and those with defaults)
vim.lsp.enable(ensure_installed)
end

-- ============================================================
Expand Down Expand Up @@ -954,8 +981,12 @@ do
---@param buf integer
---@param language string
local function treesitter_try_attach(buf, language)
-- Check if the buffer is valid (might not be after install completes)
if not vim.api.nvim_buf_is_valid(buf) then return end

-- 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)

Expand Down Expand Up @@ -1010,16 +1041,17 @@ do
-- 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.debug'
-- require 'kickstart.plugins.indent_line'
-- require 'kickstart.plugins.lint'
-- require 'kickstart.plugins.autopairs'
require 'kickstart.plugins.lint'
require 'kickstart.plugins.autopairs'
-- neo-tree is configured in lua/custom/plugins/neo-tree-config.lua instead
-- require 'kickstart.plugins.neo-tree'

-- NOTE: You can add your own plugins, configuration, etc. in `lua/custom/plugins/*.lua`.
--
-- For independent modules, uncomment the convenience loader:
-- require 'custom.plugins'
require 'custom.plugins'
--
-- `custom.plugins` automatically loads files from that directory, but their
-- order is unspecified. If plugins depend on each other, keep them in the same
Expand All @@ -1031,5 +1063,7 @@ do
-- require 'custom.plugins.git'
end

require 'custom.setup'

-- The line beneath this is called `modeline`. See `:help modeline`
-- vim: ts=2 sts=2 sw=2 et
112 changes: 112 additions & 0 deletions instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Managing plugins (vim.pack)

This config uses Neovim's built-in `vim.pack`, not `lazy.nvim`. There's no
`:Lazy` dashboard — updates go through `:lua vim.pack.update(...)`, which opens
an interactive confirmation buffer instead of a floating UI.

Every plugin here — core kickstart ones and custom ones alike — is added the
same way: bare `src`, no version pin, tracked via `nvim-pack-lock.json` like
everything else. Nothing moves until you deliberately run
`vim.pack.update(...)`, whether that's one plugin by name or everything at
once. `version` only shows up on a spec where it's a genuine branch/tag
selection (e.g. `neo-tree.nvim` defaults to `main`, but the stable line is the
separate `v3.x` branch — same idea as `nvim-treesitter`'s `version = 'main'`
in `init.lua`), never as a freeze mechanism.

- **Core kickstart plugins** — added in `init.lua` and
`lua/kickstart/plugins/*.lua`, as upstream ships them.
- **Custom plugins** — every `vim.pack.add()` call for them lives in one
place, `lua/custom/plugins/init.lua`. The individual files (`claude.lua`,
`comment.lua`, etc.) only contain `require(...).setup{}` and keymaps — they
don't call `vim.pack.add` themselves. This is deliberate: those files load
in an unspecified order (see the auto-discovery loop comment in `init.lua`),
so the `add()` calls have to happen earlier, in the one file guaranteed to
run first.

## Everyday commands

Check what's installed (name, current rev, path, spec):
```vim
:lua =vim.pack.get()
```

Preview + apply updates for everything (opens confirmation buffer, downloads first):
```vim
:lua vim.pack.update()
```

Update just one plugin (name from `vim.pack.get()`, not the file name):
```vim
:lua vim.pack.update({ 'Comment.nvim' })
```

Preview without downloading (e.g. after only editing a `version` field):
```vim
:lua vim.pack.update({ 'Comment.nvim' }, { offline = true })
```

Skip the confirmation buffer and apply immediately:
```vim
:lua vim.pack.update({ 'Comment.nvim' }, { force = true })
```

### In the confirmation buffer

- `]]` / `[[` — jump between plugin sections
- `gO` — outline of all plugins in the buffer
- `K` on a pending change — hover for changelog/details
- `gra` on a plugin — code actions: update / skip / delete it
- `:write` — apply everything shown; `:quit` — discard

## Switching a plugin's version/source, or freezing it

1. Edit its spec (in `init.lua` or `lua/custom/plugins/init.lua`) — set
`version` to a commit, tag, branch, or a range like
`vim.version.range('1.*')` if you want a ceiling; set it to an exact commit
to freeze it in place.
2. Relaunch nvim (or `:restart`). This only updates the *target* in
`nvim-pack-lock.json`, not the plugin on disk yet.
3. `:lua vim.pack.update({ 'PluginName' })`, review the diff, `:write` to apply
(or `:quit` to discard — then revert your edit too, or it'll nag again).

## Reverting a bad update

```sh
git checkout HEAD -- nvim-pack-lock.json # nvim-pack-lock.json is tracked in git
```
```vim
:restart
:lua vim.pack.update({ 'PluginName' }, { offline = true, target = 'lockfile' })
```
Review and confirm.

## Removing a plugin

Delete its entry from the `vim.pack.add {}` block in
`lua/custom/plugins/init.lua`, delete its own file under
`lua/custom/plugins/` (the `require(...).setup{}`/keymaps), then:
```vim
:lua vim.pack.del({ 'PluginName' })
```

## Where things live

- Lockfile: `nvim-pack-lock.json` (tracked in this repo — un-ignored on
purpose, see `.gitignore`).
- Update history: `nvim-pack.log` under `:lua print(vim.fn.stdpath('log'))`.
- Plugin checkouts (plain git repos): `~/.local/share/nvim/site/pack/core/opt/<name>/`
- Docs: `:help vim.pack`, `:help vim.pack-examples`, `:help vim.pack-lockfile`

## Custom plugin list

Lives in `lua/custom/plugins/init.lua`, in one `vim.pack.add {}` block at the
top of the file — that's the single source of truth for which custom plugins
exist and how each is specced, so there's no separate table here to go stale.

## Optional: a fancier UI

[pack.nvim](https://github.com/igmrrf/pack.nvim) wraps `vim.pack` in a
floating dashboard closer to what `lazy.nvim`'s `:Lazy` gave you. As of writing
it's very new (single maintainer, a handful of stars) and would sit in the
critical path of every plugin loading, so it hasn't been added here — the
built-in confirmation buffer above covers most of the same workflow already.
22 changes: 22 additions & 0 deletions lua/custom/plugins/claude.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-- installed via lua/custom/plugins/init.lua
require('claudecode').setup {
terminal_cmd = vim.fn.system('which claude'):gsub('\n', ''),
}

require('which-key').add { { '<leader>a', group = 'AI/Claude Code' } }

vim.keymap.set({ 'n', 'x' }, '<C-,>', '<cmd>ClaudeCodeFocus<cr>', { desc = 'Toggle Claude' })
vim.keymap.set('n', '<leader>ac', '<cmd>ClaudeCode<cr>', { desc = 'Toggle Claude' })
vim.keymap.set('n', '<leader>af', '<cmd>ClaudeCodeFocus<cr>', { desc = 'Focus Claude' })
vim.keymap.set('n', '<leader>ar', '<cmd>ClaudeCode --resume<cr>', { desc = 'Resume Claude' })
vim.keymap.set('n', '<leader>aC', '<cmd>ClaudeCode --continue<cr>', { desc = 'Continue Claude' })
vim.keymap.set('n', '<leader>am', '<cmd>ClaudeCodeSelectModel<cr>', { desc = 'Select Claude model' })
vim.keymap.set('n', '<leader>ab', '<cmd>ClaudeCodeAdd %<cr>', { desc = 'Add current buffer' })
vim.keymap.set('v', '<leader>as', '<cmd>ClaudeCodeSend<cr>', { desc = 'Send to Claude' })
vim.keymap.set('n', '<leader>aa', '<cmd>ClaudeCodeDiffAccept<cr>', { desc = 'Accept diff' })
vim.keymap.set('n', '<leader>ad', '<cmd>ClaudeCodeDiffDeny<cr>', { desc = 'Deny diff' })

vim.api.nvim_create_autocmd('FileType', {
pattern = { 'NvimTree', 'neo-tree', 'oil', 'minifiles', 'netrw' },
callback = function(ev) vim.keymap.set('n', '<leader>as', '<cmd>ClaudeCodeTreeAdd<cr>', { buffer = ev.buf, desc = 'Add file' }) end,
})
5 changes: 5 additions & 0 deletions lua/custom/plugins/comment.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- installed via lua/custom/plugins/init.lua
require('Comment').setup()

vim.keymap.set('n', '<leader>/', function() require('Comment.api').toggle.linewise.current() end, { desc = 'comment toggle' })
vim.keymap.set('v', '<leader>/', "<ESC><cmd>lua require('Comment.api').toggle.linewise(vim.fn.visualmode())<CR>", { desc = 'comment toggle' })
7 changes: 7 additions & 0 deletions lua/custom/plugins/copilot-chat.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- installed via lua/custom/plugins/init.lua
vim.keymap.set('n', '<leader>ch', '<Cmd>CopilotChatToggle<CR>', { noremap = true, silent = true })

require('CopilotChat').setup {
-- See Configuration section for options
model = 'claude-sonnet-4.6',
}
Loading