Files
dotfiles/nvim/.config/nvim/init.lua
T
Ivar Fatland 88cc595583 dont always use make if justfile is not found
only overwrite makeprg to just if justfile is found, otherwise default
to the default 'make' or whatever else makeprg was selected by the
compiler plugin
2026-06-12 13:49:22 +02:00

1131 lines
38 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
-- TODO: vendor the compiler plugins so I can use e.g. basedpyright instead of pyright and add matching for failing tests in c using criterion.
-- did a similar thing for the vim config.
local compiler_mapping = {
dotnet={'*.csproj', '*.sln'},
pyright={'requirements.txt', 'pyproject.toml'},
go={'go.mod'},
gcc={'*.c'},
['g++']={'*.cpp'},
cargo={'Cargo.toml'},
}
---@param pattern string
---@return boolean
local function look_for_file(pattern)
---@type string[]
local folders = {vim.fn.getcwd()}
for dir in vim.fs.parents(vim.fn.getcwd()) do
table.insert(folders, dir)
end
for _, dir in ipairs(folders) do
local result = vim.fn.globpath(dir, pattern, false, false, false)
if result ~= '' then
return true
end
end
return false
end
for compiler, patterns in pairs(compiler_mapping) do
for _, pattern in ipairs(patterns) do
if look_for_file(pattern) then
vim.cmd('compiler! '..compiler)
end
end
end
if look_for_file('justfile') then
vim.go.makeprg = 'just'
end
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()
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