Last active
April 1, 2025 00:07
-
-
Save ehzawad/47a0f2559f53499e294d7fb4ba67a9ff to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- [email protected]; email me to say hi or if there are any questions | |
vim.g.mapleader = ' ' | |
vim.g.maplocalleader = ' ' | |
-- Install package manager | |
local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim' | |
if not 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) | |
-- NOTE: Here is where you install your plugins. | |
require('lazy').setup({ | |
-- NOTE: First, some plugins that don't require any configuration | |
'tpope/vim-repeat', | |
-- Detect tabstop and shiftwidth automatically | |
'tpope/vim-sleuth', | |
-- Official GitHub Copilot plugin (no integration needed) | |
'github/copilot.vim', | |
-- NOTE: This is where your plugins related to LSP can be installed. | |
-- The configuration is done below. Search for lspconfig to find it below. | |
{ | |
-- LSP Configuration & Plugins | |
'neovim/nvim-lspconfig', | |
dependencies = { | |
-- Automatically install LSPs to stdpath for neovim | |
{ 'williamboman/mason.nvim', config = true }, | |
'williamboman/mason-lspconfig.nvim', | |
-- Useful status updates for LSP | |
-- NOTE: `opts = {}` is the same as calling `require('fidget').setup({})` | |
-- notification on the buffer that the LSP is attached to | |
{ 'j-hui/fidget.nvim', opts = {} }, | |
}, | |
}, | |
-- Autocompletion plugins | |
{ | |
'hrsh7th/nvim-cmp', | |
dependencies = { | |
'hrsh7th/cmp-nvim-lsp', -- LSP source for nvim-cmp | |
'hrsh7th/cmp-buffer', -- Buffer source | |
'hrsh7th/cmp-path', -- Path source | |
'hrsh7th/cmp-cmdline', -- Command line source | |
'saadparwaiz1/cmp_luasnip', -- Snippets source | |
'L3MON4D3/LuaSnip', -- Snippet engine | |
}, | |
config = function() | |
local cmp = require('cmp') | |
local luasnip = require('luasnip') | |
cmp.setup({ | |
snippet = { | |
expand = function(args) | |
luasnip.lsp_expand(args.body) | |
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(), | |
['<CR>'] = cmp.mapping.confirm({ select = false }), -- Don't auto-select | |
['<Tab>'] = cmp.mapping(function(fallback) | |
if cmp.visible() then | |
cmp.select_next_item() | |
elseif luasnip.expand_or_jumpable() then | |
luasnip.expand_or_jump() | |
else | |
fallback() | |
end | |
end, { 'i', 's' }), | |
['<S-Tab>'] = cmp.mapping(function(fallback) | |
if cmp.visible() then | |
cmp.select_prev_item() | |
elseif luasnip.jumpable(-1) then | |
luasnip.jump(-1) | |
else | |
fallback() | |
end | |
end, { 'i', 's' }), | |
}), | |
sources = cmp.config.sources({ | |
-- Keep LSP suggestions but put them at a lower priority than Copilot | |
{ name = 'nvim_lsp', priority = 7 }, | |
{ name = 'luasnip', priority = 5 }, | |
}, { | |
{ name = 'buffer', priority = 3 }, | |
{ name = 'path', priority = 2 }, | |
}), | |
experimental = { | |
ghost_text = false, -- Disable ghost text as it conflicts with Copilot | |
} | |
}) | |
-- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore). | |
cmp.setup.cmdline({ '/', '?' }, { | |
mapping = cmp.mapping.preset.cmdline(), | |
sources = { | |
{ name = 'buffer' } | |
} | |
}) | |
-- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore). | |
cmp.setup.cmdline(':', { | |
mapping = cmp.mapping.preset.cmdline(), | |
sources = cmp.config.sources({ | |
{ name = 'path' } | |
}, { | |
{ name = 'cmdline' } | |
}) | |
}) | |
end | |
}, | |
-- Lspsaga for enhanced LSP UI and experience | |
{ | |
'nvimdev/lspsaga.nvim', | |
event = 'LspAttach', | |
config = function() | |
require('lspsaga').setup({ | |
-- Default configuration | |
ui = { | |
border = 'rounded', | |
devicon = true, | |
}, | |
symbol_in_winbar = { | |
enable = true, | |
separator = ' › ', | |
hide_keyword = false, | |
show_file = true, | |
folder_level = 1, | |
color_mode = true, | |
delay = 300, | |
}, | |
lightbulb = { | |
enable = true, | |
sign = true, | |
virtual_text = true, | |
debounce = 10, | |
sign_priority = 40, | |
}, | |
}) | |
end, | |
dependencies = { | |
'nvim-treesitter/nvim-treesitter', -- Optional | |
'nvim-tree/nvim-web-devicons', -- Optional | |
} | |
}, | |
{ "catppuccin/nvim", name = "catppuccin", priority = 1000 }, | |
{ | |
'stevearc/oil.nvim', | |
---@module 'oil' | |
---@type oil.SetupOpts | |
opts = {}, | |
-- Optional dependencies | |
dependencies = { { "echasnovski/mini.icons", opts = {} } }, | |
-- dependencies = { "nvim-tree/nvim-web-devicons" }, -- use if you prefer nvim-web-devicons | |
-- Lazy loading is not recommended because it is very tricky to make it work correctly in all situations. | |
lazy = false, | |
}, | |
-- Useful plugin to show you pending keybinds. | |
{ | |
-- Adds git releated signs to the gutter, as well as utilities for managing changes | |
'lewis6991/gitsigns.nvim', | |
opts = { | |
-- See `:help gitsigns.txt` | |
signs = { | |
add = { text = '+' }, | |
change = { text = '~' }, | |
delete = { text = '_' }, | |
topdelete = { text = '‾' }, | |
changedelete = { text = '~' }, | |
}, | |
on_attach = function(bufnr) | |
vim.keymap.set('n', '<leader>gp', require('gitsigns').prev_hunk, | |
{ buffer = bufnr, desc = '[G]o to [P]revious Hunk' }) | |
vim.keymap.set('n', '<leader>gn', require('gitsigns').next_hunk, { buffer = bufnr, desc = '[G]o to [N]ext Hunk' }) | |
vim.keymap.set('n', '<leader>ph', require('gitsigns').preview_hunk, { buffer = bufnr, desc = '[P]review [H]unk' }) | |
end, | |
}, | |
}, | |
{ | |
-- Set lualine as statusline | |
'nvim-lualine/lualine.nvim', | |
-- See `:help lualine.txt` | |
opts = { | |
options = { | |
icons_enabled = false, | |
-- theme = 'onedark', | |
component_separators = '|', | |
section_separators = '', | |
}, | |
}, | |
}, | |
{ | |
-- Add indentation guides even on blank lines | |
'lukas-reineke/indent-blankline.nvim', | |
main = 'ibl', | |
opts = { | |
}, | |
}, | |
-- "gc" to comment visual regions/lines | |
{ 'numToStr/Comment.nvim', opts = {} }, | |
-- Fuzzy Finder (files, lsp, etc) | |
{ 'nvim-telescope/telescope.nvim', branch = '0.1.x', dependencies = { 'nvim-lua/plenary.nvim' } }, | |
-- Fuzzy Finder Algorithm which requires local dependencies to be built. | |
-- Only load if `make` is available. Make sure you have the system | |
-- requirements installed. | |
{ | |
'nvim-telescope/telescope-fzf-native.nvim', | |
-- NOTE: If you are having trouble with this installation, | |
-- refer to the README for telescope-fzf-native for more instructions. | |
build = 'make', | |
cond = function() | |
return vim.fn.executable 'make' == 1 | |
end, | |
}, | |
{ | |
-- Highlight, edit, and navigate code | |
'nvim-treesitter/nvim-treesitter', | |
dependencies = { | |
'nvim-treesitter/nvim-treesitter-textobjects', | |
}, | |
build = ':TSUpdate', | |
}, | |
}, {}) | |
-- [[ Setting options ]] | |
-- See `:help vim.o` | |
-- NOTE: You can change these options as you wish! | |
-- Set highlight on search | |
vim.o.hlsearch = false | |
-- Make line numbers default | |
vim.wo.number = true | |
-- Enable mouse mode | |
vim.o.mouse = 'a' | |
-- Enable break indent | |
vim.o.breakindent = true | |
-- Save undo history | |
vim.o.undofile = true | |
-- Case-insensitive searching UNLESS \C or capital in search | |
vim.o.ignorecase = true | |
vim.o.smartcase = true | |
-- Keep signcolumn on by default | |
vim.wo.signcolumn = 'yes' | |
-- Decrease update time | |
-- vim.o.updatetime = 250 | |
vim.o.timeoutlen = 1000 | |
-- Set completeopt to have a better completion experience for built-in LSP | |
vim.o.completeopt = 'menuone,noselect' | |
-- NOTE: You should make sure your terminal supports this | |
vim.o.termguicolors = true | |
-- [[ Basic Keymaps ]] | |
-- Keymaps for better default experience | |
-- See `:help vim.keymap.set()` vim.keymap.set({ 'n', 'v' }, '<Space>', '<Nop>', { silent = true }) | |
-- Remap for dealing with word wrap | |
vim.keymap.set('n', 'k', "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true }) | |
vim.keymap.set('n', 'j', "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true }) | |
-- [[ Highlight on yank ]] | |
-- See `:help vim.highlight.on_yank()` | |
local highlight_group = vim.api.nvim_create_augroup('YankHighlight', { clear = true }) | |
vim.api.nvim_create_autocmd('TextYankPost', { | |
callback = function() | |
vim.highlight.on_yank() | |
end, | |
group = highlight_group, | |
pattern = '*', | |
}) | |
-- | |
-- | |
-- Enable telescope fzf native, if installed | |
pcall(require('telescope').load_extension, 'fzf') | |
-- | |
-- -- See `:help telescope.builtin` for more. Try to stick with official docs or vim internal help "ALMOST ALWAYS" | |
-- [[ Configure Treesitter ]] | |
-- See `:help nvim-treesitter` | |
require('nvim-treesitter.configs').setup { | |
-- Add languages to be installed here that you want installed for treesitter | |
ensure_installed = { 'c', 'cpp', 'go', 'lua', 'python', 'rust', 'tsx', 'typescript', 'vimdoc', 'vim' }, | |
-- Autoinstall languages that are not installed. Defaults to false (but you can change for yourself!) | |
-- auto_install = false, | |
auto_install = true, | |
highlight = { enable = true }, | |
indent = { enable = true }, | |
incremental_selection = { | |
enable = true, | |
keymaps = { | |
init_selection = '<c-space>', | |
node_incremental = '<c-space>', | |
scope_incremental = '<leader>cs', | |
node_decremental = '<M-space>', | |
}, | |
}, | |
textobjects = { | |
select = { | |
enable = true, | |
lookahead = true, -- Automatically jump forward to textobj, similar to targets.vim | |
keymaps = { | |
-- You can use the capture groups defined in textobjects.scm | |
['aa'] = '@parameter.outer', | |
['ia'] = '@parameter.inner', | |
['af'] = '@function.outer', | |
['if'] = '@function.inner', | |
['ac'] = '@class.outer', | |
['ic'] = '@class.inner', | |
}, | |
}, | |
move = { | |
enable = true, | |
set_jumps = true, -- whether to set jumps in the jumplist | |
goto_next_start = { | |
[']m'] = '@function.outer', | |
[']]'] = '@class.outer', | |
}, | |
goto_next_end = { | |
[']M'] = '@function.outer', | |
[']['] = '@class.outer', | |
}, | |
goto_previous_start = { | |
['[m'] = '@function.outer', | |
['[['] = '@class.outer', | |
}, | |
goto_previous_end = { | |
['[M'] = '@function.outer', | |
['[]'] = '@class.outer', | |
}, | |
}, | |
swap = { | |
enable = true, | |
swap_next = { | |
['<leader>a'] = '@parameter.inner', | |
}, | |
swap_previous = { | |
['<leader>A'] = '@parameter.inner', | |
}, | |
}, | |
}, | |
} | |
-- [[ Configure LSP ]] | |
-- This function gets run when an LSP connects to a particular buffer. | |
local on_attach = function(client, bufnr) | |
-- NOTE: Remember that lua is a real programming language, and as such it is possible | |
-- to define small helper and utility functions so you don't have to repeat yourself | |
-- many times. | |
-- | |
-- In this case, we create a function that lets us more easily define mappings specific | |
-- for LSP related items. It sets the mode, buffer and description for us each time. | |
local nmap = function(keys, func, desc) | |
if desc then | |
desc = 'LSP: ' .. desc | |
end | |
vim.keymap.set('n', keys, func, { buffer = bufnr, desc = desc }) | |
end | |
-- Use lspsaga for better UI experience with LSP | |
-- Replace basic lsp functionalities with lspsaga enhanced versions | |
-- Rename with lspsaga | |
nmap('<leader>rn', '<cmd>Lspsaga rename<CR>', '[R]e[n]ame') | |
-- Code actions with lspsaga | |
nmap('<leader>ca', '<cmd>Lspsaga code_action<CR>', '[C]ode [A]ction') | |
-- LSP definitions | |
nmap('gd', '<cmd>Lspsaga goto_definition<CR>', '[G]oto [D]efinition') | |
nmap('gr', require('telescope.builtin').lsp_references, '[G]oto [R]eferences') | |
nmap('gI', '<cmd>Lspsaga finder imp<CR>', '[G]oto [I]mplementation') | |
nmap('<leader>D', '<cmd>Lspsaga peek_type_definition<CR>', 'Type [D]efinition') | |
nmap('<leader>ds', require('telescope.builtin').lsp_document_symbols, '[D]ocument [S]ymbols') | |
nmap('<leader>ws', require('telescope.builtin').lsp_dynamic_workspace_symbols, '[W]orkspace [S]ymbols') | |
-- Hover documentation with lspsaga | |
nmap('K', '<cmd>Lspsaga hover_doc<CR>', 'Hover Documentation') | |
nmap('<C-k>', vim.lsp.buf.signature_help, 'Signature Documentation') | |
-- Lesser used LSP functionality | |
nmap('gD', '<cmd>Lspsaga goto_definition<CR>', '[G]oto [D]eclaration') | |
nmap('<leader>wa', vim.lsp.buf.add_workspace_folder, '[W]orkspace [A]dd Folder') | |
nmap('<leader>wr', vim.lsp.buf.remove_workspace_folder, '[W]orkspace [R]emove Folder') | |
nmap('<leader>wl', function() | |
-- Use updated API | |
if vim.lsp.buf.list_workspace_folders then | |
print(vim.inspect(vim.lsp.buf.list_workspace_folders())) | |
else | |
print("list_workspace_folders not available in this Neovim version") | |
end | |
end, '[W]orkspace [L]ist Folders') | |
-- Diagnostic navigation with lspsaga | |
nmap('[e', '<cmd>Lspsaga diagnostic_jump_prev<CR>', 'Previous Diagnostic') | |
nmap(']e', '<cmd>Lspsaga diagnostic_jump_next<CR>', 'Next Diagnostic') | |
nmap('<leader>e', '<cmd>Lspsaga show_cursor_diagnostics<CR>', 'Show cursor diagnostics') | |
-- Create a command `:Format` local to the LSP buffer | |
vim.api.nvim_buf_create_user_command(bufnr, 'Format', function(_) | |
vim.lsp.buf.format() | |
end, { desc = 'Format current buffer with LSP' }) | |
-- Set up manual completion shortcut (compatible with Neovim 0.11.0) | |
vim.keymap.set('i', '<C-Space>', function() | |
-- Trigger omnifunc completion via keypress simulation | |
vim.fn.feedkeys(vim.api.nvim_replace_termcodes('<C-x><C-o>', true, true, true)) | |
end, { buffer = bufnr, desc = 'Manual LSP completion' }) | |
end | |
-- Enable the following language servers | |
-- Feel free to add/remove any LSPs that you want here. They will automatically be installed. | |
-- | |
-- Add any additional override configuration in the following tables. They will be passed to | |
-- the `settings` field of the server config. You must look up that documentation yourself. | |
-- | |
-- If you want to override the default filetypes that your language server will attach to you can | |
-- define the property 'filetypes' to the map in question. | |
local servers = { | |
-- clangd = {}, | |
-- gopls = {}, | |
pyright = {}, -- Python LSP enabled | |
-- rust_analyzer = {}, | |
-- tsserver = {}, | |
-- html = { filetypes = { 'html', 'twig', 'hbs'} }, | |
lua_ls = { | |
Lua = { | |
workspace = { checkThirdParty = false }, | |
telemetry = { enable = false }, | |
}, | |
}, | |
} | |
-- Setup nvim-cmp capabilities for LSP | |
local has_cmp, cmp_nvim_lsp = pcall(require, 'cmp_nvim_lsp') | |
local capabilities | |
-- Set up proper capabilities if nvim-cmp is available | |
if has_cmp then | |
capabilities = cmp_nvim_lsp.default_capabilities() | |
else | |
-- Fallback to basic capabilities | |
capabilities = vim.lsp.protocol.make_client_capabilities() | |
capabilities.textDocument.completion.completionItem.snippetSupport = true | |
capabilities.textDocument.completion.completionItem.resolveSupport = { | |
properties = { | |
'documentation', | |
'detail', | |
'additionalTextEdits', | |
} | |
} | |
end | |
-- Configure Copilot.vim | |
vim.g.copilot_no_tab_map = true | |
vim.g.copilot_assume_mapped = true | |
vim.g.copilot_tab_fallback = "" | |
-- Set up keybindings for Copilot | |
vim.api.nvim_set_keymap('i', '<M-l>', 'copilot#Accept("\\<CR>")', { expr = true, silent = true }) | |
vim.api.nvim_set_keymap('i', '<M-w>', '<Plug>(copilot-accept-word)', {}) | |
vim.api.nvim_set_keymap('i', '<M-]>', '<Plug>(copilot-next)', {}) | |
vim.api.nvim_set_keymap('i', '<M-[>', '<Plug>(copilot-previous)', {}) | |
-- We no longer need the omnifunc setup since nvim-cmp will handle completions | |
-- But we'll keep it as a fallback for filetypes that might not have LSP | |
vim.api.nvim_create_autocmd("FileType", { | |
pattern = {"lua", "python", "rust", "c", "cpp", "javascript", "typescript"}, | |
callback = function() | |
vim.bo.omnifunc = "v:lua.vim.lsp.omnifunc" | |
end | |
}) | |
-- Ensure the servers above are installed | |
local mason_lspconfig = require 'mason-lspconfig' | |
mason_lspconfig.setup { | |
ensure_installed = vim.tbl_keys(servers), | |
} | |
-- Standard LSP setup without external completion engines | |
mason_lspconfig.setup_handlers { | |
function(server_name) | |
require('lspconfig')[server_name].setup { | |
capabilities = capabilities, | |
on_attach = on_attach, | |
settings = servers[server_name], | |
filetypes = (servers[server_name] or {}).filetypes, | |
} | |
end | |
} | |
-- LSP diagnostic settings - default to disabled on startup | |
vim.diagnostic.config({ | |
virtual_text = false, | |
signs = false, | |
underline = true, | |
update_in_insert = false, | |
}) | |
-- Add diagnostic command to check completion status | |
vim.api.nvim_create_user_command('CheckLsp', function() | |
local status = {} | |
-- Check Copilot status - CORRECT WAY to call function with # in name | |
local copilot_enabled = vim.fn.exists('*copilot#Enabled') == 1 and vim.fn['copilot#Enabled']() == 1 | |
table.insert(status, "Copilot enabled: " .. tostring(copilot_enabled)) | |
-- Check LSP clients (using the non-deprecated API) | |
local clients = {} | |
-- Use the new API if available, fall back to old API for compatibility | |
if vim.lsp.get_clients then | |
clients = vim.lsp.get_clients({ bufnr = 0 }) | |
else | |
clients = vim.lsp.get_active_clients({ bufnr = 0 }) | |
end | |
if #clients == 0 then | |
table.insert(status, "No LSP clients attached to this buffer") | |
else | |
table.insert(status, "LSP clients:") | |
for _, client in ipairs(clients) do | |
table.insert(status, "- " .. client.name) | |
end | |
end | |
for _, line in ipairs(status) do | |
print(line) | |
end | |
end, {}) | |
-- Setup Pilott toggle command with pure LSP and Copilot | |
vim.g.copilot_mode = "enabled" -- Default to having Copilot on | |
vim.api.nvim_create_user_command('Pilott', function() | |
if vim.g.copilot_mode == "enabled" then | |
-- Turn off Copilot | |
vim.g.copilot_mode = "disabled" | |
vim.cmd("Copilot disable") | |
print("Copilot disabled - using only LSP completion") | |
else | |
-- Turn on Copilot | |
vim.g.copilot_mode = "enabled" | |
vim.cmd("Copilot enable") | |
print("Copilot enabled") | |
end | |
end, {}) | |
-- Command to toggle both virtual text and sign column indicators | |
vim.api.nvim_create_user_command('Togglediagnostics', function() | |
local virtual_text_enabled = false | |
virtual_text_enabled = not virtual_text_enabled | |
if virtual_text_enabled then | |
-- Enable both virtual text and sign column | |
vim.diagnostic.config({ | |
virtual_text = { | |
spacing = 4, | |
prefix = "■", -- Use a custom prefix | |
format = function(diagnostic) | |
-- Format message to be more concise | |
local message = diagnostic.message | |
if #message > 50 then | |
message = message:sub(1, 47) .. "..." | |
end | |
return message | |
end, | |
}, | |
signs = { | |
priority = 20, | |
text = { | |
[vim.diagnostic.severity.ERROR] = 'E', | |
[vim.diagnostic.severity.WARN] = 'W', | |
[vim.diagnostic.severity.INFO] = 'I', | |
[vim.diagnostic.severity.HINT] = 'H', | |
}, | |
} | |
}) | |
-- Make sure sign column is visible | |
vim.opt.signcolumn = "yes" | |
print("Diagnostic indicators enabled (virtual text and sign column)") | |
else | |
-- Disable both virtual text and sign column | |
vim.diagnostic.config({ | |
virtual_text = false, | |
signs = false -- Disable diagnostic signs completely | |
}) | |
-- Check if we can hide the sign column (only if no other features need it) | |
local hide_sign_column = true | |
-- Keep sign column if git signs or other features are active | |
-- Use proper Lua syntax for accessing Vim functions | |
if vim.fn.exists('*gitsigns#get_hunks') == 1 then | |
-- Use square bracket notation for functions with special characters | |
local hunks = vim.fn['gitsigns#get_hunks']() | |
if hunks and #hunks > 0 then | |
hide_sign_column = false | |
end | |
end | |
-- Try using the Lua API directly if available | |
local gs_ok, gs = pcall(require, 'gitsigns') | |
if gs_ok and gs.get_hunks and gs.get_hunks() then | |
hide_sign_column = false | |
end | |
-- Set sign column based on our decision | |
if hide_sign_column then | |
vim.opt.signcolumn = "no" | |
end | |
print("Diagnostic indicators disabled (virtual text and sign column)") | |
end | |
end, {}) | |
-- Create an autocmd to disable diagnostics on startup | |
vim.api.nvim_create_autocmd("VimEnter", { | |
callback = function() | |
-- Disable virtual text | |
vim.diagnostic.config({ virtual_text = false, signs = false }) | |
-- Clear any existing diagnostics - use namespace-safe method | |
if vim.diagnostic.get_namespaces then | |
for _, namespace in ipairs(vim.diagnostic.get_namespaces()) do | |
vim.diagnostic.reset(namespace) | |
end | |
else | |
-- Fallback for older Neovim versions | |
vim.diagnostic.reset() | |
end | |
-- Set our state variable to match | |
virtual_text_enabled = false | |
-- Hide sign column if it's safe to do so | |
local hide_sign_column = true | |
-- Check for git signs before hiding | |
local gs_ok, gs = pcall(require, 'gitsigns') | |
if gs_ok and gs.get_hunks then | |
-- Use pcall to safely get hunks, as the API might change | |
local hunks_ok, hunks = pcall(function() return gs.get_hunks() end) | |
if hunks_ok and hunks and #hunks > 0 then | |
hide_sign_column = false | |
end | |
end | |
-- Only hide sign column if safe | |
if hide_sign_column then | |
vim.opt.signcolumn = "no" | |
end | |
end, | |
group = vim.api.nvim_create_augroup("DisableDiagnosticsOnStartup", { clear = true }), | |
desc = "Disable diagnostics when Neovim starts", | |
}) | |
-- Function to set colorscheme | |
function SetColorScheme() | |
vim.cmd('colorscheme catppuccin-mocha') | |
end | |
-- Call the function to set the colorscheme | |
SetColorScheme() | |
vim.cmd('set autoread') | |
vim.cmd('au SwapExists * let v:swapchoice = "e"') | |
-- restore cursor position | |
vim.api.nvim_create_autocmd({ "BufReadPost", "BufEnter" }, { | |
pattern = "*", | |
callback = function() | |
-- check if mark `"` exists and if it's within the range of the buffer | |
local mark = vim.fn.getpos('`"') | |
local line_count = vim.api.nvim_buf_line_count(0) | |
if mark[1] ~= -1 and mark[2] <= line_count then | |
-- if mark `"` is valid, move the cursor to its position and scroll the window | |
vim.api.nvim_exec('silent! normal! g`"zv', false) | |
end | |
end, | |
}) | |
vim.cmd[[autocmd InsertEnter * :set tabstop=2 shiftwidth=2 expandtab]] | |
-- Shift text in visual mode1 | |
vim.cmd([[ | |
let s:save_cpo = &cpo | |
set cpo&vim | |
let s:pv_active = 1 | |
function! PV_On () | |
let s:pv_active = 1 | |
endfunction | |
function! PV_Off () | |
let s:pv_active = 0 | |
endfunction | |
function PV_Toggle () | |
let s:pv_active = !s:pv_active | |
endfunction | |
" When shifting, retain selection over multiple shifts... | |
silent! xmap <unique><silent><expr> > <SID>ShiftKeepingSelection(">") | |
silent! xmap <unique><silent><expr> < <SID>ShiftKeepingSelection("<") | |
" Allow selection to persist through an undo... | |
silent! xnoremap <unique><silent> u <ESC>ugv | |
silent! xnoremap <unique><silent> <C-R> <ESC><C-R>gv | |
function! s:ShiftKeepingSelection(cmd) | |
set nosmartindent | |
" No-op if plugin not active, or tab expansions are off... | |
if !s:pv_active || !&expandtab | |
return a:cmd . ":set smartindent\<CR>" | |
" Visual and Visual Line modes... | |
elseif mode() =~ '[vV]' | |
return a:cmd . ":set smartindent\<CR>gv" | |
" Visual block mode... | |
else | |
" Work out the adjustment for the way we're shifting... | |
let b:_pv_shift_motion | |
\ = &shiftwidth . (a:cmd == '>' ? "\<RIGHT>" : "\<LEFT>") | |
" Return instructions to implement the shift and reset selection... | |
return a:cmd . ":set smartindent\<CR>uM" | |
endif | |
endfunction | |
let &cpo = s:save_cpo | |
]]) | |
vim.cmd([[ | |
" Speed up viewport scrolling | |
nnoremap <C-e> 3<C-e> | |
nnoremap <C-y> 3<C-y> | |
" Magically build interim directories if necessary | |
" thanks to Author: Damian Conway | |
function! AskQuit (msg, options, quit_option) | |
if confirm(a:msg, a:options) == a:quit_option | |
exit | |
endif | |
endfunction | |
function! EnsureDirExists () | |
let required_dir = expand("%:h") | |
if !isdirectory(required_dir) | |
call AskQuit("Parent directory '" . required_dir . "' doesn't exist.", | |
\ "&Create it\nor &Quit?", 2) | |
try | |
call mkdir( required_dir, 'p' ) | |
catch | |
call AskQuit("Can't create '" . required_dir . "'", | |
\ "&Quit\nor &Continue anyway?", 1) | |
endtry | |
endif | |
endfunction | |
augroup AutoMkdir | |
autocmd! | |
autocmd BufNewFile * :call EnsureDirExists() | |
augroup END | |
" python class | |
" " Damian Conway's Blink function | |
nnoremap <silent> n n:call HLNext(0.1)<cr> | |
nnoremap <silent> N N:call HLNext(0.1)<cr> | |
function! HLNext (blinktime) | |
let target_pat = '\c\%#'.@/ | |
let ring = matchadd('ErrorMsg', target_pat, 101) | |
redraw | |
exec 'sleep ' . float2nr(a:blinktime * 2000) . 'm' | |
call matchdelete(ring) | |
redraw | |
endfunction | |
" make the command mode less annoying | |
" Emacs(readline) binding is here | |
" start of line | |
cnoremap <C-A> <Home> | |
" back one character | |
cnoremap <C-B> <Left> | |
" delete character under cursor | |
cnoremap <C-D> <Del> | |
" end of line | |
cnoremap <C-E> <End> | |
" forward one character | |
cnoremap <C-F> <Right> | |
" recall newer command-line | |
cnoremap <C-N> <Down> | |
" recall previous (older) command-line | |
cnoremap <C-P> <Up> | |
" back one word | |
inoremap <expr> <C-B> getline('.')=~'^\s*$'&&col('.')>strlen(getline('.'))?"0\<Lt>C-D>\<Lt>Esc>kJs":"\<Lt>Left>" | |
" delete character under cursor | |
inoremap <expr> <C-D> col('.')>strlen(getline('.'))?"\<Lt>C-D>":"\<Lt>Del>" | |
" end of line | |
" forward one character | |
inoremap <expr> <C-F> col('.')>strlen(getline('.'))?"\<Lt>C-F>":"\<Lt>Right>" | |
" common type-mistakes | |
" prese space btw | |
ab teh the | |
" Highlight Matched Parenthesis | |
hi MatchParen ctermbg=gray guibg=lightgray | |
" Better JUMP upwards and downwards | |
inoremap <C-k> <C-g>k | |
" remember, I have remapped <C-j> VIM's default Behavior | |
inoremap <C-j> <C-g>j | |
nnoremap Y "+Y | |
nnoremap y "+yy | |
xnoremap Y "+Y | |
xnoremap y "+y | |
function! HighlightAllOfWord(...) | |
if exists("a:1") | |
au CursorMoved * silent! exe printf('match Search /\<%s\>/', expand('<cword>')) | |
endif | |
if a:0 < 1 | |
match none /\<%s\>/ | |
endif | |
endfunction | |
command! -nargs=? HighlightAllOfWord call HighlightAllOfWord(<f-args>) | |
vnoremap J :m '>+1<CR>gv=gv | |
vnoremap K :m '<-2<CR>gv=gv | |
" STEAL FROM reactJS creator MACVIM box | |
function! s:VSplitIntoNextTab() | |
"there is only one window | |
if tabpagenr('$') == 1 && winnr('$') == 1 | |
return | |
endif | |
"preparing new window | |
let l:tab_nr = tabpagenr('$') | |
let l:cur_buf = bufnr('%') | |
if tabpagenr() < tab_nr | |
close! | |
if l:tab_nr == tabpagenr('$') | |
tabnext | |
endif | |
vsp | |
else | |
close! | |
tabnew | |
endif | |
"opening current buffer in new window | |
exe "b".l:cur_buf | |
endfunc | |
function! s:VSplitIntoPrevTab() | |
"there is only one window | |
if tabpagenr('$') == 1 && winnr('$') == 1 | |
return | |
endif | |
"preparing new window | |
let l:tab_nr = tabpagenr('$') | |
let l:cur_buf = bufnr('%') | |
if tabpagenr() != 1 | |
close! | |
if l:tab_nr == tabpagenr('$') | |
tabprev | |
endif | |
vsp | |
else | |
close! | |
exe "0tabnew" | |
endif | |
"opening current buffer in new window | |
exe "b".l:cur_buf | |
endfunc | |
command! VSplitIntoPrevTab call s:VSplitIntoPrevTab() | |
command! VSplitIntoNextTab call s:VSplitIntoNextTab() | |
]]) | |
local vim = vim | |
function load_large_file_async(filename, chunk_size) | |
chunk_size = chunk_size or 8192 -- default chunk size | |
local cmd = string.format("dd if=%s bs=%d", filename, chunk_size) | |
-- Handler for each chunk of data | |
local on_data = function(_, data, _) | |
-- Process each chunk of data here | |
-- For example, you can append it to a buffer | |
end | |
-- Handler for the end of the job | |
local on_exit = function(_, exit_code, _) | |
if exit_code == 0 then | |
print("File loaded successfully") | |
else | |
print("Error loading file") | |
end | |
end | |
-- Create an asynchronous job to read the file in chunks | |
vim.fn.jobstart(cmd, { | |
on_stdout = on_data, | |
on_stderr = on_data, | |
on_exit = on_exit, | |
}) | |
end | |
local function python_symbols(opts) | |
opts = opts or {} | |
local bufnr = vim.api.nvim_get_current_buf() | |
-- Only process Python files | |
local file_extension = vim.fn.expand('%:e') | |
if file_extension ~= 'py' and file_extension ~= 'pyc' then | |
return | |
end | |
-- Get parser and tree | |
local parser = vim.treesitter.get_parser(bufnr, 'python') | |
local tree = parser:parse()[1] | |
local root = tree:root() | |
-- Collect all symbols | |
local symbols = {} | |
-- Simple query for basic symbols | |
local query = vim.treesitter.query.parse('python', [[ | |
(class_definition name: (identifier) @class) | |
(function_definition name: (identifier) @function) | |
(decorator (identifier) @decorator) | |
(assignment left: (identifier) @variable) | |
]]) | |
-- Get parent context | |
local function get_context(node) | |
local result = "Global" | |
local parent = node:parent() | |
while parent do | |
if parent:type() == "class_definition" then | |
for i = 0, parent:named_child_count() - 1 do | |
local child = parent:named_child(i) | |
if child:type() == "identifier" then | |
result = "Class: " .. vim.treesitter.get_node_text(child, bufnr) | |
break | |
end | |
end | |
end | |
parent = parent:parent() | |
end | |
return result | |
end | |
-- Capture nodes | |
local start_row, _, end_row, _ = root:range() | |
for id, node in query:iter_captures(root, bufnr, start_row, end_row) do | |
local name = vim.treesitter.get_node_text(node, bufnr) | |
local row, col = node:start() | |
local type_name = query.captures[id] | |
local context = get_context(node) | |
-- Add prefix to decorators | |
if type_name == "decorator" then | |
name = "@" .. name | |
end | |
table.insert(symbols, { | |
name = name, | |
row = row, | |
col = col, | |
type = type_name, | |
context = context | |
}) | |
end | |
-- Sort symbols | |
table.sort(symbols, function(a, b) | |
if a.type ~= b.type then | |
if a.type == "class" then return true end | |
if b.type == "class" then return false end | |
if a.type == "decorator" then return true end | |
if b.type == "decorator" then return false end | |
if a.type == "function" then return true end | |
if b.type == "function" then return false end | |
return false | |
else | |
return a.row < b.row | |
end | |
end) | |
-- Prepare display list | |
local display_symbols = {} | |
for _, symbol in ipairs(symbols) do | |
table.insert(display_symbols, { | |
value = symbol, | |
display = symbol.name .. " [" .. symbol.context .. "] (" .. symbol.type .. ")", | |
ordinal = symbol.name, | |
lnum = symbol.row + 1, | |
col = symbol.col + 1 | |
}) | |
end | |
-- Display in Telescope | |
require('telescope.pickers').new(opts, { | |
prompt_title = 'Python Symbols', | |
finder = require('telescope.finders').new_table({ | |
results = display_symbols, | |
entry_maker = function(entry) | |
return entry | |
end | |
}), | |
sorter = require('telescope.config').values.generic_sorter(opts), | |
attach_mappings = function(prompt_bufnr) | |
local actions = require('telescope.actions') | |
local action_state = require('telescope.actions.state') | |
actions.select_default:replace(function() | |
local selection = action_state.get_selected_entry() | |
actions.close(prompt_bufnr) | |
vim.api.nvim_win_set_cursor(0, {selection.lnum, selection.col - 1}) | |
vim.cmd("normal! zz") | |
end) | |
return true | |
end | |
}):find() | |
end | |
vim.api.nvim_create_user_command('PythonSymbols', function() | |
python_symbols() | |
end, {}) | |
local function capture_python_node(node_type, innermost_only) | |
local bufnr = vim.api.nvim_get_current_buf() | |
-- Only process Python files | |
local file_extension = vim.fn.expand('%:e') | |
if file_extension ~= 'py' and file_extension ~= 'pyc' then | |
vim.notify("Not a Python file", vim.log.levels.WARN) | |
return | |
end | |
-- Get current cursor position | |
local cursor_row, cursor_col = unpack(vim.api.nvim_win_get_cursor(0)) | |
cursor_row = cursor_row - 1 -- Convert to 0-indexed | |
-- Get parser and tree | |
local parser = vim.treesitter.get_parser(bufnr, 'python') | |
local tree = parser:parse()[1] | |
local root = tree:root() | |
-- Target node types | |
local target_type | |
if node_type == "class" then | |
target_type = "class_definition" | |
else | |
target_type = "function_definition" | |
end | |
-- Find the smallest node at cursor position | |
local node_at_cursor = root:named_descendant_for_range(cursor_row, cursor_col, cursor_row, cursor_col) | |
if not node_at_cursor then | |
vim.notify("No node found at cursor position", vim.log.levels.WARN) | |
return | |
end | |
-- Collect all nodes of the target type from cursor to root | |
local target_nodes = {} | |
local current_node = node_at_cursor | |
while current_node do | |
if current_node:type() == target_type then | |
table.insert(target_nodes, current_node) | |
end | |
current_node = current_node:parent() | |
end | |
if #target_nodes == 0 then | |
vim.notify("No " .. node_type .. " found at or containing cursor position", vim.log.levels.WARN) | |
return | |
end | |
-- Select the appropriate node based on the innermost_only flag | |
local target_node | |
if innermost_only then | |
-- Take the innermost (first found from cursor) | |
target_node = target_nodes[1] | |
else | |
-- Take the outermost (last found going up to root) | |
target_node = target_nodes[#target_nodes] | |
end | |
-- Get node range | |
local start_row, start_col, end_row, end_col = target_node:range() | |
-- Convert to 1-indexed for Vim and select in visual mode | |
vim.api.nvim_win_set_cursor(0, {start_row + 1, start_col}) | |
vim.cmd("normal! v") | |
vim.api.nvim_win_set_cursor(0, {end_row + 1, end_col}) | |
end | |
-- Register commands | |
vim.api.nvim_create_user_command('PythonCaptureInnerFunction', function() | |
capture_python_node("function", true) | |
end, {}) | |
vim.api.nvim_create_user_command('PythonCaptureInnerClass', function() | |
capture_python_node("class", true) | |
end, {}) | |
vim.api.nvim_create_user_command('PythonCaptureOuterFunction', function() | |
capture_python_node("function", false) | |
end, {}) | |
vim.api.nvim_create_user_command('PythonCaptureOuterClass', function() | |
capture_python_node("class", false) | |
end, {}) | |
-- Create key mappings for normal mode | |
vim.api.nvim_set_keymap('n', '<leader>vif', ':PythonCaptureInnerFunction<CR>', { noremap = true, silent = true }) | |
vim.api.nvim_set_keymap('n', '<leader>vic', ':PythonCaptureInnerClass<CR>', { noremap = true, silent = true }) | |
vim.api.nvim_set_keymap('n', '<leader>vof', ':PythonCaptureOuterFunction<CR>', { noremap = true, silent = true }) | |
vim.api.nvim_set_keymap('n', '<leader>voc', ':PythonCaptureOuterClass<CR>', { noremap = true, silent = true }) | |
-- Extremely minimal terminal configuration | |
-- No autocmds, no complex options, just basic commands that work | |
-- Horizontal terminal | |
vim.api.nvim_create_user_command('Termhorizontal', function(opts) | |
local size = opts.args ~= "" and opts.args or "15" | |
vim.cmd(size .. "split") | |
vim.cmd("terminal") | |
vim.cmd("startinsert") | |
end, {nargs = "?"}) | |
-- Vertical terminal | |
vim.api.nvim_create_user_command('Termvertical', function(opts) | |
local size = opts.args ~= "" and opts.args or "80" | |
vim.cmd(size .. "vsplit") | |
vim.cmd("terminal") | |
vim.cmd("startinsert") | |
end, {nargs = "?"}) | |
-- Tab terminal | |
vim.api.nvim_create_user_command('Termnew', function() | |
vim.cmd("tabnew") | |
vim.cmd("terminal") | |
vim.cmd("startinsert") | |
end, {}) | |
-- Floating terminal | |
vim.api.nvim_create_user_command('Termfloat', function() | |
-- Calculate dimensions | |
local width = math.floor(vim.o.columns * 0.8) | |
local height = math.floor(vim.o.lines * 0.8) | |
local row = math.floor((vim.o.lines - height) / 2) | |
local col = math.floor((vim.o.columns - width) / 2) | |
-- Create empty buffer | |
local buf = vim.api.nvim_create_buf(false, true) | |
-- Create window | |
local win_opts = { | |
relative = "editor", | |
width = width, | |
height = height, | |
row = row, | |
col = col, | |
style = "minimal", | |
border = "rounded" | |
} | |
local win = vim.api.nvim_open_win(buf, true, win_opts) | |
-- Open terminal in buffer | |
vim.cmd("terminal") | |
vim.cmd("startinsert") | |
end, {}) | |
-- Alias Term to horizontal split | |
vim.api.nvim_create_user_command('Term', function(opts) | |
vim.cmd("Termhorizontal " .. opts.args) | |
end, {nargs = "?"}) | |
-- Simple terminal mode mappings (without autocmd) | |
vim.keymap.set('t', '<Esc>', '<C-\\><C-n>') | |
vim.keymap.set('t', '<C-h>', '<C-\\><C-n><C-w>h') | |
vim.keymap.set('t', '<C-j>', '<C-\\><C-n><C-w>j') | |
vim.keymap.set('t', '<C-k>', '<C-\\><C-n><C-w>k') | |
vim.keymap.set('t', '<C-l>', '<C-\\><C-n><C-w>l') | |
require("oil").setup({ | |
-- Oil will take over directory buffers (e.g. `vim .` or `:e src/`) | |
-- Set to false if you want some other plugin (e.g. netrw) to open when you edit directories. | |
default_file_explorer = true, | |
-- Id is automatically added at the beginning, and name at the end | |
-- See :help oil-columns | |
columns = { | |
"icon", | |
-- "permissions", | |
-- "size", | |
-- "mtime", | |
}, | |
-- Buffer-local options to use for oil buffers | |
buf_options = { | |
buflisted = false, | |
bufhidden = "hide", | |
}, | |
-- Window-local options to use for oil buffers | |
win_options = { | |
wrap = false, | |
signcolumn = "no", | |
cursorcolumn = false, | |
foldcolumn = "0", | |
spell = false, | |
list = false, | |
conceallevel = 3, | |
concealcursor = "nvic", | |
}, | |
-- Send deleted files to the trash instead of permanently deleting them (:help oil-trash) | |
delete_to_trash = false, | |
-- Skip the confirmation popup for simple operations (:help oil.skip_confirm_for_simple_edits) | |
skip_confirm_for_simple_edits = false, | |
-- Selecting a new/moved/renamed file or directory will prompt you to save changes first | |
-- (:help prompt_save_on_select_new_entry) | |
prompt_save_on_select_new_entry = true, | |
-- Oil will automatically delete hidden buffers after this delay | |
-- You can set the delay to false to disable cleanup entirely | |
-- Note that the cleanup process only starts when none of the oil buffers are currently displayed | |
cleanup_delay_ms = 2000, | |
lsp_file_methods = { | |
-- Enable or disable LSP file operations | |
enabled = true, | |
-- Time to wait for LSP file operations to complete before skipping | |
timeout_ms = 1000, | |
-- Set to true to autosave buffers that are updated with LSP willRenameFiles | |
-- Set to "unmodified" to only save unmodified buffers | |
autosave_changes = false, | |
}, | |
-- Constrain the cursor to the editable parts of the oil buffer | |
-- Set to `false` to disable, or "name" to keep it on the file names | |
constrain_cursor = "editable", | |
-- Set to true to watch the filesystem for changes and reload oil | |
watch_for_changes = false, | |
-- Keymaps in oil buffer. Can be any value that `vim.keymap.set` accepts OR a table of keymap | |
-- options with a `callback` (e.g. { callback = function() ... end, desc = "", mode = "n" }) | |
-- Additionally, if it is a string that matches "actions.<n>", | |
-- it will use the mapping at require("oil.actions").<n> | |
-- Set to `false` to remove a keymap | |
-- See :help oil-actions for a list of all available actions | |
keymaps = { | |
["g?"] = { "actions.show_help", mode = "n" }, | |
["<CR>"] = "actions.select", | |
["<C-s>"] = { "actions.select", opts = { vertical = true } }, | |
["<C-h>"] = { "actions.select", opts = { horizontal = true } }, | |
["<C-t>"] = { "actions.select", opts = { tab = true } }, | |
["<C-p>"] = "actions.preview", | |
["<C-c>"] = { "actions.close", mode = "n" }, | |
["<C-l>"] = "actions.refresh", | |
["-"] = { "actions.parent", mode = "n" }, | |
["_"] = { "actions.open_cwd", mode = "n" }, | |
["`"] = { "actions.cd", mode = "n" }, | |
["~"] = { "actions.cd", opts = { scope = "tab" }, mode = "n" }, | |
["gs"] = { "actions.change_sort", mode = "n" }, | |
["gx"] = "actions.open_external", | |
["g."] = { "actions.toggle_hidden", mode = "n" }, | |
["g\\"] = { "actions.toggle_trash", mode = "n" }, | |
}, | |
-- Set to false to disable all of the above keymaps | |
use_default_keymaps = true, | |
view_options = { | |
-- Show files and directories that start with "." | |
show_hidden = false, | |
-- This function defines what is considered a "hidden" file | |
is_hidden_file = function(name, bufnr) | |
local m = name:match("^%.") | |
return m ~= nil | |
end, | |
-- This function defines what will never be shown, even when `show_hidden` is set | |
is_always_hidden = function(name, bufnr) | |
return false | |
end, | |
-- Sort file names with numbers in a more intuitive order for humans. | |
-- Can be "fast", true, or false. "fast" will turn it off for large directories. | |
natural_order = "fast", | |
-- Sort file and directory names case insensitive | |
case_insensitive = false, | |
sort = { | |
-- sort order can be "asc" or "desc" | |
-- see :help oil-columns to see which columns are sortable | |
{ "type", "asc" }, | |
{ "name", "asc" }, | |
}, | |
-- Customize the highlight group for the file name | |
highlight_filename = function(entry, is_hidden, is_link_target, is_link_orphan) | |
return nil | |
end, | |
}, | |
-- Extra arguments to pass to SCP when moving/copying files over SSH | |
extra_scp_args = {}, | |
-- EXPERIMENTAL support for performing file operations with git | |
git = { | |
-- Return true to automatically git add/mv/rm files | |
add = function(path) | |
return false | |
end, | |
mv = function(src_path, dest_path) | |
return false | |
end, | |
rm = function(path) | |
return false | |
end, | |
}, | |
-- Configuration for the floating window in oil.open_float | |
float = { | |
-- Padding around the floating window | |
padding = 2, | |
-- max_width and max_height can be integers or a float between 0 and 1 (e.g. 0.4 for 40%) | |
max_width = 0, | |
max_height = 0, | |
border = "rounded", | |
win_options = { | |
winblend = 0, | |
}, | |
-- optionally override the oil buffers window title with custom function: fun(winid: integer): string | |
get_win_title = nil, | |
-- preview_split: Split direction: "auto", "left", "right", "above", "below". | |
preview_split = "auto", | |
-- This is the config that will be passed to nvim_open_win. | |
-- Change values here to customize the layout | |
override = function(conf) | |
return conf | |
end, | |
}, | |
-- Configuration for the file preview window | |
preview_win = { | |
-- Whether the preview window is automatically updated when the cursor is moved | |
update_on_cursor_moved = true, | |
-- How to open the preview window "load"|"scratch"|"fast_scratch" | |
preview_method = "fast_scratch", | |
-- A function that returns true to disable preview on a file e.g. to avoid lag | |
disable_preview = function(filename) | |
return false | |
end, | |
-- Window-local options to use for preview window buffers | |
win_options = {}, | |
}, | |
-- Configuration for the floating action confirmation window | |
confirmation = { | |
-- Width dimensions can be integers or a float between 0 and 1 (e.g. 0.4 for 40%) | |
-- min_width and max_width can be a single value or a list of mixed integer/float types. | |
-- max_width = {100, 0.8} means "the lesser of 100 columns or 80% of total" | |
max_width = 0.9, | |
-- min_width = {40, 0.4} means "the greater of 40 columns or 40% of total" | |
min_width = { 40, 0.4 }, | |
-- optionally define an integer/float for the exact width of the preview window | |
width = nil, | |
-- Height dimensions can be integers or a float between 0 and 1 (e.g. 0.4 for 40%) | |
-- min_height and max_height can be a single value or a list of mixed integer/float types. | |
-- max_height = {80, 0.9} means "the lesser of 80 columns or 90% of total" | |
max_height = 0.9, | |
-- min_height = {5, 0.1} means "the greater of 5 columns or 10% of total" | |
min_height = { 5, 0.1 }, | |
-- optionally define an integer/float for the exact height of the preview window | |
height = nil, | |
border = "rounded", | |
win_options = { | |
winblend = 0, | |
}, | |
}, | |
-- Configuration for the floating progress window | |
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, | |
}, | |
}, | |
-- Configuration for the floating SSH window | |
ssh = { | |
border = "rounded", | |
}, | |
-- Configuration for the floating keymaps help window | |
keymaps_help = { | |
border = "rounded", | |
}, | |
}) | |
-- Using Lua functions | |
local builtin = require('telescope.builtin') | |
vim.keymap.set('n', '<leader>ff', builtin.find_files, { desc = 'Telescope find files' }) | |
vim.keymap.set('n', '<leader>fg', builtin.live_grep, { desc = 'Telescope live grep' }) | |
vim.keymap.set('n', '<leader>fb', builtin.buffers, { desc = 'Telescope buffers' }) | |
vim.keymap.set('n', '<leader>fh', builtin.help_tags, { desc = 'Telescope help tags' }) | |
-- Treesitter folding with Lua | |
-- Later make a function to manage this, like wrap it inside a lua functions | |
-- Set foldmethod to 'expr' and foldexpr to the Lua PythonCaptureOuterFunction | |
-- Set global default foldmethod to 'manual' | |
vim.o.foldmethod = 'manual' | |
-- Define the toggle function | |
local function toggle_folding() | |
if vim.wo.foldmethod == 'manual' then | |
vim.wo.foldmethod = 'expr' | |
vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()' | |
print("Folding enabled with Treesitter") | |
else | |
vim.wo.foldmethod = 'manual' | |
print("Folding disabled") | |
end | |
end | |
-- Optionally, create a user command to call the function | |
vim.api.nvim_create_user_command('ToggleFolding', toggle_folding, {}) | |
-- Detect OS and configure clipboard | |
local function setup_clipboard() | |
local system = vim.loop.os_uname().sysname | |
if system == "Darwin" then | |
-- macOS - native clipboard should work automatically | |
vim.opt.clipboard = "unnamedplus" | |
return | |
end | |
-- For Linux, check if we're in SSH | |
local is_ssh = (vim.env.SSH_TTY ~= nil or vim.env.SSH_CLIENT ~= nil or vim.env.SSH_CONNECTION ~= nil) | |
if is_ssh then | |
-- Configure OSC52 for SSH sessions | |
vim.g.clipboard = 'osc52' | |
else | |
-- Check for X11 or Wayland | |
if vim.env.DISPLAY or vim.env.WAYLAND_DISPLAY then | |
-- GUI environment, let Neovim auto-detect (xclip, etc.) | |
vim.g.clipboard = nil | |
else | |
-- TTY environment, use OSC52 | |
vim.g.clipboard = 'osc52' | |
end | |
end | |
-- Use clipboard for all operations | |
vim.opt.clipboard = "unnamedplus" | |
end | |
setup_clipboard() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- [email protected]; email me to say hi or if there are any questions | |
vim.g.mapleader = ' ' | |
vim.g.maplocalleader = ' ' | |
-- Install package manager | |
local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim' | |
if not 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) | |
-- NOTE: Here is where you install your plugins. | |
require('lazy').setup({ | |
-- NOTE: First, some plugins that don't require any configuration | |
'tpope/vim-repeat', | |
-- Detect tabstop and shiftwidth automatically | |
'tpope/vim-sleuth', | |
-- Official GitHub Copilot plugin (no integration needed) | |
'github/copilot.vim', | |
-- NOTE: This is where your plugins related to LSP can be installed. | |
-- The configuration is done below. Search for lspconfig to find it below. | |
{ | |
-- LSP Configuration & Plugins | |
'neovim/nvim-lspconfig', | |
dependencies = { | |
-- Automatically install LSPs to stdpath for neovim | |
{ 'williamboman/mason.nvim', config = true }, | |
'williamboman/mason-lspconfig.nvim', | |
-- Useful status updates for LSP | |
-- NOTE: `opts = {}` is the same as calling `require('fidget').setup({})` | |
-- notification on the buffer that the LSP is attached to | |
{ 'j-hui/fidget.nvim', opts = {} }, | |
}, | |
}, | |
-- Autocompletion with blink.cmp | |
{ | |
'saghen/blink.cmp', | |
dependencies = { | |
'rafamadriz/friendly-snippets', | |
'onsails/lspkind.nvim', | |
}, | |
version = "1.*", | |
opts = { | |
appearance = { | |
nerd_font_variant = "mono", | |
}, | |
-- Enable cmdline mode explicitly | |
cmdline = { | |
enabled = true, | |
keymap = { | |
preset = 'cmdline', | |
['<Tab>'] = { 'show_and_insert', 'select_next' }, | |
['<S-Tab>'] = { 'show_and_insert', 'select_prev' }, | |
['<C-n>'] = { 'select_next', 'fallback' }, | |
['<C-p>'] = { 'select_prev', 'fallback' }, | |
['<CR>'] = { 'accept_and_enter', 'fallback' }, | |
}, | |
completion = { | |
-- Show the menu automatically for commands | |
menu = { auto_show = true }, | |
}, | |
sources = function() | |
local type = vim.fn.getcmdtype() | |
-- Search forward and backward | |
if type == '/' or type == '?' then return { 'buffer' } end | |
-- Commands - this is the important part for command completion | |
if type == ':' then return { 'cmdline' } end | |
return {} | |
end, | |
}, | |
completion = { | |
-- Enable ghost text (similar to your previous setting) | |
ghost_text = { enabled = false }, -- Disable ghost text to avoid conflicts with Copilot | |
-- Auto-show documentation | |
documentation = { | |
auto_show = true, | |
window = { border = "rounded" } | |
}, | |
list = { | |
selection = { | |
preselect = true, | |
auto_insert = false, -- Don't auto-select, matching your nvim-cmp setting | |
}, | |
}, | |
-- Menu appearance configuration | |
menu = { | |
border = "rounded", | |
draw = { | |
padding = 0, | |
columns = { | |
{ "kind_icon", gap = 1 }, | |
{ gap = 1, "label" }, | |
{ "kind", gap = 2 } | |
}, | |
components = { | |
kind_icon = { | |
text = function(ctx) | |
local kind = require("lspkind").symbol_map[ctx.kind] or "" | |
return " " .. kind .. " " | |
end, | |
highlight = function(ctx) | |
return "BlinkCmpKindIcon" .. ctx.kind | |
end, | |
}, | |
kind = { | |
text = function(ctx) | |
return " " .. ctx.kind .. " " | |
end, | |
}, | |
}, | |
}, | |
}, | |
-- Trigger behavior - show on trigger character | |
trigger = { | |
show_on_trigger_character = true, | |
}, | |
}, | |
-- Key mappings - adapting your previous mappings to blink.cmp's format | |
keymap = { | |
["<C-b>"] = { "scroll_documentation_up", "fallback" }, | |
["<C-f>"] = { "scroll_documentation_down", "fallback" }, | |
["<C-Space>"] = { "show", "show_documentation" }, | |
["<C-e>"] = { "hide", "fallback" }, | |
["<CR>"] = { "accept", "fallback" }, | |
["<Tab>"] = { | |
function(cmp) | |
return cmp.select_next() | |
end, | |
"fallback", | |
}, | |
["<S-Tab>"] = { | |
function(cmp) | |
return cmp.select_prev() | |
end, | |
"fallback", | |
}, | |
}, | |
-- Sources configuration with improved priority management | |
sources = { | |
default = { "lsp", "path", "snippets", "buffer" }, | |
-- Function to use when transforming the items before they're returned for all providers | |
transform_items = function(ctx, items) | |
-- Filter out less relevant completions when there are many options | |
if #items > 10 and ctx.trigger.initial_kind == 'keyword' then | |
-- Prioritize exact matches and deprioritize trivial suggestions when typing | |
return vim.tbl_filter(function(item) | |
-- Keep non-text items (functions, methods, etc) | |
if item.kind ~= require('blink.cmp.types').CompletionItemKind.Text then | |
return true | |
end | |
-- Filter out single character completions unless they're an exact match | |
if #item.label <= 1 and not (ctx.get_keyword() == item.label) then | |
return false | |
end | |
return true | |
end, items) | |
end | |
return items | |
end, | |
providers = { | |
lsp = { | |
name = "LSP", | |
score_offset = 10, -- Higher priority to ensure LSP comes first | |
-- Prevent LSP from falling back to buffer unless explicitly needed | |
fallbacks = {}, | |
-- Don't filter text items from LSP since they might be important symbols | |
}, | |
path = { | |
name = "Path", | |
score_offset = 5, | |
fallbacks = { "buffer" }, | |
}, | |
snippets = { | |
name = "Snippets", | |
score_offset = 0, | |
}, | |
buffer = { | |
name = "Buffer", | |
score_offset = -5, -- Lower priority | |
min_keyword_length = 2, -- Only show buffer completions after typing at least 2 chars | |
}, | |
}, | |
}, | |
fuzzy = { implementation = "prefer_rust" }, | |
}, | |
}, | |
-- Lspsaga for enhanced LSP UI and experience | |
-- Add this to your lazy plugin section | |
{ | |
'nvimdev/lspsaga.nvim', | |
dependencies = { | |
'nvim-treesitter/nvim-treesitter', -- optional but recommended | |
'nvim-tree/nvim-web-devicons', -- optional but recommended | |
}, | |
config = function() | |
require('lspsaga').setup({ | |
-- UI configuration | |
ui = { | |
border = 'rounded', -- Change to 'rounded' for rounded borders | |
devicon = true, -- Use devicons if available | |
title = true, -- Show title in floating windows | |
expand = '⊞', -- Icon for expanding | |
collapse = '⊟', -- Icon for collapsing | |
code_action = '💡', -- Code action icon | |
lines = { '┗', '┣', '┃', '━', '┏' }, -- Connection symbols | |
}, | |
-- Beacon (helps locate cursor during jumps) | |
beacon = { | |
enable = true, | |
frequency = 7, | |
}, | |
-- Scrolling keymaps in preview windows | |
scroll_preview = { | |
scroll_down = '<C-f>', | |
scroll_up = '<C-b>', | |
}, | |
-- LSP finder settings | |
finder = { | |
max_height = 0.5, -- Max height ratio of finder window | |
keys = { | |
jump_to = 'p', | |
expand_or_jump = 'o', | |
vsplit = 's', | |
split = 'i', | |
tabe = 't', | |
quit = { 'q', '<ESC>' }, | |
close_in_preview = '<ESC>', | |
}, | |
}, | |
}) | |
-- Key mappings for Lspsaga functionality | |
local opts = { noremap = true, silent = true } | |
-- Code actions | |
vim.keymap.set('n', '<leader>ca', '<cmd>Lspsaga code_action<CR>', opts) | |
vim.keymap.set('v', '<leader>ca', '<cmd>Lspsaga code_action<CR>', opts) | |
-- Hover documentation | |
vim.keymap.set('n', 'K', '<cmd>Lspsaga hover_doc<CR>', opts) | |
-- Symbol finder (find references) | |
vim.keymap.set('n', 'gr', '<cmd>Lspsaga finder<CR>', opts) | |
-- Go to definition | |
vim.keymap.set('n', 'gd', '<cmd>Lspsaga goto_definition<CR>', opts) | |
-- Peek definition | |
vim.keymap.set('n', 'gp', '<cmd>Lspsaga peek_definition<CR>', opts) | |
-- Rename | |
vim.keymap.set('n', '<leader>rn', '<cmd>Lspsaga rename<CR>', opts) | |
-- Show line diagnostics | |
vim.keymap.set('n', '<leader>sl', '<cmd>Lspsaga show_line_diagnostics<CR>', opts) | |
-- Jump to diagnostics | |
vim.keymap.set('n', '[e', '<cmd>Lspsaga diagnostic_jump_prev<CR>', opts) | |
vim.keymap.set('n', ']e', '<cmd>Lspsaga diagnostic_jump_next<CR>', opts) | |
end, | |
}, | |
{ "catppuccin/nvim", name = "catppuccin", priority = 1000 }, | |
{ | |
'stevearc/oil.nvim', | |
---@module 'oil' | |
---@type oil.SetupOpts | |
opts = {}, | |
-- Optional dependencies | |
dependencies = { { "echasnovski/mini.icons", opts = {} } }, | |
-- dependencies = { "nvim-tree/nvim-web-devicons" }, -- use if you prefer nvim-web-devicons | |
-- Lazy loading is not recommended because it is very tricky to make it work correctly in all situations. | |
lazy = false, | |
}, | |
-- Useful plugin to show you pending keybinds. | |
{ | |
-- Adds git releated signs to the gutter, as well as utilities for managing changes | |
'lewis6991/gitsigns.nvim', | |
opts = { | |
-- See `:help gitsigns.txt` | |
signs = { | |
add = { text = '+' }, | |
change = { text = '~' }, | |
delete = { text = '_' }, | |
topdelete = { text = '‾' }, | |
changedelete = { text = '~' }, | |
}, | |
on_attach = function(bufnr) | |
vim.keymap.set('n', '<leader>gp', require('gitsigns').prev_hunk, | |
{ buffer = bufnr, desc = '[G]o to [P]revious Hunk' }) | |
vim.keymap.set('n', '<leader>gn', require('gitsigns').next_hunk, { buffer = bufnr, desc = '[G]o to [N]ext Hunk' }) | |
vim.keymap.set('n', '<leader>ph', require('gitsigns').preview_hunk, { buffer = bufnr, desc = '[P]review [H]unk' }) | |
end, | |
}, | |
}, | |
{ | |
-- Set lualine as statusline | |
'nvim-lualine/lualine.nvim', | |
-- See `:help lualine.txt` | |
opts = { | |
options = { | |
icons_enabled = false, | |
-- theme = 'onedark', | |
component_separators = '|', | |
section_separators = '', | |
}, | |
}, | |
}, | |
{ | |
-- Add indentation guides even on blank lines | |
'lukas-reineke/indent-blankline.nvim', | |
main = 'ibl', | |
opts = { | |
}, | |
}, | |
-- "gc" to comment visual regions/lines | |
{ 'numToStr/Comment.nvim', opts = {} }, | |
-- Fuzzy Finder (files, lsp, etc) | |
{ 'nvim-telescope/telescope.nvim', branch = '0.1.x', dependencies = { 'nvim-lua/plenary.nvim' } }, | |
-- Fuzzy Finder Algorithm which requires local dependencies to be built. | |
-- Only load if `make` is available. Make sure you have the system | |
-- requirements installed. | |
{ | |
'nvim-telescope/telescope-fzf-native.nvim', | |
-- NOTE: If you are having trouble with this installation, | |
-- refer to the README for telescope-fzf-native for more instructions. | |
build = 'make', | |
cond = function() | |
return vim.fn.executable 'make' == 1 | |
end, | |
}, | |
{ | |
-- Highlight, edit, and navigate code | |
'nvim-treesitter/nvim-treesitter', | |
dependencies = { | |
'nvim-treesitter/nvim-treesitter-textobjects', | |
}, | |
build = ':TSUpdate', | |
}, | |
}, {}) | |
-- [[ Setting options ]] | |
-- See `:help vim.o` | |
-- NOTE: You can change these options as you wish! | |
-- Set highlight on search | |
vim.o.hlsearch = false | |
-- Make line numbers default | |
vim.wo.number = true | |
-- Enable mouse mode | |
vim.o.mouse = 'a' | |
-- Enable break indent | |
vim.o.breakindent = true | |
-- Save undo history | |
vim.o.undofile = true | |
-- Case-insensitive searching UNLESS \C or capital in search | |
vim.o.ignorecase = true | |
vim.o.smartcase = true | |
-- Keep signcolumn on by default | |
vim.wo.signcolumn = 'yes' | |
-- Reduce screen redraw issues, especially during resizing | |
vim.o.lazyredraw = true | |
-- Decrease update time | |
-- vim.o.updatetime = 250 | |
vim.o.timeoutlen = 1000 | |
-- Set completeopt to have a better completion experience for built-in LSP | |
vim.o.completeopt = 'menuone,noselect' | |
-- NOTE: You should make sure your terminal supports this | |
vim.o.termguicolors = true | |
-- [[ Basic Keymaps ]] | |
-- Keymaps for better default experience | |
-- See `:help vim.keymap.set()` vim.keymap.set({ 'n', 'v' }, '<Space>', '<Nop>', { silent = true }) | |
-- Remap for dealing with word wrap | |
vim.keymap.set('n', 'k', "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true }) | |
vim.keymap.set('n', 'j', "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true }) | |
-- [[ Highlight on yank ]] | |
-- See `:help vim.highlight.on_yank()` | |
local highlight_group = vim.api.nvim_create_augroup('YankHighlight', { clear = true }) | |
vim.api.nvim_create_autocmd('TextYankPost', { | |
callback = function() | |
vim.highlight.on_yank() | |
end, | |
group = highlight_group, | |
pattern = '*', | |
}) | |
-- | |
-- | |
-- Enable telescope fzf native, if installed | |
pcall(require('telescope').load_extension, 'fzf') | |
-- | |
-- -- See `:help telescope.builtin` for more. Try to stick with official docs or vim internal help "ALMOST ALWAYS" | |
-- [[ Configure Treesitter ]] | |
-- See `:help nvim-treesitter` | |
require('nvim-treesitter.configs').setup { | |
-- Add languages to be installed here that you want installed for treesitter | |
ensure_installed = { 'c', 'cpp', 'go', 'lua', 'python', 'rust', 'tsx', 'typescript', 'vimdoc', 'vim' }, | |
-- Autoinstall languages that are not installed. Defaults to false (but you can change for yourself!) | |
-- auto_install = false, | |
auto_install = true, | |
highlight = { enable = true }, | |
indent = { enable = true }, | |
incremental_selection = { | |
enable = true, | |
keymaps = { | |
init_selection = '<c-space>', | |
node_incremental = '<c-space>', | |
scope_incremental = '<leader>cs', | |
node_decremental = '<M-space>', | |
}, | |
}, | |
textobjects = { | |
select = { | |
enable = true, | |
lookahead = true, -- Automatically jump forward to textobj, similar to targets.vim | |
keymaps = { | |
-- You can use the capture groups defined in textobjects.scm | |
['aa'] = '@parameter.outer', | |
['ia'] = '@parameter.inner', | |
['af'] = '@function.outer', | |
['if'] = '@function.inner', | |
['ac'] = '@class.outer', | |
['ic'] = '@class.inner', | |
}, | |
}, | |
move = { | |
enable = true, | |
set_jumps = true, -- whether to set jumps in the jumplist | |
goto_next_start = { | |
[']m'] = '@function.outer', | |
[']]'] = '@class.outer', | |
}, | |
goto_next_end = { | |
[']M'] = '@function.outer', | |
[']['] = '@class.outer', | |
}, | |
goto_previous_start = { | |
['[m'] = '@function.outer', | |
['[['] = '@class.outer', | |
}, | |
goto_previous_end = { | |
['[M'] = '@function.outer', | |
['[]'] = '@class.outer', | |
}, | |
}, | |
swap = { | |
enable = true, | |
swap_next = { | |
['<leader>a'] = '@parameter.inner', | |
}, | |
swap_previous = { | |
['<leader>A'] = '@parameter.inner', | |
}, | |
}, | |
}, | |
} | |
-- [[ Configure LSP ]] | |
-- This function gets run when an LSP connects to a particular buffer. | |
local on_attach = function(client, bufnr) | |
-- NOTE: Remember that lua is a real programming language, and as such it is possible | |
-- to define small helper and utility functions so you don't have to repeat yourself | |
-- many times. | |
-- | |
-- In this case, we create a function that lets us more easily define mappings specific | |
-- for LSP related items. It sets the mode, buffer and description for us each time. | |
local nmap = function(keys, func, desc) | |
if desc then | |
desc = 'LSP: ' .. desc | |
end | |
vim.keymap.set('n', keys, func, { buffer = bufnr, desc = desc }) | |
end | |
-- Use lspsaga for better UI experience with LSP | |
-- Replace basic lsp functionalities with lspsaga enhanced versions | |
-- Rename with lspsaga | |
nmap('<leader>rn', '<cmd>Lspsaga rename<CR>', '[R]e[n]ame') | |
-- Code actions with lspsaga | |
nmap('<leader>ca', '<cmd>Lspsaga code_action<CR>', '[C]ode [A]ction') | |
-- LSP definitions | |
nmap('gd', '<cmd>Lspsaga goto_definition<CR>', '[G]oto [D]efinition') | |
nmap('gr', require('telescope.builtin').lsp_references, '[G]oto [R]eferences') | |
nmap('gI', '<cmd>Lspsaga finder imp<CR>', '[G]oto [I]mplementation') | |
nmap('<leader>D', '<cmd>Lspsaga peek_type_definition<CR>', 'Type [D]efinition') | |
nmap('<leader>ds', require('telescope.builtin').lsp_document_symbols, '[D]ocument [S]ymbols') | |
nmap('<leader>ws', require('telescope.builtin').lsp_dynamic_workspace_symbols, '[W]orkspace [S]ymbols') | |
-- Hover documentation with lspsaga | |
nmap('K', '<cmd>Lspsaga hover_doc<CR>', 'Hover Documentation') | |
nmap('<C-k>', vim.lsp.buf.signature_help, 'Signature Documentation') | |
-- Lesser used LSP functionality | |
nmap('gD', '<cmd>Lspsaga goto_definition<CR>', '[G]oto [D]eclaration') | |
nmap('<leader>wa', vim.lsp.buf.add_workspace_folder, '[W]orkspace [A]dd Folder') | |
nmap('<leader>wr', vim.lsp.buf.remove_workspace_folder, '[W]orkspace [R]emove Folder') | |
nmap('<leader>wl', function() | |
-- Use updated API | |
if vim.lsp.buf.list_workspace_folders then | |
print(vim.inspect(vim.lsp.buf.list_workspace_folders())) | |
else | |
print("list_workspace_folders not available in this Neovim version") | |
end | |
end, '[W]orkspace [L]ist Folders') | |
-- Diagnostic navigation with lspsaga | |
nmap('[e', '<cmd>Lspsaga diagnostic_jump_prev<CR>', 'Previous Diagnostic') | |
nmap(']e', '<cmd>Lspsaga diagnostic_jump_next<CR>', 'Next Diagnostic') | |
nmap('<leader>e', '<cmd>Lspsaga show_cursor_diagnostics<CR>', 'Show cursor diagnostics') | |
-- Create a command `:Format` local to the LSP buffer | |
vim.api.nvim_buf_create_user_command(bufnr, 'Format', function(_) | |
vim.lsp.buf.format() | |
end, { desc = 'Format current buffer with LSP' }) | |
-- Set up manual completion shortcut (compatible with Neovim 0.11.0) | |
vim.keymap.set('i', '<C-Space>', function() | |
-- Trigger manual completions with blink.cmp | |
require('blink.cmp').show() | |
end, { buffer = bufnr, desc = 'Manual completion' }) | |
end | |
-- Enable the following language servers | |
-- Feel free to add/remove any LSPs that you want here. They will automatically be installed. | |
-- | |
-- Add any additional override configuration in the following tables. They will be passed to | |
-- the `settings` field of the server config. You must look up that documentation yourself. | |
-- | |
-- If you want to override the default filetypes that your language server will attach to you can | |
-- define the property 'filetypes' to the map in question. | |
local servers = { | |
-- clangd = {}, | |
-- gopls = {}, | |
pyright = {}, -- Python LSP enabled | |
-- rust_analyzer = {}, | |
-- tsserver = {}, | |
-- html = { filetypes = { 'html', 'twig', 'hbs'} }, | |
lua_ls = { | |
Lua = { | |
workspace = { checkThirdParty = false }, | |
telemetry = { enable = false }, | |
}, | |
}, | |
} | |
-- Setup LSP capabilities for blink.cmp instead of nvim-cmp | |
local capabilities | |
local has_blink_cmp, blink_cmp = pcall(require, 'blink.cmp') | |
if has_blink_cmp then | |
capabilities = blink_cmp.get_lsp_capabilities() | |
else | |
-- Fallback to basic capabilities | |
capabilities = vim.lsp.protocol.make_client_capabilities() | |
capabilities.textDocument.completion.completionItem.snippetSupport = true | |
capabilities.textDocument.completion.completionItem.resolveSupport = { | |
properties = { | |
'documentation', | |
'detail', | |
'additionalTextEdits', | |
} | |
} | |
end | |
-- Configure Copilot.vim | |
vim.g.copilot_no_tab_map = true | |
vim.g.copilot_assume_mapped = true | |
vim.g.copilot_tab_fallback = "" | |
-- Set up keybindings for Copilot | |
vim.api.nvim_set_keymap('i', '<M-l>', 'copilot#Accept("\\<CR>")', { expr = true, silent = true }) | |
vim.api.nvim_set_keymap('i', '<M-w>', '<Plug>(copilot-accept-word)', {}) | |
vim.api.nvim_set_keymap('i', '<M-]>', '<Plug>(copilot-next)', {}) | |
vim.api.nvim_set_keymap('i', '<M-[>', '<Plug>(copilot-previous)', {}) | |
-- We no longer need the omnifunc setup since blink.cmp will handle completions | |
-- But we'll keep it as a fallback for filetypes that might not have LSP | |
vim.api.nvim_create_autocmd("FileType", { | |
pattern = {"lua", "python", "rust", "c", "cpp", "javascript", "typescript"}, | |
callback = function() | |
vim.bo.omnifunc = "v:lua.vim.lsp.omnifunc" | |
end | |
}) | |
-- Ensure the servers above are installed | |
local mason_lspconfig = require 'mason-lspconfig' | |
mason_lspconfig.setup { | |
ensure_installed = vim.tbl_keys(servers), | |
} | |
-- Standard LSP setup without external completion engines | |
mason_lspconfig.setup_handlers { | |
function(server_name) | |
require('lspconfig')[server_name].setup { | |
capabilities = capabilities, | |
on_attach = on_attach, | |
settings = servers[server_name], | |
filetypes = (servers[server_name] or {}).filetypes, | |
} | |
end | |
} | |
-- LSP diagnostic settings - default to disabled on startup | |
vim.diagnostic.config({ | |
virtual_text = false, | |
signs = false, | |
underline = true, | |
update_in_insert = false, | |
}) | |
-- Add diagnostic command to check completion status | |
vim.api.nvim_create_user_command('CheckLsp', function() | |
local status = {} | |
-- Check Copilot status - CORRECT WAY to call function with # in name | |
local copilot_enabled = vim.fn.exists('*copilot#Enabled') == 1 and vim.fn['copilot#Enabled']() == 1 | |
table.insert(status, "Copilot enabled: " .. tostring(copilot_enabled)) | |
-- Check LSP clients (using the non-deprecated API) | |
local clients = {} | |
-- Use the new API if available, fall back to old API for compatibility | |
if vim.lsp.get_clients then | |
clients = vim.lsp.get_clients({ bufnr = 0 }) | |
else | |
clients = vim.lsp.get_active_clients({ bufnr = 0 }) | |
end | |
if #clients == 0 then | |
table.insert(status, "No LSP clients attached to this buffer") | |
else | |
table.insert(status, "LSP clients:") | |
for _, client in ipairs(clients) do | |
table.insert(status, "- " .. client.name) | |
end | |
end | |
for _, line in ipairs(status) do | |
print(line) | |
end | |
end, {}) | |
-- Setup Pilott toggle command with pure LSP and Copilot | |
vim.g.copilot_mode = "enabled" -- Default to having Copilot on | |
vim.api.nvim_create_user_command('Pilott', function() | |
if vim.g.copilot_mode == "enabled" then | |
-- Turn off Copilot | |
vim.g.copilot_mode = "disabled" | |
vim.cmd("Copilot disable") | |
print("Copilot disabled - using only LSP completion") | |
else | |
-- Turn on Copilot | |
vim.g.copilot_mode = "enabled" | |
vim.cmd("Copilot enable") | |
print("Copilot enabled") | |
end | |
end, {}) | |
-- Command to toggle both virtual text and sign column indicators | |
vim.api.nvim_create_user_command('Togglediagnostics', function() | |
local virtual_text_enabled = false | |
virtual_text_enabled = not virtual_text_enabled | |
if virtual_text_enabled then | |
-- Enable both virtual text and sign column | |
vim.diagnostic.config({ | |
virtual_text = { | |
spacing = 4, | |
prefix = "■", -- Use a custom prefix | |
format = function(diagnostic) | |
-- Format message to be more concise | |
local message = diagnostic.message | |
if #message > 50 then | |
message = message:sub(1, 47) .. "..." | |
end | |
return message | |
end, | |
}, | |
signs = { | |
priority = 20, | |
text = { | |
[vim.diagnostic.severity.ERROR] = 'E', | |
[vim.diagnostic.severity.WARN] = 'W', | |
[vim.diagnostic.severity.INFO] = 'I', | |
[vim.diagnostic.severity.HINT] = 'H', | |
}, | |
} | |
}) | |
-- Make sure sign column is visible | |
vim.opt.signcolumn = "yes" | |
print("Diagnostic indicators enabled (virtual text and sign column)") | |
else | |
-- Disable both virtual text and sign column | |
vim.diagnostic.config({ | |
virtual_text = false, | |
signs = false -- Disable diagnostic signs completely | |
}) | |
-- Check if we can hide the sign column (only if no other features need it) | |
local hide_sign_column = true | |
-- Keep sign column if git signs or other features are active | |
-- Use proper Lua syntax for accessing Vim functions | |
if vim.fn.exists('*gitsigns#get_hunks') == 1 then | |
-- Use square bracket notation for functions with special characters | |
local hunks = vim.fn['gitsigns#get_hunks']() | |
if hunks and #hunks > 0 then | |
hide_sign_column = false | |
end | |
end | |
-- Try using the Lua API directly if available | |
local gs_ok, gs = pcall(require, 'gitsigns') | |
if gs_ok and gs.get_hunks and gs.get_hunks() then | |
hide_sign_column = false | |
end | |
-- Set sign column based on our decision | |
if hide_sign_column then | |
vim.opt.signcolumn = "no" | |
end | |
print("Diagnostic indicators disabled (virtual text and sign column)") | |
end | |
end, {}) | |
-- Create an autocmd to disable diagnostics on startup | |
vim.api.nvim_create_autocmd("VimEnter", { | |
callback = function() | |
-- Disable virtual text | |
vim.diagnostic.config({ virtual_text = false, signs = false }) | |
-- Clear any existing diagnostics - use namespace-safe method | |
if vim.diagnostic.get_namespaces then | |
for _, namespace in ipairs(vim.diagnostic.get_namespaces()) do | |
vim.diagnostic.reset(namespace) | |
end | |
else | |
-- Fallback for older Neovim versions | |
vim.diagnostic.reset() | |
end | |
-- Set our state variable to match | |
virtual_text_enabled = false | |
-- Hide sign column if it's safe to do so | |
local hide_sign_column = true | |
-- Check for git signs before hiding | |
local gs_ok, gs = pcall(require, 'gitsigns') | |
if gs_ok and gs.get_hunks then | |
-- Use pcall to safely get hunks, as the API might change | |
local hunks_ok, hunks = pcall(function() return gs.get_hunks() end) | |
if hunks_ok and hunks and #hunks > 0 then | |
hide_sign_column = false | |
end | |
end | |
-- Only hide sign column if safe | |
if hide_sign_column then | |
vim.opt.signcolumn = "no" | |
end | |
end, | |
group = vim.api.nvim_create_augroup("DisableDiagnosticsOnStartup", { clear = true }), | |
desc = "Disable diagnostics when Neovim starts", | |
}) | |
-- Configure Copilot.vim | |
vim.g.copilot_no_tab_map = true | |
vim.g.copilot_assume_mapped = true | |
vim.g.copilot_tab_fallback = "" | |
-- Set up keybindings for Copilot | |
vim.api.nvim_set_keymap('i', '<M-l>', 'copilot#Accept("\\<CR>")', { expr = true, silent = true }) | |
vim.api.nvim_set_keymap('i', '<M-w>', '<Plug>(copilot-accept-word)', {}) | |
vim.api.nvim_set_keymap('i', '<M-]>', '<Plug>(copilot-next)', {}) | |
vim.api.nvim_set_keymap('i', '<M-[>', '<Plug>(copilot-previous)', {}) | |
-- Configure Copilot to not interfere with blink.cmp | |
vim.g.copilot_no_tab_map = true | |
vim.g.copilot_assume_mapped = true | |
vim.g.copilot_tab_fallback = "" | |
-- Function to set colorscheme | |
function SetColorScheme() | |
vim.cmd('colorscheme catppuccin-mocha') | |
end | |
-- Call the function to set the colorscheme | |
SetColorScheme() | |
vim.cmd('set autoread') | |
vim.cmd('au SwapExists * let v:swapchoice = "e"') | |
-- restore cursor position | |
vim.api.nvim_create_autocmd({ "BufReadPost", "BufEnter" }, { | |
pattern = "*", | |
callback = function() | |
-- check if mark `"` exists and if it's within the range of the buffer | |
local mark = vim.fn.getpos('`"') | |
local line_count = vim.api.nvim_buf_line_count(0) | |
if mark[1] ~= -1 and mark[2] <= line_count then | |
-- if mark `"` is valid, move the cursor to its position and scroll the window | |
vim.api.nvim_exec('silent! normal! g`"zv', false) | |
end | |
end, | |
}) | |
vim.cmd[[autocmd InsertEnter * :set tabstop=2 shiftwidth=2 expandtab]] | |
-- Shift text in visual mode1 | |
vim.cmd([[ | |
let s:save_cpo = &cpo | |
set cpo&vim | |
let s:pv_active = 1 | |
function! PV_On () | |
let s:pv_active = 1 | |
endfunction | |
function! PV_Off () | |
let s:pv_active = 0 | |
endfunction | |
function PV_Toggle () | |
let s:pv_active = !s:pv_active | |
endfunction | |
" When shifting, retain selection over multiple shifts... | |
silent! xmap <unique><silent><expr> > <SID>ShiftKeepingSelection(">") | |
silent! xmap <unique><silent><expr> < <SID>ShiftKeepingSelection("<") | |
" Allow selection to persist through an undo... | |
silent! xnoremap <unique><silent> u <ESC>ugv | |
silent! xnoremap <unique><silent> <C-R> <ESC><C-R>gv | |
function! s:ShiftKeepingSelection(cmd) | |
set nosmartindent | |
" No-op if plugin not active, or tab expansions are off... | |
if !s:pv_active || !&expandtab | |
return a:cmd . ":set smartindent\<CR>" | |
" Visual and Visual Line modes... | |
elseif mode() =~ '[vV]' | |
return a:cmd . ":set smartindent\<CR>gv" | |
" Visual block mode... | |
else | |
" Work out the adjustment for the way we're shifting... | |
let b:_pv_shift_motion | |
\ = &shiftwidth . (a:cmd == '>' ? "\<RIGHT>" : "\<LEFT>") | |
" Return instructions to implement the shift and reset selection... | |
return a:cmd . ":set smartindent\<CR>uM" | |
endif | |
endfunction | |
let &cpo = s:save_cpo | |
]]) | |
vim.cmd([[ | |
" Speed up viewport scrolling | |
nnoremap <C-e> 3<C-e> | |
nnoremap <C-y> 3<C-y> | |
" Magically build interim directories if necessary | |
" thanks to Author: Damian Conway | |
function! AskQuit (msg, options, quit_option) | |
if confirm(a:msg, a:options) == a:quit_option | |
exit | |
endif | |
endfunction | |
function! EnsureDirExists () | |
let required_dir = expand("%:h") | |
if !isdirectory(required_dir) | |
call AskQuit("Parent directory '" . required_dir . "' doesn't exist.", | |
\ "&Create it\nor &Quit?", 2) | |
try | |
call mkdir( required_dir, 'p' ) | |
catch | |
call AskQuit("Can't create '" . required_dir . "'", | |
\ "&Quit\nor &Continue anyway?", 1) | |
endtry | |
endif | |
endfunction | |
augroup AutoMkdir | |
autocmd! | |
autocmd BufNewFile * :call EnsureDirExists() | |
augroup END | |
" python class | |
" " Damian Conway's Blink function | |
nnoremap <silent> n n:call HLNext(0.1)<cr> | |
nnoremap <silent> N N:call HLNext(0.1)<cr> | |
function! HLNext (blinktime) | |
let target_pat = '\c\%#'.@/ | |
let ring = matchadd('ErrorMsg', target_pat, 101) | |
redraw | |
exec 'sleep ' . float2nr(a:blinktime * 2000) . 'm' | |
call matchdelete(ring) | |
redraw | |
endfunction | |
" make the command mode less annoying | |
" Emacs(readline) binding is here | |
" start of line | |
cnoremap <C-A> <Home> | |
" back one character | |
cnoremap <C-B> <Left> | |
" delete character under cursor | |
cnoremap <C-D> <Del> | |
" end of line | |
cnoremap <C-E> <End> | |
" forward one character | |
cnoremap <C-F> <Right> | |
" recall newer command-line | |
cnoremap <C-N> <Down> | |
" recall previous (older) command-line | |
cnoremap <C-P> <Up> | |
" back one word | |
inoremap <expr> <C-B> getline('.')=~'^\s*$'&&col('.')>strlen(getline('.'))?"0\<Lt>C-D>\<Lt>Esc>kJs":"\<Lt>Left>" | |
" delete character under cursor | |
inoremap <expr> <C-D> col('.')>strlen(getline('.'))?"\<Lt>C-D>":"\<Lt>Del>" | |
" end of line | |
" forward one character | |
inoremap <expr> <C-F> col('.')>strlen(getline('.'))?"\<Lt>C-F>":"\<Lt>Right>" | |
" common type-mistakes | |
" prese space btw | |
ab teh the | |
" Highlight Matched Parenthesis | |
hi MatchParen ctermbg=gray guibg=lightgray | |
" Better JUMP upwards and downwards | |
inoremap <C-k> <C-g>k | |
" remember, I have remapped <C-j> VIM's default Behavior | |
inoremap <C-j> <C-g>j | |
nnoremap Y "+Y | |
nnoremap y "+yy | |
xnoremap Y "+Y | |
xnoremap y "+y | |
function! HighlightAllOfWord(...) | |
if exists("a:1") | |
au CursorMoved * silent! exe printf('match Search /\<%s\>/', expand('<cword>')) | |
endif | |
if a:0 < 1 | |
match none /\<%s\>/ | |
endif | |
endfunction | |
command! -nargs=? HighlightAllOfWord call HighlightAllOfWord(<f-args>) | |
vnoremap J :m '>+1<CR>gv=gv | |
vnoremap K :m '<-2<CR>gv=gv | |
" STEAL FROM reactJS creator MACVIM box | |
function! s:VSplitIntoNextTab() | |
"there is only one window | |
if tabpagenr('$') == 1 && winnr('$') == 1 | |
return | |
endif | |
"preparing new window | |
let l:tab_nr = tabpagenr('$') | |
let l:cur_buf = bufnr('%') | |
if tabpagenr() < tab_nr | |
close! | |
if l:tab_nr == tabpagenr('$') | |
tabnext | |
endif | |
vsp | |
else | |
close! | |
tabnew | |
endif | |
"opening current buffer in new window | |
exe "b".l:cur_buf | |
endfunc | |
function! s:VSplitIntoPrevTab() | |
"there is only one window | |
if tabpagenr('$') == 1 && winnr('$') == 1 | |
return | |
endif | |
"preparing new window | |
let l:tab_nr = tabpagenr('$') | |
let l:cur_buf = bufnr('%') | |
if tabpagenr() != 1 | |
close! | |
if l:tab_nr == tabpagenr('$') | |
tabprev | |
endif | |
vsp | |
else | |
close! | |
exe "0tabnew" | |
endif | |
"opening current buffer in new window | |
exe "b".l:cur_buf | |
endfunction | |
command! VSplitIntoPrevTab call s:VSplitIntoPrevTab() | |
command! VSplitIntoNextTab call s:VSplitIntoNextTab() | |
]]) | |
local vim = vim | |
function load_large_file_async(filename, chunk_size) | |
chunk_size = chunk_size or 8192 -- default chunk size | |
local cmd = string.format("dd if=%s bs=%d", filename, chunk_size) | |
-- Handler for each chunk of data | |
local on_data = function(_, data, _) | |
-- Process each chunk of data here | |
-- For example, you can append it to a buffer | |
end | |
-- Handler for the end of the job | |
local on_exit = function(_, exit_code, _) | |
if exit_code == 0 then | |
print("File loaded successfully") | |
else | |
print("Error loading file") | |
end | |
end | |
-- Create an asynchronous job to read the file in chunks | |
vim.fn.jobstart(cmd, { | |
on_stdout = on_data, | |
on_stderr = on_data, | |
on_exit = on_exit, | |
}) | |
end | |
local function python_symbols(opts) | |
opts = opts or {} | |
local bufnr = vim.api.nvim_get_current_buf() | |
-- Only process Python files | |
local file_extension = vim.fn.expand('%:e') | |
if file_extension ~= 'py' and file_extension ~= 'pyc' then | |
return | |
end | |
-- Get parser and tree | |
local parser = vim.treesitter.get_parser(bufnr, 'python') | |
local tree = parser:parse()[1] | |
local root = tree:root() | |
-- Collect all symbols | |
local symbols = {} | |
-- Simple query for basic symbols | |
local query = vim.treesitter.query.parse('python', [[ | |
(class_definition name: (identifier) @class) | |
(function_definition name: (identifier) @function) | |
(decorator (identifier) @decorator) | |
(assignment left: (identifier) @variable) | |
]]) | |
-- Get parent context | |
local function get_context(node) | |
local result = "Global" | |
local parent = node:parent() | |
while parent do | |
if parent:type() == "class_definition" then | |
for i = 0, parent:named_child_count() - 1 do | |
local child = parent:named_child(i) | |
if child:type() == "identifier" then | |
result = "Class: " .. vim.treesitter.get_node_text(child, bufnr) | |
break | |
end | |
end | |
end | |
parent = parent:parent() | |
end | |
return result | |
end | |
-- Capture nodes | |
local start_row, _, end_row, _ = root:range() | |
for id, node in query:iter_captures(root, bufnr, start_row, end_row) do | |
local name = vim.treesitter.get_node_text(node, bufnr) | |
local row, col = node:start() | |
local type_name = query.captures[id] | |
local context = get_context(node) | |
-- Add prefix to decorators | |
if type_name == "decorator" then | |
name = "@" .. name | |
end | |
table.insert(symbols, { | |
name = name, | |
row = row, | |
col = col, | |
type = type_name, | |
context = context | |
}) | |
end | |
-- Sort symbols | |
table.sort(symbols, function(a, b) | |
if a.type ~= b.type then | |
if a.type == "class" then return true end | |
if b.type == "class" then return false end | |
if a.type == "decorator" then return true end | |
if b.type == "decorator" then return false end | |
if a.type == "function" then return true end | |
if b.type == "function" then return false end | |
return false | |
else | |
return a.row < b.row | |
end | |
end) | |
-- Prepare display list | |
local display_symbols = {} | |
for _, symbol in ipairs(symbols) do | |
table.insert(display_symbols, { | |
value = symbol, | |
display = symbol.name .. " [" .. symbol.context .. "] (" .. symbol.type .. ")", | |
ordinal = symbol.name, | |
lnum = symbol.row + 1, | |
col = symbol.col + 1 | |
}) | |
end | |
-- Display in Telescope | |
require('telescope.pickers').new(opts, { | |
prompt_title = 'Python Symbols', | |
finder = require('telescope.finders').new_table({ | |
results = display_symbols, | |
entry_maker = function(entry) | |
return entry | |
end | |
}), | |
sorter = require('telescope.config').values.generic_sorter(opts), | |
attach_mappings = function(prompt_bufnr) | |
local actions = require('telescope.actions') | |
local action_state = require('telescope.actions.state') | |
actions.select_default:replace(function() | |
local selection = action_state.get_selected_entry() | |
actions.close(prompt_bufnr) | |
vim.api.nvim_win_set_cursor(0, {selection.lnum, selection.col - 1}) | |
vim.cmd("normal! zz") | |
end) | |
return true | |
end | |
}):find() | |
end | |
vim.api.nvim_create_user_command('PythonSymbols', function() | |
python_symbols() | |
end, {}) | |
local function capture_python_node(node_type, innermost_only) | |
local bufnr = vim.api.nvim_get_current_buf() | |
-- Only process Python files | |
local file_extension = vim.fn.expand('%:e') | |
if file_extension ~= 'py' and file_extension ~= 'pyc' then | |
vim.notify("Not a Python file", vim.log.levels.WARN) | |
return | |
end | |
-- Get current cursor position | |
local cursor_row, cursor_col = unpack(vim.api.nvim_win_get_cursor(0)) | |
cursor_row = cursor_row - 1 -- Convert to 0-indexed | |
-- Get parser and tree | |
local parser = vim.treesitter.get_parser(bufnr, 'python') | |
local tree = parser:parse()[1] | |
local root = tree:root() | |
-- Target node types | |
local target_type | |
if node_type == "class" then | |
target_type = "class_definition" | |
else | |
target_type = "function_definition" | |
end | |
-- Find the smallest node at cursor position | |
local node_at_cursor = root:named_descendant_for_range(cursor_row, cursor_col, cursor_row, cursor_col) | |
if not node_at_cursor then | |
vim.notify("No node found at cursor position", vim.log.levels.WARN) | |
return | |
end | |
-- Collect all nodes of the target type from cursor to root | |
local target_nodes = {} | |
local current_node = node_at_cursor | |
while current_node do | |
if current_node:type() == target_type then | |
table.insert(target_nodes, current_node) | |
end | |
current_node = current_node:parent() | |
end | |
if #target_nodes == 0 then | |
vim.notify("No " .. node_type .. " found at or containing cursor position", vim.log.levels.WARN) | |
return | |
end | |
-- Select the appropriate node based on the innermost_only flag | |
local target_node | |
if innermost_only then | |
-- Take the innermost (first found from cursor) | |
target_node = target_nodes[1] | |
else | |
-- Take the outermost (last found going up to root) | |
target_node = target_nodes[#target_nodes] | |
end | |
-- Get node range | |
local start_row, start_col, end_row, end_col = target_node:range() | |
-- Convert to 1-indexed for Vim and select in visual mode | |
vim.api.nvim_win_set_cursor(0, {start_row + 1, start_col}) | |
vim.cmd("normal! v") | |
vim.api.nvim_win_set_cursor(0, {end_row + 1, end_col}) | |
end | |
-- Register commands | |
vim.api.nvim_create_user_command('PythonCaptureInnerFunction', function() | |
capture_python_node("function", true) | |
end, {}) | |
vim.api.nvim_create_user_command('PythonCaptureInnerClass', function() | |
capture_python_node("class", true) | |
end, {}) | |
vim.api.nvim_create_user_command('PythonCaptureOuterFunction', function() | |
capture_python_node("function", false) | |
end, {}) | |
vim.api.nvim_create_user_command('PythonCaptureOuterClass', function() | |
capture_python_node("class", false) | |
end, {}) | |
-- Create key mappings for normal mode | |
vim.api.nvim_set_keymap('n', '<leader>vif', ':PythonCaptureInnerFunction<CR>', { noremap = true, silent = true }) | |
vim.api.nvim_set_keymap('n', '<leader>vic', ':PythonCaptureInnerClass<CR>', { noremap = true, silent = true }) | |
vim.api.nvim_set_keymap('n', '<leader>vof', ':PythonCaptureOuterFunction<CR>', { noremap = true, silent = true }) | |
vim.api.nvim_set_keymap('n', '<leader>voc', ':PythonCaptureOuterClass<CR>', { noremap = true, silent = true }) | |
-- Extremely minimal terminal configuration | |
-- No autocmds, no complex options, just basic commands that work | |
-- Horizontal terminal | |
vim.api.nvim_create_user_command('Termhorizontal', function(opts) | |
local size = opts.args ~= "" and opts.args or "15" | |
vim.cmd(size .. "split") | |
vim.cmd("terminal") | |
vim.cmd("startinsert") | |
end, {nargs = "?"}) | |
-- Vertical terminal | |
vim.api.nvim_create_user_command('Termvertical', function(opts) | |
local size = opts.args ~= "" and opts.args or "80" | |
vim.cmd(size .. "vsplit") | |
vim.cmd("terminal") | |
vim.cmd("startinsert") | |
end, {nargs = "?"}) | |
-- Tab terminal | |
vim.api.nvim_create_user_command('Termnew', function() | |
vim.cmd("tabnew") | |
vim.cmd("terminal") | |
vim.cmd("startinsert") | |
end, {}) | |
-- Floating terminal | |
vim.api.nvim_create_user_command('Termfloat', function() | |
-- Calculate dimensions | |
local width = math.floor(vim.o.columns * 0.8) | |
local height = math.floor(vim.o.lines * 0.8) | |
local row = math.floor((vim.o.lines - height) / 2) | |
local col = math.floor((vim.o.columns - width) / 2) | |
-- Create empty buffer | |
local buf = vim.api.nvim_create_buf(false, true) | |
-- Create window | |
local win_opts = { | |
relative = "editor", | |
width = width, | |
height = height, | |
row = row, | |
col = col, | |
style = "minimal", | |
border = "rounded" | |
} | |
local win = vim.api.nvim_open_win(buf, true, win_opts) | |
-- Open terminal in buffer | |
vim.cmd("terminal") | |
vim.cmd("startinsert") | |
end, {}) | |
-- Alias Term to horizontal split | |
vim.api.nvim_create_user_command('Term', function(opts) | |
vim.cmd("Termhorizontal " .. opts.args) | |
end, {nargs = "?"}) | |
-- Simple terminal mode mappings (without autocmd) | |
vim.keymap.set('t', '<Esc>', '<C-\\><C-n>') | |
vim.keymap.set('t', '<C-h>', '<C-\\><C-n><C-w>h') | |
vim.keymap.set('t', '<C-j>', '<C-\\><C-n><C-w>j') | |
vim.keymap.set('t', '<C-k>', '<C-\\><C-n><C-w>k') | |
vim.keymap.set('t', '<C-l>', '<C-\\><C-n><C-w>l') | |
require("oil").setup({ | |
-- Oil will take over directory buffers (e.g. `vim .` or `:e src/`) | |
-- Set to false if you want some other plugin (e.g. netrw) to open when you edit directories. | |
default_file_explorer = true, | |
-- Id is automatically added at the beginning, and name at the end | |
-- See :help oil-columns | |
columns = { | |
"icon", | |
-- "permissions", | |
-- "size", | |
-- "mtime", | |
}, | |
-- Buffer-local options to use for oil buffers | |
buf_options = { | |
buflisted = false, | |
bufhidden = "hide", | |
}, | |
-- Window-local options to use for oil buffers | |
win_options = { | |
wrap = false, | |
signcolumn = "no", | |
cursorcolumn = false, | |
foldcolumn = "0", | |
spell = false, | |
list = false, | |
conceallevel = 3, | |
concealcursor = "nvic", | |
}, | |
-- Send deleted files to the trash instead of permanently deleting them (:help oil-trash) | |
delete_to_trash = false, | |
-- Skip the confirmation popup for simple operations (:help oil.skip_confirm_for_simple_edits) | |
skip_confirm_for_simple_edits = false, | |
-- Selecting a new/moved/renamed file or directory will prompt you to save changes first | |
-- (:help prompt_save_on_select_new_entry) | |
prompt_save_on_select_new_entry = true, | |
-- Oil will automatically delete hidden buffers after this delay | |
-- You can set the delay to false to disable cleanup entirely | |
-- Note that the cleanup process only starts when none of the oil buffers are currently displayed | |
cleanup_delay_ms = 2000, | |
lsp_file_methods = { | |
-- Enable or disable LSP file operations | |
enabled = true, | |
-- Time to wait for LSP file operations to complete before skipping | |
timeout_ms = 1000, | |
-- Set to true to autosave buffers that are updated with LSP willRenameFiles | |
-- Set to "unmodified" to only save unmodified buffers | |
autosave_changes = false, | |
}, | |
-- Constrain the cursor to the editable parts of the oil buffer | |
-- Set to `false` to disable, or "name" to keep it on the file names | |
constrain_cursor = "editable", | |
-- Set to true to watch the filesystem for changes and reload oil | |
watch_for_changes = false, | |
-- Keymaps in oil buffer. Can be any value that `vim.keymap.set` accepts OR a table of keymap | |
-- options with a `callback` (e.g. { callback = function() ... end, desc = "", mode = "n" }) | |
-- Additionally, if it is a string that matches "actions.<n>", | |
-- it will use the mapping at require("oil.actions").<n> | |
-- Set to `false` to remove a keymap | |
-- See :help oil-actions for a list of all available actions | |
keymaps = { | |
["g?"] = { "actions.show_help", mode = "n" }, | |
["<CR>"] = "actions.select", | |
["<C-s>"] = { "actions.select", opts = { vertical = true } }, | |
["<C-h>"] = { "actions.select", opts = { horizontal = true } }, | |
["<C-t>"] = { "actions.select", opts = { tab = true } }, | |
["<C-p>"] = "actions.preview", | |
["<C-c>"] = { "actions.close", mode = "n" }, | |
["<C-l>"] = "actions.refresh", | |
["-"] = { "actions.parent", mode = "n" }, | |
["_"] = { "actions.open_cwd", mode = "n" }, | |
["`"] = { "actions.cd", mode = "n" }, | |
["~"] = { "actions.cd", opts = { scope = "tab" }, mode = "n" }, | |
["gs"] = { "actions.change_sort", mode = "n" }, | |
["gx"] = "actions.open_external", | |
["g."] = { "actions.toggle_hidden", mode = "n" }, | |
["g\\"] = { "actions.toggle_trash", mode = "n" }, | |
}, | |
-- Set to false to disable all of the above keymaps | |
use_default_keymaps = true, | |
view_options = { | |
-- Show files and directories that start with "." | |
show_hidden = false, | |
-- This function defines what is considered a "hidden" file | |
is_hidden_file = function(name, bufnr) | |
local m = name:match("^%.") | |
return m ~= nil | |
end, | |
-- This function defines what will never be shown, even when `show_hidden` is set | |
is_always_hidden = function(name, bufnr) | |
return false | |
end, | |
-- Sort file names with numbers in a more intuitive order for humans. | |
-- Can be "fast", true, or false. "fast" will turn it off for large directories. | |
natural_order = "fast", | |
-- Sort file and directory names case insensitive | |
case_insensitive = false, | |
sort = { | |
-- sort order can be "asc" or "desc" | |
-- see :help oil-columns to see which columns are sortable | |
{ "type", "asc" }, | |
{ "name", "asc" }, | |
}, | |
-- Customize the highlight group for the file name | |
highlight_filename = function(entry, is_hidden, is_link_target, is_link_orphan) | |
return nil | |
end, | |
}, | |
-- Extra arguments to pass to SCP when moving/copying files over SSH | |
extra_scp_args = {}, | |
-- EXPERIMENTAL support for performing file operations with git | |
git = { | |
-- Return true to automatically git add/mv/rm files | |
add = function(path) | |
return false | |
end, | |
mv = function(src_path, dest_path) | |
return false | |
end, | |
rm = function(path) | |
return false | |
end, | |
}, | |
-- Configuration for the floating window in oil.open_float | |
float = { | |
-- Padding around the floating window | |
padding = 2, | |
-- max_width and max_height can be integers or a float between 0 and 1 (e.g. 0.4 for 40%) | |
max_width = 0, | |
max_height = 0, | |
border = "rounded", | |
win_options = { | |
winblend = 0, | |
}, | |
-- optionally override the oil buffers window title with custom function: fun(winid: integer): string | |
get_win_title = nil, | |
-- preview_split: Split direction: "auto", "left", "right", "above", "below". | |
preview_split = "auto", | |
-- This is the config that will be passed to nvim_open_win. | |
-- Change values here to customize the layout | |
override = function(conf) | |
return conf | |
end, | |
}, | |
-- Configuration for the file preview window | |
preview_win = { | |
-- Whether the preview window is automatically updated when the cursor is moved | |
update_on_cursor_moved = true, | |
-- How to open the preview window "load"|"scratch"|"fast_scratch" | |
preview_method = "fast_scratch", | |
-- A function that returns true to disable preview on a file e.g. to avoid lag | |
disable_preview = function(filename) | |
return false | |
end, | |
-- Window-local options to use for preview window buffers | |
win_options = {}, | |
}, | |
-- Configuration for the floating action confirmation window | |
confirmation = { | |
-- Width dimensions can be integers or a float between 0 and 1 (e.g. 0.4 for 40%) | |
-- min_width and max_width can be a single value or a list of mixed integer/float types. | |
-- max_width = {100, 0.8} means "the lesser of 100 columns or 80% of total" | |
max_width = 0.9, | |
-- min_width = {40, 0.4} means "the greater of 40 columns or 40% of total" | |
min_width = { 40, 0.4 }, | |
-- optionally define an integer/float for the exact width of the preview window | |
width = nil, | |
-- Height dimensions can be integers or a float between 0 and 1 (e.g. 0.4 for 40%) | |
-- min_height and max_height can be a single value or a list of mixed integer/float types. | |
-- max_height = {80, 0.9} means "the lesser of 80 columns or 90% of total" | |
max_height = 0.9, | |
-- min_height = {5, 0.1} means "the greater of 5 columns or 10% of total" | |
min_height = { 5, 0.1 }, | |
-- optionally define an integer/float for the exact height of the preview window | |
height = nil, | |
border = "rounded", | |
win_options = { | |
winblend = 0, | |
}, | |
}, | |
-- Configuration for the floating progress window | |
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, | |
}, | |
}, | |
-- Configuration for the floating SSH window | |
ssh = { | |
border = "rounded", | |
}, | |
-- Configuration for the floating keymaps help window | |
keymaps_help = { | |
border = "rounded", | |
}, | |
}) | |
-- Using Lua functions | |
local builtin = require('telescope.builtin') | |
vim.keymap.set('n', '<leader>ff', builtin.find_files, { desc = 'Telescope find files' }) | |
vim.keymap.set('n', '<leader>fg', builtin.live_grep, { desc = 'Telescope live grep' }) | |
vim.keymap.set('n', '<leader>fb', builtin.buffers, { desc = 'Telescope buffers' }) | |
vim.keymap.set('n', '<leader>fh', builtin.help_tags, { desc = 'Telescope help tags' }) | |
-- Treesitter folding with Lua | |
-- Later make a function to manage this, like wrap it inside a lua functions | |
-- Set foldmethod to 'expr' and foldexpr to the Lua PythonCaptureOuterFunction | |
-- Set global default foldmethod to 'manual' | |
vim.o.foldmethod = 'manual' | |
-- Define the toggle function | |
local function toggle_folding() | |
if vim.wo.foldmethod == 'manual' then | |
vim.wo.foldmethod = 'expr' | |
vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()' | |
print("Folding enabled with Treesitter") | |
else | |
vim.wo.foldmethod = 'manual' | |
print("Folding disabled") | |
end | |
end | |
-- Optionally, create a user command to call the function | |
vim.api.nvim_create_user_command('ToggleFolding', toggle_folding, {}) | |
-- Detect OS and configure clipboard | |
local function setup_clipboard() | |
local system = vim.loop.os_uname().sysname | |
if system == "Darwin" then | |
-- macOS - native clipboard should work automatically | |
vim.opt.clipboard = "unnamedplus" | |
return | |
end | |
-- For Linux, check if we're in SSH | |
local is_ssh = (vim.env.SSH_TTY ~= nil or vim.env.SSH_CLIENT ~= nil or vim.env.SSH_CONNECTION ~= nil) | |
if is_ssh then | |
-- Configure OSC52 for SSH sessions | |
vim.g.clipboard = 'osc52' | |
else | |
-- Check for X11 or Wayland | |
if vim.env.DISPLAY or vim.env.WAYLAND_DISPLAY then | |
-- GUI environment, let Neovim auto-detect (xclip, etc.) | |
vim.g.clipboard = nil | |
else | |
-- TTY environment, use OSC52 | |
vim.g.clipboard = 'osc52' | |
end | |
end | |
-- Use clipboard for all operations | |
vim.opt.clipboard = "unnamedplus" | |
end | |
setup_clipboard() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment