Files
dotfiles/nvim/.config/nvim/init.lua
T
2026-06-15 11:00:49 +02:00

1168 lines
39 KiB
Lua

-- vim:foldmethod=marker
local function get_python_venv_path() --{{{1
return vim.fn.stdpath('config') .. '/.venv/bin/python'
end
vim.g.python3_host_prog = get_python_venv_path()
-- POPULATE QFLIST ON ERROR {{{1
do
local function full_trace()
local lines = {}
local level = 2
while true do
local info = debug.getinfo(level, "Sln")
if not info then break end
local src = info.source or "?"
local file = src:gsub("^@", "") -- remove @ prefix
local line = string.format(
"%s:%d: in %s",
file,
info.currentline or 0,
info.name or "?"
)
table.insert(lines, line)
level = level + 1
end
return table.concat(lines, "\n")
end
local orig = debug.traceback
---@diagnostic disable-next-line: duplicate-set-field, redundant-parameter
debug.traceback = function(thread, message, level)
local trace = vim.split(full_trace(), "\n")
local orig_trace = orig(thread, message, level)
if type(thread) ~= 'thread' then
level = message
message = thread
end
assert(type(message) == 'nil' or type(message) == 'string')
local qflist_items = vim.split(message, "\n")
-- doing this to remove truncated file location at the start of the error message
for i, msg in ipairs(qflist_items) do
local match = string.match(msg, ".*:%s*(.*)")
if match ~= nil then
qflist_items[i] = match
end
end
for _, loc in ipairs(trace) do
table.insert(qflist_items, loc)
end
vim.fn.setqflist({}, "a", {
title = "Traceback",
lines = qflist_items,
})
return orig_trace
end
end
-- GENERAL SETTINGS {{{1
vim.cmd [=[
set autowriteall
set exrc
set secure
set clipboard=unnamedplus
set tabstop=4
set shiftwidth=0
set rnu
set nu
set nowrap
set shiftround
set expandtab
set nohlsearch
set incsearch
set guicursor=n-v-c:block-Cursor
set cursorline
set noswapfile
set list
set tags+=~/tags
nnoremap ,co :copen<CR>
nnoremap ,cc :cclose<CR>
nnoremap ,cq :call setqflist([])<CR>:cclose<CR>
nnoremap <c-n> :cnext<CR>zz
nnoremap <c-p> :cprevious<CR>zz
nnoremap ,cu :colder<CR>
nnoremap ,cr :cnewer<CR>
nnoremap ,h H
nnoremap ,l L
nnoremap H ^
nnoremap L $
xnoremap H ^
xnoremap L $
nnoremap <C-a> <Nop>
nnoremap <C-x> <Nop>
nnoremap ,a <C-a>
nnoremap ,x <C-x>
nnoremap ,rl :checktime<CR>
nnoremap ,m :wa<CR>:make<CR>
nnoremap ,cD :call setqflist(filter(getqflist(), 'v:val != getqflist()[getqflist({"idx": 0}).idx - 1]'))<CR>
nnoremap ,t <c-w>v<c-w>l:terminal<CR>a
" Don't include curdir, it just causes pain.
set viewoptions=folds,cursor
autocmd BufWinLeave *.* silent! mkview
autocmd BufWinEnter *.* silent! loadview
nnoremap <c-h> <c-w>h
nnoremap <c-j> <c-w>j
nnoremap <c-k> <c-w>k
nnoremap <c-l> <c-w>l
nnoremap <c-d> <c-d>zz
nnoremap <c-u> <c-u>zz
tnoremap <c-w>c <c-\><c-n><c-w>c
autocmd TextYankPost * silent! lua vim.highlight.on_yank {higroup='Visual', timeout=100}
autocmd BufEnter *__virtual* setlocal buftype=nofile bufhidden=hide noswapfile
" Disable STUPID default rust plugin. And others
filetype plugin off
" remove annoying and bad indentation
autocmd FileType * setlocal indentexpr=
]=]
vim.keymap.set('n', ',cf', function()
local qf = vim.fn.getqflist()
for i, item in ipairs(qf) do
if item.valid == 1 then
vim.cmd('cc '..i)
return
end
end
print('no jumpable items')
end)
vim.keymap.set('n', ',cl', function()
local qf = vim.fn.getqflist()
for i = #qf, 1, -1 do
local item = qf[i]
if item.valid == 1 then
vim.cmd('cc '..i)
return
end
end
print('no jumpable items')
end)
vim.keymap.set('n', ',ct', function()
vim.fn.system('ctags -R .')
end)
do
local function escaped(text)
local _escaped = vim.fn.escape(text, "\\/.*$^~[]")
local pattern = "\\V" .. _escaped
return pattern
end
---@param pattern string
local function recursive_literal_vimgrep(pattern)
vim.cmd("vimgrep /" .. pattern .. "/ **/*")
end
---@param keymap string
---@param search_for fun(): string
local function search_for_in_same_filetype(keymap, search_for)
vim.keymap.set('n', keymap, function()
recursive_literal_vimgrep(search_for())
end, { desc = "Search for word under cursor in same filetype" })
end
search_for_in_same_filetype(',vs', function() return escaped(vim.fn.expand("<cword>")) end)
search_for_in_same_filetype(',vS', function() return escaped(vim.fn.expand("<cWORD>")) end)
local file_specific = {
odin=function()
search_for_in_same_filetype(',vd', function()
local word = vim.fn.expand("<cword>")
local pattern = "\\v"..word.." *: *[:=]"
return pattern
end)
end
}
vim.api.nvim_create_autocmd("FileType", {
callback=function()
local conf = file_specific[vim.bo.filetype]
if conf then conf() end
end
})
end
vim.api.nvim_create_autocmd({
'BufRead',
'BufNewFile'
}, {
pattern = {'*.h'},
callback = function()
vim.bo.filetype = 'c'
end
})
-- FILE SPECIFIC AND AUTOCMDS {{{1
local file_specific = {
c = function()
vim.bo.expandtab = false
end,
tsv = function()
vim.bo.tabstop = 32
vim.bo.expandtab = false
end,
odin = function()
vim.bo.expandtab = false
end,
go = function()
vim.bo.expandtab = false
end,
yaml = function()
vim.bo.tabstop = 2
end
}
vim.api.nvim_create_autocmd('BufEnter', {
callback = function()
local conf = file_specific[vim.bo.filetype]
if conf then conf() end
end,
})
-- CENTER TEXT "zen mode" {{{1
do
-- one shared statusline looks better for the split.
vim.o.laststatus = 3
local ID = '4f2de2e3-a1bf-481f-919c-7f68ec6511c9'
local function is_padding_window(win)
local ok, _ = pcall(vim.api.nvim_buf_get_var, vim.api.nvim_win_get_buf(win), ID)
return ok
end
local function calculate_padding()
local screen_width = vim.o.columns
local padding = math.floor((screen_width / 2 - 84 / 2) + 0.5)
if padding <= 0 then
return
end
return padding
end
local function get_padding_window()
local windows = vim.api.nvim_list_wins()
for _, win in ipairs(windows) do
if is_padding_window(win) then
return win
end
end
return nil
end
local padding_buffer = _G[ID]
if padding_buffer == nil then
padding_buffer = vim.api.nvim_create_buf(false, true)
vim.api.nvim_set_option_value('buftype', 'nofile', {buf = padding_buffer})
vim.api.nvim_set_option_value('modifiable', false, {buf = padding_buffer})
vim.api.nvim_create_autocmd('WinEnter', {
callback = function()
local curr_buff = vim.api.nvim_get_current_buf()
if curr_buff == padding_buffer then
if #vim.api.nvim_list_wins() == 1 then
vim.cmd"q"
end
local padding_window = vim.api.nvim_get_current_win()
vim.cmd"wincmd p"
local prev_win = vim.api.nvim_get_current_win()
local padding_window_info = vim.fn.getwininfo(padding_window)[1]
local prev_win_info = vim.fn.getwininfo(prev_win)[1]
if padding_window ~= prev_win and padding_window_info.wincol ~= prev_win_info.wincol then
return
end
local windows = vim.api.nvim_list_wins()
local leftmost_non_padding_window = nil
local min_col = math.huge
for _, win in ipairs(windows) do
local info = vim.fn.getwininfo(win)[1]
if info.wincol < min_col and padding_window_info.wincol < info.wincol then
min_col = info.wincol
leftmost_non_padding_window = win
end
end
if leftmost_non_padding_window ~= nil then
vim.api.nvim_set_current_win(leftmost_non_padding_window)
end
end
end,
})
vim.api.nvim_create_autocmd('VimResized', {
callback = function()
local padding_window = get_padding_window()
if padding_window ~= nil then
local padding = calculate_padding()
if padding == nil then
vim.api.nvim_win_close(padding_window, true)
else
vim.api.nvim_win_set_width(padding_window, padding)
end
end
vim.cmd"wincmd ="
end,
})
vim.api.nvim_buf_set_var(padding_buffer, ID, true)
_G[ID] = padding_buffer
end
local function toggle_padding()
local padding_window = get_padding_window()
if padding_window == nil then
vim.cmd"only"
local padding = calculate_padding()
if padding == nil then
return
end
local win = vim.api.nvim_open_win(padding_buffer, false, {
split = 'left',
win = -1,
width = padding,
})
vim.api.nvim_set_option_value('number', false, {win = win})
vim.api.nvim_set_option_value('relativenumber', false, {win = win})
vim.api.nvim_set_option_value('cursorline', false, {win = win})
vim.api.nvim_set_option_value('winfixwidth', true, {win = win})
vim.api.nvim_set_option_value("fillchars", "eob: ", { win = win })
vim.cmd"wincmd ="
else
vim.api.nvim_win_close(padding_window, true)
end
end
vim.keymap.set('n', ',z', toggle_padding)
end
-- auto select compiler {{{1
do
local compiler_mapping = {
dotnet={'*.csproj', '*.sln'},
pyright={'requirements.txt', 'pyproject.toml'},
go={'go.mod'},
gcc={'*.c'},
['g++']={'*.cpp'},
cargo={'Cargo.toml'},
}
---@param dir string?
---@param glob_pattern string
---@return boolean
local function file_exists(dir, glob_pattern)
if dir == nil then return false end
return vim.fn.globpath(dir, glob_pattern, false, false, false) ~= ''
end
local all_folders_till_root = nil
do
local cwd = vim.fn.getcwd()
local folders = {cwd} -- array of all folders from cwd to root
for dir in vim.fs.parents(cwd) do
table.insert(folders, dir)
end
---@param _ any
---@param i integer
---@return integer?
---@return string?
local function iter(_, i)
if file_exists(folders[i], '.git') then
return nil
end
i = i + 1
local f = folders[i]
if f == nil then
return nil
end
return i, f
end
---return iterator starting from cwd and going upwards until the project
---root is found by looking for the .git folder.
all_folders_till_root = function()
return iter, nil, 0
end
end
---@param glob_pattern string
---@return boolean
local function look_for_file(glob_pattern)
for _, dir in all_folders_till_root() do
if file_exists(dir, glob_pattern) then
return true
end
end
return false
end
local function auto_select_compiler()
for compiler, glob_patterns in pairs(compiler_mapping) do
for _, glob_pattern in ipairs(glob_patterns) do
if look_for_file(glob_pattern) then
vim.cmd('compiler! '..compiler)
end
end
end
if look_for_file('justfile') then
vim.go.makeprg = 'just'
end
end
auto_select_compiler()
vim.api.nvim_create_autocmd('DirChanged', {
callback = auto_select_compiler,
})
end
-- LAZY.NVIM BOOTSTRAP {{{1
local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
if not (vim.uv or vim.loop).fs_stat(lazypath) then
vim.fn.system({
'git',
'clone',
'--filter=blob:none',
'https://github.com/folke/lazy.nvim.git',
'--branch=stable', -- latest stable release
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
require'lazy'.setup{ --{{{1
{ "romus204/tree-sitter-manager.nvim", --{{{2
dependencies = {}, -- tree-sitter CLI must be installed system-wide
config = function()
require("tree-sitter-manager").setup({
auto_install = true
})
end
},
{ 'stevearc/oil.nvim', --{{{2
---@module 'oil'
---@type oil.SetupOpts
opts = {},
lazy = false,
config = function ()
require('oil').setup({
default_file_explorer = true,
columns = {
'icon',
'permissions',
'size',
'mtime',
},
buf_options = {
buflisted = false,
bufhidden = 'hide',
},
win_options = {
wrap = false,
signcolumn = 'no',
cursorcolumn = false,
foldcolumn = '0',
spell = false,
list = false,
conceallevel = 3,
concealcursor = 'nvic',
},
delete_to_trash = false,
skip_confirm_for_simple_edits = false,
prompt_save_on_select_new_entry = true,
cleanup_delay_ms = 2000,
lsp_file_methods = {
enabled = true,
timeout_ms = 1000,
autosave_changes = false,
},
constrain_cursor = 'editable',
watch_for_changes = true,
keymaps = {
['g?'] = { 'actions.show_help', mode = 'n' },
['<C-y>'] = { 'actions.yank_entry', opts = { modify=":." }, mode = 'n' }, -- :. makes it a relative path
['<C-h>'] = false, ['<C-j>'] = false, ['<C-k>'] = false, ['<C-l>'] = false, -- I use those keys for navigation
['<CR>'] = 'actions.select',
['-'] = { 'actions.parent', mode = 'n' },
['_'] = { 'actions.open_cwd', mode = 'n' },
[',cd'] = { 'actions.cd', mode = 'n' },
[',CD'] = { 'actions.cd', opts = { scope = 'tab' }, mode = 'n' },
['gx'] = 'actions.open_external',
['g.'] = { 'actions.toggle_hidden', mode = 'n' },
},
use_default_keymaps = true,
view_options = {
show_hidden = true,
is_hidden_file = function(name, _)
local m = name:match('^%.')
return m ~= nil
end,
is_always_hidden = function(_, _)
return false
end,
natural_order = 'fast',
case_insensitive = false,
sort = {
{ 'type', 'asc' },
{ 'name', 'asc' },
},
highlight_filename = function(_, _, _, _)
return nil
end,
},
extra_scp_args = {},
float = {
padding = 2,
max_width = 0,
max_height = 0,
border = 'rounded',
win_options = {
winblend = 0,
},
get_win_title = nil,
preview_split = 'auto',
override = function(conf)
return conf
end,
},
preview_win = {
update_on_cursor_moved = true,
preview_method = 'fast_scratch',
disable_preview = function(_)
return false
end,
win_options = {},
},
confirmation = {
max_width = 0.9,
min_width = { 40, 0.4 },
width = nil,
max_height = 0.9,
min_height = { 5, 0.1 },
height = nil,
border = 'rounded',
win_options = {
winblend = 0,
},
},
progress = {
max_width = 0.9,
min_width = { 40, 0.4 },
width = nil,
max_height = { 10, 0.9 },
min_height = { 5, 0.1 },
height = nil,
border = 'rounded',
minimized_border = 'none',
win_options = {
winblend = 0,
},
},
ssh = {
border = 'rounded',
},
keymaps_help = {
border = 'rounded',
},
})
-- oil fix relative path
vim.api.nvim_create_augroup('OilRelPathFix', {})
vim.api.nvim_create_autocmd('BufLeave', {
group = 'OilRelPathFix',
pattern = 'oil:///*',
callback = function ()
vim.cmd('cd .')
end
})
local actions = require('oil.actions')
vim.keymap.set('n', '-', actions.parent.callback, { desc = actions.parent.desc })
vim.keymap.set('n', '_', actions.open_cwd.callback, { desc = actions.open_cwd.desc })
end
},
{ 'github/copilot.vim', --{{{2
config = function()
-- q for qomplete ;)
vim.keymap.set('i', '<c-q>', 'copilot#Accept("\\<CR>")', {
expr = true,
replace_keycodes = false,
})
vim.g.copilot_no_tab_map = true
vim.keymap.set('n', '<c-q>', ':Copilot panel<CR>', { noremap = true })
vim.keymap.set('n', ',cd', ':Copilot disable<CR>', { noremap = true })
vim.keymap.set('n', ',ce', ':Copilot enable<CR>', { noremap = true })
end,
},
{ 'f-person/git-blame.nvim', --{{{2
keys = {',g'},
config = function ()
require'gitblame'.setup{
enabled = false,
}
vim.cmd[[
nnoremap ,g :GitBlameToggle<CR>
]]
end
},
{ 'unblevable/quick-scope', --{{{2
init = function()
vim.cmd [[
let g:qs_highlight_on_keys = ['f', 'F', 't', 'T']
]]
end,
},
{ 'michaeljsmith/vim-indent-object', --{{{2
},
{ 'kylechui/nvim-surround', --{{{2
version = '*', -- Use for stability; omit to use `main` branch for the latest features
event = 'VeryLazy',
config = function()
require('nvim-surround').setup{}
end
},
{ 'echasnovski/mini.align', --{{{2
version = false,
config = function()
require'mini.align'.setup()
end,
},
{ 'miikanissi/modus-themes.nvim', --{{{2
lazy = false,
priority = 1000,
config = function()
vim.o.termguicolors = true
vim.cmd.colorscheme('modus_vivendi')
end,
},
{ 'folke/lazydev.nvim', --{{{2
ft = 'lua', -- only load on lua files
opts = {
library = {
{ path = '${3rd}/luv/library', words = { 'vim%.uv' } },
{ path = '${3rd}/love2d/library', words = { 'love' } },
},
},
},
{ "seblyng/roslyn.nvim", --{{{2
dependencies = {
'williamboman/mason.nvim',
},
cond = function()
local mason_registry = require'mason-registry'
return mason_registry.is_installed('roslyn')
end,
opts = {
---function to pick which .sln file to use when opening a cs file
---@param targets string[]
choose_target=function (targets)
if targets == nil then return end
if #targets == 0 then return end
table.sort(targets, function(a, b)
return #a < #b
end)
return targets[1]
end
},
},
{ 'neovim/nvim-lspconfig', --{{{2
dependencies = {
'williamboman/mason.nvim',
'williamboman/mason-lspconfig.nvim',
},
config = function()
vim.diagnostic.config{
severity_sort=true
}
require'mason'.setup{
registries={
"github:mason-org/mason-registry",
"github:Crashdummyy/mason-registry",
}
}
require'mason-lspconfig'.setup()
vim.lsp.config.zls = {
before_init = function(_, _)
vim.g.zig_fmt_autosave = false -- may not be needed anymore?
end,
}
vim.lsp.config.lua_ls = {
settings = {
Lua = { runtime = { version = 'LuaJIT' } }
}
}
vim.lsp.config.gopls = {
filetypes = { -- unsure if this is entirely correct...
'go',
'gomod',
'gowork',
'gotmpl',
'html'
},
settings = {
gopls = {
templateExtensions = {'html', 'gotmpl'}
}
}
}
vim.lsp.config.basedpyright = {
settings = {
basedpyright = {
analysis = {
useLibraryCodeForTypes = true
},
},
},
}
vim.lsp.config.sourcekit = {
filetypes = {"swift"}
}
vim.lsp.config.ols = {
settings = {
verbose=true,
}
}
vim.lsp.enable('gdscript')
vim.lsp.config('hls', {
filetypes = { 'haskell', 'lhaskell', 'cabal' },
})
vim.lsp.enable('hls')
vim.lsp.enable('sourcekit')
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(args)
vim.bo[args.buf].tagfunc = nil
end,
})
vim.keymap.set( 'n', ',fd', vim.lsp.buf.definition, { noremap = true, silent = true})
vim.cmd [[
nnoremap ,rn :lua vim.lsp.buf.rename()<CR>
nnoremap ,ft :lua vim.lsp.buf.type_definition()<CR>
nnoremap ,fi :lua vim.lsp.buf.implementation()<CR>
nnoremap ,fr :lua vim.lsp.buf.references()<CR>
nnoremap ,ca :lua vim.lsp.buf.code_action()<CR>
nnoremap ,oe :lua vim.diagnostic.open_float()<CR>
nnoremap ,ea :lua vim.diagnostic.setqflist()<CR>
nnoremap ,ee :lua vim.diagnostic.setqflist{severity='ERROR'}<CR>
nnoremap ,ew :lua vim.diagnostic.setqflist{severity='WARN'}<CR>
nnoremap ,ei :lua vim.diagnostic.setqflist{severity='INFO'}<CR>
nnoremap ,eh :lua vim.diagnostic.setqflist{severity='HINT'}<CR>
nnoremap ,eA :lua vim.diagnostic.setloclist()<CR>
nnoremap ,eE :lua vim.diagnostic.setloclist{severity='ERROR'}<CR>
nnoremap ,eW :lua vim.diagnostic.setloclist{severity='WARN'}<CR>
nnoremap ,eI :lua vim.diagnostic.setloclist{severity='INFO'}<CR>
nnoremap ,eH :lua vim.diagnostic.setloclist{severity='HINT'}<CR>
nnoremap ,fm :lua vim.lsp.buf.format()<CR>
]]
end
},
{ 'mfussenegger/nvim-dap', --{{{2
dependencies = {
'leoluz/nvim-dap-go',
'mfussenegger/nvim-dap-python',
'nicholasmata/nvim-dap-cs',
},
keys = {
',b',
',db',
',B',
'<B',
',dh',
',ds',
',df',
},
config = function()
require'dap-go'.setup()
require'dap-python'.setup('debugpy-adapter')
require('dap-cs').setup()
local dap = require'dap'
dap.adapters.godot = { type = 'server', host = '127.0.0.1', port = 6006, }
dap.configurations.gdscript = { {type = 'godot', request = 'launch', name = 'Launch scene', project = '${workspaceFolder}',} }
dap.adapters.lldb = {
type = 'executable',
command = vim.fn.exepath('codelldb'),
name = 'lldb'
}
dap.configurations.c = {
{
name = 'Launch',
type = 'lldb',
request = 'launch',
program = function()
return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/', 'file')
end,
cwd = '${workspaceFolder}',
stopOnEntry = false,
args = function()
local i = vim.fn.input('input args: ')
return vim.fn.split(i)
end,
runInTerminal = true,
},
}
dap.configurations.cpp = dap.configurations.c
dap.configurations.rust = dap.configurations.c
local widgets = require'dap.ui.widgets'
local inspections = {}
local function map_inspection(keys, func)
local function wrapper()
if inspections[keys] == nil then
inspections[keys] = func()
return
end
inspections[keys].toggle()
end
vim.keymap.set('n', keys, wrapper, {noremap=true})
end
local function refresh_inspections()
for _, widget in pairs(inspections) do
if widget.win ~= nil then
widget.refresh()
end
end
end
local function close_inspections()
for _, widget in pairs(inspections) do
if widget.win ~= nil then
widget.close()
end
end
end
map_inspection(',dh', widgets.hover)
map_inspection(',ds', function () return widgets.centered_float(widgets.scopes) end)
map_inspection(',df', function () return widgets.centered_float(widgets.frames) end)
vim.keymap.set('n', '<Down>', dap.step_over)
vim.keymap.set('n', '<Right>', dap.step_into)
vim.keymap.set('n', '<Left>', dap.step_out)
vim.keymap.set('n', '<Up>', dap.restart_frame)
vim.keymap.set('n', ',b', dap.toggle_breakpoint)
vim.keymap.set('n', ',B', dap.clear_breakpoints)
vim.keymap.set('n', '<B', dap.clear_breakpoints)
vim.keymap.set('n', ',db', dap.continue)
vim.keymap.set('n', ',dc', close_inspections)
vim.keymap.set('n', ',dr', refresh_inspections)
end
},
{ 'dcampos/nvim-snippy', --{{{2
config = function()
require'snippy'.setup{ enable_auto = true, }
vim.cmd [[
imap <expr> <c-l> '<Plug>(snippy-next)'
imap <expr> <c-k> '<Plug>(snippy-previous)'
smap <expr> <c-l> '<Plug>(snippy-next)'
smap <expr> <c-k> '<Plug>(snippy-previous)'
nmap g; <Plug>(snippy-cut-text)
xmap g; <Plug>(snippy-cut-text)
]]
end
},
{ 'hrsh7th/nvim-cmp', --{{{2
dependencies = {
'hrsh7th/cmp-nvim-lsp',
'hrsh7th/cmp-path',
'dcampos/nvim-snippy',
'dcampos/cmp-snippy',
'quangnguyen30192/cmp-nvim-tags',
},
config = function()
local cmp = require'cmp'
cmp.setup{
snippet = {
expand = function(args)
require'snippy'.expand_snippet(args.body)
end,
},
mapping = {
['<C-y>'] = cmp.mapping.confirm{ select = true },
['<C-n>'] = cmp.mapping.select_next_item(),
['<C-p>'] = cmp.mapping.select_prev_item(),
},
sources = cmp.config.sources(
{
{ name = 'snippy', priority = 100000000000000000000 },
{ name = 'nvim_lsp', priority = 1000000000},
{ name = 'tags', priority = 100 },
{ name = 'path', priority = 1},
}
),
preselect = cmp.PreselectMode.None,
}
end,
},
{ 'nvim-telescope/telescope.nvim', --{{{2
tag = '0.1.8',
dependencies = {
'nvim-lua/plenary.nvim',
'nvim-telescope/telescope-ui-select.nvim',
},
config = function()
local actions = require'telescope.actions'
vim.o.splitright = true
require'telescope'.setup{
defaults = {
file_ignore_patterns = {'%__virtual.cs$'},
mappings = {
i = {
['<C-Q>'] = actions.smart_send_to_qflist + actions.open_qflist,
['<C-j>'] = actions.select_default,
},
n = {
['<C-Q>'] = actions.smart_send_to_qflist + actions.open_qflist,
['<C-j>'] = actions.select_default,
},
}
},
pickers = {
help_tags = {
attach_mappings = function(_, map)
map("i", "<CR>", actions.select_vertical)
map("n", "<CR>", actions.select_vertical)
map("i", "<C-j>", actions.select_vertical)
map("n", "<C-j>", actions.select_vertical)
return true
end,
},
},
extensions = { ['ui-select'] = { require'telescope.themes'.get_dropdown{}, }, },
}
vim.cmd [[
nnoremap ,fw :lua require'telescope.builtin'.lsp_dynamic_workspace_symbols()<CR>
nnoremap ,fa :lua require'telescope.builtin'.find_files({hidden=true, no_ignore=true, no_ignore_parent=true})<CR>
nnoremap ,ff :lua require'telescope.builtin'.find_files()<CR>
nnoremap ,fo :lua require'telescope.builtin'.oldfiles()<CR>
nnoremap ,fg :lua require'telescope.builtin'.live_grep()<CR>
nnoremap ,fs :lua require'telescope.builtin'.grep_string()<CR>
nnoremap ,fz :lua require'telescope.builtin'.current_buffer_fuzzy_find()<CR>
nnoremap ,fh :lua require'telescope.builtin'.help_tags()<CR>
nnoremap ,fb :lua require'telescope.builtin'.buffers()<CR>
nnoremap ,fc :lua require'telescope.builtin'.tags({default_text=vim.fn.expand("<cword>")})<CR>
nnoremap ,fC :lua require'telescope.builtin'.tags({default_text=vim.fn.expand("<cWORD>")})<CR>
nnoremap ,fea :lua require'telescope.builtin'.diagnostics()<CR>
nnoremap ,fee :lua require'telescope.builtin'.diagnostics{severity='ERROR'}<CR>
nnoremap ,few :lua require'telescope.builtin'.diagnostics{severity='WARN'}<CR>
nnoremap ,fei :lua require'telescope.builtin'.diagnostics{severity='INFO'}<CR>
nnoremap ,feh :lua require'telescope.builtin'.diagnostics{severity='HINT'}<CR>
]]
require'telescope'.load_extension'ui-select'
end,
},
}
do -- split line {{{1
local SPLIT_DELIMETERS = { -- single characters only
[','] = true,
[';'] = true,
['|'] = true,
}
local SPLIT_BETWEEN = { -- single characters only
['('] = ')',
['['] = ']',
['{'] = '}',
['<'] = '>',
}
local SPLIT_IGNORE_BETWEEN = { --single characters only
['"'] = '"',
["'"] = "'",
}
local split_line = function()
local SPLIT_WHITESPACE = ' '
if vim.o.expandtab then
SPLIT_WHITESPACE = ''
for _ = 1, vim.o.tabstop do
SPLIT_WHITESPACE = SPLIT_WHITESPACE .. ' '
end
end
local line = vim.api.nvim_get_current_line()
local _, col = unpack(vim.api.nvim_win_get_cursor(0))
col = col + 1 -- Doing this to make it 1-indexed
---@type integer?
local first_bracket_i = nil
for i = col, #line do
local char = line:sub(i, i)
if SPLIT_BETWEEN[char] ~= nil then
first_bracket_i = i
break
end
end
if not first_bracket_i then
print('No opening brackets found after cursor on this line.')
return
end
---@type integer[]
local split_indexes = {} -- Populate this array
---@type integer?
local last_bracket_i = nil -- And find this index
do
---@type string[]
local closing_bracket_stack = {}
local icon_to_close_ignore = ''
local in_ignore = false
for i = first_bracket_i, #line do
local char = line:sub(i,i)
if in_ignore then
in_ignore = not (char == icon_to_close_ignore)
goto continue
end
if SPLIT_IGNORE_BETWEEN[char] ~= nil then
icon_to_close_ignore = SPLIT_IGNORE_BETWEEN[char]
in_ignore = true
goto continue
end
-- string handling complete
if SPLIT_BETWEEN[char] ~= nil then
table.insert(
closing_bracket_stack,
SPLIT_BETWEEN[char]
)
end
if char == closing_bracket_stack[#closing_bracket_stack] then
table.remove(closing_bracket_stack)
end
if #closing_bracket_stack == 1 and SPLIT_DELIMETERS[char] then
table.insert(split_indexes, i)
end
if #closing_bracket_stack == 0 then
last_bracket_i = i
break
end
::continue::
end
end
if not last_bracket_i then
print('The first opening bracket found after the cursor was not closed on this line.')
return
end
---@type string
local leading_whitespace = string.match(line, '^%s*')
local first_line = line:sub(1, first_bracket_i)
local last_line = leading_whitespace .. line:sub(last_bracket_i, #line)
if #split_indexes == 0 then
if (last_bracket_i - first_bracket_i == 1) then return end
local row, _ = unpack(vim.api.nvim_win_get_cursor(0))
line = line:sub(first_bracket_i+1, last_bracket_i-1)
local leading_pattern = '^[%s'
for k, _ in pairs(SPLIT_DELIMETERS) do
leading_pattern = leading_pattern .. k
end
leading_pattern = leading_pattern .. ']*'
line = line:gsub(leading_pattern, leading_whitespace .. SPLIT_WHITESPACE, 1)
line = line:gsub('[%s]*$', '', 1)
vim.api.nvim_buf_set_lines(0, row-1, row, false, {first_line})
vim.api.nvim_buf_set_lines(0, row, row, false, {last_line})
vim.api.nvim_buf_set_lines(0, row, row, false, {line})
return
end
local middle_lines = {}
table.insert(
middle_lines,
line:sub(first_bracket_i+1, split_indexes[1])
)
for i = 1, #split_indexes-1 do
table.insert(
middle_lines,
line:sub(split_indexes[i], split_indexes[i+1])
)
end
table.insert(
middle_lines,
line:sub(split_indexes[#split_indexes], last_bracket_i-1)
)
local leading_pattern = '^[%s'
for k, _ in pairs(SPLIT_DELIMETERS) do
leading_pattern = leading_pattern .. k
end
leading_pattern = leading_pattern .. ']*'
-- Cleanup step
for i, middle_line in ipairs(middle_lines) do
middle_line = middle_line:gsub(leading_pattern, leading_whitespace .. SPLIT_WHITESPACE, 1)
middle_line = middle_line:gsub('[%s]*$', '', 1)
middle_lines[i] = middle_line
end
if middle_lines[#middle_lines]:match('^%s*$') ~= nil then
table.remove(middle_lines)
end
local row, _ = unpack(vim.api.nvim_win_get_cursor(0))
vim.api.nvim_buf_set_lines(0, row-1, row, false, {first_line})
vim.api.nvim_buf_set_lines(0, row, row, false, {last_line})
vim.api.nvim_buf_set_lines(0, row, row, false, middle_lines)
end
vim.keymap.set(
'n',
',s',
split_line,
{ silent = true }
)
end
do --screenshot paste {{{1
local function save_clipboard_image()
local is_mac = vim.fn.has("mac")
if not is_mac then
error("only supported for mac")
end
local filename = vim.fn.input("image name: ")
local path = filename .. ".png"
local cmd = "pngpaste " .. vim.fn.shellescape(path)
local res = os.execute(cmd)
if res == 0 then
print("saved image to ".. path)
else
error("failed to save image")
end
local row, _ = unpack(vim.api.nvim_win_get_cursor(0))
vim.api.nvim_buf_set_lines(0, row, row, false, {
"!["..filename.."]("..path..")"
})
end
vim.keymap.set(
'n',
',q',
save_clipboard_image,
{}
)
end