Skip to content

Instantly share code, notes, and snippets.

@guinslym
Created December 12, 2025 00:23
Show Gist options
  • Select an option

  • Save guinslym/8c71fc0d3d2da02d7e59106189e40329 to your computer and use it in GitHub Desktop.

Select an option

Save guinslym/8c71fc0d3d2da02d7e59106189e40329 to your computer and use it in GitHub Desktop.
-- ===================================================
-- Leader key (must be set before lazy.nvim)
-- ===================================================
vim.g.mapleader = ' ' -- Set leader to spacebar
vim.g.maplocalleader = ' '
-- ===================================================
-- Lazy.nvim bootstrap
-- ===================================================
local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
if not vim.loop.fs_stat(lazypath) then
local lazy_repo = 'https://github.com/folke/lazy.nvim.git'
local out = vim.fn.system {
'git',
'clone',
'--filter=blob:none',
'--branch=stable',
lazy_repo,
lazypath
}
if vim.v.shell_error ~= 0 then
error('Error cloning lazy.nvim:\n' .. out)
end
end
vim.opt.rtp:prepend(lazypath)
-- ===================================================
-- Plugins Setup
-- ===================================================
require('lazy').setup({
-- Neo-tree file explorer
{
"nvim-neo-tree/neo-tree.nvim",
branch = "v3.x",
dependencies = {
"nvim-lua/plenary.nvim",
"MunifTanjim/nui.nvim",
"nvim-tree/nvim-web-devicons",
},
},
-- Treesitter (MUST be installed for Neogen to work)
{
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
config = function()
require'nvim-treesitter.configs'.setup {
ensure_installed = { "lua", "python", "javascript", "markdown", "json" },
sync_install = false,
auto_install = true,
highlight = {
enable = true,
additional_vim_regex_highlighting = false,
},
indent = { enable = true },
}
end
},
-- Autocomplete engine
{
"hrsh7th/nvim-cmp",
dependencies = {
"hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-buffer",
"hrsh7th/cmp-path",
"hrsh7th/cmp-nvim-lua",
"L3MON4D3/LuaSnip",
"saadparwaiz1/cmp_luasnip",
},
config = function()
local cmp = require("cmp")
local luasnip = require("luasnip")
cmp.setup({
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
},
mapping = cmp.mapping.preset.insert({
-- Trigger completion menu
['<C-Space>'] = cmp.mapping.complete(),
-- Navigate through completion items
['<C-n>'] = cmp.mapping.select_next_item(),
['<C-p>'] = cmp.mapping.select_prev_item(),
-- Scroll docs
['<C-d>'] = cmp.mapping.scroll_docs(-4),
['<C-f>'] = cmp.mapping.scroll_docs(4),
-- Confirm selection with Enter
['<CR>'] = cmp.mapping.confirm({
behavior = cmp.ConfirmBehavior.Replace,
select = true
}),
-- Tab to confirm or jump to next snippet placeholder
['<Tab>'] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.confirm({ select = true })
elseif luasnip.expand_or_jumpable() then
luasnip.expand_or_jump()
else
fallback()
end
end, { 'i', 's' }),
-- Shift-Tab to jump to previous snippet placeholder
['<S-Tab>'] = cmp.mapping(function(fallback)
if luasnip.jumpable(-1) then
luasnip.jump(-1)
else
fallback()
end
end, { 'i', 's' }),
}),
sources = cmp.config.sources({
{ name = 'nvim_lsp', priority = 1000 },
{ name = 'luasnip', priority = 750 },
{ name = 'buffer', priority = 500 },
{ name = 'path', priority = 250 },
}),
completion = {
completeopt = 'menu,menuone,noinsert',
autocomplete = {
cmp.TriggerEvent.TextChanged,
},
},
experimental = {
ghost_text = true,
},
})
end
},
-- Docstring generator
{
"danymat/neogen",
dependencies = {
"nvim-treesitter/nvim-treesitter",
"L3MON4D3/LuaSnip",
},
config = function()
local neogen = require('neogen')
neogen.setup({
enabled = true,
snippet_engine = "luasnip",
})
end,
},
-- Function signature help
{
"ray-x/lsp_signature.nvim",
config = function()
require("lsp_signature").setup({
bind = true,
hint_enable = true,
floating_window = true,
})
end
},
-- Telescope fuzzy finder
{
"nvim-telescope/telescope.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
config = function()
require('telescope').setup{}
end,
},
-- Auto-formatter
{
"stevearc/conform.nvim",
config = function()
require("conform").setup({
formatters_by_filetype = {
python = { "black", "isort" },
},
format_on_save = {
timeout_ms = 500,
lsp_fallback = true,
},
})
end,
},
-- Git signs in the gutter
{
"lewis6991/gitsigns.nvim",
config = function()
require('gitsigns').setup()
end,
},
-- Git interface
{
"tpope/vim-fugitive",
},
-- Toggle terminal
{
"akinsho/toggleterm.nvim",
version = "*",
config = function()
require("toggleterm").setup({
direction = 'horizontal',
size = 15,
})
end,
},
-- Easy commenting
{
"numToStr/Comment.nvim",
config = function()
require('Comment').setup()
end,
},
-- Auto-close brackets
{
"windwp/nvim-autopairs",
config = function()
require("nvim-autopairs").setup{}
local cmp_autopairs = require('nvim-autopairs.completion.cmp')
local cmp = require('cmp')
cmp.event:on('confirm_done', cmp_autopairs.on_confirm_done())
end,
},
-- Indent guides
{
"lukas-reineke/indent-blankline.nvim",
main = "ibl",
config = function()
require("ibl").setup()
end,
},
-- Better statusline
{
"nvim-lualine/lualine.nvim",
dependencies = { "nvim-tree/nvim-web-devicons" },
config = function()
require('lualine').setup({
options = {
theme = 'auto',
section_separators = '',
component_separators = '|'
}
})
end,
},
-- Color scheme
{
"catppuccin/nvim",
name = "catppuccin",
priority = 1000,
config = function()
vim.cmd.colorscheme "catppuccin-mocha"
end,
},
-- Which-key (shows keybindings)
{
"folke/which-key.nvim",
config = function()
require("which-key").setup()
end,
},
})
-- ===================================================
-- Basic Settings
-- ===================================================
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.expandtab = true
vim.opt.shiftwidth = 2
vim.opt.tabstop = 2
vim.opt.smartindent = true
vim.opt.termguicolors = true
-- Set completeopt for better completion experience
vim.opt.completeopt = {'menu', 'menuone', 'noinsert'}
-- ===================================================
-- Clipboard Configuration (Fix OSC 52 issue)
-- ===================================================
vim.opt.clipboard = 'unnamedplus' -- Use system clipboard
-- Disable OSC 52 which causes the paste hang
vim.g.clipboard = {
name = 'custom',
copy = {
['+'] = {'xclip', '-selection', 'clipboard'},
['*'] = {'xclip', '-selection', 'primary'},
},
paste = {
['+'] = {'xclip', '-selection', 'clipboard', '-o'},
['*'] = {'xclip', '-selection', 'primary', '-o'},
},
cache_enabled = 0,
}
-- ===================================================
-- Keymaps
-- ===================================================
-- File Explorer
vim.keymap.set('n', '<leader>e', ':Neotree toggle<CR>', { noremap = true, silent = true, desc = 'Toggle file explorer' })
-- Telescope keymaps
vim.keymap.set('n', '<leader>ff', '<cmd>Telescope find_files<cr>', { desc = 'Find files' })
vim.keymap.set('n', '<leader>fg', '<cmd>Telescope live_grep<cr>', { desc = 'Live grep' })
vim.keymap.set('n', '<leader>fb', '<cmd>Telescope buffers<cr>', { desc = 'Find buffers' })
vim.keymap.set('n', '<leader>fh', '<cmd>Telescope help_tags<cr>', { desc = 'Help tags' })
-- Terminal
vim.keymap.set('n', '<leader>t', '<cmd>ToggleTerm<cr>', { desc = 'Toggle terminal' })
-- Format buffer
vim.keymap.set('n', '<leader>f', function()
require("conform").format({ async = true, lsp_fallback = true })
end, { desc = 'Format buffer' })
-- Git keymaps
vim.keymap.set('n', '<leader>gs', '<cmd>Git<cr>', { desc = 'Git status' })
vim.keymap.set('n', '<leader>gb', '<cmd>Git blame<cr>', { desc = 'Git blame' })
vim.keymap.set('n', '<leader>gd', '<cmd>Gitsigns diffthis<cr>', { desc = 'Git diff' })
-- Generate docstring with Neogen - improved with error handling
vim.keymap.set('n', '<leader>d', function()
local ft = vim.bo.filetype
if ft == "python" then
local ok, neogen = pcall(require, 'neogen')
if ok then
local success, err = pcall(neogen.generate, { type = "func" })
if not success then
print("Neogen error: " .. tostring(err))
print("Try running :TSUpdate python or :Lazy sync")
end
else
print("Neogen not loaded. Run :Lazy sync")
end
else
print("Neogen only configured for Python files")
end
end, { noremap = true, silent = false, desc = "Generate docstring" })
-- Alternative: generate for any type (function, class, type, file)
vim.keymap.set('n', '<leader>da', function()
require('neogen').generate()
end, { noremap = true, silent = false, desc = "Generate annotation (auto-detect)" })
-- ===================================================
-- Python LSP (pyright) using modern vim.lsp.config API
-- ===================================================
vim.lsp.config.pyright = {
cmd = { 'pyright-langserver', '--stdio' },
filetypes = { 'python' },
root_markers = { 'pyproject.toml', 'setup.py', 'requirements.txt', '.git' },
settings = {
python = {
analysis = {
autoSearchPaths = true,
useLibraryCodeForTypes = true,
diagnosticMode = "openFilesOnly",
typeCheckingMode = "basic",
}
}
},
}
vim.api.nvim_create_autocmd('FileType', {
pattern = 'python',
callback = function(args)
vim.lsp.enable('pyright')
end,
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment