|
vim.opt.number = true |
|
vim.opt.relativenumber = true |
|
|
|
-- https://raw.githubusercontent.com/neoclide/coc.nvim/master/doc/coc-example-config.lua |
|
|
|
-- Some servers have issues with backup files, see #649 |
|
vim.opt.backup = false |
|
vim.opt.writebackup = false |
|
|
|
-- Having longer updatetime (default is 4000 ms = 4s) leads to noticeable |
|
-- delays and poor user experience |
|
vim.opt.updatetime = 300 |
|
|
|
-- Always show the signcolumn, otherwise it would shift the text each time |
|
-- diagnostics appeared/became resolved |
|
vim.opt.signcolumn = "yes" |
|
|
|
vim.o.sessionoptions="blank,buffers,curdir,folds,help,tabpages,winsize,winpos,terminal,localoptions" |
|
|
|
local keyset = vim.keymap.set |
|
-- Autocomplete |
|
function _G.check_back_space() |
|
local col = vim.fn.col('.') - 1 |
|
return col == 0 or vim.fn.getline('.'):sub(col, col):match('%s') ~= nil |
|
end |
|
|
|
-- Use Tab for trigger completion with characters ahead and navigate |
|
-- NOTE: There's always a completion item selected by default, you may want to enable |
|
-- no select by setting `"suggest.noselect": true` in your configuration file |
|
-- NOTE: Use command ':verbose imap <tab>' to make sure Tab is not mapped by |
|
-- other plugins before putting this into your config |
|
local opts = {silent = true, noremap = true, expr = true, replace_keycodes = false} |
|
keyset("i", "<TAB>", 'coc#pum#visible() ? coc#pum#next(1) : v:lua.check_back_space() ? "<TAB>" : coc#refresh()', opts) |
|
keyset("i", "<S-TAB>", [[coc#pum#visible() ? coc#pum#prev(1) : "\<C-h>"]], opts) |
|
|
|
-- Make <CR> to accept selected completion item or notify coc.nvim to format |
|
-- <C-g>u breaks current undo, please make your own choice |
|
keyset("i", "<cr>", [[coc#pum#visible() ? coc#pum#confirm() : "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"]], opts) |
|
|
|
-- Use <c-j> to trigger snippets |
|
keyset("i", "<c-j>", "<Plug>(coc-snippets-expand-jump)") |
|
-- Use <c-space> to trigger completion |
|
keyset("i", "<c-space>", "coc#refresh()", {silent = true, expr = true}) |
|
|
|
-- Use `[g` and `]g` to navigate diagnostics |
|
-- Use `:CocDiagnostics` to get all diagnostics of current buffer in location list |
|
keyset("n", "[g", "<Plug>(coc-diagnostic-prev)", {silent = true}) |
|
keyset("n", "]g", "<Plug>(coc-diagnostic-next)", {silent = true}) |
|
|
|
-- GoTo code navigation |
|
keyset("n", "gd", "<Plug>(coc-definition)", {silent = true}) |
|
keyset("n", "gy", "<Plug>(coc-type-definition)", {silent = true}) |
|
keyset("n", "gi", "<Plug>(coc-implementation)", {silent = true}) |
|
keyset("n", "gr", "<Plug>(coc-references)", {silent = true}) |
|
|
|
|
|
-- Use K to show documentation in preview window |
|
function _G.show_docs() |
|
local cw = vim.fn.expand('<cword>') |
|
if vim.fn.index({'vim', 'help'}, vim.bo.filetype) >= 0 then |
|
vim.api.nvim_command('h ' .. cw) |
|
elseif vim.api.nvim_eval('coc#rpc#ready()') then |
|
vim.fn.CocActionAsync('doHover') |
|
else |
|
vim.api.nvim_command('!' .. vim.o.keywordprg .. ' ' .. cw) |
|
end |
|
end |
|
keyset("n", "K", '<CMD>lua _G.show_docs()<CR>', {silent = true}) |
|
|
|
|
|
-- Highlight the symbol and its references on a CursorHold event(cursor is idle) |
|
vim.api.nvim_create_augroup("CocGroup", {}) |
|
vim.api.nvim_create_autocmd("CursorHold", { |
|
group = "CocGroup", |
|
command = "silent call CocActionAsync('highlight')", |
|
desc = "Highlight symbol under cursor on CursorHold" |
|
}) |
|
|
|
|
|
-- Symbol renaming |
|
keyset("n", "<leader>rn", "<Plug>(coc-rename)", {silent = true}) |
|
|
|
|
|
-- Formatting selected code |
|
keyset("x", "<leader>f", "<Plug>(coc-format-selected)", {silent = true}) |
|
keyset("n", "<leader>f", "<Plug>(coc-format-selected)", {silent = true}) |
|
|
|
|
|
-- Apply codeAction to the selected region |
|
-- Example: `<leader>aap` for current paragraph |
|
local opts = {silent = true, nowait = true} |
|
keyset("x", "<leader>a", "<Plug>(coc-codeaction-selected)", opts) |
|
keyset("n", "<leader>a", "<Plug>(coc-codeaction-selected)", opts) |
|
|
|
-- Remap keys for apply code actions at the cursor position. |
|
keyset("n", "<leader>ac", "<Plug>(coc-codeaction-cursor)", opts) |
|
-- Remap keys for apply source code actions for current file. |
|
keyset("n", "<leader>as", "<Plug>(coc-codeaction-source)", opts) |
|
-- Apply the most preferred quickfix action on the current line. |
|
keyset("n", "<leader>qf", "<Plug>(coc-fix-current)", opts) |
|
|
|
-- Remap keys for apply refactor code actions. |
|
keyset("n", "<leader>re", "<Plug>(coc-codeaction-refactor)", { silent = true }) |
|
keyset("x", "<leader>r", "<Plug>(coc-codeaction-refactor-selected)", { silent = true }) |
|
keyset("n", "<leader>r", "<Plug>(coc-codeaction-refactor-selected)", { silent = true }) |
|
|
|
-- Run the Code Lens actions on the current line |
|
keyset("n", "<leader>cl", "<Plug>(coc-codelens-action)", opts) |
|
|
|
|
|
-- Map function and class text objects |
|
-- NOTE: Requires 'textDocument.documentSymbol' support from the language server |
|
keyset("x", "if", "<Plug>(coc-funcobj-i)", opts) |
|
keyset("o", "if", "<Plug>(coc-funcobj-i)", opts) |
|
keyset("x", "af", "<Plug>(coc-funcobj-a)", opts) |
|
keyset("o", "af", "<Plug>(coc-funcobj-a)", opts) |
|
keyset("x", "ic", "<Plug>(coc-classobj-i)", opts) |
|
keyset("o", "ic", "<Plug>(coc-classobj-i)", opts) |
|
keyset("x", "ac", "<Plug>(coc-classobj-a)", opts) |
|
keyset("o", "ac", "<Plug>(coc-classobj-a)", opts) |
|
|
|
|
|
-- Remap <C-f> and <C-b> to scroll float windows/popups |
|
---@diagnostic disable-next-line: redefined-local |
|
local opts = {silent = true, nowait = true, expr = true} |
|
keyset("n", "<C-f>", 'coc#float#has_scroll() ? coc#float#scroll(1) : "<C-f>"', opts) |
|
keyset("n", "<C-b>", 'coc#float#has_scroll() ? coc#float#scroll(0) : "<C-b>"', opts) |
|
keyset("i", "<C-f>", |
|
'coc#float#has_scroll() ? "<c-r>=coc#float#scroll(1)<cr>" : "<Right>"', opts) |
|
keyset("i", "<C-b>", |
|
'coc#float#has_scroll() ? "<c-r>=coc#float#scroll(0)<cr>" : "<Left>"', opts) |
|
keyset("v", "<C-f>", 'coc#float#has_scroll() ? coc#float#scroll(1) : "<C-f>"', opts) |
|
keyset("v", "<C-b>", 'coc#float#has_scroll() ? coc#float#scroll(0) : "<C-b>"', opts) |
|
|
|
|
|
-- Use CTRL-S for selections ranges |
|
-- Requires 'textDocument/selectionRange' support of language server |
|
keyset("n", "<C-s>", "<Plug>(coc-range-select)", {silent = true}) |
|
keyset("x", "<C-s>", "<Plug>(coc-range-select)", {silent = true}) |
|
|
|
|
|
-- Add `:Format` command to format current buffer |
|
vim.api.nvim_create_user_command("Format", "call CocAction('format')", {}) |
|
|
|
-- " Add `:Fold` command to fold current buffer |
|
vim.api.nvim_create_user_command("Fold", "call CocAction('fold', <f-args>)", {nargs = '?'}) |
|
|
|
-- Add `:OR` command for organize imports of the current buffer |
|
vim.api.nvim_create_user_command("OR", "call CocActionAsync('runCommand', 'editor.action.organizeImport')", {}) |
|
|
|
-- Add (Neo)Vim's native statusline support |
|
-- NOTE: Please see `:h coc-status` for integrations with external plugins that |
|
-- provide custom statusline: lightline.vim, vim-airline |
|
vim.opt.statusline:prepend("%{coc#status()}%{get(b:,'coc_current_function','')}") |
|
|
|
-- Mappings for CoCList |
|
-- code actions and coc stuff |
|
---@diagnostic disable-next-line: redefined-local |
|
local opts = {silent = true, nowait = true} |
|
-- Show all diagnostics |
|
keyset("n", "<space>a", ":<C-u>CocList diagnostics<cr>", opts) |
|
-- Manage extensions |
|
keyset("n", "<space>e", ":<C-u>CocList extensions<cr>", opts) |
|
-- Show commands |
|
keyset("n", "<space>c", ":<C-u>CocList commands<cr>", opts) |
|
-- Find symbol of current document |
|
keyset("n", "<space>o", ":<C-u>CocList outline<cr>", opts) |
|
-- Search workspace symbols |
|
keyset("n", "<space>s", ":<C-u>CocList -I symbols<cr>", opts) |
|
-- Do default action for next item |
|
keyset("n", "<space>j", ":<C-u>CocNext<cr>", opts) |
|
-- Do default action for previous item |
|
keyset("n", "<space>k", ":<C-u>CocPrev<cr>", opts) |
|
-- Resume latest coc list |
|
keyset("n", "<space>p", ":<C-u>CocListResume<cr>", opts) |
|
|
|
|
|
-- When started with `-p $DIR` (e.g. NeoVIde), set $DIR as CWD |
|
vim.api.nvim_create_autocmd('VimEnter', { |
|
desc = 'cd to passed $PWD when vim starts.', |
|
callback = function() |
|
local args = vim.v.argv |
|
for i = 1, #args - 1 do |
|
if args[i] == "-p" then |
|
local dir = args[i + 1] |
|
local stat = vim.loop.fs_stat(dir) |
|
if stat and stat.type == "directory" then |
|
vim.cmd("cd " .. vim.fn.fnameescape(dir)) |
|
vim.g.session_loaded = false |
|
require("auto-session").setup({ |
|
log_level = 'info', |
|
auto_session_enable_last_session = false, |
|
auto_session_enabled = true, |
|
auto_save_enabled = true, |
|
auto_restore_enabled = true, |
|
pre_save_cmds = { "tabdo NvimTreeClose" }, |
|
post_restore_cmds = { |
|
function() |
|
vim.g.session_loaded = true |
|
end |
|
}, |
|
}) |
|
require("neo-tree").setup({ |
|
sources = { "filesystem", "git_status", "buffers" }, |
|
hide_hidden = false, |
|
hide_dotfiles = false, |
|
hide_gitignored = false, |
|
filesystem = { |
|
follow_current_file = { enabled = true }, |
|
}, |
|
}) |
|
|
|
vim.schedule(function() |
|
if vim.g.session_loaded then return end |
|
|
|
-- Move to main editing window (right side) |
|
vim.cmd("wincmd l") |
|
vim.cmd("enew") -- Empty buffer |
|
|
|
-- Open terminal in horizontal split at bottom |
|
vim.cmd("belowright split | terminal") |
|
vim.cmd("resize 10") -- Set terminal height |
|
|
|
-- Focus back to editing buffer |
|
vim.cmd("wincmd k") |
|
end) |
|
return |
|
end |
|
end |
|
end |
|
end, |
|
}) |
|
vim.keymap.set('n', '<D-p>', require('telescope.builtin').find_files, { noremap = true, silent = true }) |
|
vim.keymap.set('n', '<D-S-p>', require('telescope.builtin').commands, {}) |
|
vim.keymap.set('n', '<Leader>gg', function() require('neogit').open({ kind = "floating" }) end) |
|
vim.keymap.set('n', '<Leader>b', function() vim.cmd("CocCommand git.showCommit") end) |
|
|
|
require('nvim-treesitter.configs').setup({ |
|
sync_install = false, |
|
auto_install = false, |
|
highlight = { |
|
enable = true, |
|
-- Setting this to true will run `:h syntax` and tree-sitter at the same time. |
|
-- Set this to `true` if you depend on 'syntax' being enabled (like for indentation). |
|
-- Using this option may slow down your editor, and you may see some duplicate highlights. |
|
-- Instead of true it can also be a list of languages |
|
additional_vim_regex_highlighting = false, |
|
}, |
|
}) |
|
vim.cmd.colorscheme("catppuccin") |
|
|
|
local function copy_relative_path() |
|
local file_path = vim.fn.expand("%:p") |
|
file_path = file_path:gsub(vim.fn.getcwd(), ""):gsub("^/", "") |
|
-- Copy to clipboard |
|
vim.fn.setreg("+", file_path) |
|
print("Relative path copied to clipboard: " .. file_path) |
|
end |
|
|
|
-- Get the GitHub remote URL |
|
local function copy_github_permalink() |
|
-- Get the current SHA |
|
local SHA = vim.fn.system("git rev-parse HEAD 2>/dev/null | tr -d '\n'") |
|
if SHA == "" then |
|
print("Not a Git repository, was not able to get the current SHA.") |
|
return |
|
end |
|
|
|
local git_url = vim.fn.system("git config --get remote.upstream.url 2>/dev/null | tr -d '\n'") |
|
if git_url == "" then |
|
git_url = vim.fn.system("git config --get remote.origin.url 2>/dev/null | tr -d '\n'") |
|
end |
|
|
|
-- Convert [email protected]:user/repo.git to https://github.com/user/repo |
|
git_url = git_url:gsub("[email protected]:", "https://github.com/") |
|
git_url = git_url:gsub("%.git$", "") |
|
|
|
|
|
-- Get the current file path relative to the repo root |
|
local file_path = vim.fn.expand("%:p") |
|
local repo_root = vim.fn.system("git rev-parse --show-toplevel 2>/dev/null | tr -d '\n'") |
|
if repo_root == "" then |
|
print("Not a Git repository, was not able to find the root folder.") |
|
return |
|
end |
|
file_path = file_path:gsub(repo_root, ""):gsub("^/", "") |
|
|
|
-- Get line number(s) |
|
local line1, line2 |
|
if vim.fn.mode() == "v" or vim.fn.mode() == "V" or vim.fn.mode() == "\22" then |
|
-- Visual mode: get start and end lines |
|
local pos1 = vim.fn.getpos("'<") |
|
local pos2 = vim.fn.getpos("'>") |
|
line1 = pos1[2] |
|
line2 = pos2[2] |
|
else |
|
-- Normal mode: just current line |
|
line1 = vim.fn.line(".") |
|
line2 = line1 |
|
end |
|
|
|
-- Construct the URL |
|
local url |
|
if line1 == line2 then |
|
url = string.format("%s/blob/%s/%s#L%d", git_url, SHA, file_path, line1) |
|
else |
|
url = string.format("%s/blob/%s/%s#L%d-L%d", git_url, SHA, file_path, line1, line2) |
|
end |
|
|
|
-- Copy to clipboard |
|
vim.fn.setreg("+", url) |
|
print("GitHub permalink copied to clipboard: " .. url) |
|
end |
|
|
|
vim.keymap.set({'n', 'v'}, vim.g.neovide and '<D-S-c>' or '<leader>pc', copy_github_permalink, {desc = "Copy GitHub permalink"}) |
|
vim.keymap.set({'n', 'v'}, vim.g.neovide and '<D-S-x>' or '<leader>pc', copy_relative_path, {desc = "Copy GitHub permalink"}) |
|
|
|
local function toggle_or_focus_terminal() |
|
local cur_win = vim.api.nvim_get_current_win() |
|
local cur_buf = vim.api.nvim_win_get_buf(cur_win) |
|
local cur_buftype = vim.api.nvim_buf_get_option(cur_buf, 'buftype') |
|
|
|
if cur_buftype == 'terminal' then |
|
-- If we're currently in a terminal buffer, |
|
-- switch to the first normal (editing) buffer |
|
for i = 1, vim.fn.winnr('$') do |
|
local bufnr = vim.fn.winbufnr(i) |
|
local buftype = vim.api.nvim_buf_get_option(bufnr, 'buftype') |
|
if buftype == "" then -- normal buffer has empty 'buftype' |
|
vim.cmd(i .. 'wincmd w') |
|
return |
|
end |
|
end |
|
-- If no normal buffer found, just open a new empty buffer |
|
vim.cmd('enew') |
|
else |
|
-- Not currently in a terminal, so try to focus an existing terminal |
|
for i = 1, vim.fn.winnr('$') do |
|
local bufnr = vim.fn.winbufnr(i) |
|
local buftype = vim.api.nvim_buf_get_option(bufnr, 'buftype') |
|
if buftype == 'terminal' then |
|
vim.cmd(i .. 'wincmd w') |
|
return |
|
end |
|
end |
|
-- No terminal found, open a new one at the bottom |
|
vim.cmd('belowright split | terminal') |
|
vim.cmd('resize 10') |
|
end |
|
end |
|
|
|
vim.keymap.set('n', '<F1>', toggle_or_focus_terminal, { noremap = true, silent = true }) |
|
vim.keymap.set('t', '<F1>', toggle_or_focus_terminal, { noremap = true, silent = true }) |
|
|
|
if vim.g.neovide then |
|
vim.o.mouse = 'a' |
|
vim.g.neovide_fullscreen = true |
|
|
|
vim.keymap.set('n', '<D-s>', ':w<CR>') -- Save |
|
vim.keymap.set('v', '<D-c>', '"+y') -- Copy |
|
vim.keymap.set('n', '<D-v>', '"+P') -- Paste normal mode |
|
vim.keymap.set('v', '<D-v>', '"+P') -- Paste visual mode |
|
vim.keymap.set('c', '<D-v>', '<C-R>+') -- Paste command mode |
|
vim.keymap.set('i', '<D-v>', '<ESC>l"+Pli') -- Paste insert mode |
|
vim.keymap.set('n', '<C-Tab>', require('telescope.builtin').oldfiles, { noremap = true, silent = true }) |
|
vim.keymap.set('n', '<D-S-f>', require('telescope.builtin').live_grep, { noremap = true, silent = true }) |
|
vim.keymap.set('n', '<D-n>', function() vim.cmd("enew") end) |
|
|
|
vim.api.nvim_create_augroup("AutoSaveOnFocusLost", { clear = true }) |
|
vim.api.nvim_create_autocmd("FocusLost", { |
|
group = "AutoSaveOnFocusLost", |
|
command = "silent! wa", |
|
desc = "Save all buffers when focus is lost", |
|
}) |
|
else |
|
vim.o.mouse = '' |
|
end |