aboutsummaryrefslogtreecommitdiff
path: root/nvim/init.lua
diff options
context:
space:
mode:
Diffstat (limited to 'nvim/init.lua')
-rw-r--r--nvim/init.lua608
1 files changed, 130 insertions, 478 deletions
diff --git a/nvim/init.lua b/nvim/init.lua
index c373e36..1aca305 100644
--- a/nvim/init.lua
+++ b/nvim/init.lua
@@ -1,524 +1,176 @@
-- Plugins
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", lazypath,
- })
+ vim.fn.system({
+ "git", "clone", "--filter=blob:none",
+ "https://github.com/folke/lazy.nvim.git",
+ "--branch=stable", lazypath,
+ })
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup({
- {
- 'nvim-telescope/telescope.nvim',
- dependencies = {
- 'nvim-lua/plenary.nvim',
- { 'nvim-telescope/telescope-fzf-native.nvim', build = 'make' },
- },
- keys = {
- { '<leader>ff', '<cmd>Telescope find_files<cr>' },
- { '<leader>fg', '<cmd>Telescope live_grep<cr>' },
- { '<leader>fb', '<cmd>Telescope buffers<cr>' },
- },
+ {
+ 'nvim-telescope/telescope.nvim',
+ dependencies = {
+ 'nvim-lua/plenary.nvim',
+ { 'nvim-telescope/telescope-fzf-native.nvim', build = 'make' },
+ { 'nvim-telescope/telescope-file-browser.nvim' },
},
- {
- "rcarriga/nvim-dap-ui",
- dependencies = { "mfussenegger/nvim-dap", "nvim-neotest/nvim-nio" },
+ keys = {
+ { '<leader>ff', '<cmd>Telescope find_files<cr>' },
+ { '<leader>fg', '<cmd>Telescope live_grep<cr>' },
+ { '<leader>fb', '<cmd>Telescope buffers<cr>' },
+ { '<leader>e', '<cmd>Telescope file_browser<cr>' },
},
- {
- 'lewis6991/gitsigns.nvim',
- event = { 'BufReadPre', 'BufNewFile' },
- opts = {
- signs = {
- add = { text = '+' },
- change = { text = '~' },
- delete = { text = '_' },
- topdelete = { text = '-' },
- changedelete = { text = '~' },
- },
- },
- },
- {
- "iamcco/markdown-preview.nvim",
- cmd = { "MarkdownPreviewToggle", "MarkdownPreview", "MarkdownPreviewStop" },
- build = "cd app && npm install",
- init = function()
- vim.g.mkdp_filetypes = { "markdown" }
- end,
- ft = { "markdown" },
+ },
+ {
+ "rcarriga/nvim-dap-ui",
+ dependencies = { "mfussenegger/nvim-dap", "nvim-neotest/nvim-nio" },
+ },
+ {
+ 'lewis6991/gitsigns.nvim',
+ event = { 'BufReadPre', 'BufNewFile' },
+ opts = {
+ signs = {
+ add = { text = '+' },
+ change = { text = '~' },
+ delete = { text = '_' },
+ topdelete = { text = '-' },
+ changedelete = { text = '~' },
+ },
},
+ },
+ {
+ "iamcco/markdown-preview.nvim",
+ cmd = { "MarkdownPreviewToggle", "MarkdownPreview", "MarkdownPreviewStop" },
+ build = "cd app && npm install",
+ init = function()
+ vim.g.mkdp_filetypes = { "markdown" }
+ end,
+ ft = { "markdown" },
+ },
})
--- theme & transparency
+-- theme
vim.cmd.colorscheme("unokai")
vim.api.nvim_set_hl(0, "Normal", { bg = "none" })
vim.api.nvim_set_hl(0, "NormalNC", { bg = "none" })
vim.api.nvim_set_hl(0, "EndOfBuffer", { bg = "none" })
--- Basic settings
-vim.opt.number = true -- Line numbers
-vim.opt.relativenumber = true -- Relative line numbers
-vim.opt.cursorline = true -- Highlight current line
-vim.opt.wrap = false -- Don't wrap lines
-vim.opt.scrolloff = 10 -- Keep 10 lines above/below cursor
-vim.opt.list = true -- Enable list mode for overflow indicators
+-- basic settings
+vim.opt.number = true
+vim.opt.relativenumber = true
+vim.opt.cursorline = true
+vim.opt.wrap = false
+vim.opt.scrolloff = 10
+vim.opt.list = true
vim.opt.listchars = { extends = '…', precedes = '…', tab = ' ' }
-vim.opt.sidescrolloff = 1 -- Keep 1 column for the overflow indicator
-
--- Indentation
-vim.opt.tabstop = 2 -- Tab width
-vim.opt.shiftwidth = 2 -- Indent width
-vim.opt.softtabstop = 2 -- Soft tab stop
-vim.opt.expandtab = true -- Use spaces instead of tabs
-vim.opt.smartindent = true -- Smart auto-indenting
-vim.opt.autoindent = true -- Copy indent from current line
+vim.opt.sidescrolloff = 1
--- Search settings
-vim.opt.ignorecase = true -- Case insensitive search
-vim.opt.smartcase = true -- Case sensitive if uppercase in search
-vim.opt.hlsearch = true -- Highlight search results
-vim.opt.incsearch = true -- Show matches as you type
+vim.opt.tabstop = 2
+vim.opt.shiftwidth = 2
+vim.opt.softtabstop = 2
+vim.opt.expandtab = true
+vim.opt.smartindent = true
--- Visual settings
-vim.opt.termguicolors = true -- Enable 24-bit colors
-vim.opt.signcolumn = "yes" -- Always show sign column
-vim.opt.colorcolumn = "100" -- Show column at 100 characters
-vim.opt.showmatch = true -- Highlight matching brackets
-vim.opt.matchtime = 2 -- How long to show matching bracket
-vim.opt.cmdheight = 1 -- Command line height
-vim.opt.completeopt = "menuone,noinsert,noselect" -- Completion options
-vim.opt.showmode = false -- Don't show mode in command line
-vim.opt.pumheight = 10 -- Popup menu height
-vim.opt.pumblend = 10 -- Popup menu transparency
-vim.opt.winblend = 0 -- Floating window transparency
-vim.opt.conceallevel = 0 -- Don't hide markup
-vim.opt.concealcursor = "" -- Don't hide cursor line markup
-vim.opt.lazyredraw = true -- Don't redraw during macros
-vim.opt.synmaxcol = 300 -- Syntax highlighting limit
+-- search
+vim.opt.ignorecase = true
+vim.opt.smartcase = true
+vim.opt.hlsearch = true
+vim.opt.incsearch = true
--- File handling
-vim.opt.backup = false -- Don't create backup files
-vim.opt.writebackup = false -- Don't create backup before writing
-vim.opt.swapfile = false -- Don't create swap files
-vim.opt.undofile = true -- Persistent undo
-vim.opt.undodir = vim.fn.expand("~/.vim/undodir") -- Undo directory
-vim.opt.updatetime = 300 -- Faster completion
-vim.opt.timeoutlen = 500 -- Key timeout duration
-vim.opt.ttimeoutlen = 0 -- Key code timeout
-vim.opt.autoread = true -- Auto reload files changed outside vim
-vim.opt.autowrite = false -- Don't auto save
+-- visuals
+vim.opt.termguicolors = true
+vim.opt.signcolumn = "yes"
+vim.opt.colorcolumn = "100"
+vim.opt.showmatch = true
+vim.opt.matchtime = 2
+vim.opt.cmdheight = 1
+vim.opt.completeopt = "menuone,noinsert,noselect"
+vim.opt.showmode = false
+vim.opt.pumheight = 10
+vim.opt.pumblend = 10
+vim.opt.winblend = 0
+vim.opt.conceallevel = 0
+vim.opt.lazyredraw = true
--- Behavior settings
-vim.opt.hidden = true -- Allow hidden buffers
-vim.opt.errorbells = false -- No error bells
-vim.opt.backspace = "indent,eol,start" -- Better backspace behavior
-vim.opt.autochdir = false -- Don't auto change directory
-vim.opt.iskeyword:append("-") -- Treat dash as part of word
-vim.opt.path:append("**") -- include subdirectories in search
-vim.opt.selection = "exclusive" -- Selection behavior
-vim.opt.mouse = "a" -- Enable mouse support
-vim.opt.clipboard:append("unnamedplus") -- Use system clipboard
-vim.opt.modifiable = true -- Allow buffer modifications
-vim.opt.encoding = "UTF-8" -- Set encoding
+-- files
+vim.opt.swapfile = false
+vim.opt.undofile = true
+vim.opt.undodir = vim.fn.expand("~/.vim/undodir")
+vim.opt.updatetime = 300
+vim.opt.timeoutlen = 500
+vim.opt.autoread = true
--- Cursor settings
-vim.opt.guicursor =
-"n-v-c:block,i-ci-ve:block,r-cr:hor20,o:hor50,a:blinkwait700-blinkoff400-blinkon250-Cursor/lCursor,sm:block-blinkwait175-blinkoff150-blinkon175"
+-- behavior
+vim.opt.hidden = true
+vim.opt.backspace = "indent,eol,start"
+vim.opt.iskeyword:append("-")
+vim.opt.path:append("**")
+vim.opt.clipboard:append("unnamedplus")
+vim.opt.encoding = "UTF-8"
--- Normal mode mappings
-vim.keymap.set("n", "<leader>c", ":nohlsearch<CR>", { desc = "Clear search highlights" })
-
--- Delete without yanking
+-- keymaps
vim.keymap.set({ "n", "v" }, "<leader>d", '"_d', { desc = "Delete without yanking" })
+vim.keymap.set("n", "<leader>w", ":w<CR>", { desc = "Save file" })
+vim.keymap.set("n", "<leader>h", ":nohlsearch<CR>", { desc = "Clear search highlight" })
+vim.keymap.set("n", "J", "mzJ`z")
--- Move lines up/down
-vim.keymap.set("n", "<A-j>", ":m .+1<CR>==", { desc = "Move line down" })
-vim.keymap.set("n", "<A-k>", ":m .-2<CR>==", { desc = "Move line up" })
-vim.keymap.set("v", "<A-j>", ":m '>+1<CR>gv=gv", { desc = "Move selection down" })
-vim.keymap.set("v", "<A-k>", ":m '<-2<CR>gv=gv", { desc = "Move selection up" })
-
--- Better indenting in visual mode
-vim.keymap.set("v", "<", "<gv", { desc = "Indent left and reselect" })
-vim.keymap.set("v", ">", ">gv", { desc = "Indent right and reselect" })
+-- move lines (visual only)
+vim.keymap.set("v", "J", ":m '>+1<CR>gv=gv")
+vim.keymap.set("v", "K", ":m '<-2<CR>gv=gv")
--- Quick file navigation
-vim.keymap.set("n", "<leader>e", ":Explore<CR>", { desc = "Open file explorer" })
+-- indent keep selection
+vim.keymap.set("v", "<", "<gv")
+vim.keymap.set("v", ">", ">gv")
--- Netrw: h/l to navigate directory tree
-vim.api.nvim_create_autocmd("FileType", {
- group = augroup,
- pattern = "netrw",
- callback = function()
- local opts = { buffer = true, remap = true }
- vim.keymap.set("n", "h", "-", opts) -- go up a directory
- vim.keymap.set("n", "l", "<CR>", opts) -- open file/directory
- end,
-})
-
--- Better J behavior
-vim.keymap.set("n", "J", "mzJ`z", { desc = "Join lines and keep cursor position" })
-
--- ============================================================================
--- USEFUL FUNCTIONS
--- ============================================================================
-
--- Copy Full File-Path
-vim.keymap.set("n", "<leader>pa", function()
- local path = vim.fn.expand("%:p")
- vim.fn.setreg("+", path)
- print("file:", path)
+-- copy full path
+vim.keymap.set("n", "<leader>pp", function()
+ local path = vim.fn.expand("%:p")
+ vim.fn.setreg("+", path)
+ print("file:", path)
end)
--- Basic autocommands
+-- autocommands
local augroup = vim.api.nvim_create_augroup("UserConfig", {})
--- Highlight yanked text
vim.api.nvim_create_autocmd("TextYankPost", {
- group = augroup,
- callback = function()
- vim.highlight.on_yank()
- end,
-})
-
--- Return to last edit position when opening files
-vim.api.nvim_create_autocmd("BufReadPost", {
- group = augroup,
- callback = function()
- local mark = vim.api.nvim_buf_get_mark(0, '"')
- local lcount = vim.api.nvim_buf_line_count(0)
- if mark[1] > 0 and mark[1] <= lcount then
- pcall(vim.api.nvim_win_set_cursor, 0, mark)
- end
- end,
-})
-
--- Set filetype-specific settings
-vim.api.nvim_create_autocmd("FileType", {
- group = augroup,
- pattern = { "lua", "python" },
- callback = function()
- vim.opt_local.tabstop = 4
- vim.opt_local.shiftwidth = 4
- end,
-})
-
-vim.api.nvim_create_autocmd("FileType", {
- group = augroup,
- pattern = { "javascript", "typescript", "json", "html", "css" },
- callback = function()
- vim.opt_local.tabstop = 2
- vim.opt_local.shiftwidth = 2
- end,
-})
-
--- Auto-close terminal when process exits
-vim.api.nvim_create_autocmd("TermClose", {
- group = augroup,
- callback = function()
- if vim.v.event.status == 0 then
- vim.api.nvim_buf_delete(0, {})
- end
- end,
-})
-
--- Disable line numbers in terminal
-vim.api.nvim_create_autocmd("TermOpen", {
- group = augroup,
- callback = function()
- vim.opt_local.number = false
- vim.opt_local.relativenumber = false
- vim.opt_local.signcolumn = "no"
- end,
-})
-
--- Create directories when saving files
-vim.api.nvim_create_autocmd("BufWritePre", {
- group = augroup,
- callback = function()
- local dir = vim.fn.expand('<afile>:p:h')
- if vim.fn.isdirectory(dir) == 0 then
- vim.fn.mkdir(dir, 'p')
- end
- end,
-})
-
--- Command-line completion
-vim.opt.wildmenu = true
-vim.opt.wildmode = "longest:full,full"
-vim.opt.wildignore:append({ "*.o", "*.obj", "*.pyc", "*.class", "*.jar" })
-
--- Better diff options
-vim.opt.diffopt:append("linematch:60")
-
--- Performance improvements
-vim.opt.redrawtime = 10000
-vim.opt.maxmempattern = 20000
-
--- Create undo directory if it doesn't exist
-local undodir = vim.fn.expand("~/.vim/undodir")
-if vim.fn.isdirectory(undodir) == 0 then
- vim.fn.mkdir(undodir, "p")
-end
-
--- ============================================================================
--- STATUSLINE
--- ============================================================================
-
-local function statusline_mode()
- local modes = {
- n = "NORMAL",
- i = "INSERT",
- v = "VISUAL",
- V = "V-LINE",
- ["\22"] = "V-BLOCK",
- c = "COMMAND",
- R = "REPLACE",
- }
- return modes[vim.fn.mode()] or vim.fn.mode():upper()
-end
-
-local function statusline_branch()
- local branch = vim.b.gitsigns_head
- if branch and branch ~= "" then return " " .. branch end
- return ""
-end
-
-_G.statusline_mode = statusline_mode
-_G.statusline_branch = statusline_branch
-
-vim.api.nvim_set_hl(0, "StatusLineBold", { bold = true })
-
-vim.api.nvim_create_autocmd({ "WinEnter", "BufEnter" }, {
- callback = function()
- vim.opt_local.statusline =
- " %#StatusLineBold#%{v:lua.statusline_mode()}%#StatusLine#" ..
- " %f%m%r%{v:lua.statusline_branch()}" ..
- "%=" ..
- "%y %l:%c %P "
- end
-})
-
-vim.api.nvim_create_autocmd({ "WinLeave", "BufLeave" }, {
- callback = function()
- vim.opt_local.statusline = " %f%m%r%= %l:%c %P "
- end
+ group = augroup,
+ callback = function()
+ vim.highlight.on_yank()
+ end,
})
--- ============================================================================
-- LSP
--- ============================================================================
-
--- Function to find project root
-local function find_root(patterns)
- local path = vim.fn.expand('%:p:h')
- local root = vim.fs.find(patterns, { path = path, upward = true })[1]
- return root and vim.fn.fnamemodify(root, ':h') or path
-end
-
--- Shell LSP setup
-local function setup_shell_lsp()
- vim.lsp.start({
- name = 'bashls',
- cmd = { 'bash-language-server', 'start' },
- filetypes = { 'sh', 'bash', 'zsh' },
- root_dir = find_root({ '.git', 'Makefile' }),
- settings = {
- bashIde = {
- globPattern = "*@(.sh|.inc|.bash|.command)"
- }
- }
- })
-end
-
--- Python LSP setup
-local function setup_python_lsp()
- vim.lsp.start({
- name = 'pylsp',
- cmd = { 'pylsp' },
- filetypes = { 'python' },
- root_dir = find_root({ 'pyproject.toml', 'setup.py', 'setup.cfg', 'requirements.txt', '.git' }),
- settings = {
- pylsp = {
- plugins = {
- pycodestyle = {
- enabled = false
- },
- flake8 = {
- enabled = true,
- },
- black = {
- enabled = true
- }
- }
- }
- }
- })
-end
-
--- C/C++ LSP setup (clangd)
-local function setup_clangd()
- vim.lsp.start({
- name = 'clangd',
- cmd = { 'clangd', '--background-index' },
- root_dir = find_root({ 'compile_commands.json', 'CMakeLists.txt', 'Makefile', '.git' }),
- })
-end
-
--- Rust LSP setup (rust-analyzer)
-local function setup_rust_analyzer()
- vim.lsp.start({
- name = 'rust-analyzer',
- cmd = { 'rust-analyzer' },
- root_dir = find_root({ 'Cargo.toml', '.git' }),
- settings = {
- ['rust-analyzer'] = {
- check = { command = 'clippy' },
- }
- }
- })
-end
-
--- Auto-start LSPs based on filetype
-vim.api.nvim_create_autocmd('FileType', {
- pattern = 'sh,bash,zsh',
- callback = setup_shell_lsp,
- desc = 'Start shell LSP'
-})
-
-vim.api.nvim_create_autocmd('FileType', {
- pattern = 'python',
- callback = setup_python_lsp,
- desc = 'Start Python LSP'
-})
-
-vim.api.nvim_create_autocmd('FileType', {
- pattern = 'c,cpp',
- callback = setup_clangd,
- desc = 'Start clangd LSP'
-})
-
-vim.api.nvim_create_autocmd('FileType', {
- pattern = 'rust',
- callback = setup_rust_analyzer,
- desc = 'Start rust-analyzer LSP'
-})
-
--- formatting
-local function format_code()
- local bufnr = vim.api.nvim_get_current_buf()
- local filename = vim.api.nvim_buf_get_name(bufnr)
- local filetype = vim.bo[bufnr].filetype
-
- -- Save cursor position
- local cursor_pos = vim.api.nvim_win_get_cursor(0)
-
- if filetype == 'python' or filename:match('%.py$') then
- if filename == '' then
- print("Save the file first before formatting Python")
- return
- end
-
- local black_cmd = "black --quiet " .. vim.fn.shellescape(filename)
- local black_result = vim.fn.system(black_cmd)
-
- if vim.v.shell_error == 0 then
- vim.cmd('checktime')
- vim.api.nvim_win_set_cursor(0, cursor_pos)
- print("Formatted with black")
- return
- else
- print("No Python formatter available (install black)")
- return
- end
- end
-
- if filetype == 'sh' or filetype == 'bash' or filename:match('%.sh$') then
- local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
- local content = table.concat(lines, '\n')
-
- local cmd = { 'shfmt', '-i', '2', '-ci', '-sr' } -- 2 spaces, case indent, space redirects
- local result = vim.fn.system(cmd, content)
-
- if vim.v.shell_error == 0 then
- local formatted_lines = vim.split(result, '\n')
- if formatted_lines[#formatted_lines] == '' then
- table.remove(formatted_lines)
- end
- vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, formatted_lines)
- vim.api.nvim_win_set_cursor(0, cursor_pos)
- print("Shell script formatted with shfmt")
- return
- else
- print("shfmt error: " .. result)
- return
- end
- end
-
- print("No formatter available for " .. filetype)
-end
-
-vim.api.nvim_create_user_command("FormatCode", format_code, {
- desc = "Format current file"
-})
-
-vim.keymap.set('n', '<leader>fm', format_code, { desc = 'Format file' })
-
--- LSP keymaps
vim.api.nvim_create_autocmd('LspAttach', {
- callback = function(event)
- local opts = { buffer = event.buf }
+ callback = function(event)
+ local opts = { buffer = event.buf }
- -- Navigation
- vim.keymap.set('n', 'gD', vim.lsp.buf.definition, opts)
- vim.keymap.set('n', 'gs', vim.lsp.buf.declaration, opts)
- vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts)
- vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, opts)
+ -- navigation (fixed)
+ vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts)
+ vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, opts)
+ vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts)
+ vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, opts)
- -- Information
- vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts)
- vim.keymap.set('n', '<C-k>', vim.lsp.buf.signature_help, opts)
+ -- info
+ vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts)
+ vim.keymap.set('n', '<C-k>', vim.lsp.buf.signature_help, opts)
- -- Code actions
- vim.keymap.set('n', '<leader>ca', vim.lsp.buf.code_action, opts)
- vim.keymap.set('n', '<leader>rn', vim.lsp.buf.rename, opts)
+ -- actions
+ vim.keymap.set('n', '<leader>ca', vim.lsp.buf.code_action, opts)
+ vim.keymap.set('n', '<leader>rn', vim.lsp.buf.rename, opts)
- -- Diagnostics
- vim.keymap.set('n', '<leader>nd', vim.diagnostic.goto_next, opts)
- vim.keymap.set('n', '<leader>pd', vim.diagnostic.goto_prev, opts)
- vim.keymap.set('n', '<leader>d', vim.diagnostic.open_float, opts)
- vim.keymap.set('n', '<leader>q', vim.diagnostic.setloclist, opts)
- end,
+ -- diagnostics
+ vim.keymap.set('n', '<leader>nd', vim.diagnostic.goto_next, opts)
+ vim.keymap.set('n', '<leader>pd', vim.diagnostic.goto_prev, opts)
+ vim.keymap.set('n', '<leader>q', vim.diagnostic.setloclist, opts)
+ end,
})
--- Better LSP UI
vim.diagnostic.config({
- virtual_text = { prefix = '●' },
- signs = true,
- underline = true,
- update_in_insert = false,
- severity_sort = true,
+ virtual_text = { prefix = '●' },
+ signs = true,
+ underline = true,
})
-
-vim.diagnostic.config({
- signs = {
- text = {
- [vim.diagnostic.severity.ERROR] = "✗",
- [vim.diagnostic.severity.WARN] = "⚠",
- [vim.diagnostic.severity.INFO] = "ℹ",
- [vim.diagnostic.severity.HINT] = "💡",
- }
- }
-})
-
-vim.api.nvim_create_user_command('LspInfo', function()
- local clients = vim.lsp.get_clients({ bufnr = 0 })
- if #clients == 0 then
- print("No LSP clients attached to current buffer")
- else
- for _, client in ipairs(clients) do
- print("LSP: " .. client.name .. " (ID: " .. client.id .. ")")
- end
- end
-end, { desc = 'Show LSP client info' })