Compare commits

111 Commits

Author SHA1 Message Date
Chris
bd2349c1ba Merge branch 'main' of labs.scarif.space:chris/nvim 2026-03-31 14:15:49 +01:00
Chris
b4fd6c1988 Fixing treesitter 2026-03-31 14:15:12 +01:00
8d1278b84a Fix pywal missing 2026-03-09 23:20:40 +00:00
e4a935de25 Use tokyo for fallback 2026-03-08 20:58:50 +00:00
d8732c5e2e Update files 2026-03-08 20:50:10 +00:00
ba41c9a054 Add pywal theme 2026-03-08 20:48:24 +00:00
894d2fcabf Update files 2026-03-06 17:06:16 +00:00
40adefb70c Update files 2026-03-06 17:05:20 +00:00
faea500177 Update files 2026-03-06 17:02:36 +00:00
6f74961fc6 Fix treesitter 2026-03-01 20:52:19 +00:00
cc7139c2ff Add keymap to reload file 2026-02-22 20:02:46 +00:00
Chris
bac22a5657 Comment out annoying snippets 2026-02-19 09:04:46 +00:00
20d080e223 Stuff 2026-02-15 21:35:09 +00:00
847c71a194 Update projects 2025-12-23 22:52:37 +00:00
Chris
78b8bf177c Merge branch 'main' of labs.scarif.space:chris/nvim 2025-12-18 09:18:41 +00:00
Chris
4f8e722f13 Snippets 2025-12-18 09:18:00 +00:00
1f58b9f136 More snippets 2025-12-17 16:52:51 +00:00
Chris
4d3aada204 Remove textobjects 2025-12-10 14:26:27 +00:00
Chris
d53821dbf7 textobjects 2025-12-10 11:47:00 +00:00
e89dbcac87 Cool stuff 2025-12-09 23:07:24 +00:00
5bf1ec232e Super keymaps 2025-12-09 22:49:24 +00:00
aded597ffe Trying stuff 2025-12-09 22:10:16 +00:00
Chris
282301e206 Plugins 2025-12-09 16:24:08 +00:00
9bd219f053 Snippets 2025-12-09 10:35:51 +00:00
0cce7837f2 God of snippets 2025-12-08 20:18:20 +00:00
Chris
f79e89d335 Snippets 2025-12-08 16:33:11 +00:00
Chris
1f5a3d19f2 Migrate map 2025-12-08 09:29:10 +00:00
dc5d2e20ff Snippets 2025-12-08 00:52:01 +00:00
256a5695ed Super keymaps 2025-12-07 18:47:34 +00:00
2a4578e1eb Better typescript 2025-11-21 19:36:05 +00:00
52ae098ac6 Add laravel maps 2025-11-16 10:01:02 +00:00
1c96d03649 Fix some things 2025-11-15 13:55:47 +00:00
Chris
344623eaf6 Hylark settings 2025-11-12 09:21:24 +00:00
f16cb91875 Stuff 2025-11-11 22:58:02 +00:00
8e2d413e0a Yazi plugin 2025-11-11 21:51:41 +00:00
2062c442b2 Fix copilot check 2025-11-10 20:58:07 +00:00
Chris
2255489fd8 Sharing config 2025-11-10 09:19:30 +00:00
a21a1a3386 More changes 2025-11-09 23:03:51 +00:00
529cfa79c8 More project specific stuff 2025-11-07 22:10:53 +00:00
f8f6d8e776 Quicker and project specific settings 2025-11-07 14:27:25 +00:00
5016dd4ee8 Add completion ignore ft 2025-10-29 20:29:38 +00:00
37b4d8a6e4 Ignore buffer 2025-10-25 14:50:02 +01:00
Chris
d44eac696f Remove 2025-10-21 09:52:22 +01:00
Chris
5c08ce032e Rename files 2025-10-21 09:50:49 +01:00
9415b1df07 More on AI 2025-10-19 13:07:29 +01:00
406e5cfe8e AI stuff 2025-10-19 10:01:51 +01:00
Chris
6a0c90bf26 Merge branch 'main' of labs.scarif.space:chris/nvim 2025-09-08 09:22:01 +01:00
Chris
7744e83086 Update snippets 2025-09-08 09:20:42 +01:00
d4ecc5aa67 Improve debugging 2025-09-08 09:19:08 +01:00
Chris
2b1d2ed5be Update snippets 2025-08-26 18:23:17 +01:00
ca6e7089fa Type 2025-08-23 12:16:33 +01:00
4f6f50cd6f Update phpactor 2025-08-13 09:04:55 +01:00
Chris
b4821e8a52 Import with extensions 2025-07-30 16:20:50 +01:00
Chris
dc0fed3735 Cleaning up 2025-07-25 12:32:22 +01:00
Chris
b72760d868 Remove go server 2025-07-24 14:34:27 +01:00
Chris
7ec52ae64a Merge branch 'main' of labs.scarif.space:chris/nvim 2025-07-24 14:31:25 +01:00
Chris
278f31d4ea Fixing lsp 2025-07-24 14:27:38 +01:00
ebb69274ba Update aider and projects 2025-07-19 11:52:57 +01:00
ff00984c4e Reordering 2025-07-01 22:44:17 +01:00
6fb67640ef Improve dashboard 2025-07-01 22:39:59 +01:00
Chris
2dc48b5b4c More aider commands 2025-06-30 09:10:05 +01:00
379f2acd55 Update aider shortcut 2025-06-26 16:46:04 +01:00
ed1f52af11 Comment out vectorcode 2025-06-20 22:16:56 +01:00
Chris
f090b1a43e More settings 2025-05-12 17:09:14 +01:00
Chris
4975f4c459 Improvements to Code companion 2025-05-12 09:04:50 +01:00
Chris
d97fdc798f Lighten line number colors 2025-05-12 09:04:50 +01:00
6f3a5a40e5 Install Aider 2025-05-11 18:22:49 +01:00
Chris
ea9ee8267a Start on insert mode 2025-05-08 07:59:46 +01:00
Chris
b8d7a1c9ab Updating debug 2025-05-07 07:58:00 +01:00
Chris
ed622165b8 Fixing some things 2025-05-06 07:18:21 +01:00
3ba111e55c Fix typo 2025-05-05 07:28:57 +01:00
c084f286a1 Merge branch 'fix-detached' 2025-05-05 07:28:04 +01:00
acccc74130 Fixing the keymap for changing model 2025-05-05 07:27:24 +01:00
c329bab9d6 Adding MCP Hub 2025-05-05 07:25:00 +01:00
Chris
6dfef7bd87 Upgrade config 2025-05-02 20:58:31 +01:00
Chris
17e642dcd3 Adding some snippets and keymaps 2025-04-29 17:22:36 +01:00
767d2595cd Delete chroma.log 2025-04-28 09:20:31 +01:00
cfb3885afd Fix closing logic 2025-04-28 08:38:30 +01:00
Chris
f6c23ab11a Fix merge conflict 2025-04-24 12:02:34 +01:00
Chris
ca3a910401 Snippets 2025-04-24 12:01:48 +01:00
Chris
62b3b156fa More changes 2025-04-24 12:00:18 +01:00
c7d39fe79c Close vim if only non-file windows are open 2025-04-23 22:38:44 +01:00
bf83c416c5 Typo 2025-04-22 16:55:58 +01:00
0940219a08 Only use Wakatime on mac 2025-04-15 21:03:11 +01:00
Chris
eeb4e44367 Improved AI tools 2025-04-15 20:48:35 +01:00
Chris
c3574de9bc First day of development changes 2025-04-14 15:20:54 +01:00
Chris
01164c6d8b More plugin configuration 2025-04-14 11:38:42 +01:00
f2f3b1812a Loads of changes 2025-04-13 22:53:08 +01:00
dd502a800b Massive changes!! 2025-04-12 23:49:02 +01:00
df042cfac2 Comment out wakatime 2023-10-12 22:09:23 +01:00
Chris
c62942a6fc Update mappings and install CoC 2023-06-13 09:13:09 +01:00
Chris
4dafaf9154 Sorting things out 2023-01-18 17:09:15 +00:00
ChrisExP
3ff95478b3 Add icons 2022-07-18 14:00:21 +01:00
6e6d769d6c Update bindings and add consistency 2021-12-05 20:36:40 +00:00
33211744c8 Fix colorscheme 2021-11-23 19:33:07 +00:00
61f98e0d8e Fix commit key binding 2021-10-23 10:53:10 +01:00
b44d1aeb66 Add carriage return 2021-10-15 21:06:07 +01:00
10de5ba6f5 Add push and pull 2021-10-15 21:05:28 +01:00
6190015222 Add git key bindings 2021-10-15 21:04:15 +01:00
47b7681b02 Fork commentary to work with template files 2021-10-12 22:10:43 +01:00
fba50be42b Add git 2021-10-09 23:54:58 +01:00
489aa75216 Better key bindings 2021-10-09 22:46:37 +01:00
e535a07c61 Fix folds and rulers 2021-10-09 00:22:02 +01:00
d45c929847 better cursorline 2021-10-09 00:07:31 +01:00
8e56b8e025 Fix colors in chadtree 2021-10-08 19:32:15 +01:00
179d23770d Adding chadtree plugin 2021-10-07 20:43:23 +01:00
f7d2632d20 Change sudo to doas 2021-07-16 16:53:23 +01:00
ffb080ca7f Add markdown support 2021-06-20 15:15:40 +01:00
40b9ec87f9 Fix split management 2021-06-13 11:42:15 +01:00
2b5957097a FiX typo 2021-06-10 22:53:25 +01:00
b4987eec8d Allow saving files as sudo 2021-05-17 21:08:28 +01:00
53 changed files with 4139 additions and 1539 deletions

11
.gitignore vendored
View File

@@ -1,2 +1,9 @@
*
!init.vim
.env
tags
test.sh
.luarc.json
nvim
spell/
lazy-lock.json

6
.stylua.toml Normal file
View File

@@ -0,0 +1,6 @@
column_width = 160
line_endings = "Unix"
indent_type = "Spaces"
indent_width = 4
quote_style = "AutoPreferSingle"
call_parentheses = "None"

View File

@@ -0,0 +1,114 @@
{
"name": "Neovim Configuration",
"version": "1.0.0",
"system_prompt": "You are an expert Neovim configuration assistant. Help the user understand and modify their Neovim setup. Focus on clear explanations and suggest improvements when appropriate.",
"vars": {
"lua_dir": "lua"
},
"groups": [
{
"name": "Core Configuration",
"system_prompt": "These files define the core Neovim behavior including options, keymaps, and autocommands. When suggesting changes, ensure they align with Neovim best practices.",
"data": [
"core_opt",
"core_keymap",
"core_autocmd",
"core_helpers"
]
},
{
"name": "Plugin Management",
"system_prompt": "This file contains the plugin manager setup. Help the user understand plugin dependencies and installation patterns.",
"data": [
"lazy_init"
]
},
{
"name": "LSP Configuration",
"system_prompt": "These files define the Language Server Protocol setup. Help the user configure language servers, diagnostics, and code actions.",
"data": [
"lsp_config"
]
},
{
"name": "Frequently Used Plugins",
"system_prompt": "These are plugins the user frequently configures. Provide detailed explanations about their options and how they interact with the rest of the configuration.",
"data": [
"plugin_codecompanion",
"plugin_edgy",
"plugin_snacks",
"plugin_mini",
"plugin_telescope"
]
},
{
"name": "UI and Theme",
"system_prompt": "These files define the visual appearance of Neovim. Help the user understand how to customize colors and UI elements.",
"data": [
"plugin_colorscheme"
]
}
],
"data": {
"core_opt": {
"type": "file",
"path": "${lua_dir}/opt.lua",
"description": "Neovim options configuration"
},
"core_keymap": {
"type": "file",
"path": "${lua_dir}/keymap.lua",
"description": "Key mappings configuration"
},
"core_autocmd": {
"type": "file",
"path": "${lua_dir}/autocmd.lua",
"description": "Automatic commands configuration"
},
"core_helpers": {
"type": "file",
"path": "${lua_dir}/helpers.lua",
"description": "Helper functions for Neovim configuration"
},
"lazy_init": {
"type": "file",
"path": "${lua_dir}/lazy_init.lua",
"description": "Lazy plugin manager initialization"
},
"lsp_config": {
"type": "file",
"path": "${lua_dir}/plugins/lsp.lua",
"description": "LSP plugins and configuration"
},
"plugin_codecompanion": {
"type": "file",
"path": "${lua_dir}/plugins/codecompanion.lua",
"description": "CodeCompanion plugin configuration"
},
"plugin_edgy": {
"type": "file",
"path": "${lua_dir}/plugins/edgy.lua",
"description": "Edgy plugin configuration"
},
"plugin_snacks": {
"type": "file",
"path": "${lua_dir}/plugins/snacks.lua",
"description": "Snacks plugin configuration"
},
"plugin_mini": {
"type": "file",
"path": "${lua_dir}/plugins/mini.lua",
"description": "Mini plugins configuration"
},
"plugin_telescope": {
"type": "file",
"path": "${lua_dir}/plugins/telescope.lua",
"description": "Telescope fuzzy finder configuration"
},
"plugin_colorscheme": {
"type": "file",
"path": "${lua_dir}/plugins/color.lua",
"description": "Color scheme and UI appearance configuration"
}
}
}

File diff suppressed because it is too large Load Diff

64
init.lua Normal file
View File

@@ -0,0 +1,64 @@
-- Set <space> as the leader key
-- See `:help mapleader`
-- NOTE: Must happen before plugins are loaded (otherwise wrong leader will be used)
vim.g.mapleader = ','
vim.g.maplocalleader = ','
-- Set to true if you have a Nerd Font installed and selected in the terminal
vim.g.have_nerd_font = true
require 'opt'
require 'keymap'
require 'autocmd'
require 'lazy_init'
require 'visuals'
require 'projects'
require('helpers').edit_cf('v', '/init.lua')
--[[
TODO: Neovim configurations I want to add:
- [x] Clearer line numbers (weirdly not as simple as it sounds)
- [ ] Debugging keymap that works like PHPStorm
- [ ] Improve snippet expansion (and get rid of that stupid #endsection snippet)
- [ ] Better organising of buffers when opening side panels (like AI chat and test summary)
- [ ] Close test panel when opening debugger and vice versa using edgy
- [ ] Close terminal from inside terminal buffer
- [ ] Get shift key bindings working inside tmux
- [ ] Fix ctrl+shift+a keybinding for AI actions
- [ ] Get VectorCode working
- [ ] Add LSP symbols for Pest tests
- [ ] More prompts
- [ ] Give AI better context and tools for working with Hylark
- [ ] Figure out AI workspaces
- [ ] Figure out agentic workflow
- [ ] Figure out a better way to add relevant buffers to AI
- [ ] Better inline AI assistant
- [ ] Keymap to copy visual selection to chat
- [ ] Better register management
- [ ] Figure out debug expressions
- [ ] Better keymaps for debug movements
- [ ] Chat history
]]
-- " Auto-Commands --- {{{
--
-- augroup modes
-- autocmd!
-- autocmd FocusLost * call feedkeys("\<Esc>") "Go to normal mode when moving away
-- autocmd BufNewFile * call feedkeys("i") "Go to insert mode when starting a new file
-- augroup END
--
-- "Recompile suckless software when updating config
-- augroup suckless
-- autocmd BufWritePost ~/.local/src/dwmblocks/config.h !cd ~/.local/src/dwmblocks/; doas make install && { killall -q dwmblocks;setsid -f dwmblocks }
-- autocmd BufWritePost ~/.local/src/dwm/config.h !cd ~/.local/src/dwm/; doas make clean install
-- autocmd BufWritePost ~/.local/src/st/config.h !cd ~/.local/src/st/; doas make clean install
-- " }}}
--
-- " Notes and tips
-- " - press 'zz' to instantly center the line where the cursor is located.
-- " - You can increment numbers with <c-a>.
-- " - To operate on multiple lines use <c-v> to select the lines, <c-i> to go to
-- " insert mode, perform edit, press <esc>.
-- " - Use the command :r to paste the output of a command to the buffer.

224
init.vim
View File

@@ -1,224 +0,0 @@
" Plugins --- {{{
if ! filereadable(system('echo -n "${XDG_CONFIG_HOME:-$HOME/.config}/nvim/autoload/plug.vim"'))
echo "Downloading junegunn/vim-plug to manage plugins..."
silent !mkdir -p ${XDG_CONFIG_HOME:-$HOME/.config}/nvim/autoload/
silent !curl "https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim" > ${XDG_CONFIG_HOME:-$HOME/.config}/nvim/autoload/plug.vim
autocmd VimEnter * PlugInstall
endif
call plug#begin(stdpath('data') . '/plugged')
Plug 'rafi/awesome-vim-colorschemes'
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'
Plug 'tpope/vim-surround'
Plug 'tpope/vim-commentary'
Plug 'tpope/vim-unimpaired'
Plug 'jiangmiao/auto-pairs'
Plug 'pangloss/vim-javascript'
Plug 'mattn/emmet-vim'
Plug 'dylanaraps/wal.vim'
"Plug 'sheerun/vim-polyglot'
"Plug 'phpactor/phpactor', { 'do': 'composer install', 'for': 'php' }
"Plug 'ncm2/ncm2'
"Plug 'roxma/nvim-yarp'
"autocmd BufEnter * call ncm2#enable_for_buffer()
"set completeopt=noinsert,menuone,noselect
"Plug 'phpactor/ncm2-phpactor'
call plug#end()
" }}}
" Basic settings ---- {{{
set nocompatible "Use the latest vim settings/options
syntax enable "Enable syntax highlighting
let mapleader = ',' "The default leader is \, but a comma is much better
let localleader = '\\' "The leader to be used for filetype specific mappings
set number relativenumber "Show relative line numbers
set noerrorbells visualbell t_vb= "Remove the bells
set tabstop=4 "Set how many columns a tab counts for
set shiftwidth=4 "How many columns text is indented when using reindent
set softtabstop=4 "Set columns for tabs in insert mode
set expandtab "Use spaces instead of tabs
set smartindent "Automatically indent code
set ignorecase "Ignores case when searching
set smartcase "Doesn't ignore case when the search includes upper case characters
set backupdir=/tmp// "Store backup files in the /tmp directory
set directory=/tmp// "Store swap files in the /tmp directory
set undodir=/tmp// "Store undo history in the /tmp directory
set undofile "Store the undo history
"set spell "Enable spell checking
set autowriteall "Save the file when switching buffers
"}}}
" Visuals ---- {{{
" colorscheme atom-dark
colorscheme wal
" set t_Co=256 "User 256 colors. This is useful for terminal vim
set guifont=Fira_Code:h17
set guioptions-=e "We don't want GUI tabs
set guioptions-=l
set guioptions-=L
set guioptions-=r
set guioptions-=R
set nowrap "Don't wrap lines around
"Set line number Colour to be same as background
hi LineNr guibg=bg
"Get rid of ugly split borders
hi vertsplit guifg=bg guibg=bg
" }}}
" Split Management --- {{{
set splitbelow
set splitright
"We'll set simpler mappings to switch between splits
nnoremap <C-J> <C-W><C-J>
nnoremap <C-K> <C-W><C-K>
nnoremap <C-H> <C-W><C-H>
nnoremap <C-L> <C-W><C-L>
" }}}
" Search --- {{{
set hlsearch
set incsearch
set path+=**
" }}}
" Mappings --- {{{
" Editing files - {{{
"Make it easy to edit the vimrc file
nnoremap <Leader>ev :tabedit $MYVIMRC<cr>
"Source the vimrc file
nnoremap <Leader>es :source $MYVIMRC<cr>
" }}}
"Add simple highlight removal
nnoremap <Leader><space> :nohlsearch<cr>
"Convert tabs to spaces
nnoremap <Leader><Tab> :retab<cr>
"Map movement keys to Escape
inoremap jj <Esc>
inoremap jk <Esc>
inoremap kk <Esc>
inoremap hh <Esc>
"Delete a line in insert mode
inoremap <C-d> <Esc>ddi
"Use semicolon instead of colon for commands
nnoremap ; :
"Append the line with a semicolon
inoremap <Leader>; <Esc>mzA;<Esc>`za
nnoremap <Leader>; mzA;<Esc>`za<Esc>
"Easily navigate items in the quickfix menu
nnoremap <Leader>] :cnext<cr>
nnoremap <Leader>[ :cprevious<cr>
"Indent arrays
nnoremap <Leader>{ mzF[`a<cr><Esc>``%i<cr><Esc>`z
nnoremap <Leader>} mzF[`a<cr><Esc>``%i<cr><Esc>`zvi[:s/,\s*/,\r/g<cr>vi[=<Esc>`z:nohlsearch<cr>
"A command to properly indent json code
com! FormatJSON %!python -m json.tool
" }}}
" Plugins --- {{{
" Toggle emmet completion useing <Tab> with <Leader>em
let g:emmet_completion = 0
function ToggleEmmet()
if g:emmet_completion
echo "Emmet completion off!"
let g:user_emmet_expandabbr_key=','
iunmap <tab>
let g:emmet_completion = 0
else
echo "Emmet completion on!"
let g:user_emmet_expandabbr_key='<Tab>'
imap <expr> <tab> emmet#expandAbbrIntelligent("\<tab>")
let g:emmet_completion = 1
endif
endfunction
nnoremap <Leader>em :call ToggleEmmet()<cr>
" }}}
" Moving around --- {{{
"Use capital H and L to move to the start and end of lines
nnoremap H ^
nnoremap L $
"Move a line up or down
nnoremap <C-j> ddp
nnoremap <C-k> ddkP
" }}}
" Operator mappings --- {{{
onoremap in( :<C-u>normal! f(vi(<cr>
onoremap il( :<C-u>normal! F)vi(<cr>
onoremap an( :<C-u>normal! f(va(<cr>
onoremap al( :<C-u>normal! F)va(<cr>
onoremap an{ :<C-u>normal! f{vi(<cr>
onoremap al{ :<C-u>normal! F}vi(<cr>
" }}}
" Abbreviations --- {{{
iabbrev adn and
iabbrev waht what
iabbrev tehn then
iabbrev tihs this
iabbrev teh the
iabbrev Teh The
" }}}
" Auto-Commands --- {{{
"Automatically source the config files on save.
augroup autosourcing
autocmd!
autocmd BufWritePost $MYVIMRC source % "Source the vimrc file
augroup END
"Fold vimrc and zshrc files on open
augroup autofolding
autocmd!
autocmd BufReadPost $MYVIMRC :setlocal foldlevelstart=0
autocmd FileType vim setlocal foldmethod=marker
autocmd BufReadPost zsh :setlocal foldlevelstart=0
autocmd FileType zsh setlocal foldmethod=marker
augroup END
"Automatically save files
augroup autosaving
autocmd!
autocmd FocusLost * silent! wa "Save all files when moving away from the window
augroup END
augroup modes
autocmd!
autocmd FocusLost * call feedkeys("\<Esc>") "Go to normal mode when moving away
autocmd BufNewFile * call feedkeys("i") "Go to insert mode when starting a new file
augroup END
"Recompile suckless software when updating config
augroup suckless
autocmd BufWritePost ~/.local/src/dwmblocks/config.h !cd ~/.local/src/dwmblocks/; sudo make install && { killall -q dwmblocks;setsid -f dwmblocks }
autocmd BufWritePost ~/.local/src/dwm/config.h !cd ~/.local/src/dwm/; sudo make clean install
autocmd BufWritePost ~/.local/src/st/config.h !cd ~/.local/st/dwm/; sudo make clean install
" }}}
" Notes and tips
" - press 'zz' to instantly center the line where the cursor is located.
" - You can increment numbers with <c-a>.
" - To operate on multiple lines use <c-v> to select the lines, <c-i> to go to
" insert mode, perform edit, press <esc>.
" - Use the command :r to paste the output of a command to the buffer.

210
lua/autocmd.lua Normal file
View File

@@ -0,0 +1,210 @@
-- [[ Basic Autocommands ]]
-- See `:help lua-guide-autocommands`
-- Highlight when yanking (copying) text
-- Try it with `yap` in normal mode
-- See `:help vim.highlight.on_yank()`
vim.api.nvim_create_autocmd('TextYankPost', {
desc = 'Highlight when yanking (copying) text',
group = vim.api.nvim_create_augroup('kickstart-highlight-yank', { clear = true }),
callback = function()
vim.highlight.on_yank()
end,
})
local autosave_group = vim.api.nvim_create_augroup('autosaving', { clear = true })
vim.api.nvim_create_autocmd('FocusLost', {
group = autosave_group,
pattern = '*',
command = 'silent! wa', -- Save all files when moving away from the window
})
vim.api.nvim_create_autocmd('InsertLeave', {
group = autosave_group,
pattern = '*',
command = 'silent! wa', -- Save all files when leaving insert mode
})
vim.api.nvim_create_autocmd('SwapExists', {
desc = 'Always choose to delete the swap file, files are saved automatically',
group = vim.api.nvim_create_augroup('NoSwaps', { clear = true }),
callback = function(args)
vim.cmd "let v:swapchoice = 'd'"
end,
})
-- vim.api.nvim_create_autocmd('TextChanged', {
-- group = autosave_group,
-- pattern = '*',
-- command = 'silent! wa', -- Save all files when text is changed
-- })
vim.api.nvim_create_autocmd('User', {
pattern = 'OilActionsPost',
callback = function(event)
if event.data.actions.type == 'move' then
Snacks.rename.on_rename_file(event.data.actions.src_url, event.data.actions.dest_url)
end
end,
})
local fidget_group = vim.api.nvim_create_augroup('CodeCompanionFidgetHooks', { clear = true })
vim.api.nvim_create_autocmd({ 'User' }, {
pattern = 'CodeCompanionRequestStarted',
group = fidget_group,
callback = function(event)
local FidgetHelper = require 'utils.fidget_helper'
-- Pass event instead of request if the callback receives the full event object
local handle = FidgetHelper:create_progress_handle(event)
FidgetHelper:store_progress_handle(event.data.id, handle)
end,
})
vim.api.nvim_create_autocmd({ 'User' }, {
pattern = 'CodeCompanionRequestFinished',
group = fidget_group,
callback = function(event)
local FidgetHelper = require 'utils.fidget_helper'
local handle = FidgetHelper:pop_progress_handle(event.data.id)
if handle then
FidgetHelper:report_exit_status(handle, event)
handle:finish()
end
end,
})
-- vim.api.nvim_create_autocmd('BufEnter', {
-- callback = function(event)
-- local windows = vim.api.nvim_list_wins()
--
-- for _, window in ipairs(windows) do
-- local bufnr = vim.api.nvim_win_get_buf(window)
-- local ft = vim.api.nvim_get_option_value('filetype', { buf = bufnr })
-- if vim.api.nvim_get_option_value('buflisted', { buf = bufnr })
-- or ft == 'oil'
-- or ft == 'snacks_dashboard' then
-- return
-- end
-- end
-- vim.cmd 'qa'
-- end,
-- })
local modes_group = vim.api.nvim_create_augroup('modes', { clear = true })
vim.api.nvim_create_autocmd('FocusLost', {
group = modes_group,
pattern = '*',
command = 'call feedkeys("\\<Esc>")',
})
vim.api.nvim_create_autocmd('BufNewFile', {
group = modes_group,
pattern = '*',
command = 'call feedkeys("i")',
})
-- Reload LuaSnip snippets when saving files in the snippets directory
local snippets_dir = vim.fn.stdpath 'config' .. '/lua/snippets'
vim.api.nvim_create_autocmd('BufWritePost', {
pattern = snippets_dir .. '/*.json', -- Adjust the path to match your snippets directory
desc = 'Reload LuaSnip snippets on save',
callback = function()
require('luasnip.loaders.from_vscode').lazy_load { paths = { snippets_dir } }
vim.notify('Snippets reloaded!', vim.log.levels.INFO)
end,
})
local configs = {
{
path = os.getenv("HOME") .. "/.config/nixos",
worktree = nil,
git_dir = nil,
track_untracked = false,
force_add = false
},
{
path = os.getenv("HOME") .. "/.config/nvim",
worktree = nil,
git_dir = nil,
track_untracked = false,
force_add = false
},
{
path = os.getenv("HOME"),
worktree = os.getenv("HOME"),
git_dir = os.getenv("HOME") .. "/.config/dotfiles/.git",
track_untracked = true,
force_add = true, -- Handles ignored files in dotfiles
include_dirs = { ".config", ".local/bin", ".local/share" }
}
}
local function get_git_status(config)
local base = "git"
if config.git_dir and config.worktree then
base = string.format("git --git-dir=%s --worktree=%s", config.git_dir, config.worktree)
end
-- Check modified and untracked (including ignored if force_add is true)
local cmd = base .. " status --porcelain"
if config.force_add then cmd = cmd .. " --ignored" end
local handle = io.popen(cmd)
local result = handle:read("*a")
handle:close()
local has_changes = false
for line in result:gmatch("[^\r\n]+") do
local status = line:sub(1, 2)
local file = line:sub(4)
if status:match("[MAR]") then
has_changes = true
elseif (status == "??" or status == "!!") and config.track_untracked then
if config.include_dirs then
for _, dir in ipairs(config.include_dirs) do
if file:sub(1, #dir) == dir then
has_changes = true
break
end
end
else
has_changes = true
end
end
end
return has_changes, base
end
vim.api.nvim_create_autocmd("VimLeavePre", {
callback = function()
local cwd = vim.fn.getcwd()
for _, config in ipairs(configs) do
if cwd:sub(1, #config.path) == config.path then
local has_changes, git_base = get_git_status(config)
if has_changes then
local confirm = vim.fn.confirm("Uncommitted changes in managed path. Commit?", "&Yes\n&No", 2)
if confirm == 1 then
local msg = vim.fn.input("Commit message: ", "chore: update files")
if msg ~= "" then
msg = "Update files"
end
local add_cmd = " add -A"
os.execute(git_base .. add_cmd)
os.execute(git_base .. " commit -m " .. vim.fn.shellescape(msg))
os.execute(git_base .. " push")
print("\nChanges committed.")
end
end
break
end
end
end,
})
require('helpers').edit_cf('a', '/lua/autocmd.lua')

58
lua/helpers.lua Normal file
View File

@@ -0,0 +1,58 @@
local helpers = {}
--- Creates a keymap to edit a certain config file
--- @param map string the keys that follow <Leader>e
--- @param path string the relative path from the config root
helpers.edit_cf = function(map, path)
vim.keymap.set('n', '<Leader>e' .. map, function()
vim.cmd('tabedit ' .. vim.fn.stdpath 'config' .. '/' .. path)
end, { desc = 'Edit ' .. path .. ' in a new tab' })
end
helpers.map = function(keys, func, opts, mode)
mode = mode or 'n'
vim.keymap.set(mode, keys, func, opts)
end
helpers.edit_cf('h', '/lua/helpers.lua')
---@param opts? { cmd?: string }
helpers.open_term = function(opts)
opts = opts or { cmd = '' }
local buf = vim.api.nvim_create_buf(false, true)
vim.api.nvim_set_option_value('bufhidden', 'wipe', { buf = buf })
vim.api.nvim_set_option_value('modifiable', false, { buf = buf })
local height = math.ceil(vim.o.lines * 0.9)
local width = math.ceil(vim.o.columns * 0.9)
local win = vim.api.nvim_open_win(buf, true, {
style = 'minimal',
relative = 'editor',
width = width,
height = height,
row = math.ceil((vim.o.lines - height) / 2),
col = math.ceil((vim.o.columns - width) / 2),
border = 'single',
})
vim.api.nvim_set_current_win(win)
vim.fn.jobstart(opts.cmd, {
term = true,
on_exit = function(_, _, _)
if vim.api.nvim_win_is_valid(win) then
vim.api.nvim_win_close(win, true)
end
end,
})
vim.cmd.startinsert()
end
helpers.has_copilot = function()
return vim.fn.getenv('COPILOT_API_KEY') ~= vim.NIL
end
return helpers
-- nnoremap <Leader>ev :tabedit $MYVIMRC<CR>

374
lua/keymap.lua Normal file
View File

@@ -0,0 +1,374 @@
-- Basic Keymaps
-- See `:help vim.keymap.set()`
local helpers = require 'helpers'
-- Swap : and ; around
vim.keymap.set({ 'n', 'v' }, ':', ';')
vim.keymap.set({ 'n', 'v' }, ';', ':')
-- Clear highlights on search when pressing <Esc> in normal mode
-- See `:help hlsearch`
vim.keymap.set('n', '<Esc>', '<cmd>nohlsearch<CR>')
-- Diagnostic keymaps
vim.keymap.set('n', '<leader>q', vim.diagnostic.setloclist, { desc = 'Open diagnostic [Q]uickfix list' })
vim.keymap.set({ 'n', 'v' }, 'c', '"zc', { desc = 'Change without copying to clipboard' })
vim.keymap.set({ 'n', 'v' }, 'x', '"zx', { desc = 'Cut without copying to clipboard' })
vim.keymap.set('v', 'p', '"zdP', { desc = 'Paste over selection without yanking replaced text' })
-- Exit terminal mode in the builtin terminal with a shortcut that is a bit easier
-- for people to discover. Otherwise, you normally need to press <C-\><C-n>, which
-- is not what someone will guess without a bit more experience.
--
-- NOTE: This won't work in all terminal emulators/tmux/etc. Try your own mapping
-- or just use <C-\><C-n> to exit terminal mode
vim.keymap.set('t', '<Esc><Esc>', '<C-\\><C-n>', { desc = 'Exit terminal mode' })
vim.keymap.set('n', '<Leader>c', function()
vim.treesitter.inspect_tree()
end, { desc = 'Treesitter' })
vim.keymap.set('n', '<C-S-D>', function()
local node = vim.treesitter.get_node {}
local range = { vim.treesitter.get_node_range(node) }
vim.api.nvim_win_set_cursor(0, { range[3] + 1, range[4] - 1 })
vim.fn.setpos("'x", { 0, range[1] + 1, range[2] + 1, 0 })
vim.cmd.normal 'v`x'
end, { desc = 'Select surrounding treesitter node' })
vim.keymap.set('v', '<C-S-D>', function()
local start = vim.api.nvim_win_get_cursor(0)
local start_row, start_column
if start[2] == 0 then
start_row = start[1] - 1
start_column = 0
else
start_row = start[1]
start_column = start[2] - 1
end
vim.api.nvim_win_set_cursor(0, { start_row, start_column })
local node = vim.treesitter.get_node {}
local range = { vim.treesitter.get_node_range(node) }
vim.api.nvim_win_set_cursor(0, { range[3] + 1, range[4] - 1 })
vim.fn.setpos("'x", { 0, range[1] + 1, range[2] + 1, 0 })
vim.cmd.normal 'i'
vim.cmd.normal 'v`x'
end, { desc = 'Select surrounding treesitter node' })
local swappable_nodes = { 'argument', 'array_element_initializer', 'simple_parameter', 'string', 'integer', 'member_call_expression', 'method_declaration' }
local function closest_swappable_node(node)
while node and not vim.list_contains(swappable_nodes, node:type()) and (not node:next_named_sibling() or not node:prev_named_sibling()) do
node = node:parent()
end
return node
end
vim.keymap.set({ 'n' }, '<C-S-h>', function()
local node = closest_swappable_node(vim.treesitter.get_node())
if not node then
return
end
local prev_node = node:prev_named_sibling()
while prev_node and not vim.list_contains(swappable_nodes, prev_node:type()) do
prev_node = prev_node:prev_named_sibling()
end
if prev_node == nil then
return
end
require('nvim-treesitter.ts_utils').swap_nodes(node, prev_node, 0, true)
end, { desc = 'Swap with node to the left' })
vim.keymap.set({ 'n' }, '<C-S-l>', function()
local node = closest_swappable_node(vim.treesitter.get_node())
if not node then
return
end
local next_node = node:next_named_sibling()
while next_node and not vim.list_contains(swappable_nodes, next_node:type()) do
next_node = next_node:next_named_sibling()
end
if next_node == nil then
return
end
require('nvim-treesitter.ts_utils').swap_nodes(node, next_node, 0, true)
end, { desc = 'Swap with node to the right' })
vim.keymap.set('n', '<C-S-j>', 'ddp', { desc = 'Move line down' })
vim.keymap.set('n', '<C-S-k>', 'ddkP', { desc = 'Move line up' })
vim.keymap.set('v', '<C-S-j>', 'do<Esc>p`[v`]', { desc = 'Move selection down' })
vim.keymap.set('v', '<C-S-k>', 'dkO<Esc>p`[v`]', { desc = 'Move selection up' })
-- Keybinds to make split navigation easier.
-- Use CTRL+<hjkl> to switch between windows
--
-- See `:help wincmd` for a list of all window commands
local function win_or_treesj(dir_cmd, desc)
return function()
local cur = vim.api.nvim_get_current_win()
vim.cmd('wincmd ' .. dir_cmd)
if vim.api.nvim_get_current_win() == cur then
local ok, treesj = pcall(require, 'treesj')
if ok and type(treesj.toggle) == 'function' then
treesj.toggle()
end
end
end, { desc = desc }
end
vim.keymap.set('n', '<C-h>', '<C-w><C-h>', { desc = 'Move focus to the left window' })
vim.keymap.set('n', '<C-l>', '<C-w><C-l>', { desc = 'Move focus to the right window' })
vim.keymap.set('n', '<C-j>', (win_or_treesj)('j', 'Move focus to the lower window or treesj.toggle()'))
vim.keymap.set('n', '<C-k>', (win_or_treesj)('k', 'Move focus to the upper window or treesj.toggle()'))
vim.keymap.set({ 'i' }, '<C-J>', function()
local ls = require 'luasnip'
if ls.choice_active() then
ls.change_choice(1)
end
end, { desc = 'Toggle snippet choice', silent = true })
vim.keymap.set({ 'i' }, '<C-k>', function()
local ls = require 'luasnip'
if ls.choice_active() then
ls.change_choice(-1)
end
end, { desc = 'Toggle snippet choice', silent = true })
vim.keymap.set({ 'i', 's' }, '<C-L>', function()
local ls = require 'luasnip'
if ls.expandable() then
ls.expand()
elseif ls.in_snippet() then
ls.jump(1)
end
end, { desc = 'Expand snippet', silent = true })
vim.keymap.set({ 'i', 's' }, '<C-H>', function()
local ls = require 'luasnip'
if ls.in_snippet() then
ls.jump(-1)
end
end, { desc = 'Go back a snippet slot', silent = true })
vim.keymap.set('n', '<Leader>.', '<Cmd>tabnext<CR>', { desc = 'Next tab' })
vim.keymap.set('n', '<Leader>,', '<Cmd>tabprevious<CR>', { desc = 'Previous tab' })
-- Overriding CTRL mappings because some of them are stupid
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-S-B>', '<CMD>Git blame<CR>', { desc = 'Git blame' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-Q>', '<CMD>Telescope lsp_document_symbols<CR>', { desc = 'Show symbols in current document' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-S-Q>', '<CMD>Telescope lsp_workspace_symbols<CR>', { desc = 'Show symbols in workspace' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-E>', '<CMD>Telescope oldfiles<CR>', { desc = 'Show recently opened files' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-P>', function()
require('telescope.builtin').find_files {
show_untracked = true,
no_ignore = false,
hidden = true,
}
end, { desc = 'Find all files' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-S-P>', function()
require('telescope.builtin').find_files {
show_untracked = true,
no_ignore = true,
hidden = true,
}
end, { desc = 'Find all files' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-f>', function()
require('telescope.builtin').live_grep {
hidden = true,
}
end, { desc = 'Search within the whole project' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-Y>', '<CMD>Telescope quickfix<CR>', { desc = 'Show quickfix list' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-S-Y>', '<CMD>Telescope quickfixhistory<CR>', { desc = 'Show quickfix history' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-A>', '<CMD>CodeCompanionChat Toggle<CR>', { desc = 'Open AI Actions' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-S-A>', '<CMD>CodeCompanionActions<CR>', { desc = 'Open AI Actions' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-S>', function()
require('snacks').scratch()
end, { desc = 'Open scratchpad' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-S-S>', function()
require('snacks').scratch.select()
end, { desc = 'Open scratchpad buffers' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-T>', function()
require('snacks').terminal.toggle()
end, { desc = 'Open terminal' })
-- Editing helpers
vim.keymap.set('i', '<C-O>', '<Esc>o', { desc = 'Add line below' })
vim.keymap.set('i', '<C-S-O>', '<Esc>O', { desc = 'Add line above' })
local esc_keys = { 'jj', 'jk', 'kk' }
for _, key in ipairs(esc_keys) do
vim.keymap.set('i', key, '<Esc>', { desc = 'Exit insert mode' })
end
vim.keymap.set('i', '<C-D>', '<Esc>ddi', { desc = 'Delete line' })
vim.keymap.set('i', '<Leader>;', '<Esc>mzA;<Esc>`za', { desc = 'Append a semicolon' })
vim.keymap.set('n', '<Leader>;', 'mzA;<Esc>`za', { desc = 'Append a semicolon' })
vim.keymap.set('n', '<Leader>{', 'mzF[`a<CR><Esc>``%i<CR><Esc>`z', { desc = 'Indent an array' })
vim.keymap.set('n', '<Leader>}', 'mzF[`a<CR><Esc>``%i<CR><Esc>`zvi[:s/,\\s*/,\\r/g<CR>vi[=<Esc>`z:nohlsearch<CR>', { desc = 'Indent an array some other way?' })
-- Git mappings
vim.keymap.set('n', '<Leader>gb', '<CMD>Git blame<CR>', { desc = 'Git blame' })
vim.keymap.set('n', '<Leader>gd', '<CMD>Git diff<CR>', { desc = 'Git diff' })
vim.keymap.set('n', '<Leader>gdc', '<CMD>Git diff --cached<CR>', { desc = 'Git diff' })
vim.keymap.set('n', '<Leader>G', function()
helpers.open_term { cmd = 'lazygit' }
end, { desc = 'Git' })
-- Add keymaps for diff mode
vim.api.nvim_create_autocmd('BufEnter', {
callback = function()
if vim.wo.diff then
-- Keymaps for navigating hunks
vim.api.nvim_buf_set_keymap(0, 'n', '<Tab>', ']c', { noremap = true, silent = true, desc = 'Next hunk in diff mode' })
vim.api.nvim_buf_set_keymap(0, 'n', '<S-Tab>', '[c', { noremap = true, silent = true, desc = 'Previous hunk in diff mode' })
-- Keymaps for resolving conflicts
vim.api.nvim_buf_set_keymap(0, 'n', '<leader>dl', ':diffget LOCAL<CR>', { noremap = true, silent = true, desc = 'Get LOCAL changes' })
vim.api.nvim_buf_set_keymap(0, 'n', '<leader>dr', ':diffget REMOTE<CR>', { noremap = true, silent = true, desc = 'Get REMOTE changes' })
end
end,
})
-- AI mappings
-- vim.keymap.set('v', '<Leader>ae', '<CMD>CodeCompanion<CR>', { desc = 'Edit selection with AI' })
-- vim.keymap.set('n', '<Leader>ac', '<CMD>CodeCompanionCmd<CR>', { desc = 'Run Neovim commands with AI' })
vim.api.nvim_create_autocmd('FileType', {
pattern = 'codecompanion',
callback = function()
vim.keymap.set('i', '<Enter>', function()
require('codecompanion').last_chat():submit()
end, { buffer = true, desc = 'Use enter to send the message' })
vim.keymap.set('i', '<S-Enter>', '<Enter>', { buffer = true, desc = 'Use shift enter to start a new line' })
vim.keymap.set('n', '<Enter>', 'G', { buffer = true, desc = 'Use enter in normal mode to go to the end of the chat' })
local models = { vim.env.DEFAULT_AI_MODEL, vim.env.REASONING_MODEL, vim.env.FAST_MODEL }
-- Loop through models and create keymaps for each
for i, model in ipairs(models) do
vim.keymap.set('n', '<C-' .. i .. '>', 'mzggj0W"_C' .. model .. '<Esc>`z', { desc = 'Switch to ' .. model })
vim.keymap.set('i', '<C-' .. i .. '>', '<Esc>mzggj0W"_C' .. model .. '<Esc>`za', { desc = 'Switch to ' .. model })
end
end,
})
-- Search mappings
vim.keymap.set('n', '<Leader>sGb', '<CMD>Telescope git_branches<CR>', { desc = 'Search git branches' })
vim.keymap.set('n', '<Leader>sGc', '<CMD>Telescope git_commits<CR>', { desc = 'Search git history' })
vim.keymap.set('n', '<Leader>sGh', '<CMD>Telescope git_bcommits<CR>', { desc = 'Search git history within current buffer/selection' })
vim.keymap.set('n', '<Leader>sGs', '<CMD>Telescope git_status<CR>', { desc = 'Search git status' })
vim.keymap.set('n', '<Leader>sGS', '<CMD>Telescope git_stash<CR>', { desc = 'Search git stash' })
-- Misc
vim.keymap.set('n', '<Leader>]', '<CMD>cnext<CR>', { desc = 'Next item in quickfix list' })
vim.keymap.set('n', '<Leader>[', '<CMD>cprevious<CR>', { desc = 'Previous item in quickfix list' })
vim.keymap.set('n', 'gd', '<CMD>Telescope lsp_definitions<CR>', { desc = 'Go to definition' })
vim.keymap.set('n', '<Leader>r', '<CMD>e!<CR>', { desc = 'Reload buffer' })
local function open_test()
require('neotest').summary.open()
require('neotest').output_panel.open()
end
-- Testing
-- local test_maps = {
-- {
-- keys = { '<F12>', '<Leader>tn' },
-- action = function()
-- require('neotest').run.run()
-- open_test()
-- end,
-- desc = 'Run nearest test',
-- },
-- {
-- keys = { '<F9>', '<Leader>ta' },
-- action = function()
-- require('neotest').run.run { suite = true }
-- open_test()
-- end,
-- desc = 'Run all tests in the project',
-- },
-- {
-- keys = { '<F11>', '<Leader>tp' },
-- action = function()
-- require('neotest').run.run_last()
-- open_test()
-- end,
-- desc = 'Run previous test again',
-- },
-- {
-- keys = { '<F10>', '<Leader>td' },
-- action = function()
-- local dap = require 'dap'
-- if dap.session() == nil then
-- dap.continue()
-- end
-- require('dapui').open()
-- local neotest = require 'neotest'
-- local bufnr = vim.api.nvim_get_current_buf()
-- local row = vim.api.nvim_win_get_cursor(0)[1] - 1
--
-- local adapters = neotest.state.adapter_ids()
-- local found = false
--
-- for _, adapter_id in ipairs(adapters) do
-- local tree = neotest.state.positions(adapter_id, { buffer = bufnr })
-- if tree then
-- local nearest = require('neotest.lib.positions').nearest(tree, row)
-- if nearest and nearest:data().type ~= 'file' then
-- neotest.run.run()
-- found = true
-- break
-- end
-- end
-- end
--
-- if not found then
-- neotest.run.run_last()
-- end
-- end,
-- desc = 'Run last test with debugger',
-- },
-- }
--
-- for _, map_info in ipairs(test_maps) do
-- for _, key in ipairs(map_info.keys) do
-- vim.keymap.set('n', key, map_info.action, { desc = map_info.desc })
-- end
-- end
-- vim.keymap.set('n', '<Leader>tf', function()
-- require('neotest').run.run(vim.fn.expand '%')
-- open_test()
-- end, { desc = 'Run all tests in the current file' })
-- vim.keymap.set('n', '<Leader>tc', function()
-- require('neotest').summary.close()
-- require('neotest').output_panel.close()
-- end, { desc = 'Close test panels' })
-- vim.keymap.set('i', '<Tab>', function()
-- local copilot = require 'copilot.suggestion'
-- local ls = require 'luasnip'
-- if copilot.is_visible() then
-- vim.api.nvim_echo({{'Accepting copilot suggestion'}}, false, {})
-- copilot.accept()
-- copilot.dismiss()
-- elseif ls.jumpable(1) then
-- vim.api.nvim_echo({{'Jumping in snippet'}}, false, {})
-- ls.jump()
-- else
-- vim.api.nvim_echo({{'Inserting tab'}}, false, {})
-- vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<Tab>', true, true, true), 'n', true)
-- end
-- end, { desc = 'Luasnip accept copilot or jump forward' })
-- Leaving this commented out, I will try the format command instead
-- "A command to properly indent json code
-- command! FormatJSON %!python -m json.tool
-- Edit the snippet file for the current buffer filetype or the snippets
-- directory if the file does not exist
vim.keymap.set('n', '<Leader>es', function()
local ft = vim.bo.filetype
if ft == 'vue' then
ft = 'javascript'
end
local snippets_dir = vim.fn.stdpath 'config' .. '/lua/snippets'
local snippets_file = snippets_dir .. '/' .. ft .. '.lua'
vim.cmd('tabedit ' .. snippets_file)
end, { desc = 'Edit snippets file' })
require('helpers').edit_cf('k', '/lua/keymap.lua')

49
lua/lazy_init.lua Normal file
View File

@@ -0,0 +1,49 @@
-- [[ Install `lazy.nvim` plugin manager ]]
-- See `:help lazy.nvim.txt` or https://github.com/folke/lazy.nvim for more info
-- For additional information with loading, sourcing and examples see `:help lazy.nvim-🔌-plugin-spec`
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
error('Error cloning lazy.nvim:\n' .. out)
end
end ---@diagnostic disable-next-line: undefined-field
vim.opt.rtp:prepend(lazypath)
-- [[ Configure and install plugins ]]
--
-- To check the current status of your plugins, run
-- :Lazy
--
-- You can press `?` in this menu for help. Use `:q` to close the window
--
-- To update plugins you can run
-- :Lazy update
--
-- NOTE: Here is where you install your plugins.
require('lazy').setup({
{ import = 'plugins' },
}, {
ui = {
-- If you are using a Nerd Font: set icons to an empty table which will use the
-- default lazy.nvim defined Nerd Font icons, otherwise define a unicode icons table
icons = vim.g.have_nerd_font and {} or {
cmd = '',
config = '🛠',
event = '📅',
ft = '📂',
init = '',
keys = '🗝',
plugin = '🔌',
runtime = '💻',
require = '🌙',
source = '📄',
start = '🚀',
task = '📌',
lazy = '💤 ',
},
},
})
require('helpers').edit_cf('l', '/lua/lazy_init.lua')

87
lua/opt.lua Normal file
View File

@@ -0,0 +1,87 @@
-- [[ Setting options ]]
-- See `:help vim.opt` and `:help option-list`
-- Make line numbers default
vim.opt.number = true
-- Line number indicates distance from cursor line
vim.opt.relativenumber = true
-- Enable mouse mode, can be useful for resizing splits for example!
vim.opt.mouse = 'a'
-- Don't show the mode, since it's already in the status line
vim.opt.showmode = false
-- Sync clipboard between OS and Neovim.
-- Schedule the setting after `UiEnter` because it can increase startup-time.
-- Remove this option if you want your OS clipboard to remain independent.
-- See `:help 'clipboard'`
vim.schedule(function()
vim.opt.clipboard = 'unnamedplus'
end)
-- Enable break indent
vim.opt.breakindent = true
-- Save undo history
vim.opt.undofile = true
-- Store undo history in the /tmp directory
vim.opt.undodir = '/tmp'
-- Case-insensitive searching UNLESS \C or one or more capital letters in the search term
vim.opt.ignorecase = true
vim.opt.smartcase = true
-- Keep signcolumn on by default
vim.opt.signcolumn = 'yes'
-- Decrease update time
vim.opt.updatetime = 250
-- Decrease mapped sequence wait time
vim.opt.timeoutlen = 300
-- Configure how new splits should be opened
vim.opt.splitright = true
vim.opt.splitbelow = true
-- Sets how neovim will display certain whitespace characters in the editor.
-- See `:help 'list'`
-- and `:help 'listchars'`
vim.opt.list = true
vim.opt.listchars = { tab = '» ', trail = '·', nbsp = '' }
-- Preview substitutions live, as you type!
vim.opt.inccommand = 'split'
-- Show which line your cursor is on
vim.opt.cursorline = true
-- Minimal number of screen lines to keep above and below the cursor.
vim.opt.scrolloff = 10
-- if performing an operation that would fail due to unsaved changes in the buffer (like `:q`),
-- instead raise a dialog asking if you wish to save the current file(s)
-- See `:help 'confirm'`
vim.opt.confirm = true
-- How many columns text is indented when using reindent
vim.opt.shiftwidth = 4
-- How many columns a tab counts for
vim.opt.tabstop = 4
-- Set columns for tabs in insert mode
vim.opt.softtabstop = 4
-- Use spaces instead of tabs
vim.opt.expandtab = true
-- Automatically indent code
vim.opt.smartindent = true
-- Save the file when switching buffers
vim.opt.autowriteall = true
-- Add lines at 80 and 120 columns
vim.opt.colorcolumn = '80,120'
vim.opt.iskeyword:remove '$'
require('helpers').edit_cf('o', '/lua/opt.lua')

3
lua/plugins/actually.lua Normal file
View File

@@ -0,0 +1,3 @@
return {
'mong8se/actually.nvim',
}

View File

@@ -0,0 +1,72 @@
-- AI code completion
if vim.fn.getenv 'COPILOT_API_KEY' ~= vim.NIL then
return {
'zbirenbaum/copilot.lua',
event = 'InsertEnter',
config = function()
require('copilot').setup {
suggestion = {
enabled = true,
auto_trigger = true,
keymap = {
accept = '<A-a>',
},
},
filetypes = {
yaml = true,
markdown = true,
gitcommit = true,
gitrebase = true,
},
}
end,
}
end
return {
'milanglacier/minuet-ai.nvim',
dependencies = { 'nvim-lua/plenary.nvim' },
config = function()
require('minuet').setup {
virtualtext = {
auto_trigger_ft = { '*' },
auto_trigger_ignore_ft = { 'help', 'TelescopePrompt', 'codecompanion', 'snacks_input' },
keymap = {
accept = '<A-A>',
accept_line = '<A-a>',
-- accept n lines (prompts for number)
-- e.g. "A-z 2 CR" will accept 2 lines
accept_n_lines = '<A-z>',
-- Cycle to prev completion item, or manually invoke completion
prev = '<A-[>',
-- Cycle to next completion item, or manually invoke completion
next = '<A-]>',
dismiss = '<A-e>',
},
},
provider = 'openai_compatible',
request_timeout = 3,
throttle = 500, -- Increase to reduce costs and avoid rate limits
debounce = 400, -- Increase to reduce costs and avoid rate limits
n_completions = 1,
before_cursor_filter_length = 10,
provider_options = {
openai_compatible = {
api_key = 'COMPLETION_OPENAI_API_KEY',
end_point = vim.env.COMPLETION_OPENAI_API_BASE .. '/v1/chat/completions',
model = vim.env.COMPLETION_MODEL,
name = 'Openrouter',
optional = {
max_tokens = 300,
top_p = 0.9,
provider = {
-- Prioritize throughput for faster completion
sort = 'throughput',
},
},
},
},
}
end,
}

67
lua/plugins/aider.lua Normal file
View File

@@ -0,0 +1,67 @@
require('helpers').edit_cf('pa', '/lua/plugins/aider.lua')
local change_model_function = function(model)
return function()
require('nvim_aider').api.send_command('/model', model)
end
end
return {
'GeorgesAlkhouri/nvim-aider',
cmd = 'Aider',
keys = {
{ '<leader>a/', '<cmd>Aider toggle<cr>', desc = 'Toggle Aider' },
{ '<leader>as', '<cmd>Aider send<cr>', desc = 'Send to Aider', mode = { 'n', 'v' } },
{ '<leader>ac', '<cmd>Aider command<cr>', desc = 'Aider Commands' },
{ '<leader>ab', '<cmd>Aider buffer<cr>', desc = 'Send Buffer' },
{ '<leader>a+', '<cmd>Aider add<cr>', desc = 'Add File' },
{ '<leader>a-', '<cmd>Aider drop<cr>', desc = 'Drop File' },
{ '<leader>ar', '<cmd>Aider add readonly<cr>', desc = 'Add Read-Only' },
{ '<leader>aR', '<cmd>Aider reset<cr>', desc = 'Reset Session' },
-- Example nvim-tree.lua integration if needed
{ '<leader>a+', '<cmd>AiderTreeAddFile<cr>', desc = 'Add File from Tree to Aider', ft = 'NvimTree' },
{ '<leader>a-', '<cmd>AiderTreeDropFile<cr>', desc = 'Drop File from Tree from Aider', ft = 'NvimTree' },
{ '<leader>am4', change_model_function 'gpt-4.1', desc = 'Switch aider model to GPT-4.1' },
{ '<leader>amo', change_model_function 'openai/o4-mini', desc = 'Switch aider model to o4-mini' },
{ '<leader>amg', change_model_function 'openai/gemini-2.5-pro', desc = 'Switch aider model to Gemini 2.5 Pro' },
{ '<leader>ams', change_model_function 'openai/claude-sonnet-4', desc = 'Switch aider model to Claude Sonnet 4' },
},
dependencies = {
'folke/snacks.nvim',
--- The below dependencies are optional
'catppuccin/nvim',
'nvim-tree/nvim-tree.lua',
--- Neo-tree integration
{
'nvim-neo-tree/neo-tree.nvim',
opts = function(_, opts)
-- Example mapping configuration (already set by default)
-- opts.window = {
-- mappings = {
-- ["+"] = { "nvim_aider_add", desc = "add to aider" },
-- ["-"] = { "nvim_aider_drop", desc = "drop from aider" }
-- ["="] = { "nvim_aider_add_read_only", desc = "add read-only to aider" }
-- }
-- }
require('nvim_aider.neo_tree').setup(opts)
end,
},
},
config = function()
require('nvim_aider').setup {
aider_cmd = 'aider',
args = {
'--config=$HOME/.config/aider/aider.yaml',
'--env-file=$(pwd)/aider.env',
'--watch',
'--architect',
},
auto_reload = true,
win = {
wo = { winbar = 'Aider' },
style = 'nvim_aider',
position = 'bottom',
},
}
end,
}

View File

@@ -0,0 +1,8 @@
-- autopairs
-- https://github.com/windwp/nvim-autopairs
return {
'windwp/nvim-autopairs',
event = 'InsertEnter',
opts = {},
}

79
lua/plugins/blink.lua Normal file
View File

@@ -0,0 +1,79 @@
-- Autocompletion
return {
'saghen/blink.cmp',
event = 'VimEnter',
version = '1.*',
dependencies = {
-- 'L3MON4D3/LuaSnip',
'folke/lazydev.nvim',
},
--- @module 'blink.cmp'
--- @type blink.cmp.Config
opts = {
keymap = {
-- 'default' (recommended) for mappings similar to built-in completions
-- <c-y> 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:
-- <tab>/<s-tab>: move to right/left of your snippet expansion
-- <c-space>: Open menu or open docs if already open
-- <c-n>/<c-p> or <up>/<down>: Select next/previous item
-- <c-e>: Hide menu
-- <c-k>: Toggle signature help
--
-- See :h blink-cmp-config-keymap for defining your own keymap
preset = 'enter',
['<C-K>'] = false,
-- For more advanced Luasnip keymaps (e.g. selecting choice nodes, expansion) see:
-- https://github.com/L3MON4D3/LuaSnip?tab=readme-ov-file#keymaps
},
appearance = {
-- 'mono' (default) for 'Nerd Font Mono' or 'normal' for 'Nerd Font'
-- Adjusts spacing to ensure icons are aligned
nerd_font_variant = 'normal',
},
completion = {
-- By default, you may press `<c-space>` to show the documentation.
-- Optionally, set `auto_show = true` to show the documentation after a delay.
documentation = { auto_show = true, auto_show_delay_ms = 200 },
},
sources = {
default = { 'lsp', 'path', 'snippets', 'lazydev' },
providers = {
lazydev = { module = 'lazydev.integrations.blink', score_offset = 100 },
-- avante = { module = 'blink-cmp-avante', name = 'Avante', opts = {} },
},
per_filetype = {
codecompanion = { 'codecompanion' },
},
},
-- snippets = { preset = 'luasnip' },
-- 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 :h blink-cmp-config-fuzzy for more information
fuzzy = { implementation = 'lua' },
-- Shows a signature help window while you type arguments for a function
signature = { enabled = true },
},
}

View File

@@ -0,0 +1,339 @@
return {
'olimorris/codecompanion.nvim',
config = function()
require('codecompanion').setup {
adapters = {
http = {
default = function()
if (require('helpers').has_copilot()) then
return require('codecompanion.adapters').extend('copilot', {
schema = {
model = {
default = vim.env.DEFAULT_AI_MODEL,
},
max_tokens = {
default = 1000000,
},
}
})
end
return require('codecompanion.adapters').extend('openai_compatible', {
env = {
url = vim.env.DEFAULT_OPENAI_API_BASE,
api_key = vim.env.DEFAULT_OPENAI_API_KEY,
chat_url = '/v1/chat/completions',
models_endpoint = '/v1/models',
},
schema = {
model = {
default = vim.env.DEFAULT_AI_MODEL,
},
max_tokens = {
default = 1000000,
},
},
})
end,
},
},
display = {
chat = {
show_settings = true,
start_in_insert_mode = false,
},
},
strategies = {
chat = {
adapter = 'default',
slash_commands = {
-- codebase = require('vectorcode.integrations').codecompanion.chat.make_slash_command(),
},
tools = {
-- vectorcode = {
-- description = 'Run VectorCode to retrieve the project context.',
-- callback = require('vectorcode.integrations').codecompanion.chat.make_tool(),
-- },
['cmd_runner'] = {
opts = {
requires_approval = false,
},
},
},
roles = {
---@type string|fun(adapter: CodeCompanion.Adapter): string
llm = function(adapter)
return 'CodeCompanion (' .. adapter.formatted_name .. ': ' .. adapter.parameters.model .. ')'
end,
},
keymaps = {
send = {
modes = { n = '<C-s>', i = '<C-s>' },
},
close = {
modes = { n = '<C-c>', i = '<C-c>' },
},
},
},
inline = {
adapter = {
name = 'default',
model = vim.env.FAST_MODEL,
},
},
cmd = {
adapter = {
name = 'default',
model = vim.env.FAST_MODEL,
},
},
},
extensions = {
mcphub = {
callback = 'mcphub.extensions.codecompanion',
opts = {
show_result_in_chat = true,
make_vars = true,
make_slash_commands = true,
},
},
},
system_prompt = function(opts)
local language = opts.language or 'English'
return string.format(
[[You are an AI programming assistant named "CodeCompanion". You are currently plugged into the Neovim text editor on a user's machine.
Your core tasks include:
- Answering general programming questions.
- Explaining how the code in a Neovim buffer works.
- Reviewing the selected code from a Neovim buffer.
- Generating unit tests for the selected code.
- Proposing fixes for problems in the selected code.
- Scaffolding code for a new workspace.
- Finding relevant code to the user's query.
- Proposing fixes for test failures.
- Answering questions about Neovim.
- Running tools.
You must:
- Follow the user's requirements carefully and to the letter.
- Keep your answers short and impersonal, especially if the user's context is outside your core tasks.
- Minimize additional prose unless clarification is needed.
- Use Markdown formatting in your answers.
- Include the programming language name at the start of each Markdown code block.
- Avoid including line numbers in code blocks.
- Avoid wrapping the whole response in triple backticks.
- Only return code that's directly relevant to the task at hand. You may omit code that isnt necessary for the solution.
- Avoid using H1, H2 or H3 headers in your responses as these are reserved for the user.
- Use actual line breaks in your responses; only use "\n" when you want a literal backslash followed by 'n'.
- All non-code text responses must be written in the %s language indicated.
- Multiple, different tools can be called as part of the same response.
- Use full path names when using tools to read and modify files.
When given a task:
1. Think step-by-step and, unless the user requests otherwise or the task is very simple, describe your plan in detailed pseudocode.
2. Output the final code in a single code block, ensuring that only relevant code is included.
3. End your response with a short suggestion for the next user turn that directly supports continuing the conversation.
4. Provide exactly one complete reply per conversation turn.
5. If necessary, execute multiple tools in a single turn.]],
language
)
end,
prompt_library = {
['Code Expert'] = {
strategy = 'chat',
description = 'Get some special advice from an LLM.',
opts = {
mapping = '<Leader>ce',
modes = { 'v' },
short_name = 'expert',
auto_submit = true,
stop_context_insertion = true,
user_prompt = true,
},
prompts = {
{
role = 'system',
content = function(context)
return 'I want you to act as a senior'
.. context.filetype
.. 'developer I will ask you specific questions and I want you to return concise explanations and codeblock examples.'
end,
},
{
role = 'user',
content = function(context)
local text = require('codecompanion.helpers.actions').get_code(context.start_line, context.end_line)
return 'I have the following code:\n\n```' .. context.filetype .. '\n' .. text .. '\n```\n\n'
end,
opts = {
contains_code = true,
},
},
},
},
['Games Master'] = {
strategy = 'chat',
description = 'A personal Games Master Assistant.',
opts = {
user_prompt = false,
},
prompts = {
{
role = 'system',
content = [[
You are a personal Games Master Assistant. You are currently plugged in to the Neovim text editor on a user's machine.
Your core tasks include:
- Crafting engaging role playing sessions
- Building immersive and authentic worlds
- Creating compelling characters for the players to interact with and drive the story
- Reviewing session summaries and building on them
- Providing advice on how to bring sessions to life
- Create exciting encounters to challenge the players
- Encounters can be combat, social, or exploration based
- There should always be a story reason for the encounter
- Combine player character backgrounds and motivations into the world
- Build tension and drama into the game
- Ensure each session provides opportunities for the players to engage with and drive the story
You must:
- Follow the user's requirements carefully and to the letter.
- Keep answers focused on the task at hand.
- Provide original ideas and suggestions.
- Use Markdown formatting in your answers.
- Use actual line breaks instead of '\n' in your response to begin new lines.
- Use '\n' only when you want a literal backslash followed by a character 'n'.
- All responses must be written in English.
- Multiple, different tools can be called as part of the same response.
- Help sessions be fast paced and fun.
- Ensure there are multiple soltuions to each problem.
- Avoid railroading the players.
When given a task:
1. Consider the existing world and characters. Use tools to gather information that may be relevant.
2. Provide exactly one complete reply per conversation turn.
3. If necessary, execute multiple tools in a single turn.
]],
},
{
role = 'user',
content = '',
},
},
},
['PHPStan Fixer'] = {
strategy = 'workflow',
description = 'Use a workflow to fix PHPStan errors until there are none left.',
opts = {
short_name = 'phpstan',
},
prompts = {
{
{
name = 'Run PHPStan',
role = 'user',
opts = { auto_submit = false },
content = function()
-- Enable turbo mode!!!
vim.g.codecompanion_auto_tool_mode = true
return [[PHPStan is a static analysis tool for PHP. It is currently reporting errors in the code. Your task is to fix these errors and run PHPStan again until there are no errors left.
First of all use the @cmd_runner tool to run the `composer type-check` command. This will run PHPStan and output type errors in the code.]]
end,
},
},
{
{
name = 'Fetch files',
role = 'user',
opts = { auto_submit = false },
content = function()
-- Enable turbo mode!!!
vim.g.codecompanion_auto_tool_mode = true
return 'PHPStan has reported errors. Look at the output and see where the files are reported. Use the @mcp tool to read all the offending files so you can implement the fixes.'
end,
},
},
{
{
name = 'Fix errors and run',
role = 'user',
opts = { auto_submit = false },
content = function()
-- Enable turbo mode!!!
vim.g.codecompanion_auto_tool_mode = true
return [[### Instructions
Now you have the errors and the appropriate context you can fix the errors.
### Steps to Follow
You are required to analyse the PHPStan errors and write code to fix them.
Reason through the errors and write out the possible causes and fixes for each.
1. Then use the @mcp tool to update the files with the fixes. When editing files use the full path name including the project name /Users/chris/Code/Sites/hylark/
2. After editing the files use the @cmd_runner tool again to run the `composer type-check` command to see if any errors remain.
We'll repeat this cycle until there are no errors. Ensure no deviations from these steps.
### Tips for fixing PHPStan errors
- Do not ignore the errors
- Use Webmozart Assert library to narrow types
- Most errors are due to missing docblocks or calling methods/parameters on types that PHPStan cannot infer
- Use fully qualified namespaces for classes in doc blocks
- The code is working so fixes should not change the behaviour of the code
- There are some custom types in this project that help define types
- closure<T> creates T|Closure(): T, you can add a second argument to specify the depth so closure<T, 2> creates T|Closure(): T|Closure(): (Closure(): T). This is useful because GraphQL queries can return closures.
- promise<T> creates T|SyncPromise<T>, as with closure, you can add a second argument for depth. You can also add a third argument if T is an array to allow adding promises to each value, so promise<array{a: int}, 1, 1> will create array{a: int}|SyncPromise<array{a: int}>|array{a: SyncPromise<int>}|SyncPromise<array{a: SyncPromise<int>}>. This is useful because GraphQL queries can return promises and arrays of promises.
- GraphQL schema types (these should only be used in the Query classes)
- GArgs<T> will look at the GraphQL schema and create an array type for the arguments of a field on one of the root types (Query or Mutation)
- GArgs<TType, TField> will create a type for the arguments of a field on a type
- GType<T> will create an type for a specific GraphQL type, input, interface, or enum
- GVal<T> will create a type for the return value of a field on one of the root types (Query or Mutation)
- GVal<TType, TField> will create a type for the return value of a field on a type
- pick<T, TKeys> will create an array from T with only the keys in TKeys (e.g. pick<array{a: int, b: int, c: int}, 'a'|'b'> will create array{a: int, b: int})
- except<T, TKeys> works like pick only it excludes the keys in TKeys (e.g. except<array{a: int, b: int, c: int}, 'a'|'b'> will create array{c: int})
- union<T, U> creates a union array of T and U (e.g. union<array{a: int}, array{b: int}> will create array{a: int, b: int})]]
end,
},
},
{
{
name = 'Repeat On Failure',
role = 'user',
opts = { auto_submit = false },
-- Scope this prompt to the cmd_runner tool
condition = function()
return _G.codecompanion_current_tool == 'cmd_runner'
end,
-- Repeat until the tests pass, as indicated by the testing flag
-- which the cmd_runner tool sets on the chat buffer
repeat_until = function(chat)
-- Check if the last message in the chat buffer contains "[ERROR] found"
local messages = chat.messages
local last_message = messages[#messages]
if last_message and last_message.role == 'assistant' then
local content = last_message.content
return not content:find '[ERROR] found'
end
return true
end,
content = 'PHPStan is still reporting errors. Edit the code to fix the errors and run PHPStan again.',
},
},
},
},
},
}
end,
dependencies = {
'nvim-lua/plenary.nvim',
'nvim-treesitter/nvim-treesitter',
-- 'Davidyz/VectorCode',
'ravitemer/mcphub.nvim',
},
}

27
lua/plugins/color.lua Normal file
View File

@@ -0,0 +1,27 @@
-- You can easily change to a different colorscheme.
return {
-- Change the name of the colorscheme plugin below, and then
-- change the command in the config to whatever the name of that colorscheme is.
--
-- If you want to see what colorschemes are already installed, you can use `:Telescope colorscheme`.
'AlphaTechnolog/pywal.nvim',
dependencies = {
'folke/tokyonight.nvim',
},
priority = 1000, -- Make sure to load this before all the other start plugins.
config = function()
---@diagnostic disable-next-line: missing-fields
require('tokyonight').setup()
vim.cmd.colorscheme 'tokyonight-night'
-- Check if wal directory exists otherwise use tokyo
local handle = io.popen 'ls -d $HOME/.cache/wal 2>/dev/null'
local result = handle:read '*a'
handle:close()
if result ~= '' then
require('pywal').setup()
end
end,
}

44
lua/plugins/conform.lua Normal file
View File

@@ -0,0 +1,44 @@
return { -- Autoformat
'stevearc/conform.nvim',
event = { 'BufWritePre' },
cmd = { 'ConformInfo' },
keys = {
{
'<leader>f',
function()
require('conform').format { async = true, lsp_format = 'fallback' }
end,
mode = '',
desc = '[F]ormat buffer',
},
},
config = function()
require('conform').setup({
notify_on_error = false,
format_on_save = function(bufnr)
-- Disable "format_on_save lsp_fallback" for languages that don't
-- have a well standardized coding style. You can add additional
-- languages here or re-enable it for the disabled ones.
local disable_filetypes = { c = true, cpp = true, vue = true, js = true }
if disable_filetypes[vim.bo[bufnr].filetype] then
return nil
else
return {
timeout_ms = 500,
lsp_format = 'fallback',
}
end
end,
formatters_by_ft = {
lua = { 'stylua' },
php = { 'pint' },
-- 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 },
},
log_level = vim.log.levels.DEBUG
})
end
}

234
lua/plugins/debug.lua Normal file
View File

@@ -0,0 +1,234 @@
require('helpers').edit_cf('pd', '/lua/plugins/debug.lua')
-- debug.lua
--
-- Shows how to use the DAP plugin to debug your code.
--
-- Primarily focused on configuring the debugger for Go, but can
-- be extended to other languages as well. That's why it's called
-- kickstart.nvim and not kitchen-sink.nvim ;)
--
return {
'mfussenegger/nvim-dap',
dependencies = {
-- Creates a beautiful debugger UI
'rcarriga/nvim-dap-ui',
-- Required dependency for nvim-dap-ui
'nvim-neotest/nvim-nio',
-- Installs the debug adapters for you
'williamboman/mason.nvim',
'jay-babu/mason-nvim-dap.nvim',
-- Add your own debuggers here
'leoluz/nvim-dap-go',
},
keys = {
-- Basic debugging keymaps, feel free to change to your liking!
{
'<Leader>dc',
function()
require('dap').continue()
end,
desc = 'Debug: Start/Continue',
},
{
'<Leader>di',
function()
require('dap').step_into()
end,
desc = 'Debug: Step Into',
},
{
'<Leader>do',
function()
require('dap').step_over()
end,
desc = 'Debug: Step Over',
},
{
'<Leader>du',
function()
require('dap').step_out()
end,
desc = 'Debug: Step Out',
},
{
'<leader>db',
function()
require('dap').toggle_breakpoint()
end,
desc = 'Debug: Toggle Breakpoint',
},
{
'<leader>dB',
function()
require('dap').set_breakpoint(vim.fn.input 'Breakpoint condition: ')
end,
desc = 'Debug: Set Breakpoint',
},
-- Toggle to see last session result. Without this, you can't see session output in case of unhandled exception.
{
'<Leader>ds',
function()
require('dapui').toggle()
end,
desc = 'Debug: Toggle UI',
},
},
config = function()
local dap = require 'dap'
local dapui = require 'dapui'
require('mason-nvim-dap').setup {
-- Makes a best effort to setup the various debuggers with
-- reasonable debug configurations
automatic_installation = true,
-- You can provide additional configuration to the handlers,
-- see mason-nvim-dap README for more information
handlers = {
function(config)
require('mason-nvim-dap').default_setup(config)
end,
php = function(config)
config.configurations = {
{
type = 'php',
request = 'launch',
name = 'Listen for XDebug',
port = 9003,
log = true,
-- pathMappings = {
-- ['/var/www/html/'] = vim.fn.getcwd() .. '/',
-- },
hostname = '0.0.0.0',
},
}
require('mason-nvim-dap').default_setup(config)
end,
},
-- You'll need to check that you have the required things installed
-- online, please don't ask me how to install them :)
ensure_installed = {
-- Update this to ensure that you have the debuggers for the langs you want
'delve',
},
}
dap.adapters.php = {
type = 'executable',
command = 'node',
args = {
vim.fn.expand '$MASON/packages/php-debug-adapter/extension/out/phpDebug.js',
},
}
dap.configurations.php = {
{
type = 'php',
request = 'launch',
name = 'Listen for XDebug',
port = 9003,
log = true,
-- pathMappings = {
-- ['/var/www/html/'] = vim.fn.getcwd() .. '/',
-- },
hostname = '0.0.0.0',
},
}
-- Dap UI setup
-- For more information, see |:help nvim-dap-ui|
dapui.setup {
-- Set icons to characters that are more likely to work in every terminal.
-- Feel free to remove or use ones that you like more! :)
-- Don't feel like these are good choices.
icons = { expanded = '', collapsed = '', current_frame = '*' },
controls = {
icons = {
pause = '',
play = '',
step_into = '󰆹',
step_over = '󰆷',
step_out = '󰆸',
step_back = '',
run_last = '',
terminate = '',
disconnect = '',
},
},
element_mappings = {
stacks = {
open = '<CR>',
expand = 'o',
},
},
}
-- Change breakpoint icons
vim.api.nvim_set_hl(0, 'DapBreak', { fg = '#e51400' })
vim.api.nvim_set_hl(0, 'DapStop', { fg = '#ffcc00' })
local breakpoint_icons = vim.g.have_nerd_font
and { Breakpoint = '', BreakpointCondition = '', BreakpointRejected = '', LogPoint = '', Stopped = '' }
or { Breakpoint = '', BreakpointCondition = '', BreakpointRejected = '', LogPoint = '', Stopped = '' }
for type, icon in pairs(breakpoint_icons) do
local tp = 'Dap' .. type
local hl = (type == 'Stopped') and 'DapStop' or 'DapBreak'
vim.fn.sign_define(tp, { text = icon, texthl = hl, numhl = hl })
end
local function get_php_ini_dir()
local handle = io.popen 'php --ini 2>/dev/null'
if not handle then
return nil
end
local result = handle:read '*a'
handle:close()
local dir = result:match 'Scan for additional .ini files in:%s+([^\n]+)'
if dir and dir:find '%(none%)' == nil then
return vim.trim(dir)
end
return nil
end
local function enable_xdebug()
local ini_dir = get_php_ini_dir()
if not ini_dir then
return
end
os.execute(string.format('mv "%s/20-xdebug.ini.disabled" "%s/20-xdebug.ini" 2>/dev/null', ini_dir, ini_dir))
end
local function disable_xdebug()
local ini_dir = get_php_ini_dir()
if not ini_dir then
return
end
os.execute(string.format('mv "%s/20-xdebug.ini" "%s/20-xdebug.ini.disabled" 2>/dev/null', ini_dir, ini_dir))
end
dap.listeners.after.event_initialized['xdebug_enable'] = enable_xdebug
dap.listeners.before.event_terminated['xdebug_disable'] = disable_xdebug
dap.listeners.before.event_exited['xdebug_disable'] = disable_xdebug
-- dap.listeners.after.event_output['neotest_display'] = function(_, body)
-- require('neotest').output.open { enter = true, last = true }
-- end
dap.listeners.after.event_initialized['dapui_config'] = dapui.open
dap.listeners.before.event_terminated['dapui_config'] = dapui.close
dap.listeners.before.event_exited['dapui_config'] = dapui.close
-- Install golang specific config
require('dap-go').setup {
delve = {
-- On Windows delve must be run attached or it crashes.
-- See https://github.com/leoluz/nvim-dap-go/blob/main/README.md#configuring
detached = vim.fn.has 'win32' == 0,
},
}
end,
}

3
lua/plugins/dotenv.lua Normal file
View File

@@ -0,0 +1,3 @@
return {
'ellisonleao/dotenv.nvim',
}

101
lua/plugins/edgy.lua Normal file
View File

@@ -0,0 +1,101 @@
return {
"folke/edgy.nvim",
event = "VeryLazy",
init = function()
vim.opt.laststatus = 3
vim.opt.splitkeep = "screen"
end,
opts = {
bottom = {
-- toggleterm / lazyterm at the bottom with a height of 40% of the screen
{
ft = "toggleterm",
size = { height = 0.4 },
-- exclude floating windows
filter = function(buf, win)
return vim.api.nvim_win_get_config(win).relative == ""
end,
},
{
ft = "lazyterm",
title = "LazyTerm",
size = { height = 0.4 },
filter = function(buf)
return not vim.b[buf].lazyterm_cmd
end,
},
{
ft = "snack_terminal",
size = { height = 0.4 },
title = "%{b:snacks_terminal.id}: %{b:term_title}",
filter = function(_buf, win)
return vim.w[win].snacks_win
and vim.w[win].snacks_win.position == pos
and vim.w[win].snacks_win.relative == "editor"
and not vim.w[win].trouble_preview
end,
},
"Trouble",
{ ft = "qf", title = "QuickFix" },
{
ft = "help",
size = { height = 20 },
-- only show help buffers
filter = function(buf)
return vim.bo[buf].buftype == "help"
end,
},
{ ft = "spectre_panel", size = { height = 0.4 } },
},
left = {
-- Neo-tree filesystem always takes half the screen height
{
title = "Neo-Tree",
ft = "neo-tree",
filter = function(buf)
return vim.b[buf].neo_tree_source == "filesystem"
end,
size = { height = 0.5 },
},
{
title = "Neo-Tree Git",
ft = "neo-tree",
filter = function(buf)
return vim.b[buf].neo_tree_source == "git_status"
end,
pinned = true,
collapsed = true, -- show window as closed/collapsed on start
open = "Neotree position=right git_status",
},
{
title = "Neo-Tree Buffers",
ft = "neo-tree",
filter = function(buf)
return vim.b[buf].neo_tree_source == "buffers"
end,
pinned = true,
collapsed = true, -- show window as closed/collapsed on start
open = "Neotree position=top buffers",
},
{
title = function()
local buf_name = vim.api.nvim_buf_get_name(0) or "[No Name]"
return vim.fn.fnamemodify(buf_name, ":t")
end,
ft = "Outline",
pinned = true,
open = "SymbolsOutlineOpen",
},
-- any other neo-tree windows
"neo-tree",
},
right = {
{
title = 'Code Companion',
ft = 'codecompanion',
size = { width = 0.3 },
}
}
},
}

3
lua/plugins/fidget.lua Normal file
View File

@@ -0,0 +1,3 @@
return {
'j-hui/fidget.nvim',
}

37
lua/plugins/fugitive.lua Normal file
View File

@@ -0,0 +1,37 @@
return {
'tpope/vim-fugitive',
config = function()
vim.keymap.set('n', '<leader>gg', vim.cmd.Git)
local ThePrimeagen_Fugitive = vim.api.nvim_create_augroup('ThePrimeagen_Fugitive', {})
local autocmd = vim.api.nvim_create_autocmd
autocmd('BufWinEnter', {
group = ThePrimeagen_Fugitive,
pattern = '*',
callback = function()
if vim.bo.ft ~= 'fugitive' then
return
end
local bufnr = vim.api.nvim_get_current_buf()
local opts = { buffer = bufnr, remap = false }
vim.keymap.set('n', '<leader>gp', function()
vim.cmd.Git 'push'
end, opts)
-- rebase always
vim.keymap.set('n', '<leader>gP', function()
vim.cmd.Git { 'pull', '--rebase' }
end, opts)
-- NOTE: It allows me to easily set the branch i am pushing and any tracking
-- needed if i did not set the branch up correctly
vim.keymap.set('n', '<leader>gt', ':Git push -u origin ', opts)
end,
})
vim.keymap.set('n', '<Leader>gu', '<cmd>diffget //2<CR>')
vim.keymap.set('n', '<Leader>gh', '<cmd>diffget //3<CR>')
end,
}

10
lua/plugins/git_blame.lua Normal file
View File

@@ -0,0 +1,10 @@
return {
'f-person/git-blame.nvim',
event = 'VeryLazy',
opts = {
enabled = true, -- if you want to enable the plugin
message_template = ' <summary> • <date> • <author> • <<sha>>', -- template for the blame message, check the Message template section for more options
date_format = '%m-%d-%Y %H:%M:%S', -- template for the date, check Date format section for more options
virtual_text_column = 1, -- virtual text start column, check Start virtual text at column section for more options
},
}

65
lua/plugins/gitsigns.lua Normal file
View File

@@ -0,0 +1,65 @@
require('helpers').edit_cf('pg', '/lua/plugins/gitsigns.lua')
-- Adds git related signs to the gutter, as well as utilities for managing changes
-- See `:help gitsigns`
return {
'lewis6991/gitsigns.nvim',
opts = {
signs = {
add = { text = '+' },
change = { text = '~' },
delete = { text = '_' },
topdelete = { text = '' },
changedelete = { text = '~' },
},
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'
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', '<leader>hs', function()
gitsigns.stage_hunk { vim.fn.line '.', vim.fn.line 'v' }
end, { desc = 'git [s]tage hunk' })
map('v', '<leader>hr', function()
gitsigns.reset_hunk { vim.fn.line '.', vim.fn.line 'v' }
end, { desc = 'git [r]eset hunk' })
-- normal mode
map('n', '<leader>hs', gitsigns.stage_hunk, { desc = 'git [s]tage hunk' })
map('n', '<leader>hr', gitsigns.reset_hunk, { desc = 'git [r]eset hunk' })
map('n', '<leader>hS', gitsigns.stage_buffer, { desc = 'git [S]tage buffer' })
map('n', '<leader>hu', gitsigns.stage_hunk, { desc = 'git [u]ndo stage hunk' })
map('n', '<leader>hR', gitsigns.reset_buffer, { desc = 'git [R]eset buffer' })
map('n', '<leader>hp', gitsigns.preview_hunk, { desc = 'git [p]review hunk' })
map('n', '<leader>hb', gitsigns.blame_line, { desc = 'git [b]lame line' })
map('n', '<leader>hd', gitsigns.diffthis, { desc = 'git [d]iff against index' })
map('n', '<leader>hD', function()
gitsigns.diffthis '@'
end, { desc = 'git [D]iff against last commit' })
-- Toggles
map('n', '<leader>tb', gitsigns.toggle_current_line_blame, { desc = '[T]oggle git show [b]lame line' })
map('n', '<leader>tD', gitsigns.preview_hunk_inline, { desc = '[T]oggle git show [D]eleted' })
end,
},
}

View File

@@ -0,0 +1,8 @@
-- Add indentation guides even on blank lines
return {
'lukas-reineke/indent-blankline.nvim',
-- Enable `lukas-reineke/indent-blankline.nvim`
-- See `:help ibl`
main = 'ibl',
opts = {},
}

12
lua/plugins/lazydev.lua Normal file
View File

@@ -0,0 +1,12 @@
-- `lazydev` configures Lua LSP for your Neovim config, runtime and plugins
-- used for completion, annotations and signatures of Neovim apis
return {
"folke/lazydev.nvim",
ft = "lua",
opts = {
library = {
-- Load luvit types when the `vim.uv` word is found
{ path = "${3rd}/luv/library", words = { "vim%.uv" } },
},
},
}

62
lua/plugins/lint.lua Normal file
View File

@@ -0,0 +1,62 @@
-- Linting
return {
'mfussenegger/nvim-lint',
event = { 'BufReadPre', 'BufNewFile' },
config = function()
local lint = require 'lint'
-- lint.linters_by_ft = {
-- markdown = { 'markdownlint' },
-- }
lint.linters_by_ft['markdown'] = nil
lint.linters_by_ft['javascript'] = nil
lint.linters_by_ft['vue'] = nil
lint.linters_by_ft['html'] = nil
-- 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.opt_local.modifiable:get() then
lint.try_lint()
end
end,
})
end,
}

216
lua/plugins/lsp.lua Normal file
View File

@@ -0,0 +1,216 @@
-- Main LSP Configuration
require('helpers').edit_cf('pl', '/lua/plugins/lsp.lua')
return {
'neovim/nvim-lspconfig',
dependencies = {
{ 'williamboman/mason.nvim', opts = {} },
'williamboman/mason-lspconfig.nvim',
'WhoIsSethDaniel/mason-tool-installer.nvim',
{ 'j-hui/fidget.nvim', opts = {} },
'saghen/blink.cmp',
'folke/lazydev.nvim',
},
build = function()
vim.fn.system 'composer global require jetbrains/phpstorm-stubs friendsofphp/php-cs-fixer'
end,
config = function()
-- 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('lsp-attach', { clear = true }),
callback = function(event)
local map = function(keys, func, desc, mode)
require('helpers').map(keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc }, mode)
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('grr', require('telescope.builtin').lsp_references, '[G]oto [R]eferences')
map('gri', require('telescope.builtin').lsp_implementations, '[G]oto [I]mplementation')
map('grd', require('telescope.builtin').lsp_definitions, '[G]oto [D]efinition')
map('grD', vim.lsp.buf.declaration, '[G]oto [D]eclaration')
map('gO', require('telescope.builtin').lsp_document_symbols, 'Open Document Symbols')
map('gW', require('telescope.builtin').lsp_dynamic_workspace_symbols, 'Open Workspace Symbols')
map('grt', require('telescope.builtin').lsp_type_definitions, '[G]oto [T]ype Definition')
-- This function resolves a difference between neovim nightly (version 0.11) and stable (version 0.10)
---@param client vim.lsp.Client
---@param method vim.lsp.protocol.Method
---@param bufnr? integer some lsp support methods only in specific files
---@return boolean
local function client_supports_method(client, method, bufnr)
if vim.fn.has 'nvim-0.11' == 1 then
return client:supports_method(method, bufnr)
else
return client.supports_method(method, { bufnr = bufnr })
end
end
-- 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(client, vim.lsp.protocol.Methods.textDocument_documentHighlight, event.buf) then
local highlight_augroup = vim.api.nvim_create_augroup('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('lsp-detach', { clear = true }),
callback = function(event2)
vim.lsp.buf.clear_references()
vim.api.nvim_clear_autocmds { group = 'lsp-highlight', buffer = event2.buf }
end,
})
end
if client and client_supports_method(client, vim.lsp.protocol.Methods.textDocument_inlayHint, event.buf) then
map('<leader>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.diagnostic.config {
severity_sort = true,
float = { border = 'rounded', source = 'if_many' },
underline = { severity = vim.diagnostic.severity.ERROR },
signs = vim.g.have_nerd_font and {
text = {
[vim.diagnostic.severity.ERROR] = '󰅚 ',
[vim.diagnostic.severity.WARN] = '󰀪 ',
[vim.diagnostic.severity.INFO] = '󰋽 ',
[vim.diagnostic.severity.HINT] = '󰌶 ',
},
} or {},
virtual_text = {
source = 'if_many',
spacing = 2,
format = function(diagnostic)
local diagnostic_message = {
[vim.diagnostic.severity.ERROR] = diagnostic.message,
[vim.diagnostic.severity.WARN] = diagnostic.message,
[vim.diagnostic.severity.INFO] = diagnostic.message,
[vim.diagnostic.severity.HINT] = diagnostic.message,
}
return diagnostic_message[diagnostic.severity]
end,
},
}
-- Enable the following language servers
--
-- Add any additional override configuration in the following tables. Available keys are:
-- - cmd (table): Override the default command used to start the server
-- - filetypes (table): Override the default list of associated filetypes for the server
-- - capabilities (table): Override fields in capabilities. Can be used to disable certain LSP features.
-- - settings (table): Override the default settings passed when initializing the server.
-- For example, to see the options for `lua_ls`, you could go to: https://luals.github.io/wiki/settings/
local mason_registry = require 'mason-registry'
local vue_language_server_path = vim.fn.expand '$MASON/packages/vue-language-server/node_modules/@vue/language-server'
local servers = {
clangd = {},
pyright = {},
rust_analyzer = {},
lua_ls = {
settings = {
Lua = {
completion = {
callSnippet = 'Replace',
},
},
},
},
phpactor = {},
vtsls = {
settings = {
vtsls = {
tsserver = {
globalPlugins = {
{
name = '@vue/typescript-plugin',
location = vue_language_server_path,
languages = { 'vue' },
configNamespace = 'typescript',
},
},
},
},
javascript = {
preferences = {
importModuleSpecifierPreference = 'non-relative',
importModuleSpecifierEnding = 'js',
},
},
},
filetypes = { 'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue' },
},
['vue-language-server'] = {
on_init = function(client)
client.handlers['tsserver/request'] = function(_, result, context)
local clients = vim.lsp.get_clients { bufnr = context.bufnr, name = 'vtsls' }
if #clients == 0 then
vim.notify('Could not find `vtsls` lsp client, `vue-language-server` would not work without it.', vim.log.levels.ERROR)
return
end
local ts_client = clients[1]
local param = unpack(result)
local id, command, payload = unpack(param)
ts_client:exec_cmd({
title = 'vue_request_forward', -- You can give title anything as it's used to represent a command in the UI, `:h Client:exec_cmd`
command = 'typescript.tsserverRequest',
arguments = {
command,
payload,
},
}, { bufnr = context.bufnr }, function(_, r)
local response_data = { { id, r.body } }
---@diagnostic disable-next-line: param-type-mismatch
client:notify('tsserver/response', response_data)
end)
end
end,
},
}
local ensure_installed = vim.tbl_keys(servers or {})
vim.list_extend(ensure_installed, {
'stylua', -- Used to format Lua code
})
-- LSP servers and clients are able to communicate to each other what features they support.
-- By default, Neovim doesn't support everything that is in the LSP specification.
-- When you add blink.cmp, luasnip, etc. Neovim now has *more* capabilities.
-- So, we create new capabilities with blink.cmp, and then broadcast that to the servers.
local capabilities = require('blink.cmp').get_lsp_capabilities()
for name, cfg in pairs(servers) do
cfg.capabilities = vim.tbl_deep_extend('force', {}, capabilities, cfg.capabilities or {})
vim.lsp.config(name, cfg) -- new Neovim 0.11 API
end
require('mason-tool-installer').setup { ensure_installed = ensure_installed }
require('mason').setup {}
require('mason-lspconfig').setup {}
end,
}

74
lua/plugins/mini.lua Normal file
View File

@@ -0,0 +1,74 @@
-- Collection of various small independent plugins/modules
return {
'echasnovski/mini.nvim',
config = function()
-- Better Around/Inside textobjects
--
-- Examples:
-- - va) - [V]isually select [A]round [)]paren
-- - yinq - [Y]ank [I]nside [N]ext [Q]uote
-- - ci' - [C]hange [I]nside [']quote
require('mini.ai').setup { 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 {
mappings = {
add = 'ys',
delete = 'ds',
replace = 'cs',
},
}
require('mini.pairs').setup()
require('mini.jump').setup {
mappings = {
repeat_jump = ':',
},
}
local MiniJump2d = require 'mini.jump2d'
MiniJump2d.setup {
spotter = MiniJump2d.gen_spotter.union(
MiniJump2d.gen_spotter.pattern('[([{][^$]', 'end'),
MiniJump2d.gen_spotter.pattern('%$.', 'end'),
MiniJump2d.gen_spotter.pattern('->.', 'end'),
MiniJump2d.gen_spotter.pattern('^%s*%S', 'end')
),
mappings = {
start_jumping = 'S',
},
allowed_lines = {
blank = false,
cursor_at = false,
fold = false,
},
}
require('mini.splitjoin').setup()
require('mini.map').setup()
-- Simple and easy statusline.
-- You could remove this setup call i 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/echasnovski/mini.nvim
end,
}

24
lua/plugins/oil.lua Normal file
View File

@@ -0,0 +1,24 @@
-- Filesystem manager
-- require('helpers').edit_cf('po', '/lua/plugins/oil.lua')
--
-- vim.keymap.set('n', '-', '<CMD>Oil<CR>', { desc = 'Open parent directory' })
return {
'stevearc/oil.nvim',
---@module 'oil'
---@type oil.SetupOpts
opts = {
view_options = {
show_hidden = true,
},
keymaps = {
['<C-p>'] = false,
['-'] = false,
},
},
-- Optional dependencies
dependencies = { { 'echasnovski/mini.icons', opts = {} } },
-- dependencies = { "nvim-tree/nvim-web-devicons" }, -- use if you prefer nvim-web-devicons
-- Lazy loading is not recommended because it is very tricky to make it work correctly in all situations.
lazy = false,
}

3
lua/plugins/pywal.lua Normal file
View File

@@ -0,0 +1,3 @@
return {
'AlphaTechnolog/pywal.nvim',
}

34
lua/plugins/quicker.lua Normal file
View File

@@ -0,0 +1,34 @@
vim.keymap.set("n", "<leader>q", function()
require("quicker").toggle()
end, { desc = "Toggle quickfix" })
vim.keymap.set("n", "<leader>l", function()
require("quicker").toggle({ loclist = true })
end, { desc = "Toggle loclist" })
return {
'stevearc/quicker.nvim',
ft = 'qf',
---@module "quicker"
---@type quicker.SetupOptions
opts = {},
config = function()
require('quicker').setup({
keys = {
{
">",
function()
require("quicker").expand({ before = 2, after = 2, add_to_existing = true })
end,
desc = "Expand quickfix context",
},
{
"<",
function()
require("quicker").collapse()
end,
desc = "Collapse quickfix context",
},
},
})
end,
}

9
lua/plugins/refactor.lua Normal file
View File

@@ -0,0 +1,9 @@
return {
"ThePrimeagen/refactoring.nvim",
dependencies = {
"nvim-lua/plenary.nvim",
"nvim-treesitter/nvim-treesitter",
},
lazy = false,
opts = {},
}

View File

@@ -0,0 +1,10 @@
return {
'MeanderingProgrammer/render-markdown.nvim',
dependencies = { 'nvim-treesitter/nvim-treesitter', 'echasnovski/mini.nvim' }, -- if you use the mini.nvim suite
-- dependencies = { 'nvim-treesitter/nvim-treesitter', 'echasnovski/mini.icons' }, -- if you use standalone mini plugins
-- dependencies = { 'nvim-treesitter/nvim-treesitter', 'nvim-tree/nvim-web-devicons' }, -- if you prefer nvim-web-devicons
---@module 'render-markdown'
---@type render.md.UserConfig
opts = {},
ft = { 'markdown', 'codecompanion' },
}

75
lua/plugins/snacks.lua Normal file
View File

@@ -0,0 +1,75 @@
return {
'folke/snacks.nvim',
priority = 1000,
lazy = false,
---@type snacks.Config
opts = {
-- your configuration comes here
-- or leave it empty to use the default settings
-- refer to the configuration section below
bigfile = { enabled = true },
dashboard = {
enabled = true,
preset = {
keys = {
{ icon = '', key = 'f', desc = 'Find File', action = ":lua Snacks.dashboard.pick('files')" },
{ icon = '', key = 'n', desc = 'New File', action = ':ene | startinsert' },
{ icon = '', key = 'g', desc = 'Find Text', action = ":lua Snacks.dashboard.pick('live_grep')" },
{ icon = '', key = 'r', desc = 'Recent Files', action = ":lua Snacks.dashboard.pick('oldfiles')" },
{ icon = '', key = 'c', desc = 'Config', action = ":lua Snacks.dashboard.pick('files', {cwd = vim.fn.stdpath('config')})" },
-- { icon = " ", key = "s", desc = "Restore Session", section = "session" },
{ icon = '󰒲 ', key = 'L', desc = 'Lazy', action = ':Lazy', enabled = package.loaded.lazy ~= nil },
{ icon = '', key = 'q', desc = 'Quit', action = ':qa' },
},
},
sections = {
{ section = 'header' },
{ section = 'keys', gap = 1, padding = 1 },
{
pane = 2,
icon = '',
title = 'Projects',
section = 'projects',
indent = 2,
padding = 1,
session = false,
dirs = function()
return {
vim.fn.expand '~/Code/Sites/runcats',
vim.fn.expand '~/Code/Sites/moovaza',
vim.fn.expand '~/Code/Sites/tuxtoolkit',
vim.fn.expand '~/Code/Sites/chrisstarling',
vim.fn.stdpath 'config',
}
end,
},
{ pane = 2, icon = '', title = 'Recent Files', section = 'recent_files', indent = 2, padding = 1 },
{
pane = 2,
icon = '',
title = 'Git Status',
section = 'terminal',
enabled = function()
return Snacks.git.get_root() ~= nil
end,
cmd = 'git status --short --branch --renames',
height = 5,
padding = 1,
ttl = 5 * 60,
indent = 3,
},
},
},
indent = { enabled = true },
input = { enabled = true },
notifier = { enabled = true },
quickfile = { enabled = true },
scope = { enabled = true },
-- scroll = { enabled = true },
statuscolumn = { enabled = true },
words = { enabled = true },
terminal = { enabled = true },
scratch = { enabled = true },
rename = { enabled = true },
},
}

26
lua/plugins/snippets.lua Normal file
View File

@@ -0,0 +1,26 @@
return {
'L3MON4D3/LuaSnip',
version = '2.*',
build = (function()
-- Build Step is needed for regex support in snippets.
-- This step is not supported in many windows environments.
-- Remove the below condition to re-enable on windows.
if vim.fn.has 'win32' == 1 or vim.fn.executable 'make' == 0 then
return
end
return 'make install_jsregexp'
end)(),
config = function()
local ls = require 'luasnip'
ls.filetype_extend('vue', { 'javascript' })
local snippets_dir = vim.fn.stdpath 'config' .. '/lua/snippets'
require('luasnip.loaders.from_lua').load {
paths = { snippets_dir },
}
ls.setup {
update_events = 'TextChanged,TextChangedI',
enable_autosnippets = true,
}
end,
opts = {},
}

6
lua/plugins/suda.lua Normal file
View File

@@ -0,0 +1,6 @@
return {
'lambdalisue/vim-suda',
config = function()
vim.g.suda_smart_edit = 1
end,
}

122
lua/plugins/telescope.lua Normal file
View File

@@ -0,0 +1,122 @@
-- Fuzzy Finder (files, lsp, etc)
-- See :help telescope
return {
'nvim-telescope/telescope.nvim',
event = 'VimEnter',
dependencies = {
'nvim-lua/plenary.nvim',
{ -- If encountering errors, see telescope-fzf-native README for installation instructions
'nvim-telescope/telescope-fzf-native.nvim',
-- `build` is used to run some command when the plugin is installed/updated.
-- This is only run then, not every time Neovim starts up.
build = 'make',
-- `cond` is a condition used to determine whether this plugin should be
-- installed and loaded.
cond = function()
return vim.fn.executable 'make' == 1
end,
},
{ 'nvim-telescope/telescope-ui-select.nvim' },
-- Useful for getting pretty icons, but requires a Nerd Font.
{ 'nvim-tree/nvim-web-devicons', enabled = vim.g.have_nerd_font },
},
config = function()
-- 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!
--
-- 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: <c-/>
-- - 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!
-- [[ Configure Telescope ]]
-- 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 = {}
extensions = {
['ui-select'] = {
require('telescope.themes').get_dropdown(),
},
},
defaults = {
mappings = {
i = {
-- Insert mode mappings for Telescope
['<C-j>'] = 'move_selection_next',
['<C-k>'] = 'move_selection_previous',
},
n = {
-- Normal mode mappings for Telescope
['<C-j>'] = 'move_selection_next',
['<C-k>'] = 'move_selection_previous',
},
},
file_ignore_patterns = {
'.obsidian',
},
},
}
-- 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', '<leader>sh', builtin.help_tags, { desc = '[S]earch [H]elp' })
vim.keymap.set('n', '<leader>sk', builtin.keymaps, { desc = '[S]earch [K]eymaps' })
vim.keymap.set('n', '<leader>sf', builtin.find_files, { desc = '[S]earch [F]iles' })
vim.keymap.set('n', '<leader>ss', builtin.builtin, { desc = '[S]earch [S]elect Telescope' })
vim.keymap.set('n', '<leader>sw', builtin.grep_string, { desc = '[S]earch current [W]ord' })
vim.keymap.set('n', '<leader>sg', builtin.live_grep, { desc = '[S]earch by [G]rep' })
vim.keymap.set('n', '<leader>sd', builtin.diagnostics, { desc = '[S]earch [D]iagnostics' })
vim.keymap.set('n', '<leader>sr', builtin.resume, { desc = '[S]earch [R]esume' })
vim.keymap.set('n', '<leader>s.', builtin.oldfiles, { desc = '[S]earch Recent Files ("." for repeat)' })
vim.keymap.set('n', '<leader><leader>', builtin.buffers, { desc = '[ ] Find existing buffers' })
-- Slightly advanced example of overriding default behavior and theme
vim.keymap.set('n', '<leader>/', 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', '<leader>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', '<leader>sn', function()
builtin.find_files { cwd = vim.fn.stdpath 'config' }
end, { desc = '[S]earch [N]eovim files' })
end,
}

View File

@@ -0,0 +1,7 @@
-- Highlight todo, notes, etc in comments
return {
'folke/todo-comments.nvim',
event = 'VimEnter',
dependencies = { 'nvim-lua/plenary.nvim' },
opts = { signs = false },
}

View File

@@ -0,0 +1,32 @@
-- Highlight, edit, and navigate code
return {
'nvim-treesitter/nvim-treesitter',
branch = 'main',
build = ':TSUpdate',
-- [[ Configure Treesitter ]] See `:help nvim-treesitter`
config = function()
local langs = {
'bash',
'c',
'diff',
'html',
'lua',
'luadoc',
'markdown',
'markdown_inline',
'query',
'vim',
'vimdoc',
'php',
'yaml',
}
require('nvim-treesitter').install(langs)
vim.api.nvim_create_autocmd('FileType', {
pattern = langs,
callback = function()
vim.treesitter.start()
end,
})
end,
}

10
lua/plugins/treesj.lua Normal file
View File

@@ -0,0 +1,10 @@
return {
'Wansmer/treesj',
lazy = true,
dependencies = { 'nvim-treesitter/nvim-treesitter' }, -- if you install parsers with `nvim-treesitter`
config = function()
require('treesj').setup({
use_default_keymaps = false,
})
end,
}

54
lua/plugins/which-key.lua Normal file
View File

@@ -0,0 +1,54 @@
-- Useful plugin to show you pending keybinds.
-- See :help which-key
return {
'folke/which-key.nvim',
event = 'VimEnter', -- Sets the loading event to 'VimEnter'
opts = {
-- delay between pressing a key and opening which-key (milliseconds)
-- this setting is independent of vim.opt.timeoutlen
delay = 0,
icons = {
-- set icon mappings to true if you have a Nerd Font
mappings = vim.g.have_nerd_font,
-- If you are using a Nerd Font: set icons.keys to an empty table which will use the
-- default which-key.nvim defined Nerd Font icons, otherwise define a string table
keys = vim.g.have_nerd_font and {} or {
Up = '<Up> ',
Down = '<Down> ',
Left = '<Left> ',
Right = '<Right> ',
C = '<C-…> ',
M = '<M-…> ',
D = '<D-…> ',
S = '<S-…> ',
CR = '<CR> ',
Esc = '<Esc> ',
ScrollWheelDown = '<ScrollWheelDown> ',
ScrollWheelUp = '<ScrollWheelUp> ',
NL = '<NL> ',
BS = '<BS> ',
Space = '<Space> ',
Tab = '<Tab> ',
F1 = '<F1>',
F2 = '<F2>',
F3 = '<F3>',
F4 = '<F4>',
F5 = '<F5>',
F6 = '<F6>',
F7 = '<F7>',
F8 = '<F8>',
F9 = '<F9>',
F10 = '<F10>',
F11 = '<F11>',
F12 = '<F12>',
},
},
-- Document existing key chains
spec = {
{ '<leader>s', group = '[S]earch' },
{ '<leader>t', group = '[T]oggle' },
{ '<leader>h', group = 'Git [H]unk', mode = { 'n', 'v' } },
},
},
}

9
lua/plugins/yanky.lua Normal file
View File

@@ -0,0 +1,9 @@
-- For when I'm ready
return {
-- "gbprod/yanky.nvim",
-- opts = {
-- -- your configuration comes here
-- -- or leave it empty to use the default settings
-- -- refer to the configuration section below
-- },
}

32
lua/plugins/yazi.lua Normal file
View File

@@ -0,0 +1,32 @@
---@type LazySpec
return {
'mikavilpas/yazi.nvim',
version = '*', -- use the latest stable version
event = 'VeryLazy',
dependencies = {
{ 'nvim-lua/plenary.nvim', lazy = true },
},
keys = {
-- 👇 in this section, choose your own keymappings!
{
'-',
mode = { 'n', 'v' },
'<cmd>Yazi<cr>',
desc = 'Open yazi at the current file',
},
{
-- Open in the current working directory
'\\',
'<cmd>Yazi cwd<cr>',
desc = "Open the file manager in nvim's working directory",
},
},
---@type YaziConfig | {}
opts = {
-- if you want to open yazi instead of netrw, see below for more info
open_for_directories = false,
keymaps = {
show_help = '<f1>',
},
},
}

296
lua/projects.lua Normal file
View File

@@ -0,0 +1,296 @@
-- Project specific settings
local M = {}
-- Helper to create mappings
local helpers = require 'helpers'
local map = helpers.map
-- Get the last folder name from a path
local function project_name_from_cwd(cwd)
return vim.fn.fnamemodify(cwd, ':t')
end
local function command_with_dir(dir, cmd)
if dir then
return '!cd ' .. dir .. ' && ' .. cmd
end
return '!' .. cmd
end
local function make_laravel_file(dir, cmd)
local cwd = vim.fn.getcwd()
if dir then
vim.fn.chdir(dir)
end
vim.ui.input({ prompt = 'Make: ' .. cmd }, function(input)
if input == nil then
vim.fn.chdir(cwd)
return
end
local output = vim.system({ 'vendor/bin/sail', 'artisan', 'make:' .. cmd, input }):wait().stdout
local new_file = output:match '%[([%w%./]+)%]'
if new_file ~= nil then
vim.cmd('edit ' .. new_file)
end
vim.fn.chdir(cwd)
end)
end
local function get_scope_from_file(filename)
local ext = filename:match '%.(%w+)$'
local base_name = filename:match '^(%w+)%.?%w*$'
local extensionSuffixes = {
php = { 'Controller', 'Repository', 'StoreRequest', 'UpdateRequest', 'Request', 'Resource', 'Test', 'Observer', 'Policy', 'Seeder', 'Factory' },
['[jt]s'] = { 'Service' },
}
for suffix_type, _ in pairs(extensionSuffixes) do
if ext:match(suffix_type) then
local suffixes = extensionSuffixes[suffix_type]
for _, suffix in ipairs(suffixes) do
local scope = base_name:match('^(%w+)' .. suffix .. '$')
if scope then
return scope
end
end
end
end
return base_name
end
local function navigate_using_suffix(suffix)
local scope = get_scope_from_file(vim.fn.expand '%:t')
local file_name = scope .. suffix
local file_path = vim.system({ 'git', 'ls-files', file_name, '**/' .. file_name }):wait().stdout
if file_path ~= '' then
vim.cmd('edit ' .. file_path)
else
vim.notify('File ' .. file_name .. ' not found in git ls-files', vim.log.levels.ERROR)
end
end
local function create_navigation_maps(maps)
for key, suffix_and_name in pairs(maps) do
map('<Leader>n' .. key, function()
navigate_using_suffix(suffix_and_name[1])
end, { desc = 'Navigate to relevant ' .. suffix_and_name[2] })
end
end
local function create_bookmark(key, bookmark)
map('<Leader>b' .. key, function()
vim.cmd('edit ' .. bookmark)
end, { desc = 'Navigate to ' .. bookmark })
end
local function create_bookmark_maps(maps)
for key, bookmark in pairs(maps) do
create_bookmark(key, bookmark)
end
end
local function laravel_bookmarks_with_dir(dir)
create_bookmark_maps {
['e'] = dir .. '.env',
['l'] = dir .. 'storage/logs/laravel.log',
['w'] = dir .. 'routes/web.php',
['a'] = dir .. 'routes/api.php',
['m'] = dir .. 'database/migrations',
['dc'] = dir .. 'app/Core/',
['dd'] = dir .. 'app/Data/',
['dE'] = dir .. 'app/Enums/',
['de'] = dir .. 'app/Events/',
['dh'] = dir .. 'app/Http/',
['dj'] = dir .. 'app/Jobs/',
['dl'] = dir .. 'app/Listeners/',
['dM'] = dir .. 'app/Mail/',
['dm'] = dir .. 'app/Models/',
['dn'] = dir .. 'app/Notifications/',
['do'] = dir .. 'app/Observers/',
['dp'] = dir .. 'app/Providers/',
['pa'] = dir .. 'app/Providers/AppServiceProvider.php',
['pe'] = dir .. 'app/Providers/EventServiceProvider.php',
['cA'] = dir .. 'config/app.php',
['ca'] = dir .. 'config/auth.php',
['cb'] = dir .. 'config/broadcasting.php',
['cd'] = dir .. 'config/database.php',
['cf'] = dir .. 'config/filesystems.php',
['ch'] = dir .. 'config/filesystems.php',
['cl'] = dir .. 'config/logging.php',
['cm'] = dir .. 'config/mail.php',
['cq'] = dir .. 'config/queue.php',
['cS'] = dir .. 'config/services.php',
['cs'] = dir .. 'config/session.php',
}
end
local function laravel_keymaps(dir)
map('sl ', command_with_dir(dir, 'vendor/bin/sail '), { desc = 'Run sail command' }, 'c')
map('art ', command_with_dir(dir, 'php artisan '), { desc = 'Run artisan command' }, 'c')
map('sart ', command_with_dir(dir, 'vendor/bin/sail artisan '), { desc = 'Run artisan command with sail' }, 'c')
map('cmp ', command_with_dir(dir, 'composer '), { desc = 'Run composer script' }, 'c')
map('<Leader>pm', ':' .. command_with_dir(dir, 'vendor/bin/sail artisan migrate<CR>'))
map('<Leader>pr', ':' .. command_with_dir(dir, 'vendor/bin/sail artisan migrate:rollback<CR>'))
map('<Leader>pM', ':' .. command_with_dir(dir, 'vendor/bin/sail artisan make:'))
create_navigation_maps {
['m'] = { '.php', 'model' },
['c'] = { 'Controller.php', 'controller' },
['p'] = { 'Policy.php', 'policy' },
['R'] = { 'Resource.php', 'resource' },
['r'] = { 'Request.php', 'request' },
['t'] = { 'Test.php', 'test file' },
}
if dir == nil then
dir = ''
end
laravel_bookmarks_with_dir(dir)
end
local function laravel_makes(dir)
for key, name in pairs {
c = 'controller',
d = 'data',
e = 'event',
f = 'factory',
j = 'job',
l = 'listener',
ma = 'mail',
mi = 'migration',
mo = 'model',
mw = 'middleware',
n = 'notification',
o = 'observer',
pi = 'model --pivot',
po = 'policy',
pr = 'provider',
t = 'test --pest',
v = 'view',
x = 'exception',
} do
map('<Leader>m' .. key, function()
make_laravel_file(dir, name)
end, { desc = 'Make and navigate to relevant ' .. name })
end
end
-- Define per-project configuration here.
-- Keys are folder names (last segment of your cwd).
local PROJECTS = {
-- Example: a repo folder
['runcats'] = function(dir)
-- local dump_buf = vim.api.nvim_create_buf(false, true)
-- vim.api.nvim_set_option_value('bufhidden', 'hide', { buf = dump_buf })
-- vim.api.nvim_set_option_value('modifiable', false, { buf = dump_buf })
--
-- vim.fn.jobstart('cd server && sail artisan dump-server', {
-- term = true,
-- })
-- map('<leader>dd', function()
-- local height = math.ceil(vim.o.lines * 0.8)
-- local width = math.ceil(vim.o.columns * 0.8)
-- vim.api.nvim_open_win(dump_buf, true, {
-- style = 'minimal',
-- relative = 'editor',
-- width = width,
-- height = height,
-- row = math.ceil((vim.o.lines - height) / 2),
-- col = math.ceil((vim.o.columns - width) / 2),
-- border = 'single',
-- })
--
-- vim.cmd.startinsert()
-- end, { desc = 'Open the dump-server window' })
map(
'<leader>pl',
':cexpr system("cd server && vendor/bin/phpstan analyse --no-progress --error-format=raw --memory-limit=2G -vv") <CR>',
{ desc = 'Run lint' }
)
map('<leader>pd', function()
helpers.open_term { cmd = 'lazysql mysql://root@localhost:3306/runcats' }
end, { desc = 'Open database manager' })
map('s ', '!cd server && ', { desc = 'Run command in server directory' }, 'c')
map('c ', '!cd client && ', { desc = 'Run command in client directory' }, 'c')
laravel_keymaps 'server/'
laravel_makes 'server/'
map('yrn ', '!cd client && yarn ', { desc = 'Run yarn script' }, 'c')
map('<Leader>pt', ':!cd server && php artisan typescript:transform --format<CR>', { desc = 'Compile typescript' })
require('conform').formatters.pint = {
append_args = {
'--config=' .. dir .. '/server/pint.json',
},
}
create_bookmark('E', dir .. '/client/src/types/api/endpointMap.d.ts')
create_bookmark('q', dir .. '/client/quasar.config.ts')
create_bookmark('db', dir .. '/client/src/boot')
create_bookmark('ds', dir .. '/client/src/stores')
create_bookmark('dS', dir .. '/client/src/services')
end,
['hylark'] = function(dir)
map('<leader>pl', ':cexpr system("vendor/bin/phpstan analyse --no-progress --error-format=raw --memory-limit=2G -vv") <CR>', { desc = 'Run lint' })
map('<leader>pd', function()
helpers.open_term { cmd = 'lazysql pgsql://homestead:password@localhost:5432/homestead' }
end, { desc = 'Open database manager' })
laravel_keymaps()
laravel_makes()
map('yrn ', '!cd frontend && yarn ', { desc = 'Run yarn script' }, 'c')
map('<Leader>pm', ':vendor/bin/sail composer migrate<CR>')
end,
default = function() end,
}
local last_applied = nil
function M.apply(cwd)
local dir = cwd or vim.fn.getcwd()
local name = project_name_from_cwd(dir)
if last_applied == name then
return
end
last_applied = name
local setup = PROJECTS[name]
if type(setup) == 'function' then
setup(dir)
vim.notify(('Project config loaded: %s'):format(name), vim.log.levels.INFO, { title = 'projects.lua' })
else
PROJECTS.default(dir)
end
end
-- Apply on startup and when the working directory changes
do
local grp = vim.api.nvim_create_augroup('ProjectConfig', { clear = true })
vim.api.nvim_create_autocmd('VimEnter', {
group = grp,
callback = function()
M.apply()
end,
})
vim.api.nvim_create_autocmd('DirChanged', {
group = grp,
callback = function(args)
-- args.file is the new cwd for DirChanged
M.apply(args and args.file or nil)
end,
})
end
-- Optional command to manually re-apply
vim.api.nvim_create_user_command('ProjectReload', function()
last_applied = nil
M.apply()
end, {})
-- Keep your helper line
require('helpers').edit_cf('w', '/lua/projects.lua')

1
lua/snippets/all.lua Normal file
View File

@@ -0,0 +1 @@
return {}

128
lua/snippets/javascript.lua Normal file
View File

@@ -0,0 +1,128 @@
local ls = require 'luasnip'
local s = ls.snippet
local sn = ls.snippet_node
local fn = ls.function_node
local ms = ls.multi_snippet
local t = ls.text_node
local c = ls.choice_node
local i = ls.insert_node
local f = ls.function_node
local d = ls.dynamic_node
local fmt = require('luasnip.extras.fmt').fmt
local rep = require('luasnip.extras').rep
local extend_decorator = require 'luasnip.util.extend_decorator'
local fmta = extend_decorator.apply(fmt, { delimiters = '#~' })
local utils = require 'snippets.snip_utils'
local tr = utils.tr
local etr = utils.etr
local atr = utils.atr
local ctr = utils.ctr
local bs = utils.bs
return {
s(etr('du ', 'Dump a variable to the console'), fmta('console.log(#~);', { i(0) })),
s(
etr('vue', 'Vue Single File Component skeleton'),
fmta(
[[
<template>
</template>
<script setup>
#~
</script>
<style scoped>
</style>
]],
{ i(0) }
)
),
-- bs(atr('t ', 'this'), fmta('this.#~', { i(0) })),
s(etr('return ', 'Add semicolon after return'), fmta('return #~;', { i(0) })),
s(etr('rt ', 'return alias'), fmta('return #~;', { i(0) })),
s(etr('const ', 'const declaration'), {
c(1, {
sn(nil, fmta('const #~ = #~;', { i(1, 'variableName'), i(2, 'value') })),
sn(
nil,
fmta(
[[
const #~ = (#~) => {
#~
}
]],
{ i(1), i(2), i(3) }
)
),
}),
}),
s(
etr('fn ', 'function block'),
fmta(
[[
function #~(#~) {
#~
}
]],
{ i(1), i(2), i(0) }
)
),
bs(atr('fn ', 'function block'), {
c(1, {
sn(
nil,
fmta(
[[
(#~) => {
#~
}
]],
{ i(1), i(2) }
)
),
sn(
nil,
fmta(
[[
function (#~) {
#~
}
]],
{ i(1), i(2) }
)
),
}),
}),
bs(atr('afn ', 'async function block'), {
c(1, {
sn(
nil,
fmta(
[[
async (#~) => {
#~
}
]],
{ i(1), i(2) }
)
),
sn(
nil,
fmta(
[[
async function (#~) {
#~
}
]],
{ i(1), i(2) }
)
),
}),
}),
}

613
lua/snippets/php.lua Normal file
View File

@@ -0,0 +1,613 @@
local ls = require 'luasnip'
local s = ls.snippet
local sn = ls.snippet_node
local fn = ls.function_node
local ms = ls.multi_snippet
local t = ls.text_node
local c = ls.choice_node
local i = ls.insert_node
local f = ls.function_node
local d = ls.dynamic_node
local fmt = require('luasnip.extras.fmt').fmt
local rep = require('luasnip.extras').rep
local extend_decorator = require 'luasnip.util.extend_decorator'
local fmta = extend_decorator.apply(fmt, { delimiters = '#~' })
local utils = require 'snippets.snip_utils'
local tr = utils.tr
local etr = utils.etr
local Etr = utils.Etr
local atr = utils.atr
local ctr = utils.ctr
local bs = utils.bs
local function psr_namespace()
local path = vim.fn.expand '%'
-- Get the directory of the path
local dir = vim.fs.dirname(path)
-- Loop through parent directories to find composer.json
while dir ~= '/' and dir ~= nil do
local composer_json_path = dir .. '/composer.json'
if vim.fn.filereadable(composer_json_path) == 1 then
break
end
dir = vim.fs.dirname(dir)
end
-- If no composer.json found, return empty string
if dir == '/' or dir == nil then
return ''
end
-- Decode composer.json and get PSR-4 autoload mappings
local composer = vim.json.decode(vim.iter(vim.fn.readfile(dir .. '/composer.json')):join '')
local psr4 = composer['autoload'] and composer['autoload']['psr-4']
-- If no PSR-4 mappings, return empty string
if not psr4 then
return ''
end
-- Get the relative path from the composer.json directory
local relative_path = path:sub(#dir + 2)
-- Loop through PSR-4 mappings
for namespace, map in pairs(psr4) do
-- Check if the relative path matches the mapping
if relative_path:match('^' .. map:gsub('/', '%%/')) then
-- Extract the suffix of the path after the mapping, removing the filename
local suffix = relative_path:sub(#map + 1):match '^(.*)/[^/]+%.php$' or ''
local trimmed = namespace:gsub('\\$', '')
return trimmed .. (suffix ~= '' and ('\\' .. suffix:gsub('/', '\\')) or '')
end
end
end
local function class_name(args, snip)
local filename = snip.env.TM_FILENAME or ''
return filename:match '([^%.]+)' or 'ClassName'
end
return {
---------------
-- DEBUGGING --
---------------
s(etr('du ', 'Dump a variable to the dump server', { priority = 1001 }), fmta('dump(#~);', { i(0) })),
bs(etr('du ', 'Dump a variable to the dump server'), fmta('dump(#~)', { i(0) })),
s(etr('r ', 'ray', { priority = 1001 }), fmta('ray(#~);', { i(0) })),
bs(etr('r ', 'ray'), fmta('ray(#~)', { i(0) })),
s(etr('dt ', 'Dump PHPStan type definition'), fmta('\\PhpStan\\dumpType(#~);', { i(0) })),
s(
etr('ql ', 'Log all queries'),
fmta(
[[
\Illuminate\Support\Facades\DB::listen(function (\Illuminate\Database\Events\QueryExecuted $e) {
dump($e->sql, $e->bindings);
});
#~
]],
{ i(0) }
)
),
--------------
-- COMMENTS --
--------------
s(etr('/**', 'Docblock comment'), {
c(1, {
sn(
nil,
fmta(
[[
/**
* #~
*/
]],
{ i(1) }
)
),
sn(nil, fmta('/** #~ */', { i(1) })),
}),
}),
s(etr('@v', '@var docblock'), fmta('/** @var #~ $#~ */', { i(1), i(0) })),
s(ctr('@v', '@var docblock'), fmta('@var #~ $#~', { i(1), i(0) })),
s(Etr('@pi', '@phpstan-ignore'), fmta('// @phpstan-ignore #~ (#~)', { i(1), i(0) })),
s(ctr('* @pr', 'Class property docblock'), fmta('* @property #~ $#~', { i(1), i(0) })),
s(ctr('* @pb', 'Class boolean property docblock'), fmta('* @property bool $#~', { i(0) })),
s(ctr('* @pi', 'Class int property docblock'), fmta('* @property int $#~', { i(0) })),
s(ctr('* @ps', 'Class string property docblock'), fmta('* @property string $#~', { i(0) })),
s(ctr('* @pc', 'Class collection property docblock'), fmta('* @property \\Illuminate\\Database\\Eloquent\\Collection<#~> $#~', { i(1), i(0) })),
s(ctr('* @pd', 'Class date property docblock'), fmta('* @property \\Illuminate\\Support\\Carbon $#~', { i(0) })),
s(
etr('@pm', 'Model magic properties docblock'),
fmta(
[[
/**
* @property int $id
* #~
* @property \Illuminate\Support\Carbon $created_at
* @property \Illuminate\Support\Carbon $updated_at
*
* Relationships
* #~
*/
]],
{ i(1), i(0) }
)
),
------------
-- SYNTAX --
------------
s(
etr('if ', 'if block'),
fmta(
[[
if (#~) {
#~
}
]],
{ i(1), i(0) }
)
),
s(
etr('fe ', 'foreach block'),
fmta(
[[
foreach (#~ as #~) {
#~
}
]],
{ i(1), i(2), i(0) }
)
),
s(etr('foreach', 'foreach block'), fmta('fe', {})),
s(
etr('for ', 'for block'),
fmta(
[[
for (#~; #~; #~) {
#~
}
]],
{ i(1, '$i'), i(2), i(3, '$i++'), i(0) }
)
),
s(etr('return ', 'Add semicolon after return'), fmta('return #~;', { i(0) })),
-- s(atr(' use ', 'Add use to function'), fmta(' use (#~)', { i(0) })),
s(etr('rt ', 'return alias'), fmta('return #~;', { i(0) })),
bs(atr('fn ', 'Shorthand function block'), {
c(1, {
sn(nil, fmta('fn (#~) => #~', { i(1), i(2) })),
sn(
nil,
fmta(
[[
function (#~) {
#~
}
]],
{ i(1), i(2) }
)
),
}),
}),
bs(atr('fun ', 'Shorthand function block'), {
c(1, {
sn(
nil,
fmta(
[[
function (#~) {
#~
}
]],
{ i(1), i(2) }
)
),
sn(
nil,
fmta(
[[
function (#~) use (#~) {
#~
}
]],
{ i(1), i(2), i(3) }
)
),
}),
}),
-- s(
-- etr('con', 'Constructor function block'),
-- c(1, {
-- sn(
-- nil,
-- fmta(
-- [[
-- public function __construct(#~)
-- {
-- #~
-- }
-- ]],
-- { i(1), i(2) }
-- )
-- ),
-- sn(
-- nil,
-- fmta(
-- [[
-- public function __construct(
-- #~
-- ) {
-- #~
-- }
-- ]],
-- { i(1), i(2) }
-- )
-- ),
-- })
-- ),
bs(atr('function', 'Shorthand function block'), fmta('fun', {})),
bs(atr('s%$', 'string type parameter'), fmta('string $#~', { i(0, 'var') })),
bs(atr('i%$', 'int type parameter'), fmta('int $#~', { i(0, 'var') })),
bs(atr('b%$', 'bool type parameter'), fmta('bool $#~', { i(0, 'var') })),
bs(atr('a%$', 'array type parameter'), fmta('array $#~', { i(0, 'var') })),
s(atr('$ ', 'Expand $this->'), fmta('$this->#~', { i(0) })),
bs(etr('am ', 'array_map function'), {
c(1, {
sn(nil, fmta('array_map(fn (#~) => #~, #~)', { i(2), i(3), i(1) })),
sn(
nil,
fmta(
[[
array_map(function (#~) {
#~
}, #~)
]],
{ i(2), i(0), i(1) }
)
),
}),
}),
bs(etr('array_map', 'array_map function'), fmta('am', {})),
bs(etr('af ', 'array_filter function'), {
c(1, {
sn(nil, fmta('array_filter(#~, fn (#~) => #~)', { i(1), i(2), i(3) })),
sn(
nil,
fmta(
[[
array_filter(#~, function (#~) {
#~
})
]],
{ i(1), i(2), i(0) }
)
),
}),
}),
bs(etr('array_filter', 'array_filter function'), fmta('af', {})),
s(
etr('php', 'php class'),
fmta(
[[
<?php
declare(strict_types=1);
namespace #~;
class #~
{
public function __construct()
{
#~
}
}
]],
{ f(psr_namespace, {}), f(class_name, {}), i(0) }
)
),
s(
etr('met', 'public class method'),
fmta(
[[
public function #~(#~)
{
#~
}
]],
{ i(1), i(2), i(0) }
)
),
s(
etr('pmet', 'protected class method'),
fmta(
[[
protected function #~(#~)
{
#~
}
]],
{ i(1), i(2), i(0) }
)
),
s(
etr('smet', 'public static class method'),
fmta(
[[
public static function #~(#~)
{
#~
}
]],
{ i(1), i(2), i(0) }
)
),
s(
etr('spmet', 'protected static class method'),
fmta(
[[
protected static function #~(#~)
{
#~
}
]],
{ i(1), i(2), i(0) }
)
),
-------------
-- PROJECT --
-------------
s(
etr('test', 'Create a test function'),
fmta(
[[
test('#~', function () {
#~
});
]],
{ i(1), i(0) }
)
),
s(
etr('it ', 'Create a test function'),
fmta(
[[
it('#~', function () {
#~
});
]],
{ i(1), i(0) }
)
),
s(etr('nn ', 'Assert not null'), fmta('Assert::notNull(#~)', { i(0) })),
-------------
-- LARAVEL --
-------------
s(
etr('bt', 'belongsTo Laravel relationship method'),
c(1, {
sn(
nil,
fmta(
[[
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\#~, $this>
*/
public function #~(): BelongsTo
{
return $this->belongsTo(#~::class);
}
]],
{ rep(1), i(2), i(1) }
)
),
sn(
nil,
fmta(
[[
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\#~, $this>
*/
public function #~(): BelongsTo
{
return $this->belongsTo(#~::class, #~);
}
]],
{ rep(1), i(2), i(1), i(3) }
)
),
})
),
s(
etr('hm', 'hasMany Laravel relationship method'),
c(1, {
sn(
nil,
fmta(
[[
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany<\App\Models\#~, $this>
*/
public function #~(): HasMany
{
return $this->hasOne(#~::class);
}
]],
{ rep(1), i(2), i(1) }
)
),
sn(
nil,
fmta(
[[
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany<\App\Models\#~, $this>
*/
public function #~(): HasMany
{
return $this->hasOne(#~::class, #~);
}
]],
{ rep(1), i(2), i(1), i(3) }
)
),
})
),
s(
etr('ho', 'hasOne Laravel relationship method'),
c(1, {
sn(
nil,
fmta(
[[
/**
* @return \Illuminate\Database\Eloquent\Relations\HasOne<\App\Models\#~, $this>
*/
public function #~(): HasOne
{
return $this->hasOne(#~::class);
}
]],
{ rep(1), i(2), i(1) }
)
),
sn(
nil,
fmta(
[[
/**
* @return \Illuminate\Database\Eloquent\Relations\HasOne<\App\Models\#~, $this>
*/
public function #~(): HasOne
{
return $this->hasOne(#~::class, #~);
}
]],
{ rep(1), i(2), i(1), i(3) }
)
),
})
),
s(
etr('bm', 'belongsToMany Laravel relationship method'),
c(1, {
sn(
nil,
fmta(
[[
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany<\App\Models\#~, $this>
*/
public function #~(): BelongsToMany
{
return $this->belongsToMany(#~::class, #~);
}
]],
{ rep(1), i(2), i(1), i(3) }
)
),
sn(
nil,
fmta(
[[
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany<\App\Models\#~, $this>
*/
public function #~(): BelongsToMany
{
return $this->belongsToMany(#~::class, #~, #~);
}
]],
{ rep(1), i(2), i(1), i(3), i(4) }
)
),
})
),
-- s(
-- atr('->wr', 'Eloquent where method'),
-- c(0, {
-- sn(nil, fmta("->where('#~', #~)", { i(1), i(0) })),
-- sn(nil, fmta('->where(fn ($query) => #~)', { i(0) })),
-- sn(
-- nil,
-- fmta(
-- [[
-- ->where(function ($query) {
-- #~
-- })
-- ]],
-- { i(0) }
-- )
-- ),
-- sn(
-- nil,
-- fmta(
-- [[
-- ->where(function ($query) use (#~) {
-- #~
-- })
-- ]],
-- { i(1), i(0) }
-- )
-- ),
-- })
-- ),
-- s(atr('->wi', 'Eloquent where in method'), fmta("->whereIn('#~', #~)", { i(1), i(0) })),
-- s(atr('->wn', 'Eloquent where not in method'), fmta("->whereNotIn('#~', #~)", { i(1), i(0) })),
-- s(
-- atr('->wha', 'Eloquent where has method'),
-- c(0, {
-- sn(nil, fmta("->whereHas('#~')", { i(1) })),
-- sn(nil, fmta("->whereHas('#~', fn ($query) => #~)", { i(1), i(0) })),
-- sn(
-- nil,
-- fmta(
-- [[
-- ->whereHas('#~', function ($query) {
-- #~
-- })
-- ]],
-- { i(1), i(0) }
-- )
-- ),
-- sn(
-- nil,
-- fmta(
-- [[
-- ->whereHas('#~', function ($query) use (#~) {
-- #~
-- })
-- ]],
-- { i(1), i(2), i(0) }
-- )
-- ),
-- })
-- ),
-- s(
-- atr('->we', 'Eloquent where exists method'),
-- c(0, {
-- sn(nil, fmta('->whereExists(fn ($query) => #~)', { i(0) })),
-- sn(
-- nil,
-- fmta(
-- [[
-- ->whereExists(function ($query) {
-- #~
-- })
-- ]],
-- { i(0) }
-- )
-- ),
-- sn(
-- nil,
-- fmta(
-- [[
-- ->whereExists(function ($query) use (#~) {
-- #~
-- })
-- ]],
-- { i(1), i(0) }
-- )
-- ),
-- })
-- ),
}

152
lua/snippets/snip_utils.lua Normal file
View File

@@ -0,0 +1,152 @@
local ls = require 'luasnip'
local s = ls.snippet
local sn = ls.snippet_node
local fn = ls.function_node
local ms = ls.multi_snippet
local t = ls.text_node
local c = ls.choice_node
local i = ls.insert_node
local f = ls.function_node
local d = ls.dynamic_node
local fmt = require('luasnip.extras.fmt').fmt
local rep = require('luasnip.extras').rep
local line_begin = require('luasnip.extras.conditions').line_begin
local line_end = require('luasnip.extras.conditions').line_end
local extend_decorator = require 'luasnip.util.extend_decorator'
local fmta = extend_decorator.apply(fmt, { delimiters = '#~' })
local utils = {}
--- Check if the trigger is at the beginning of a line
---@param line_to_cursor string
---@param matched_trigger string
---@return boolean
utils.line_begin = function(line_to_cursor, matched_trigger)
return line_to_cursor:sub(1, -(#matched_trigger + 1)):match '^%s*$'
end
--- Check if the trigger is on an empty line
---@param _ string
---@param matched_trigger string
---@return boolean
utils.empty_line = function(_, matched_trigger)
return vim.api.nvim_get_current_line():match('^%s*' .. vim.pesc(matched_trigger) .. '$')
end
--- Check if the trigger is at the start of a file
---@param line_to_cursor string
---@param matched_trigger string
---@return boolean
utils.file_begin = function(line_to_cursor, matched_trigger)
local line_number = vim.fn.line '.'
return line_number == 1 and line_begin(line_to_cursor, matched_trigger)
end
--- Check if the trigger is inside a string
---@return boolean
utils.in_string = function()
local node_type = vim.treesitter.get_node():type()
return node_type == 'string_content' or node_type == 'string'
end
--- Check if the trigger is inside a comment
---@return boolean
utils.in_comment = function()
local node_type = vim.treesitter.get_node():type()
return node_type == 'comment'
end
--- Check if the trigger is not inside a string or a comment
---@return boolean
utils.not_in_string_or_comment = function()
return (not utils.in_string()) and (not utils.in_comment())
end
--- Create a basic auto expand trigger
---@param trigger string
---@param description? string
---@param options? table
---@return table
utils.tr = function(trigger, description, options)
return vim.tbl_extend('force', {
trig = trigger,
desc = description,
snippetType = 'autosnippet',
}, options or {})
end
--- Create a trigger for an empty line snippet
---@param trigger string
---@param description? string
---@param options? table
---@return table
utils.etr = function(trigger, description, options)
return utils.tr(trigger, description, vim.tbl_extend('force', { condition = utils.empty_line }, options or {}))
end
--- Create a trigger for a comment trigger
---@param trigger string
---@param description? string
---@param options? table
---@return table
utils.ctr = function(trigger, description, options)
return utils.tr(trigger, description, vim.tbl_extend('force', { condition = utils.in_comment }, options or {}))
end
--- Create a trigger for a snippet to expand anywhere outside a string/comment
---@param trigger string
---@param description? string
---@param options? table
---@return table
utils.atr = function(trigger, description, options)
return utils.tr(
trigger,
description,
vim.tbl_extend('force', {
regTrig = true,
wordTrig = false,
condition = utils.not_in_string_or_comment,
}, options or {})
)
end
--- Create a trigger for a snippet to expand at the end of a line
---@param trigger string
---@param description? string
---@param options? table
---@return table
utils.Etr = function(trigger, description, options)
return utils.tr(
trigger,
description,
vim.tbl_extend('force', {
condition = line_end
}, options or {})
)
end
--- Create a snippet that will expand anywhere but in the middle of a word
---@param trigger any
---@param nodes any
---@param options? any
---@return table
utils.bs = function(trigger, nodes, options)
local btrigger
if type(trigger) == 'string' then
btrigger = utils.atr('([^%w_-])' .. trigger)
else
btrigger = vim.tbl_extend('keep', utils.atr('([^%w_-])' .. trigger.trig), trigger)
end
return ms(
{
trigger,
btrigger,
},
vim.list_extend({ fn(function(args, snip)
return snip.captures[1] or ''
end) }, nodes),
options
)
end
return utils

View File

@@ -0,0 +1,53 @@
local progress = require 'fidget.progress'
local M = {}
M.handles = {}
function M:store_progress_handle(id, handle)
M.handles[id] = handle
end
function M:pop_progress_handle(id)
local handle = M.handles[id]
M.handles[id] = nil
return handle
end
function M:create_progress_handle(request)
-- Ensure request.data and request.data.adapter exist before accessing them
local strategy = request.data and request.data.strategy or 'unknown'
local adapter_info = request.data and request.data.adapter or {}
return progress.handle.create {
title = ' Requesting assistance (' .. strategy .. ')',
message = 'In progress...',
lsp_client = {
name = M:llm_role_title(adapter_info),
},
}
end
function M:llm_role_title(adapter)
local parts = {}
-- Use adapter.formatted_name if available, otherwise default
local name = adapter.formatted_name or 'LLM'
table.insert(parts, name)
if adapter.model and adapter.model ~= '' then
table.insert(parts, '(' .. adapter.model .. ')')
end
return table.concat(parts, ' ')
end
function M:report_exit_status(handle, request)
-- Ensure request.data exists before accessing status
local status = request.data and request.data.status or 'unknown'
if status == 'success' then
handle.message = 'Completed'
elseif status == 'error' then
handle.message = ' Error'
else -- Includes "cancelled" or any other status
handle.message = '󰜺 Cancelled/Other'
end
end
return M

8
lua/visuals.lua Normal file
View File

@@ -0,0 +1,8 @@
require('helpers').edit_cf('c', '/lua/visuals.lua')
local line_number_color = '#5d6487'
vim.cmd('highlight LineNr guifg=' .. line_number_color)
vim.cmd('highlight LineNrAbove guifg=' .. line_number_color)
vim.cmd('highlight LineNrBelow guifg=' .. line_number_color)
vim.api.nvim_set_hl(0, "CopilotSuggestion", { fg = "#888888", italic = true })