Compare commits

47 Commits

Author SHA1 Message Date
Chris
a086657031 Treesitter update 2025-12-10 14:19:07 +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
42 changed files with 2119 additions and 862 deletions

View File

@@ -1 +0,0 @@
AIHUBMIX_API_KEY=

View File

@@ -12,6 +12,7 @@ require 'keymap'
require 'autocmd'
require 'lazy_init'
require 'visuals'
require 'projects'
require('helpers').edit_cf('v', '/init.lua')
@@ -19,7 +20,7 @@ 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 (an get rid of that stupid #endsection snippet)
- [ ] 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

View File

@@ -26,6 +26,14 @@ vim.api.nvim_create_autocmd('InsertLeave', {
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 = '*',
@@ -108,4 +116,33 @@ vim.api.nvim_create_autocmd('BufWritePost', {
end,
})
vim.api.nvim_create_autocmd('FileType', {
pattern = {
'bash',
'c',
'diff',
'html',
'lua',
'luadoc',
'markdown',
'markdown_inline',
'query',
'vim',
'vimdoc',
'php',
'javascript',
'typescript',
'json',
},
callback = function()
-- syntax highlighting, provided by Neovim
vim.treesitter.start()
-- folds, provided by Neovim
vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()'
vim.wo.foldmethod = 'expr'
-- indentation, provided by nvim-treesitter
vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
end,
})
require('helpers').edit_cf('a', '/lua/autocmd.lua')

View File

@@ -9,7 +9,50 @@ helpers.edit_cf = function(map, 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>

View File

@@ -1,5 +1,7 @@
-- [[ Basic Keymaps ]]
-- See `:help vim.keymap.set()`
-- Basic Keymaps
-- See `:help vim.keymap.set()`
local helpers = require 'helpers'
-- Swap : and ; around
vim.keymap.set({ 'n', 'v' }, ':', ';')
@@ -12,6 +14,10 @@ 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.
@@ -20,19 +26,127 @@ vim.keymap.set('n', '<leader>q', vim.diagnostic.setloclist, { desc = 'Open diagn
-- 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>', '<C-w><C-j>', { desc = 'Move focus to the lower window' })
vim.keymap.set('n', '<C-k>', '<C-w><C-k>', { desc = 'Move focus to the upper 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('n', '<C-S-h>', '<C-w>H', { desc = 'Move window to the left' })
vim.keymap.set('n', '<C-S-l>', '<C-w>L', { desc = 'Move window to the right' })
vim.keymap.set('n', '<C-S-j>', '<C-w>J', { desc = 'Move window to the lower' })
vim.keymap.set('n', '<C-S-k>', '<C-w>K', { desc = 'Move window to the upper' })
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' })
@@ -56,7 +170,7 @@ vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-S-P>', function()
hidden = true,
}
end, { desc = 'Find all files' })
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-F>', function()
vim.keymap.set({ 'n', 'v', 'c', 'i' }, '<C-f>', function()
require('telescope.builtin').live_grep {
hidden = true,
}
@@ -89,24 +203,12 @@ vim.keymap.set('n', '<Leader>{', 'mzF[`a<CR><Esc>``%i<CR><Esc>`z', { desc = 'Ind
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>gaf', '<CMD>Git add %<CR>', { desc = 'Git add current file' })
vim.keymap.set('n', '<Leader>gaa', '<CMD>Git add --all<CR>', { desc = 'Git add all unstaged changes' })
vim.keymap.set('n', '<Leader>gap', '<CMD>Git add --patch --all<CR>', { desc = 'Git add all unstaged changes interactively' })
vim.keymap.set('n', '<Leader>gb', '<CMD>Git blame<CR>', { desc = 'Git blame' })
vim.keymap.set('n', '<Leader>gcm', '<CMD>Git commit -v<CR>', { desc = 'Git commit' })
vim.keymap.set('n', '<Leader>gp', '<CMD>Git push<CR>', { desc = 'Git push' })
vim.keymap.set('n', '<Leader>gup', '<CMD>Git pull --rebase<CR>', { desc = 'Git pull --rebase' })
vim.keymap.set('n', '<Leader>gsb', '<CMD>Git status<CR>', { desc = 'Git status' })
vim.keymap.set('n', '<Leader>gd', '<CMD>Git diff<CR>', { desc = 'Git diff' })
vim.keymap.set('n', '<Leader>gf', '<CMD>Git fetch<CR>', { desc = 'Git fetch' })
vim.keymap.set('n', '<Leader>gdc', '<CMD>Git diff --cached<CR>', { desc = 'Git diff' })
vim.keymap.set('n', '<Leader>gl', '<CMD>Git log<CR>', { desc = 'Git log' })
vim.keymap.set('n', '<Leader>gun', '<CMD>Git reset -- %<CR>', { desc = 'Git unstage file' })
vim.keymap.set('n', '<Leader>gco', '<CMD>Git checkout -- %<CR>', { desc = 'Git checkout' })
vim.keymap.set('n', '<Leader>G', '<CMD>Git', { desc = 'Git' })
vim.keymap.set('n', '<Leader>gsta', '<CMD>Git stash push<CR>', { desc = 'Git stash' })
vim.keymap.set('n', '<Leader>gstA', '<CMD>Git stash apply<CR>', { desc = 'Git stash apply' })
vim.keymap.set('n', '<Leader>gstp', '<CMD>Git stash pop<CR>', { desc = 'Git stash pop' })
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', {
@@ -135,7 +237,7 @@ vim.api.nvim_create_autocmd('FileType', {
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 = { 'gpt-4.1', 'gemini-2.5-pro', 'gemini-2.0-flash-001', 'claude-3.7-sonnet-thought', 'o4-mini' }
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 })
@@ -161,79 +263,95 @@ local function open_test()
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 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' })
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
@@ -243,8 +361,11 @@ end, { desc = 'Close test panels' })
-- 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 .. '.json'
local snippets_file = snippets_dir .. '/' .. ft .. '.lua'
vim.cmd('tabedit ' .. snippets_file)
end, { desc = 'Edit snippets file' })

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,
}

View File

@@ -1,3 +1,11 @@
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',
@@ -13,6 +21,10 @@ return {
-- 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',
@@ -36,12 +48,13 @@ return {
},
},
config = function()
require('nvim_aider').setup({
require('nvim_aider').setup {
aider_cmd = 'aider',
args = {
'--config=$HOME/.config/aider/aider.yaml',
'--no-auto-commits',
'--copy-paste',
'--env-file=$(pwd)/aider.env',
'--watch',
'--architect',
},
auto_reload = true,
win = {
@@ -49,6 +62,6 @@ return {
style = 'nvim_aider',
position = 'bottom',
},
})
}
end,
}

View File

@@ -2,7 +2,7 @@
-- https://github.com/windwp/nvim-autopairs
return {
"windwp/nvim-autopairs",
event = "InsertEnter",
opts = {},
'windwp/nvim-autopairs',
event = 'InsertEnter',
opts = {},
}

View File

@@ -1,75 +0,0 @@
return {}
-- require('helpers').edit_cf('pa', '/lua/plugins/avante.lua')
--
-- return {
-- 'yetone/avante.nvim',
-- event = 'VeryLazy',
-- version = false, -- Never set this value to "*"! Never!
-- opts = {
-- -- add any opts here
-- -- for example
-- provider = 'aihubmix',
-- -- cursor_applying_provider = 'aihubmix_llama_versatile',
-- aihubmix = {
-- -- model = 'claude-3-7-sonnet-20250219',
-- model = 'DeepSeek-V3',
-- },
-- openai = {
-- endpoint = 'https://api.openai.com/v1',
-- model = 'gpt-4o', -- your desired model (or use gpt-4o, etc.)
-- timeout = 30000, -- Timeout in milliseconds, increase this for reasoning models
-- temperature = 0,
-- max_completion_tokens = 8192, -- Increase this to include reasoning tokens (for reasoning models)
-- --reasoning_effort = "medium", -- low|medium|high, only used for reasoning models
-- },
-- vendors = {
-- aihubmix_llama_versatile = {
-- __inherited_from = 'openai',
-- api_key_name = 'AIHUBMIX_API_KEY',
-- endpoint = 'https://aihubmix.com/v1',
-- model = 'llama-3.3-70b-versatile',
-- },
-- },
-- },
-- -- if you want to build from source then do `make BUILD_FROM_SOURCE=true`
-- build = 'make',
-- -- build = "powershell -ExecutionPolicy Bypass -File Build.ps1 -BuildFromSource false" -- for windows
-- dependencies = {
-- 'nvim-treesitter/nvim-treesitter',
-- 'stevearc/dressing.nvim',
-- 'nvim-lua/plenary.nvim',
-- 'MunifTanjim/nui.nvim',
-- --- The below dependencies are optional,
-- 'echasnovski/mini.pick', -- for file_selector provider mini.pick
-- 'nvim-telescope/telescope.nvim', -- for file_selector provider telescope
-- 'hrsh7th/nvim-cmp', -- autocompletion for avante commands and mentions
-- 'ibhagwan/fzf-lua', -- for file_selector provider fzf
-- 'nvim-tree/nvim-web-devicons', -- or echasnovski/mini.icons
-- 'zbirenbaum/copilot.lua', -- for providers='copilot'
-- {
-- -- support for image pasting
-- 'HakonHarnes/img-clip.nvim',
-- event = 'VeryLazy',
-- opts = {
-- -- recommended settings
-- default = {
-- embed_image_as_base64 = false,
-- prompt_for_file_name = false,
-- drag_and_drop = {
-- insert_mode = true,
-- },
-- -- required for Windows users
-- use_absolute_path = true,
-- },
-- },
-- },
-- {
-- -- Make sure to set this up properly if you have lazy=true
-- 'MeanderingProgrammer/render-markdown.nvim',
-- opts = {
-- file_types = { 'markdown', 'Avante' },
-- },
-- ft = { 'markdown', 'Avante' },
-- },
-- },
-- }

View File

@@ -4,10 +4,7 @@ return {
event = 'VimEnter',
version = '1.*',
dependencies = {
-- Compatibility for Avante with Blink (it typically only works with cmp)
-- 'Kaiser-Yang/blink-cmp-avante',
-- Snippet Engine
'L3MON4D3/LuaSnip',
-- 'L3MON4D3/LuaSnip',
'folke/lazydev.nvim',
},
--- @module 'blink.cmp'
@@ -36,6 +33,7 @@ return {
--
-- 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
@@ -54,7 +52,7 @@ return {
},
sources = {
default = { 'codecompanion', 'lsp', 'path', 'snippets', 'lazydev' },
default = { 'lsp', 'path', 'snippets', 'lazydev' },
providers = {
lazydev = { module = 'lazydev.integrations.blink', score_offset = 100 },
-- avante = { module = 'blink-cmp-avante', name = 'Avante', opts = {} },
@@ -64,7 +62,7 @@ return {
},
},
snippets = { preset = 'luasnip' },
-- snippets = { preset = 'luasnip' },
-- Blink.cmp includes an optional, recommended rust fuzzy matcher,
-- which automatically downloads a prebuilt binary when enabled.

View File

@@ -1,120 +1,106 @@
require('helpers').edit_cf('pa', '/lua/plugins/codecompanion.lua')
vim.cmd [[cab cc CodeCompanion]]
return {
'olimorris/codecompanion.nvim',
opts = function(_, opts)
opts.adapters = {
gpt = function()
return require('codecompanion.adapters').extend('copilot', {
schema = {
model = {
default = 'gpt-4.1',
},
max_tokens = {
default = 1000000,
},
},
})
end,
flash = function()
return require('codecompanion.adapters').extend('copilot', {
schema = {
model = {
default = 'gemini-2.0-flash-001',
},
max_tokens = {
default = 1000000,
},
},
})
end,
gemini = function()
return require('codecompanion.adapters').extend('copilot', {
schema = {
model = {
default = 'gemini-2.5-pro',
},
max_tokens = {
default = 1000000,
},
},
})
end,
sonnet = function()
return require('codecompanion.adapters').extend('copilot', {
schema = {
model = {
default = 'claude-3.7-sonnet',
},
max_tokens = {
default = 1000000,
},
},
})
end,
}
opts.display = {
chat = {
show_settings = true,
start_in_insert_mode = false,
},
}
opts.strategies = {
chat = {
adapter = 'gpt',
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 .. ')'
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,
},
keymaps = {
send = {
modes = { n = '<C-s>', i = '<C-s>' },
},
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(),
},
close = {
modes = { n = '<C-c>', i = '<C-c>' },
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,
},
},
},
inline = {
adapter = 'flash',
},
}
opts.extensions = {
mcphub = {
callback = 'mcphub.extensions.codecompanion',
opts = {
show_result_in_chat = true,
make_vars = true,
make_slash_commands = true,
extensions = {
mcphub = {
callback = 'mcphub.extensions.codecompanion',
opts = {
show_result_in_chat = true,
make_vars = true,
make_slash_commands = true,
},
},
},
}
opts.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.
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.
@@ -149,64 +135,53 @@ When given a task:
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
opts.prompt_library = {
['Code Expert'] = {
strategy = 'chat',
description = 'Get some special adcvice 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,
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,
},
{
role = 'user',
content = function(context)
local text = require('codecompanion.helpers.actions').get_code(context.start_line, context.end_line)
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,
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 = {
mapping = '<Leader>cd',
modes = { 'n' },
short_name = 'gm',
auto_submit = false,
stop_context_insertion = false,
user_prompt = false,
is_default = true,
adapter = {
temperature = 1,
['Games Master'] = {
strategy = 'chat',
description = 'A personal Games Master Assistant.',
opts = {
user_prompt = false,
},
},
prompts = {
{
role = 'system',
content = function(context)
return [[
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:
@@ -239,65 +214,59 @@ 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.
]]
end,
},
{
role = 'user',
content = function(context)
return ''
end,
opts = {
contains_code = false,
]],
},
{
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 = {
{
['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
{
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.
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,
end,
},
},
},
{
{
name = 'Fetch files',
role = 'user',
opts = { auto_submit = false },
content = function()
-- Enable turbo mode!!!
vim.g.codecompanion_auto_tool_mode = true
{
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,
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
{
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
return [[### Instructions
Now you have the errors and the appropriate context you can fix the errors.
### Steps to Follow
@@ -329,31 +298,32 @@ We'll repeat this cycle until there are no errors. Ensure no deviations from the
- 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,
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.',
{
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.',
},
},
},
},
@@ -363,7 +333,7 @@ We'll repeat this cycle until there are no errors. Ensure no deviations from the
dependencies = {
'nvim-lua/plenary.nvim',
'nvim-treesitter/nvim-treesitter',
'Davidyz/VectorCode',
-- 'Davidyz/VectorCode',
'ravitemer/mcphub.nvim',
},
}

View File

@@ -12,29 +12,33 @@ return { -- Autoformat
desc = '[F]ormat buffer',
},
},
opts = {
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 }
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' },
-- 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 },
},
},
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
}

View File

@@ -1,3 +0,0 @@
return {
'github/copilot.vim',
}

View File

@@ -121,7 +121,9 @@ return {
dap.adapters.php = {
type = 'executable',
command = 'node',
args = { '/Users/chris/.local/src/vscode-php-debug/out/phpDebug.js' },
args = {
vim.fn.expand '$MASON/packages/php-debug-adapter/extension/out/phpDebug.js',
},
}
dap.configurations.php = {
@@ -158,6 +160,12 @@ return {
disconnect = '',
},
},
element_mappings = {
stacks = {
open = '<CR>',
expand = 'o',
},
},
}
-- Change breakpoint icons

View File

@@ -4,9 +4,10 @@ return {
event = { 'BufReadPre', 'BufNewFile' },
config = function()
local lint = require 'lint'
lint.linters_by_ft = {
markdown = { 'markdownlint' },
}
-- 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

View File

@@ -4,98 +4,38 @@ require('helpers').edit_cf('pl', '/lua/plugins/lsp.lua')
return {
'neovim/nvim-lspconfig',
dependencies = {
-- Automatically install LSPs and related tools to stdpath for Neovim
-- Mason must be loaded before its dependents so we need to set it up here.
-- NOTE: `opts = {}` is the same as calling `require('mason').setup({})`
{ 'williamboman/mason.nvim', opts = {} },
'williamboman/mason-lspconfig.nvim',
'WhoIsSethDaniel/mason-tool-installer.nvim',
-- Useful status updates for LSP.
{ 'j-hui/fidget.nvim', opts = {} },
-- Allows extra capabilities provided by blink.cmp
'saghen/blink.cmp',
'folke/lazydev.nvim',
},
build = function()
vim.fn.system 'composer global require jetbrains/phpstorm-stubs friendsofphp/php-cs-fixer'
end,
config = function()
-- Brief aside: **What is LSP?**
--
-- LSP is an initialism you've probably heard, but might not understand what it is.
--
-- LSP stands for Language Server Protocol. It's a protocol that helps editors
-- and language tooling communicate in a standardized fashion.
--
-- In general, you have a "server" which is some tool built to understand a particular
-- language (such as `gopls`, `lua_ls`, `rust_analyzer`, etc.). These Language Servers
-- (sometimes called LSP servers, but that's kind of like ATM Machine) are standalone
-- processes that communicate with some "client" - in this case, Neovim!
--
-- LSP provides Neovim with features like:
-- - Go to definition
-- - Find references
-- - Autocompletion
-- - Symbol Search
-- - and more!
--
-- Thus, Language Servers are external tools that must be installed separately from
-- Neovim. This is where `mason` and related plugins come into play.
--
-- If you're wondering about lsp vs treesitter, you can check out the wonderfully
-- and elegantly composed help section, `:help lsp-vs-treesitter`
-- This function gets run when an LSP attaches to a particular buffer.
-- That is to say, every time a new file is opened that is associated with
-- an lsp (for example, opening `main.rs` is associated with `rust_analyzer`) this
-- function will be executed to configure the current buffer
vim.api.nvim_create_autocmd('LspAttach', {
group = vim.api.nvim_create_augroup('kickstart-lsp-attach', { clear = true }),
group = vim.api.nvim_create_augroup('lsp-attach', { clear = true }),
callback = function(event)
-- NOTE: Remember that Lua is a real programming language, and as such it is possible
-- to define small helper and utility functions so you don't have to repeat yourself.
--
-- In this case, we create a function that lets us more easily define mappings specific
-- for LSP related items. It sets the mode, buffer and description for us each time.
local map = function(keys, func, desc, mode)
mode = mode or 'n'
vim.keymap.set(mode, keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc })
require('helpers').map(keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc }, mode)
end
-- Rename the variable under your cursor.
-- Most Language Servers support renaming across files, etc.
map('grn', vim.lsp.buf.rename, '[R]e[n]ame')
-- Execute a code action, usually your cursor needs to be on top of an error
-- or a suggestion from your LSP for this to activate.
map('gra', vim.lsp.buf.code_action, '[G]oto Code [A]ction', { 'n', 'x' })
-- Find references for the word under your cursor.
map('grr', require('telescope.builtin').lsp_references, '[G]oto [R]eferences')
-- Jump to the implementation of the word under your cursor.
-- Useful when your language has ways of declaring types without an actual implementation.
map('gri', require('telescope.builtin').lsp_implementations, '[G]oto [I]mplementation')
-- Jump to the definition of the word under your cursor.
-- This is where a variable was first declared, or where a function is defined, etc.
-- To jump back, press <C-t>.
map('grd', require('telescope.builtin').lsp_definitions, '[G]oto [D]efinition')
-- WARN: This is not Goto Definition, this is Goto Declaration.
-- For example, in C this would take you to the header.
map('grD', vim.lsp.buf.declaration, '[G]oto [D]eclaration')
-- Fuzzy find all the symbols in your current document.
-- Symbols are things like variables, functions, types, etc.
map('gO', require('telescope.builtin').lsp_document_symbols, 'Open Document Symbols')
-- Fuzzy find all the symbols in your current workspace.
-- Similar to document symbols, except searches over your entire project.
map('gW', require('telescope.builtin').lsp_dynamic_workspace_symbols, 'Open Workspace Symbols')
-- Jump to the type of the word under your cursor.
-- Useful when you're not sure what type a variable is and you want to see
-- the definition of its *type*, not where it was *defined*.
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)
@@ -118,7 +58,7 @@ return {
-- 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('kickstart-lsp-highlight', { clear = false })
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,
@@ -132,18 +72,14 @@ return {
})
vim.api.nvim_create_autocmd('LspDetach', {
group = vim.api.nvim_create_augroup('kickstart-lsp-detach', { clear = true }),
group = vim.api.nvim_create_augroup('lsp-detach', { clear = true }),
callback = function(event2)
vim.lsp.buf.clear_references()
vim.api.nvim_clear_autocmds { group = 'kickstart-lsp-highlight', buffer = event2.buf }
vim.api.nvim_clear_autocmds { group = 'lsp-highlight', buffer = event2.buf }
end,
})
end
-- The following code creates a keymap to toggle inlay hints in your
-- code, if the language server you are using supports them
--
-- This may be unwanted, since they displace some of your code
if client and client_supports_method(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 })
@@ -152,8 +88,6 @@ return {
end,
})
-- Diagnostic Config
-- See :help vim.diagnostic.Opts
vim.diagnostic.config {
severity_sort = true,
float = { border = 'rounded', source = 'if_many' },
@@ -181,14 +115,7 @@ return {
},
}
-- 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()
-- Enable the following language servers
-- Feel free to add/remove any LSPs that you want here. They will automatically be installed.
--
-- Add any additional override configuration in the following tables. Available keys are:
-- - cmd (table): Override the default command used to start the server
@@ -199,111 +126,91 @@ return {
local mason_registry = require 'mason-registry'
local vue_language_server_path = vim.fn.expand '$MASON/packages/vue-language-server/node_modules/@vue/language-server'
print('Vue Language Server Path: ' .. vue_language_server_path)
local servers = {
-- clangd = {},
-- gopls = {},
-- pyright = {},
-- rust_analyzer = {},
-- ... etc. See `:help lspconfig-all` for a list of all the pre-configured LSPs
--
-- Some languages (like typescript) have entire language plugins that can be useful:
-- https://github.com/pmizio/typescript-tools.nvim
--
-- But for many setups, the LSP (`ts_ls`) will work just fine
-- ts_ls = {},
--
clangd = {},
pyright = {},
rust_analyzer = {},
lua_ls = {
-- cmd = { ... },
-- filetypes = { ... },
-- capabilities = {},
settings = {
Lua = {
completion = {
callSnippet = 'Replace',
},
-- You can toggle below to ignore Lua_LS's noisy `missing-fields` warnings
-- diagnostics = { disable = { 'missing-fields' } },
},
},
},
ts_ls = {
init_options = {
plugins = {
{
name = '@vue/typescript-plugin',
location = vue_language_server_path,
languages = { 'vue' },
phpactor = {},
vtsls = {
settings = {
vtsls = {
tsserver = {
globalPlugins = {
{
name = '@vue/typescript-plugin',
location = vue_language_server_path,
languages = { 'vue' },
configNamespace = 'typescript',
},
},
},
},
preferences = {
importModuleSpecifierEnding = 'js',
importModuleSpecifierPreference = 'project-relative',
javascript = {
preferences = {
importModuleSpecifierPreference = 'non-relative',
importModuleSpecifierEnding = 'js',
},
},
},
filetypes = { 'typescript', 'javascript', 'javascriptreact', 'typescriptreact', 'vue' },
capabilities = {
documentFormattingProvider = true,
documentRangeFormattingProvider = true,
},
},
['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]
volar = {
on_attach = function(client, bufnr)
client.server_capabilities.documentFormattingProvider = false
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,
capabilities = {
documentFormattingProvider = true,
documentRangeFormattingProvider = true,
},
},
phpactor = {
on_attach = function(client, bufnr)
client.server_capabilities.documentFormattingProvider = false
end,
init_options = {
['language_server_phpstan.enabled'] = false,
['language_server_psalm.enabled'] = false,
['language_server_php_cs_fixer.enabled'] = true,
['language_server_php_cs_fixer.bin'] = '~/.local/share/composer/vendor/bin/php-cs-fixer',
},
},
}
-- Ensure the servers and tools above are installed
--
-- To check the current status of installed tools and/or manually install
-- other tools, you can run
-- :Mason
--
-- You can press `g?` for help in this menu.
--
-- `mason` had to be setup earlier: to configure its options see the
-- `dependencies` table for `nvim-lspconfig` above.
--
-- You can add other tools here that you want Mason to install
-- for you, so that they are available from within Neovim.
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-lspconfig').setup {
ensure_installed = {}, -- explicitly set to an empty table (Kickstart populates installs via mason-tool-installer)
automatic_installation = false,
handlers = {
function(server_name)
local server = servers[server_name] or {}
-- This handles overriding only values explicitly passed
-- by the server configuration above. Useful when disabling
-- certain features of an LSP (for example, turning off formatting for ts_ls)
server.capabilities = vim.tbl_deep_extend('force', {}, capabilities, server.capabilities or {})
require('lspconfig')[server_name].setup(server)
end,
},
}
require('mason').setup {}
require('mason-lspconfig').setup {}
end,
}

View File

@@ -1,16 +0,0 @@
return {
'ravitemer/mcphub.nvim',
dependencies = {
'nvim-lua/plenary.nvim', -- Required for Job and HTTP requests
},
-- uncomment the following line to load hub lazily
cmd = 'MCPHub', -- lazy load
build = 'npm install -g mcp-hub@latest', -- Installs required mcp-hub npm module
-- uncomment this if you don't want mcp-hub to be available globally or can't use -g
-- build = "bundled_build.lua", -- Use this and set use_bundled_binary = true in opts (see Advanced configuration)
config = function()
require('mcphub').setup({
auto_approve = true,
})
end,
}

View File

@@ -25,16 +25,36 @@ return {
require('mini.pairs').setup()
-- require('mini.jump').setup()
require('mini.jump').setup {
mappings = {
repeat_jump = ':',
},
}
require('mini.jump2d').setup()
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 if you don't like it,
-- 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

View File

@@ -1,39 +0,0 @@
-- Neo-tree is a Neovim plugin to browse the file system
-- https://github.com/nvim-neo-tree/neo-tree.nvim
return {
'nvim-neo-tree/neo-tree.nvim',
version = '*',
dependencies = {
'nvim-lua/plenary.nvim',
'nvim-tree/nvim-web-devicons', -- not strictly required, but recommended
'MunifTanjim/nui.nvim',
},
cmd = 'Neotree',
keys = {
{ '\\', ':Neotree reveal<CR>', desc = 'NeoTree reveal', silent = true },
},
opts = function(_, opts)
local function on_move(data)
Snacks.rename.on_rename_file(data.source, data.destination)
end
local events = require("neo-tree.events")
opts.event_handlers = opts.event_handlers or {}
vim.list_extend(opts.event_handlers, {
{ event = events.FILE_MOVED, handler = on_move },
{ event = events.FILE_RENAMED, handler = on_move },
})
opts.filesystem = {
window = {
mappings = {
['\\'] = 'close_window',
},
},
filtered_items = {
hide_dotfiles = false,
},
}
end,
}

View File

@@ -1,27 +0,0 @@
require('helpers').edit_cf('pt', '/lua/plugins/neotest.lua')
return {
'nvim-neotest/neotest',
lazy = true,
dependencies = {
'nvim-neotest/nvim-nio',
'nvim-lua/plenary.nvim',
'antoinemadec/FixCursorHold.nvim',
'nvim-treesitter/nvim-treesitter',
-- Adapters
'V13Axel/neotest-pest',
-- "olimorris/neotest-phpunit",
},
config = function()
require('neotest').setup {
adapters = {
require 'neotest-pest' {
sail_enabled = function()
return false
end,
parallel = 10,
},
-- require('neotest-phpunit'),
},
}
end,
}

View File

@@ -1,7 +1,7 @@
-- Filesystem manager
require('helpers').edit_cf('po', '/lua/plugins/oil.lua')
vim.keymap.set('n', '-', '<CMD>Oil<CR>', { desc = 'Open parent directory' })
-- require('helpers').edit_cf('po', '/lua/plugins/oil.lua')
--
-- vim.keymap.set('n', '-', '<CMD>Oil<CR>', { desc = 'Open parent directory' })
return {
'stevearc/oil.nvim',
@@ -13,6 +13,7 @@ return {
},
keymaps = {
['<C-p>'] = false,
['-'] = false,
},
},
-- Optional dependencies

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,
}

View File

@@ -8,7 +8,58 @@ return {
-- or leave it empty to use the default settings
-- refer to the configuration section below
bigfile = { enabled = true },
dashboard = { 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 },

View File

@@ -11,21 +11,16 @@ return {
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_vscode').lazy_load {
require('luasnip.loaders.from_lua').load {
paths = { snippets_dir },
}
ls.setup {
update_events = 'TextChanged,TextChangedI',
enable_autosnippets = true,
}
end,
dependencies = {
-- `friendly-snippets` contains a variety of premade snippets.
-- See the README about individual language/framework/plugin snippets:
-- https://github.com/rafamadriz/friendly-snippets
{
'rafamadriz/friendly-snippets',
config = function()
require('luasnip.loaders.from_vscode').lazy_load()
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,
}

View File

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

View File

@@ -0,0 +1,153 @@
-- Highlight, edit, and navigate code
return {
-- 'nvim-treesitter/nvim-treesitter-textobjects',
-- lazy = true,
-- branch = 'main',
-- dependencies = {
-- 'nvim-treesitter/nvim-treesitter',
-- },
-- config = function()
-- -- configuration
-- require('nvim-treesitter-textobjects').setup {
-- select = {
-- lookahead = true,
-- selection_modes = {
-- ['@parameter.outer'] = 'v', -- charwise
-- ['@function.outer'] = 'V', -- linewise
-- ['@class.outer'] = 'V', -- blockwise
-- },
-- include_surrounding_whitespace = false,
-- },
-- move = {
-- set_jumps = true,
-- },
-- }
-- for keys, query in
-- {
-- -- or you use the queries from supported languages with textobjects.scm
-- ['af'] = '@function.outer',
-- ['if'] = '@function.inner',
-- ['aC'] = '@class.outer',
-- ['iC'] = '@class.inner',
-- ['ay'] = '@conditional.outer',
-- ['iy'] = '@conditional.inner',
-- ['aj'] = '@loop.outer',
-- ['ij'] = '@loop.inner',
-- ['is'] = '@statement.inner',
-- ['as'] = '@statement.outer',
-- ['ac'] = '@comment.outer',
-- ['ic'] = '@comment.inner',
-- ['ap'] = '@comment.parameter',
-- ['ip'] = '@comment.parameter',
-- ['an'] = '@local.scope',
-- }
-- do
-- vim.keymap.set({ 'n', 'x', 'o' }, keys, function()
-- require('nvim-treesitter-textobjects.select').select_textobject(query, 'textobjects')
-- end)
-- end
-- for keys, query in
-- {
-- -- or you use the queries from supported languages with textobjects.scm
-- [']'] = '@function.outer',
-- ['o'] = { '@loop.inner', '@loop.outer' },
-- ['n'] = '@local.scope',
-- ['y'] = '@conditional.outer',
-- ['e'] = '@statement.outer',
-- ['/'] = '@comment.outer',
-- }
-- do
-- vim.keymap.set({ 'n', 'x', 'o' }, ']' .. keys, function()
-- require('nvim-treesitter-textobjects.move').goto_next_start(query, 'textobjects')
-- end)
-- vim.keymap.set({ 'n', 'x', 'o' }, '[' .. keys, function()
-- require('nvim-treesitter-textobjects.move').goto_previous_start(query, 'textobjects')
-- end)
-- end
-- -- require('nvim-treesitter.configs').setup {
-- -- incremental_selection = {
-- -- enable = true,
-- -- keymaps = {
-- -- -- mappings for incremental selection (visual mappings)
-- -- init_selection = '<C-S-D>', -- maps in normal mode to init the node/scope selection
-- -- node_incremental = '<C-S-D>', -- increment to the upper named parent
-- -- scope_incremental = '<C-S-U>', -- increment to the upper scope (as defined in locals.scm)
-- -- node_decremental = '<C-S-S>', -- decrement to the previous node
-- -- },
-- -- },
-- -- textobjects = {
-- -- -- syntax-aware textobjects
-- -- enable = true,
-- -- keymaps = {
-- -- ['iL'] = {
-- -- -- you can define your own textobjects directly here
-- -- go = '(function_definition) @function',
-- -- },
-- -- -- or you use the queries from supported languages with textobjects.scm
-- -- ['af'] = '@function.outer',
-- -- ['if'] = '@function.inner',
-- -- ['aC'] = '@class.outer',
-- -- ['iC'] = '@class.inner',
-- -- ['ay'] = '@conditional.outer',
-- -- ['iy'] = '@conditional.inner',
-- -- ['aj'] = '@loop.outer',
-- -- ['ij'] = '@loop.inner',
-- -- ['is'] = '@statement.inner',
-- -- ['as'] = '@statement.outer',
-- -- ['ac'] = '@comment.outer',
-- -- ['ic'] = '@comment.inner',
-- -- ['ap'] = '@comment.parameter',
-- -- ['ip'] = '@comment.parameter',
-- -- },
-- -- move = {
-- -- enable = true,
-- -- set_jumps = true, -- whether to set jumps in the jumplist
-- -- goto_next_start = {
-- -- [']m'] = '@function.outer',
-- -- [']]'] = '@class.outer',
-- -- },
-- -- goto_next_end = {
-- -- [']M'] = '@function.outer',
-- -- [']['] = '@class.outer',
-- -- },
-- -- goto_previous_start = {
-- -- ['[m'] = '@function.outer',
-- -- ['[['] = '@class.outer',
-- -- },
-- -- goto_previous_end = {
-- -- ['[M'] = '@function.outer',
-- -- ['[]'] = '@class.outer',
-- -- },
-- -- },
-- -- select = {
-- -- enable = true,
-- -- keymaps = {
-- -- -- You can use the capture groups defined in textobjects.scm
-- -- ['af'] = '@function.outer',
-- -- ['if'] = '@function.inner',
-- -- ['ac'] = '@class.outer',
-- -- ['ic'] = '@class.inner',
-- -- -- Or you can define your own textobjects like this
-- -- ['iF'] = {
-- -- python = '(function_definition) @function',
-- -- cpp = '(function_definition) @function',
-- -- c = '(function_definition) @function',
-- -- java = '(method_declaration) @function',
-- -- go = '(method_declaration) @function',
-- -- },
-- -- },
-- -- },
-- -- },
-- -- }
-- end,
-- opts = {},
-- -- There are additional nvim-treesitter modules that you can use to interact
-- -- with nvim-treesitter. You should go explore a few and see what interests you:
-- --
-- -- - Incremental selection: Included, see `:help nvim-treesitter-incremental-selection-mod`
-- -- - Show your current context: https://github.com/nvim-treesitter/nvim-treesitter-context
-- -- - Treesitter + textobjects: https://github.com/nvim-treesitter/nvim-treesitter-textobjects
}

View File

@@ -2,10 +2,11 @@
return {
'nvim-treesitter/nvim-treesitter',
build = ':TSUpdate',
main = 'nvim-treesitter.configs', -- Sets main module to use for opts
branch = 'main',
-- [[ Configure Treesitter ]] See `:help nvim-treesitter`
opts = {
ensure_installed = {
config = function()
require('nvim-treesitter').setup {}
require('nvim-treesitter').install {
'bash',
'c',
'diff',
@@ -17,18 +18,13 @@ return {
'query',
'vim',
'vimdoc',
},
-- Autoinstall languages that are not installed
auto_install = true,
highlight = {
enable = true,
-- Some languages depend on vim's regex highlighting system (such as Ruby) for indent rules.
-- If you are experiencing weird indenting issues, add the language to
-- the list of additional_vim_regex_highlighting and disabled languages for indent.
additional_vim_regex_highlighting = { 'ruby' },
},
indent = { enable = true, disable = { 'ruby' } },
},
'php',
'javascript',
'typescript',
'json',
}
end,
opts = {},
-- There are additional nvim-treesitter modules that you can use to interact
-- with nvim-treesitter. You should go explore a few and see what interests you:
--

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,
}

View File

@@ -1,11 +0,0 @@
require('helpers').edit_cf('pv', '/lua/plugins/vectorcode.lua')
return {
'Davidyz/VectorCode',
version = '*', -- optional, depending on whether you're on nightly or release
dependencies = { 'nvim-lua/plenary.nvim' },
build = 'pipx upgrade vectorcode',
cmd = 'VectorCode', -- if you're lazy-loading VectorCode
opts = {
async_backend = 'lsp',
},
}

View File

@@ -1,8 +0,0 @@
if vim.loop.os_uname().sysname == 'Darwin' then
return {
'wakatime/vim-wakatime',
lazy = false,
}
else
return {}
end

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>',
},
},
}

294
lua/projects.lua Normal file
View File

@@ -0,0 +1,294 @@
-- 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] or PROJECTS.default
if type(setup) == 'function' then
setup(dir)
vim.notify(('Project config loaded: %s'):format(name), vim.log.levels.INFO, { title = 'projects.lua' })
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')

View File

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

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

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

View File

@@ -1,9 +0,0 @@
{
"Log function": {
"prefix": "du",
"body": [
"console.log($0);"
],
"description": "Log variable"
}
}

View File

@@ -0,0 +1,45 @@
local ls = require 'luasnip'
local s = ls.snippet
local t = ls.text_node
local i = ls.insert_node
local f = ls.function_node
return {
s('du', { t 'console.log(', i(0), t ');' }),
s('vue', {
t { '<template>', '' },
t { '', '</template>', '', '', '<script setup>', '' },
i(0),
t { '', '</script>', '', '', '<style scoped>', '', '.o-share-page {', '}', '', '</style>' },
}),
s('fun', {
t 'function ',
i(1),
t '(',
i(2),
t ') {',
t { '', ' ' },
i(0),
t { '', '}' },
}),
s('afun', {
t 'async function ',
i(1),
t '(',
i(2),
t ') {',
t { '', ' ' },
i(0),
t { '', '}' },
}),
s('()', {
t '() => {',
t { '', ' ' },
i(0),
t { '', '}' },
}),
}

View File

@@ -1,26 +0,0 @@
{
"name": "example-snippets",
"contributes": {
"snippets": [
{
"language": [
"all"
],
"path": "./snippets/all.json"
},
{
"language": [
"php"
],
"path": "./php.json"
},
{
"language": [
"javascript",
"vue"
],
"path": "./javascript-vue.json"
}
]
}
}

View File

@@ -1,78 +0,0 @@
{
"Dump function": {
"prefix": "du",
"body": [
"dump($0);"
],
"description": "Dump variable"
},
"Type dump function": {
"prefix": "dt",
"body": [
"\\PhpStan\\dumpType($0);"
],
"description": "Dump PHPStan type"
},
"Test case": {
"prefix": "test",
"body": [
"test($1, function () {",
" $0",
"});"
],
"description": "Test case"
},
"Create doc block": {
"prefix": "/**",
"body": [
"/**",
" * $0",
" */"
]
},
"DocBlock property": {
"prefix": "@p",
"body": "@property $1 $$0",
"description": "DocBlock property"
},
"DocBlock boolean property": {
"prefix": "@pb",
"body": "@property bool $$0",
"description": "DocBlock boolean property"
},
"DocBlock string property": {
"prefix": "@ps",
"body": "@property string $$0",
"description": "DocBlock string property"
},
"DocBlock int property": {
"prefix": "@pi",
"body": "@property int $$0",
"description": "DocBlock int property"
},
"DocBlock Collection property": {
"prefix": "@pc",
"body": "@property \\Illuminate\\Support\\Collection<int, $1> $$0",
"description": "DocBlock int property"
},
"DocBlock date property": {
"prefix": "@pd",
"body": "@property \\Illuminate\\Support\\Carbon $$0",
"description": "DocBlock date property"
},
"DocBlock model properties": {
"prefix": "@pp",
"body": [
"/**",
" * @property int $$id",
" * $1",
" * @property \\Illuminate\\Support\\Carbon $$created_at",
" * @property \\Illuminate\\Support\\Carbon $$updated_at",
" *",
" * Relationships",
" * $2",
" */"
],
"description": "DocBlock model properties"
}
}

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

@@ -0,0 +1,600 @@
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
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'), fmta('dump(#~);', { i(0) })),
bs(atr('du ', 'Dump a variable to the dump server'), fmta('dump(#~)', { i(0) })),
s(etr('r ', 'ray'), fmta('ray(#~);', { i(0) })),
bs(atr('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(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(etr('fn ', 'Shorthand function block'), {
c(1, {
sn(nil, fmta('fn (#~) => #~', { i(1), i(2) })),
sn(
nil,
fmta(
[[
function (#~) {
#~
}
]],
{ i(1), i(2) }
)
),
}),
}),
bs(etr('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('nn ', 'Assert not null'), fmta('Assert::notNull(#~)', { i(0) })),
-------------
-- LARAVEL --
-------------
s(
etr('bt', 'belongsTo Laravel relationship method'),
c(0, {
sn(
nil,
fmta(
[[
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\#~, $this>
*/
public function #~(): BelongsTo
{
return $this->belongsTo(#~::class);
}
]],
{ rep(1), i(0), 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(0) }
)
),
})
),
s(
etr('hm', 'hasMany Laravel relationship method'),
c(0, {
sn(
nil,
fmta(
[[
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany<\App\Models\#~, $this>
*/
public function #~(): HasMany
{
return $this->hasOne(#~::class);
}
]],
{ rep(1), i(0), 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(0) }
)
),
})
),
s(
etr('ho', 'hasOne Laravel relationship method'),
c(0, {
sn(
nil,
fmta(
[[
/**
* @return \Illuminate\Database\Eloquent\Relations\HasOne<\App\Models\#~, $this>
*/
public function #~(): HasOne
{
return $this->hasOne(#~::class);
}
]],
{ rep(1), i(0), 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(0) }
)
),
})
),
s(
etr('bm', 'belongsToMany Laravel relationship method'),
c(0, {
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(0) }
)
),
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(0) }
)
),
})
),
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('->wh', '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) }
)
),
})
),
}

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

@@ -0,0 +1,136 @@
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 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 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

@@ -4,3 +4,5 @@ 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 })