nvim-setup/nvim/init.lua

1530 lines
46 KiB
Lua
Raw Permalink Normal View History

-- Mbess lefuturiste nvim config (2024-01-17) (sorry, not very well organized)
-- TODO: add lot of keybindings
--
-- Add keybinding to close a tab (all views in a tab neotree + buffer)
-- Investigate why it's taking so long to switch tabs in vim
-- Individually sort files by updated_at date inside each directory in nvim-neo-tree/neo-tree.nvim (recent files in each dir)
-- Debugger feature
-- Twig treesitter support
-- Change name of variable with LSP -> <leader>rn
-- PHP helpers?
-- Python helpers?
-- Tabs features? Or recent tabs? Quickly switch between tabs
-- Add shortcut to open symbol definition in new tab
local ensure_packer = function()
local fn = vim.fn
local install_path = fn.stdpath('data')..'/site/pack/packer/start/packer.nvim'
if fn.empty(fn.glob(install_path)) > 0 then
fn.system({'git', 'clone', '--depth', '1', 'https://github.com/wbthomason/packer.nvim', install_path})
vim.cmd [[packadd packer.nvim]]
return true
end
return false
end
function str2bool(str_inp)
return str_inp ~= nil and (str_inp == "1" or str_inp:lower() == "true" or str_inp:lower() == "yes")
end
local packer_bootstrap = ensure_packer()
-- disable some built-in
local disabled_built_ins = {
"netrw",
"netrwPlugin",
"netrwSettings",
"netrwFileHandlers",
-- "gzip",
-- "zip",
-- "zipPlugin",
-- "tar",
-- "tarPlugin",
"getscript",
"getscriptPlugin",
"vimball",
"vimballPlugin",
"2html_plugin",
"logipat",
"rrhelper",
-- "spellfile_plugin",
"matchit"
}
local user_log = function(message)
local log_file_path = '/home/mbess/.logs/neovim.log'
local log_file = io.open(log_file_path, "a")
io.output(log_file)
io.write(message.."\n")
io.close(log_file)
end
for _, plugin in pairs(disabled_built_ins) do
vim.g["loaded_" .. plugin] = 1
end
local opt = vim.opt
vim.cmd("set background=dark")
opt.guifont = "Fira Code"
opt.background = "dark"
opt.number = true
opt.relativenumber = true
opt.hidden = true
-- Hide default menu mode status (I have lualine so this is duplicated)
opt.showmode = false
-- Tabs options
opt.autoindent = true
opt.cindent = true
opt.wrap = true
opt.expandtab = true
opt.smartindent = true
opt.tabstop = 4
opt.softtabstop = 4
opt.shiftwidth = 4
opt.breakindent = true
opt.showbreak = string.rep(" ", 3) -- Make it so that long lines wrap smartly
opt.linebreak = true
--
opt.wildmenu = true
opt.updatetime = 50
opt.termguicolors = true
opt.signcolumn = 'yes'
opt.belloff = 'all'
-- Keep padding
opt.scrolloff = 10
-- Always ignore case when searching, unless there is a capital letter in the query
opt.ignorecase = true
opt.smartcase = true
opt.splitright = true
opt.splitbelow = true
-- Cool floating window popup menu for completion on command line
opt.pumblend = 17
opt.wildmode = "longest:full"
opt.wildoptions = "pum"
-- Ignore compiled files
opt.wildignore = "__pycache__"
opt.wildignore:append { "*.o", "*~", "*.pyc", "*pycache*" }
opt.wildignore:append "Cargo.lock"
opt.colorcolumn = "100"
-- Highlight on yank (copy). It will do a nice highlight blink of the thing you just copied.
-- use [[ ]] to do multi-line strings
vim.api.nvim_exec(
[[
augroup YankHighlight
autocmd!
autocmd TextYankPost * silent! lua vim.highlight.on_yank()
augroup end
]],
false
)
vim.g.mapleader = " "
-- Plugin list
-- Packer
require("packer").startup(function()
use("wbthomason/packer.nvim")
use("lewis6991/impatient.nvim")
use("nvim-lua/plenary.nvim")
use("nvim-lua/popup.nvim")
use {
"nvim-telescope/telescope.nvim",
config = function()
local actions = require('telescope.actions')
require('telescope').setup {
defaults = {
mappings = {
i = {
['<C-Down>'] = actions.cycle_history_next,
['<C-Up>'] = actions.cycle_history_prev
}
}
}
}
end
}
use {
"nvim-telescope/telescope-live-grep-args.nvim"
}
use {
-- neotree
"nvim-neo-tree/neo-tree.nvim",
branch = "v2.x",
requires = {
"nvim-lua/plenary.nvim",
"kyazdani42/nvim-web-devicons", -- not strictly required, but recommended
"MunifTanjim/nui.nvim",
},
config = function ()
require('neo-tree').setup({
enable_refresh_on_write = true,
filesystem = {
use_libuv_file_watcher = true,
window = {
mappings = {
["W"] = function (state)
local Node = state.tree:get_node()
print(node.name)
end
}
}
}
})
end
}
-- TODO: figure how to show an outline for only the first level element, limit the depth
-- have a choice of precision between the top levels components only and the deeper components
-- the basic choice is to hop between functions or methods in a file
use {
"simrat39/symbols-outline.nvim",
config = function ()
require("symbols-outline").setup({
autofold_depth = 1 -- not working?
})
end
-- commons shortcuts by default o, K, Ctrl+Space, r, a, h, l, W, E, R, ?
}
-- Language Server Protocol stuff
use("neovim/nvim-lspconfig")
use("hrsh7th/nvim-cmp")
use("hrsh7th/cmp-nvim-lsp")
use("hrsh7th/cmp-buffer")
use("hrsh7th/cmp-path")
use("ray-x/cmp-treesitter")
use("saadparwaiz1/cmp_luasnip")
-- use("WhoIsSethDaniel/toggle-lsp-diagnostics.nvim")
use {
"L3MON4D3/LuaSnip",
tag = "v1.2.1",
config = function ()
on_luasnip_load()
end
}
use("rafamadriz/friendly-snippets")
--use("williamboman/mason.nvim")
-- Tree sitter stuff
use {
"nvim-treesitter/nvim-treesitter",
-- commit = "26105050aae3a15dd85feaeb0439e253e31d5ceb", -- end of september
run = ":TSUpdate"
}
use("nvim-treesitter/playground")
-- add text objects like class, function
use {
"nvim-treesitter/nvim-treesitter-textobjects"
}
use {
"nvim-treesitter/nvim-treesitter-context",
config = function ()
require("treesitter-context").setup{
enable = true
}
end
}
use {
"JoosepAlviste/nvim-ts-context-commentstring",
config = function ()
require("nvim-treesitter.configs").setup{
context_commentstring = {enable = true}
}
end
}
-- use treesitter to auto add HTML tags
-- use {
-- 'windwp/nvim-ts-autotag',
-- config = function ()
-- require('nvim-ts-autotag').setup({
-- autotag = {
-- enable = false,
-- }
-- })
-- end
-- }
-- use treesitter to swap arguments
use {
'mizlan/iswap.nvim',
-- '~/workspace/iswap.nvim',
config = function ()
require('iswap').setup({
autoswap = true
})
end
}
-- Smart comments
use("tpope/vim-commentary")
-- Git integration
-- use("tpope/vim-fugitive")
use {
'TimUntersberger/neogit',
commit = "74c9e29b61780345d3ad9d7a4a4437607caead4a",
requires = 'nvim-lua/plenary.nvim',
config = function ()
require('neogit').setup{
disable_builtin_notifications = true,
disable_commit_confirmation = true
}
end
}
use {
'lewis6991/gitsigns.nvim',
config = function ()
require('gitsigns').setup()
end,
on_attach = function(bufnr)
end
}
-- Format
use("sbdchd/neoformat")
-- Resume issues found with LSP
use {
"folke/trouble.nvim",
requires = "kyazdani42/nvim-web-devicons",
config = function()
require("trouble").setup {}
end
}
use {
"windwp/nvim-autopairs",
config = function() require("nvim-autopairs").setup {} end
}
-- Enhanced increment and decrement
use("monaqa/dial.nvim")
-- Toggle helper
-- plugin to toggle boolean values
use {
"rmagatti/alternate-toggler"
}
-- Lua pad: REPL lua in neovim context
-- Useful to mess around with the lua API
use { 'rafcamlet/nvim-luapad', requires = "antoinemadec/FixCursorHold.nvim" }
-- Spell check helper
--
-- use("kamykn/spelunker.vim")
-- File navigation helper
use {
"ThePrimeagen/harpoon",
-- config = function()
-- require('harpoon').setup({
-- })
-- end
}
-- -- Colorscheme section
use {
"catppuccin/nvim",
as = "catppuccin",
config = function ()
end
}
use {
'kyazdani42/nvim-web-devicons',
config = function()
require'nvim-web-devicons'.setup {
-- your personnal icons can go here (to override)
-- you can specify color or cterm_color instead of specifying both of them
-- DevIcon will be appended to `name`
override = {
vue = {
icon = "",
color = "#428850",
cterm_color = "65",
name = "Vue"
}
};
-- globally enable default icons (default to false)
-- will get overriden by `get_icons` option
default = true;
}
end
}
-- Preview HTML colors
use("lilydjwg/colorizer")
-- Add Sticky Buffers
use {
"stevearc/stickybuf.nvim",
config = function()
require("stickybuf").setup()
end
}
-- add surround with 's'
use {
"ur4ltz/surround.nvim",
config = function()
require"surround".setup {mappings_style = "sandwich"}
end
}
use {
"tpope/vim-unimpaired"
}
use {
"tpope/vim-repeat"
}
-- In-buffer navigation
use {
"mfussenegger/nvim-treehopper"
}
use {
"phaazon/hop.nvim",
branch = 'v2',
config = function()
require'hop'.setup { keys = 'etovxqpdygfblzhckisuran' }
end
}
use {
"indianboy42/hop-extensions",
requires = {'phaazon/hop.nvim'}
}
-- Align things by comma
-- use : `:Tabularize /,`
-- It would be nicer if someone (me?) could develop a plugin that is based on treesitter and can automagically detect when it's a array, object etc.
use("godlygeek/tabular")
-- Ascii boxes
-- Diagramms
use("jbyuki/venn.nvim")
use("gyim/vim-boxdraw")
-- Old tab plugin
-- use {
-- 'romgrk/barbar.nvim',
-- requires = {'kyazdani42/nvim-web-devicons'}
-- }
-- Implement the editorconfig specification (format rules for each project)
use('editorconfig/editorconfig-vim')
-- Non-LSP Language config
-- Language specific config
-- Use emmet
use('mattn/emmet-vim')
-- Consider using https://github.com/danymat/neogen to easily create functions annotation (can support php docs)
-- use('lervag/vimtex') -- tex support is already here?
--
use "folke/lua-dev.nvim"
-- Trying to have gohtmltemplate Highlighting
use "fatih/vim-go"
use { 'mfussenegger/nvim-dap' }
use { "rcarriga/nvim-dap-ui", requires = {"mfussenegger/nvim-dap"} }
use {
'nvim-lualine/lualine.nvim',
requires = { 'kyazdani42/nvim-web-devicons', opt = true },
config = function ()
require('lualine').setup {
options = {
icons_enabled = true,
theme = 'auto',
component_separators = { left = '', right = ''},
section_separators = { left = '', right = ''},
disabled_filetypes = {
statusline = {},
winbar = {},
},
ignore_focus = {},
always_divide_middle = true,
globalstatus = false,
refresh = {
statusline = 1000,
tabline = 1000,
winbar = 1000,
}
},
sections = {
lualine_a = {'mode'},
lualine_b = {'branch', 'diff', 'diagnostics'},
lualine_c = {{'filename', path = 1}},
-- lualine_x = {'filetype'},
lualine_y = {'progress'},
lualine_z = {'location'}
},
inactive_sections = {
lualine_a = {},
lualine_b = {},
lualine_c = {'filename'},
lualine_x = {'location'},
lualine_y = {},
lualine_z = {}
},
tabline = {},
winbar = {},
inactive_winbar = {},
extensions = {}
}
end
}
-- Language specific plugins
use "aklt/plantuml-syntax"
use "tyru/open-browser.vim"
use "weirongxu/plantuml-previewer.vim"
-- allow to easily create new telescope pickers
-- useful to create ppq git recent files
use {
'axkirillov/easypick.nvim',
requires = 'nvim-telescope/telescope.nvim',
config = function ()
local easypick = require("easypick")
local base_branch = "master"
easypick.setup({
pickers = {
-- list recent updated files tracked by git
{
name = "recent_files",
-- don't use the uniq util with sort, to preserve the original sorting order
command = "git -c core.quotepath=off log --name-only --format='' | head -n 100 | awk '!seen[$0]++'",
previewer = easypick.previewers.default()
}
}
})
end
}
use {
'ethanholz/nvim-lastplace',
config = function ()
require'nvim-lastplace'.setup {
lastplace_ignore_buftype = {"quickfix", "nofile", "help"},
lastplace_ignore_filetype = {"gitcommit", "gitrebase", "svn", "hgcommit"},
lastplace_open_folds = true
}
end
}
-- markdown note plugins
use({
"iamcco/markdown-preview.nvim",
run = function() vim.fn["mkdp#util#install"]() end,
})
-- disable it for now bc it overrode shit in NeoTree
-- use({'jakewvincent/mkdnflow.nvim',
-- config = function()
-- require('mkdnflow').setup({
-- -- Config goes here; leave blank for defaults
-- })
-- end
-- })
-- new plugins
-- append new plugins here
if packer_bootstrap then
require('packer').sync()
end
end)
-- local map = vim.api.nvim_set_keymap
local map = vim.keymap.set
-- reload nvim config
map("n", "<Leader><Leader>r", "<cmd>source ~/.config/nvim/init.lua<CR>")
-- short cut to access system clipboard
map("n", "Y", '"+y')
map("v", "Y", '"+y')
-- handy little things
map("n", "<C-q>", "<Cmd>:q<CR>") -- close a single buffer
map("n", "<C-Q>", "<Cmd>:tabclose<CR>") -- close a whole tab (with Q uppercase)
map("n", "<C-s>", "<Cmd>:w<CR>")
-- back to last buffer
map("n", "<Leader>bb", "<C-^>")
-- No highlights
map("n", "<Leader>nh", "<Cmd>noh<CR>")
map("n", "<Leader><Leader>h", "<Cmd>noh<CR>")
-- Copy current buffer paths to system clipboard
map("n", "<Leader>yp", function() copy_rel_path_with_line() end)
map("n", "<Leader>ypr", function() copy_rel_path() end)
map("n", "<Leader>ypr", function() copy_rel_path_with_line() end)
map("n", "<Leader>ypa", function() copy_abs_path() end)
-- Open URL in browser (replace netrw-gx)
map("n", "gx", function()
print()
vim.fn.jobstart(
{"xdg-open", vim.fn.expand("<cfile>")},
{ on_stdout = print_stdout, detach = true }
)
end)
-- Insert date + time
map("n", "<Leader>dt", function()
local res = os.date("%Y-%m-%d %H:%M:%S")
vim.api.nvim_put({res}, "", true, false)
end)
-- Insert only day date
map("n", "<Leader>dd", function()
local res = os.date("%Y-%m-%d")
vim.api.nvim_put({res}, "", true, false)
end)
-- using netrw
-- map("n", "<Leader>tt", "<Cmd>Explore<CR>")
-- map("n", "<Leader>th", "<Cmd>Sexplore<CR>")
-- map("n", "<Leader>tv", "<Cmd>Vexplore<CR>")
-- launch neotree
map("n", "<Leader>tt", function() vim.api.nvim_command('Neotree') end)
-- focus file in tree
-- locate file, locate path, locate buffer in tree
map("n", "<Leader>tf", function() vim.api.nvim_command('Neotree reveal') end)
map("n", "<Leader>tb", function() vim.api.nvim_command('Neotree buffers') end)
-- launch neogit
map("n", "<Leader>ng", function() vim.api.nvim_command('Neogit') end)
-- launch neoformat
map("n", "<Leader>nf", function() vim.api.nvim_command('Neoformat') end)
-- launch troubles
map("n", "<Leader>tr", function() vim.api.nvim_command('Trouble') end)
-- in buffer navigation
-- map("v", "<C-h>", function() require('tsht').nodes() end)
-- map("n", "<C-h>", function() require('tsht').move({ side = "start" }) end)
-- Hop nvim keybindings (quick jumps)
-- Similar function can be triggered with Ctrl+BackSpace
map("n", "<Leader>H", function()
-- hop in all the buffer by word
require('hop').hint_words()
end)
map("n", "<Leader>hl", function()
-- hop to a line
require('hop').hint_lines_skip_whitespace()
end)
map("n", "<Leader>hv", function()
-- keep the position of the cursor column wise
require('hop').hint_vertical()
end)
map("n", "<Leader>hs", function()
require('hop-extensions').hint_textobjects()
end)
map("n", "<C-h>", function()
require('hop-extensions').hint_textobjects()
end)
-- Symbols outline
-- TODO: add a command variant to only show the top-level elements
map("n", "<Leader>so", function ()
vim.cmd("SymbolsOutline")
end)
-- map("n", "<Leader>sO", function ()
-- vim.cmd("SymbolsOutlineOpen")
-- end)
-- Harpoon
-- map("n", "<Leader>h", function() require("harpoon.ui").toggle_quick_menu() end)
-- map("n", "<Leader>a", function() require("harpoon.mark").add_file() end)
-- map("n", "<A-h>", function () require("harpoon.ui").nav_file(1) end)
-- map("n", "<A-j>", function () require("harpoon.ui").nav_file(2) end)
-- map("n", "<A-k>", function () require("harpoon.ui").nav_file(3) end)
-- map("n", "<A-l>", function () require("harpoon.ui").nav_file(4) end)
-- reserved for style file
-- map("n", "<A-s>", function () require("harpoon.ui").nav_file(1) end)
-- reserved for template file
-- reserved for controller file
-- map("n", "<A-s>", function () require("harpoon.ui").nav_file("Controller") end)
-- Dial: Improved increment
map("n", "<C-a>", require("dial.map").inc_normal(), {noremap = true})
map("n", "<C-x>", require("dial.map").dec_normal(), {noremap = true})
map("v", "<C-a>", require("dial.map").inc_visual(), {noremap = true})
map("v", "<C-x>", require("dial.map").dec_visual(), {noremap = true})
map("v", "g<C-a>", require("dial.map").inc_gvisual(), {noremap = true})
map("v", "g<C-x>", require("dial.map").dec_gvisual(), {noremap = true})
-- let g:at_custom_alternates = {'===': '!==', 'yes':'no'}
-- vim.cmd [[
-- let g:at_custom_alternates = {'===': '!==', 'yes': 'no'}
-- ]]
-- https://github.com/rmagatti/alternate-toggler/issues/6
vim.g.at_custom_alternates = {
['==='] = '!==',
['yes'] = 'no',
['open'] = 'close',
['always'] = 'never',
['allow'] = 'deny',
['before'] = 'after',
['let'] = 'var',
['public'] = 'private',
['begin'] = 'end'
}
map("n", "<Leader>ta", "<Cmd>:ToggleAlternate<CR>")
-- swap with
map("n", "<Leader>ss", function() vim.api.nvim_command('ISwap') end)
map("n", "<Leader>sw", function() vim.api.nvim_command('ISwapWith') end)
map("n", "<Leader>sl", function() vim.api.nvim_command('ISwapNodeWithLeft') end)
map("n", "<Leader>sr", function() vim.api.nvim_command('ISwapNodeWithRight') end)
-- Telescope binding
map("n", "<Leader>ff", function ()
require('telescope.builtin').find_files()
end)
-- Ctrl+P
map("n", "<C-p>", function ()
-- It would be great if we could enter regex pattern to match on files
require('telescope.builtin').find_files()
end)
-- TODO: find files with telescope but also search in the ignored files
-- map("n", "<C-P>", function ()
-- require('telescope.builtin').find_files()
-- end)
-- live grep keybind
map("n", "<Leader>fg", function ()
-- previously was:
-- require('telescope.builtin').live_grep()
--
-- arguments of ripgrep
-- use '"search" --type py' to search in python file only
-- or use '"search" -g "*.py"' to do glob search on file name
-- or use '"search" -g "!*.py"' to exclude file name pattern
-- another cool feature will be to do only search on a subdirectory (preferentially the current directory of neotree)
require('telescope').extensions.live_grep_args.live_grep_args()
end)
map("n", "<Leader>SS", function ()
require('telescope').extensions.live_grep_args.live_grep_args({search = "hello world"})
end)
map("n", "<Leader>fb", function ()
require('telescope.builtin').buffers()
end)
map("n", "<Leader>fh", function ()
require('telescope.builtin').help_tags()
end)
map("n", "<Leader>fs", function ()
require('telescope.builtin').lsp_workspace_symbols()
end)
map("n", "<Leader>fw", function ()
-- useful to quickly jump to ANY workspace symbols (also include random variables)
require('telescope.builtin').lsp_dynamic_workspace_symbols()
end)
map("n", "<Leader>fo", function ()
-- recent files history
require('telescope.builtin').oldfiles({only_cwd = true})
end)
map("n", "<Leader>fW", function ()
-- useful to quickly jump to major workspace symbols (class, functions, interfaces, etc...)
-- require('telescope.builtin').lsp_dynamic_workspace_symbols()
end)
-- Search for symbols accross project
-- map("n", "<Leader>fs", function ()
-- require('telescope.builtin').lsp()
-- end)
-- find recent files
map("n", "<Leader>fr", function ()
vim.api.nvim_command('Easypick recent_files')
end)
-- Treesitter config
require'nvim-treesitter.configs'.setup {
ensure_installed = "all",
sync_install = false,
highlight = {
enable = true,
additional_vim_regex_highlighting = false,
},
indent = {
enable = true
},
incremental_selection = {
enable = true,
keymaps = {
init_selection = "<C-n>",
node_incremental = "<C-n>",
scope_incremental = "<C-s>",
node_decremental = "<C-r>",
},
},
textobjects = {
select = {
enable = true,
-- Automatically jump forward to textobj, similar to targets.vim
lookahead = true,
keymaps = {
-- You can use the capture groups defined in textobjects.scm
["af"] = "@function.outer",
["if"] = "@function.inner",
["ac"] = "@class.outer",
["ic"] = "@class.inner",
["aa"] = "@block.outer",
["ii"] = "@block.inner",
["i,"] = '@parameter.inner',
["a,"] = '@parameter.outer',
},
-- You can choose the select mode (default is charwise 'v')
selection_modes = {
['@parameter.outer'] = 'v', -- charwise
['@function.outer'] = 'V', -- linewise
['@class.outer'] = '<c-v>', -- blockwise
},
-- Useful to include whitespace after a function for example (so the whitespace get deleted or copied and stick with the belonging block)
include_surrounding_whitespace = true,
},
move = {
enable = true,
set_jumps = true, -- whether to set jumps in the jumplist
goto_next_start = {
["]m"] = "@function.outer",
["]]"] = { query = "@class.outer", desc = "Next class start" },
--
-- You can use regex matching (i.e. lua pattern) and/or pass a list in a "query" key to group multiple queires.
["]o"] = "@loop.*",
-- ["]o"] = { query = { "@loop.inner", "@loop.outer" } }
--
-- You can pass a query group to use query from `queries/<lang>/<query_group>.scm file in your runtime path.
-- Below example nvim-treesitter's `locals.scm` and `folds.scm`. They also provide highlights.scm and indent.scm.
["]s"] = { query = "@scope", query_group = "locals", desc = "Next scope" },
["]z"] = { query = "@fold", query_group = "folds", desc = "Next fold" },
},
goto_next_end = {
["]M"] = "@function.outer",
["]["] = "@class.outer",
},
goto_previous_start = {
["[m"] = "@function.outer",
["[["] = "@class.outer",
},
goto_previous_end = {
["[M"] = "@function.outer",
["[]"] = "@class.outer",
},
-- Below will go to either the start or the end, whichever is closer.
-- Use if you want more granular movements
-- Make it even more gradual by adding multiple queries and regex.
goto_next = {
["]d"] = "@conditional.outer",
},
goto_previous = {
["[d"] = "@conditional.outer",
}
},
},
}
vim.opt.foldmethod = "expr"
vim.opt.foldexpr = "nvim_treesitter#foldexpr()"
vim.opt.foldlevelstart = 8
-- LSP Config
local nvim_lsp = require 'lspconfig'
-- TODO: fix auto-imports not working with rust
-- LSP Servers
-- docs: WHERE IS THE FING DOCS?
-- https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md
local servers = {'clangd', 'pyright', 'tsserver', 'gopls', 'volar', 'svelte' }
for _, lsp in ipairs(servers) do
nvim_lsp[lsp].setup {
on_attach = on_attach,
}
end
nvim_lsp['rust_analyzer'].setup{
on_attach = on_attach,
init_options = {
["rust-analyzer.checkOnSave.command"] = "clippy"
}
}
nvim_lsp.phpactor.setup{
on_attach = on_attach,
init_options = {
["language_server_phpstan.enabled"] = false,
["language_server_psalm.enabled"] = false,
}
}
nvim_lsp.svelte.setup{
init_options = {
["svelte.plugin.typescript.enable"] = false,
["svelte.plugin.typescript.diagnostics.enable"] = false,
}
}
nvim_lsp['hls'].setup{
filetypes = { 'haskell', 'lhaskell', 'cabal' }
}
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.textDocument.completion.completionItem.snippetSupport = true
nvim_lsp.cssls.setup{
capabilities = capabilities
}
local runtime_path = vim.split(package.path, ';')
table.insert(runtime_path, 'lua/?.lua')
table.insert(runtime_path, 'lua/?/init.lua')
-- Cmp config
local cmp = require'cmp'
cmp.setup({
snippet = {
-- REQUIRED - you must specify a snippet engine
expand = function(args)
-- vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users.
require('luasnip').lsp_expand(args.body) -- For `luasnip` users.
-- require('snippy').expand_snippet(args.body) -- For `snippy` users.
-- vim.fn["UltiSnips#Anon"](args.body) -- For `ultisnips` users.
end,
},
window = {
-- completion = cmp.config.window.bordered(),
-- documentation = cmp.config.window.bordered(),
},
mapping = cmp.mapping.preset.insert({
['<C-b>'] = cmp.mapping.scroll_docs(-4),
['<C-f>'] = cmp.mapping.scroll_docs(4),
['<C-Space>'] = cmp.mapping.complete(),
['<C-e>'] = cmp.mapping.abort(),
['<S-CR>'] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
}),
sources = {
{ name = 'nvim_lsp', keyword_length = 4 },
{ name = 'nvim_lua', keyword_length = 4 },
{ name = 'path', keyword_length = 4 },
{ name = 'treesitter', keyword_length = 4 },
{ name = "luasnip", keyword_length = 4 },
{ name = "buffer", keyword_length = 5 },
},
experimental = {
-- I like the new menu better! Nice work hrsh7th
native_menu = false,
-- Let's play with this for a day or two
ghost_text = false,
},
sorting = {
-- TODO: Would be cool to add stuff like "See variable names before method names" in rust, or something like that.
comparators = {
cmp.config.compare.offset,
cmp.config.compare.exact,
cmp.config.compare.score,
-- copied from cmp-under, but I don't think I need the plugin for this.
-- I might add some more of my own.
function(entry1, entry2)
local _, entry1_under = entry1.completion_item.label:find "^_+"
local _, entry2_under = entry2.completion_item.label:find "^_+"
entry1_under = entry1_under or 0
entry2_under = entry2_under or 0
if entry1_under > entry2_under then
return false
elseif entry1_under < entry2_under then
return true
end
end,
cmp.config.compare.kind,
cmp.config.compare.sort_text,
cmp.config.compare.length,
cmp.config.compare.order,
},
},
-- sources = cmp.config.sources({
-- { name = 'nvim_lsp' },
-- -- { name = 'vsnip' }, -- For vsnip users.
-- -- { name = 'luasnip' }, -- For luasnip users.
-- -- { name = 'ultisnips' }, -- For ultisnips users.
-- -- { name = 'snippy' }, -- For snippy users.
-- }, {
-- {
-- name = 'buffer',
-- options = {
-- keyword_length = 5
-- }
-- },
-- })
})
-- Toggle diags
DiagnosticsConfig = vim.diagnostic.config()
DiagnosticsEnabled = true
function toggle_lsp_diag()
if not DiagnosticsEnabled then
vim.diagnostic.config(DiagnosticsConfig)
DiagnosticsEnabled = true
else
DiagnosticsConfig = vim.diagnostic.config()
vim.diagnostic.config({
virtual_text = false,
sign = false,
float = false,
update_in_insert = false,
severity_sort = false,
underline = false,
})
DiagnosticsEnabled = false
end
end
-- Language server keybindings
-- LSP keybindings
map("n", "gd", function ()
vim.lsp.buf.definition()
end)
map("n", "<Leader>od", function ()
-- open definition in a new tab
-- vim.lsp.buf.definition()
print("Open def in new tab")
-- vim.api.nvim_exec(
-- [[ normal <Ctrl+w>] ]],
-- -- [[normal dd]],
-- false
-- )
end)
map("n", "gD", function ()
vim.lsp.buf.declaration()
end)
-- go to implementation
map("n", "gi", function ()
vim.lsp.buf.implementation()
end)
-- go to usage
-- go to callers of a function
map("n", "<Leader>lc", function ()
vim.lsp.buf.incoming_calls()
end)
map("n", "gw", function ()
vim.lsp.buf.document_symbol()
end)
map("n", "gr", function ()
vim.lsp.buf.references()
end)
map("n", "<Leader>ld", function ()
vim.lsp.buf.type_definition()
end)
map("n", "K", function ()
vim.lsp.buf.hover()
end)
map("n", "<c-k>", function ()
vim.lsp.buf.signature_help()
end)
map("n", "<Leader>ac", function ()
vim.lsp.buf.code_action()
end)
-- Rename action
map("n", "<Leader>rn", function ()
vim.lsp.buf.rename()
end)
-- Show_line_diagnostics
map("n", "<Leader>di", function ()
vim.diagnostic.open_float()
end)
-- Format whole buffer with LSP
map("n", "<Leader>F", function ()
vim.lsp.buf.format { async = true }
end)
-- Toggle LSP diags
-- keywords: disable lsp
map("n", "<Leader>td", function() toggle_lsp_diag() end)
-- Tabs keymaps
-- -- Move to previous/next
-- map('n', '<A-,>', '<Cmd>BufferPrevious<CR>')
-- map('n', '<A-.>', '<Cmd>BufferNext<CR>')
-- -- Re-order to previous/next
-- map('n', '<A-<>', '<Cmd>BufferMovePrevious<CR>')
-- map('n', '<A->>', '<Cmd>BufferMoveNext<CR>')
-- -- Goto buffer in position...
-- map('n', '<A-1>', '<Cmd>BufferGoto 1<CR>')
-- map('n', '<A-2>', '<Cmd>BufferGoto 2<CR>')
-- map('n', '<A-3>', '<Cmd>BufferGoto 3<CR>')
-- map('n', '<A-4>', '<Cmd>BufferGoto 4<CR>')
-- map('n', '<A-5>', '<Cmd>BufferGoto 5<CR>')
-- map('n', '<A-6>', '<Cmd>BufferGoto 6<CR>')
-- map('n', '<A-7>', '<Cmd>BufferGoto 7<CR>')
-- map('n', '<A-8>', '<Cmd>BufferGoto 8<CR>')
-- map('n', '<A-9>', '<Cmd>BufferGoto 9<CR>')
-- map('n', '<A-0>', '<Cmd>BufferLast<CR>')
-- -- Pin/unpin buffer
-- map('n', '<A-p>', '<Cmd>BufferPin<CR>')
-- -- Close buffer
-- map('n', '<A-c>', '<Cmd>BufferClose<CR>')
-- -- Wipeout buffer
-- -- :BufferWipeout
-- -- Close commands
-- -- :BufferCloseAllButCurrent
-- -- :BufferCloseAllButPinned
-- -- :BufferCloseAllButCurrentOrPinned
-- -- :BufferCloseBuffersLeft
-- -- :BufferCloseBuffersRight
-- -- Magic buffer-picking mode
-- map('n', '<C-p>', '<Cmd>BufferPick<CR>')
-- -- Sort automatically by...
-- map('n', '<Space>bb', '<Cmd>BufferOrderByBufferNumber<CR>')
-- map('n', '<Space>bd', '<Cmd>BufferOrderByDirectory<CR>')
-- map('n', '<Space>bl', '<Cmd>BufferOrderByLanguage<CR>')
-- map('n', '<Space>bw', '<Cmd>BufferOrderByWindowNumber<CR>')
map("n", "<Leader>gh", "<Cmd>:lua print('this is a msg')<CR>")
vim.g.hook_cmp_toggle = true
-- LuaSnip config / Snippets
-- imap <silent><expr> <Tab> luasnip#expand_or_jumpable() ? '<Plug>luasnip-expand-or-jump' : '<Tab>'
-- " -1 for jumping backwards.
-- inoremap <silent> <S-Tab> <cmd>lua require'luasnip'.jump(-1)<Cr>
-- snoremap <silent> <Tab> <cmd>lua require('luasnip').jump(1)<Cr>
-- snoremap <silent> <S-Tab> <cmd>lua require('luasnip').jump(-1)<Cr>
-- " For changing choices in choiceNodes (not strictly necessary for a basic setup).
-- imap <silent><expr> <C-E> luasnip#choice_active() ? '<Plug>luasnip-next-choice' : '<C-E>'
-- smap <silent><expr> <C-E> luasnip#choice_active() ? '<Plug>luasnip-next-choice' : '<C-E>'
function on_luasnip_load()
local ls = require("luasnip")
ls.config.set_config({
history = true,
updateevents = "TextChanged,TextChangedI",
enable_autosnippets = true,
})
ls.filetype_extend("svelte", { "html" })
ls.filetype_extend("svelte", { "typescript" })
require("luasnip.loaders.from_vscode").lazy_load()
-- This replace the diagraph menu
vim.keymap.set({"i", "s"}, "<c-k>", function ()
if ls.expand_or_jumpable() then
ls.expand_or_jump()
end
end)
vim.keymap.set({"i", "s"}, "<c-j>", function ()
if ls.jumpable(-1) then
ls.jump(-1)
end
end)
vim.keymap.set("i", "<c-l>", function ()
if ls.choice_active() then
ls.change_choice()
end
end)
local events = require("luasnip.util.events")
local ai = require("luasnip.nodes.absolute_indexer")
local fmt = require("luasnip.extras.fmt").fmt
local extras = require("luasnip.extras")
local m = extras.m
local l = extras.l
local rep = extras.rep
local postfix = require("luasnip.extras.postfix").postfix
ls.add_snippets("all", {
ls.snippet("somefoobarlel", {
-- equivalent to "${1:cond} ? ${2:then} : ${3:else}"
ls.insert_node(1, "cond"), ls.text_node(" ? "), ls.insert_node(2, "then"), ls.text_node(" : "), ls.insert_node(3, "else")
}),
ls.snippet("lorem", {
ls.text_node("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
})
})
ls.add_snippets("rust", {
ls.snippet("dbg", {
ls.text_node("dbg!("), ls.insert_node(1, "value"), ls.text_node(");")
})
})
function mysplit (inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end
vim.api.nvim_create_user_command('SnipList', function ()
-- Will create a read only buffer and show the description of all the snippets
local res = vim.inspect(require'luasnip'.available())
if win and vim.api.nvim_win_is_valid(win) then
vim.api.nvim_set_current_win(win)
else
-- We open a new buffer
vim.api.nvim_command('botright vnew')
win = vim.api.nvim_get_current_win()
buf = vim.api.nvim_get_current_buf()
vim.api.nvim_buf_set_name(buf, "SnipList")
vim.api.nvim_buf_set_option(buf, 'buftype', 'nofile')
vim.api.nvim_buf_set_option(buf, 'swapfile', false)
vim.api.nvim_buf_set_option(buf, 'bufhidden', 'wipe')
vim.api.nvim_buf_set_option(buf, 'modifiable', true)
vim.api.nvim_buf_set_option(buf, 'filetype', 'lua')
-- Uncomment to disable numbers
-- vim.api.nvim_set_option_value('number', false, { scope = "local" })
-- vim.api.nvim_set_option_value('relativenumber', false, { scope = "local" })
-- We set the buffer content
vim.api.nvim_buf_set_lines(buf, 0, -1, false, mysplit(res, "\n"))
vim.api.nvim_buf_set_option(buf, 'modifiable', false)
end
end, {})
end
require("catppuccin").setup({
flavour = "mocha", -- redondant
color_overrides = {
all = {
}
},
custom_highlights = function(colors)
return {
["@constant.builtin"] = { fg = colors.peach, style = {} },
-- change the syntax highlighting of comments to make them easier to read and notice
-- I once read a blog post about how comments in code should be put in front and not hidden with some gray colorscheme
["@comment"] = { fg = colors.red, style = { "italic", "bold" } },
}
end
})
vim.cmd.colorscheme "catppuccin"
vim.api.nvim_exec(
[[
function! DetectGoHtmlTmpl()
if expand('%:e') == "html" && search("{{") != 0
set filetype=gohtmltmpl
endif
endfunction
augroup filetypedetect
au! BufRead,BufNewFile * call DetectGoHtmlTmpl()
augroup END
]], true
)
-- vim.g.gruvbox_contrast_dark = "hard"
-- little shortcut to insert new line without going into insert mode with Ctrl+Enter
map("n", "<C-Enter>", function ()
vim.api.nvim_put({"",""}, "", true, false)
end)
-- Tabs manipulations
map("n", "<Leader>T0", function() vim.api.nvim_command('tabm 0') end)
map("n", "<Leader>Ti", function() vim.api.nvim_command('tabm +1') end)
map("n", "<Leader>Td", function() vim.api.nvim_command('tabm -1') end)
-- Move after last tab
vim.api.nvim_create_user_command('MoveTabAtLastTab', function ()
local tabpages = vim.api.nvim_list_tabpages()
vim.api.nvim_command('tabm '..#tabpages)
end, {})
map("n", "<Leader>Te", function() vim.api.nvim_command('MoveTabAtLastTab') end)
-- Tabs/Tabspages navigation with alt
map("n", "<A-Left>", function () vim.api.nvim_command("tabp") end)
map("n", "<A-Right>", function () vim.api.nvim_command("tabn") end)
map("n", "<A-h>", function () vim.api.nvim_command("tabp") end)
-- Go to nth tab
local function jump_to_nth_tab(tab_position)
local tabpages = vim.api.nvim_list_tabpages()
if tab_position > #tabpages then
return
end
print(tab_position)
vim.api.nvim_set_current_tabpage(tabpages[tab_position])
end
local function jump_to_last_tab()
local tabpages = vim.api.nvim_list_tabpages()
print(#tabpages)
end
map("n", "<A-L>", function () jump_to_nth_tab(0) end)
map("n", "<A-H>", function () jump_to_last_tab() end)
map("n", "<A-0>", function () jump_to_nth_tab(10) end)
map("n", "<A-->", function () jump_to_nth_tab(11) end)
map("n", "<A-=>", function () jump_to_nth_tab(12) end)
for i = 1, 9 do
map("n", "<A-" .. i .. ">", function ()
jump_to_nth_tab(i)
end)
end
-- common utils function to accept user input from bottom status line
local function user_input(message)
vim.api.nvim_call_function("inputsave", {})
local val = vim.api.nvim_call_function("input", { message })
vim.api.nvim_call_function("inputrestore", {})
return val
end
-- Now a way to jump to specific tabs via file name match
map("n", "<A-j>", function ()
-- Ask user the file startup
user_res = user_input("TabJump: ")
pages = vim.api.nvim_list_tabpages()
if #pages == 1 then
return
end
for tab_pos in ipairs(pages) do
win = vim.api.nvim_tabpage_get_win(tab_pos)
buf = vim.api.nvim_win_get_buf(win)
file_path = vim.api.nvim_buf_get_name(buf)
res = mysplit(file_path, "/")
file_name = res[#res]
search_res = string.find(file_name, user_res)
if search_res then
vim.api.nvim_set_current_tabpage(tab_pos)
vim.api.nvim_echo({}, false, {})
return
end
end
vim.api.nvim_notify("TabJump: No match found", 0, {})
end)
-- Search helper
local function visual_selection_range()
local _, csrow, cscol, _ = unpack(vim.fn.getpos("'<"))
local _, cerow, cecol, _ = unpack(vim.fn.getpos("'>"))
if csrow < cerow or (csrow == cerow and cscol <= cecol) then
return csrow - 1, cscol - 1, cerow - 1, cecol
else
return cerow - 1, cecol - 1, csrow - 1, cscol
end
end
function get_current_selected()
local current_mode = vim.api.nvim_get_mode()['mode']
if (
current_mode == "v" or
current_mode == "V"
) then
local _, select_start_row, select_start_col, _ = unpack(vim.fn.getpos("'<"))
local _, select_end_row, select_end_col, _ = unpack(vim.fn.getpos("'>"))
-- get the range
-- print(select_start_row, select_start_col)
-- print(select_end_row, select_end_col)
selected_text = vim.api.nvim_buf_get_text(0, select_start_row-1, select_start_col-1, select_end_row-1, select_end_col-1, {})
if #selected_text == 0 then
return nil
end
return selected_text[1]
end
return nil
end
function copy_rel_path()
-- get full path: expand("%:p")
-- get relative path: expand("%")
-- vim.fn.setreg("+", vim.fn.expand("%"))
path = vim.fn.fnamemodify(vim.fn.expand("%"), ":~:.")
vim.fn.setreg("+", path)
print("Copied relative to system clipboard")
end
function copy_rel_path_with_line()
path = vim.fn.fnamemodify(vim.fn.expand("%"), ":~:.") .. ':' .. vim.fn.getpos('.')[2]
vim.fn.setreg("+", path)
end
function copy_abs_path()
vim.fn.setreg("+", vim.fn.expand("%:p"))
print("Copied absolute to system clipboard")
end
function copy_abs_path_with_line()
path = vim.fn.setreg("+", vim.fn.expand("%:p")) .. ':' .. vim.fn.getpos('.')[2]
vim.fn.setreg("+", path)
end
-- Search the term selected
function handle_search_selection()
print("handle search selection")
selected = get_current_selected()
if selected == nil then
return nil
end
vim.api.nvim_exec(
"normal! /lelhello",
false
)
end
map("n", "<Leader>S", handle_search_selection)
map("v", "<Leader>S", handle_search_selection)
-- Restrict the search to a range
-- map("n", "<Leader>S", function ()
-- end)
-- Handy Git signs shortcuts
map("n", "<Leader>gb", function() vim.api.nvim_command('Gitsigns blame_line') end)
map("n", "<Leader>gs", function() vim.api.nvim_command('Gitsigns stage_hunk') end)
map("n", "<Leader>gu", function() vim.api.nvim_command('Gitsigns undo_stage_hunk') end)
map("n", "<Leader>gd", function() vim.api.nvim_command('Gitsigns toggle_deleted') end)
map("n", "<Leader>gD", function() vim.api.nvim_command('Gitsigns diffthis') end)
map("n", "<Leader>gS", function() vim.api.nvim_command('Gitsigns stage_buffer') end)
map("n", "<Leader>ghr", function() vim.api.nvim_command('Gitsigns reset_hunk') end)
map("n", "<Leader>ghp", function() vim.api.nvim_command('Gitsigns preview_hunk') end)
vim.api.nvim_create_user_command('CopyRelPath', function () copy_rel_path() end, {})
vim.api.nvim_create_user_command('CopyAbsPath', copy_abs_path, {})
vim.api.nvim_create_user_command('CopyRelPathWithLine', copy_rel_path_with_line, {})
vim.api.nvim_create_user_command('CopyAbsPathWithLine', copy_abs_path_with_line, {})
vim.api.nvim_create_user_command('ReverseLinesOder', function ()
-- https://superuser.com/questions/189947/how-do-i-reverse-selected-lines-order-in-vim
-- step 1: select lines
-- 2: hit :
-- 3: type !tac
-- 4: profit
print("select lines : then !tac")
end, {})
-- PATCH: in order to address the message:
-- vim.treesitter.query.get_query() is deprecated, use vim.treesitter.query.get() instead. :help deprecated
-- This feature will be removed in Nvim version 0.10
local orig_notify = vim.notify
local filter_notify = function(text, level, opts)
-- more specific to this case
if type(text) == "string" and (string.find(text, "get_query", 1, true) or string.find(text, "get_node_text", 1, true)) then
-- for all deprecated and stack trace warnings
-- if type(text) == "string" and (string.find(text, ":help deprecated", 1, true) or string.find(text, "stack trace", 1, true)) then
return
end
orig_notify(text, level, opts)
end
vim.notify = filter_notify
-- Check for POPEQUER notebook env var
-- launch the popequer lua file
local popequer_enabled = str2bool(os.getenv("POPEQUER_ENABLED"))
if popequer_enabled then
require "popequer"
end
vim.cmd("set wrap")