dotfiles

My dotfiles and configs
git clone https://git.dasho.dev/dotfiles.git
Log | Files | Refs | README

init.lua (14974B)


      1 -- Neovim init.lua
      2 
      3 -- Disable unused providers
      4 vim.g.loaded_perl_provider = 0
      5 vim.g.loaded_ruby_provider = 0
      6 vim.g.loaded_node_provider = 0
      7 vim.g.loaded_python3_provider = 0
      8 
      9 -- Basic options
     10 vim.opt.number = true                  -- enable absolute line numbers
     11 vim.opt.relativenumber = true          -- enable relative line numbers
     12 vim.opt.clipboard = "unnamedplus"     -- use system clipboard
     13 vim.opt.mouse = "a"                   -- enable mouse
     14 vim.opt.termguicolors = true           -- true color support
     15 vim.opt.signcolumn = "yes"            -- always show signcolumn
     16 vim.opt.showmode = false               -- don't show mode (we use statusline)
     17 vim.opt.cursorline = true              -- highlight current line
     18 vim.opt.hidden = true                  -- allow buffer switching without saving
     19 
     20 -- Indentation
     21 vim.opt.expandtab = true               -- spaces instead of tabs
     22 vim.opt.shiftwidth = 2                 -- size of an indent
     23 vim.opt.tabstop = 2                    -- number of spaces tabs count for
     24 vim.opt.softtabstop = 2                -- spaces when hitting <Tab>
     25 
     26 -- Searching
     27 vim.opt.ignorecase = true              -- ignore case
     28 vim.opt.smartcase = true               -- unless uppercase present
     29 vim.opt.incsearch = true               -- incremental search
     30 vim.opt.hlsearch = false               -- no persistent highlight
     31 
     32 -- Splits & Windows
     33 vim.opt.splitbelow = true              -- horizontal splits go below
     34 vim.opt.splitright = true              -- vertical splits go right
     35 vim.opt.equalalways = true             -- auto-resize splits
     36 
     37 -- Backups & Undo
     38 vim.opt.backup = false
     39 vim.opt.writebackup = false
     40 vim.opt.swapfile = false
     41 vim.opt.undofile = true                -- enable persistent undo
     42 vim.opt.undodir = vim.fn.stdpath('state') .. '/undo'
     43 
     44 -- Timing
     45 vim.opt.updatetime = 300               -- faster CursorHold
     46 vim.opt.timeoutlen = 500               -- faster mapped sequences
     47 
     48 -- Leader Key
     49 vim.g.mapleader = ' '
     50 vim.g.maplocalleader = ' '
     51 
     52 -- Bootstrap lazy.nvim
     53 local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
     54 if not vim.loop.fs_stat(lazypath) then
     55  vim.fn.system({
     56    'git', 'clone', '--filter=blob:none',
     57    'https://github.com/folke/lazy.nvim.git',
     58    '--branch=stable', lazypath,
     59  })
     60 end
     61 vim.opt.rtp:prepend(lazypath)
     62 
     63 -- Plugin setup
     64 require('lazy').setup({
     65  -- lazy.nvim manager
     66  { 'folke/lazy.nvim', version = '*' },
     67 
     68  -- Lualine statusline
     69  {
     70    'nvim-lualine/lualine.nvim',
     71    event = 'VeryLazy',
     72    dependencies = { 'kyazdani42/nvim-web-devicons', opt = true },
     73    config = function()
     74      require('lualine').setup {
     75        options = {
     76          icons_enabled = true,
     77          theme = 'auto',
     78          component_separators = { left = '', right = '' },
     79          section_separators   = { left = '', right = '' },
     80        },
     81        sections = {
     82          lualine_a = {'mode'},
     83          lualine_b = {'branch', 'diff', 'diagnostics'},
     84          lualine_c = {'filename'},
     85          lualine_x = {'encoding', 'fileformat', 'filetype'},
     86          lualine_y = {'progress'},
     87          lualine_z = {'location'},
     88        },
     89      }
     90    end,
     91  },
     92  {
     93    "zbirenbaum/copilot.lua",
     94    event = "VeryLazy",
     95    config = function()
     96      require("copilot").setup({
     97        suggestion = {
     98          enabled = true,
     99          auto_trigger = true,
    100          accept = false,
    101        },
    102        panel = {
    103          enabled = false
    104        },
    105        filetypes = {
    106          markdown = true,
    107          help = true,
    108          html = true,
    109          javascript = true,
    110          typescript = true,
    111          ["*"] = true
    112        },
    113      })
    114 
    115      vim.keymap.set("i", '<Tab>', function()
    116        if require("copilot.suggestion").is_visible() then
    117          require("copilot.suggestion").accept()
    118        else
    119          vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<Tab>", true, false, true), "n", false)
    120        end
    121      end, {
    122          silent = true,
    123        })
    124    end,
    125  },
    126  -- Telescope fuzzy finder
    127  {
    128    'nvim-telescope/telescope.nvim',
    129    cmd = 'Telescope',
    130    dependencies = { 'nvim-lua/plenary.nvim' },
    131    config = function()
    132      require('telescope').setup {
    133        defaults = {
    134          layout_strategy = 'flex',
    135          file_ignore_patterns = {'node_modules'}
    136        }
    137      }
    138    end,
    139  },
    140 
    141  -- File explorer
    142  {
    143    'nvim-tree/nvim-tree.lua',
    144    cmd = { 'NvimTreeToggle', 'NvimTreeFocus' },
    145    dependencies = { 'kyazdani42/nvim-web-devicons' },
    146    config = function()
    147      require('nvim-tree').setup {
    148        view = { width = 30 },
    149        update_focused_file = { enable = true },
    150      }
    151    end,
    152  },
    153 
    154  -- Treesitter for syntax
    155  {
    156    'nvim-treesitter/nvim-treesitter',
    157    build = ':TSUpdate',
    158    event = { 'BufReadPost', 'BufNewFile' },
    159    config = function()
    160      require('nvim-treesitter.configs').setup {
    161        ensure_installed = { 'lua', 'python', 'javascript', 'go', 'rust', 'regex', 'bash' },
    162        highlight = { enable = true },
    163        indent = { enable = true },
    164      }
    165    end,
    166  },
    167 
    168  -- Mason LSP installer
    169  { 'williamboman/mason.nvim', cmd = 'Mason', config = true },
    170  {
    171    'williamboman/mason-lspconfig.nvim',
    172    dependencies = 'neovim/nvim-lspconfig',
    173    config = function()
    174      require('mason-lspconfig').setup {
    175        ensure_installed = { 'pyright', 'ts_ls', 'lua_ls' },
    176        automatic_enable = false,
    177      }
    178      vim.lsp.config('lua_ls', {
    179        settings = {
    180          Lua = {
    181            runtime = { version = 'LuaJIT' },
    182            diagnostics = { globals = {'vim'} },
    183            workspace = { library = vim.api.nvim_get_runtime_file('', true) },
    184            telemetry = { enable = false },
    185          },
    186        },
    187      })
    188      vim.lsp.enable({ 'pyright', 'ts_ls', 'lua_ls' })
    189    end,
    190  },
    191 
    192  -- Completion
    193  {
    194    'hrsh7th/nvim-cmp',
    195    event = 'InsertEnter',
    196    dependencies = {
    197      'hrsh7th/cmp-nvim-lsp', 'hrsh7th/cmp-path',
    198      'L3MON4D3/LuaSnip', 'saadparwaiz1/cmp_luasnip',
    199    },
    200    config = function()
    201      local cmp = require('cmp')
    202      cmp.setup {
    203        snippet = { expand = function(args) require('luasnip').lsp_expand(args.body) end },
    204        sources = cmp.config.sources({{ name = 'nvim_lsp' },{ name = 'path' },{ name = 'luasnip' }}),
    205      }
    206    end,
    207  },
    208 
    209  -- Git signs
    210  {
    211    'lewis6991/gitsigns.nvim',
    212    event = 'BufReadPre',
    213    config = function() require('gitsigns').setup {} end,
    214  },
    215 
    216  -- Autopairs
    217  {
    218    'windwp/nvim-autopairs',
    219    event = 'InsertEnter',
    220    config = function() require('nvim-autopairs').setup {} end,
    221  },
    222 
    223  -- Commenting
    224  {
    225  'numToStr/Comment.nvim',
    226  keys = {
    227    { '<Leader>/', function() require('Comment.api').toggle.linewise.current() end, desc = 'Toggle comment (line)' },
    228    { '<Leader>/', '<Esc><cmd>lua require("Comment.api").toggle.blockwise(vim.fn.visualmode())<CR>', mode = 'v', desc = 'Toggle comment (block)' },
    229  },
    230  config = function()
    231    require('Comment').setup({
    232      -- Add any custom config here; these are the defaults:
    233      padding = true,         -- add a space b/w comment and line
    234      sticky = true,          -- cursor stays put
    235      mappings = {
    236        basic = false,        -- disable builtin mappings because we're using our own
    237        extra = false,
    238      },
    239      toggler = {
    240        line   = '<Leader>/', -- won't be set by default since basic=false
    241        block  = '<Leader>/', -- same here
    242      },
    243    })
    244  end,
    245  },
    246 
    247 
    248  -- Which-key
    249  {
    250    'folke/which-key.nvim',
    251    event = 'VeryLazy',
    252    config = function() require('which-key').setup {} end,
    253  },
    254 
    255  -- Bufferline
    256  {
    257    'akinsho/bufferline.nvim',
    258    event = 'BufWinEnter',
    259    dependencies = 'kyazdani42/nvim-web-devicons',
    260    config = function()
    261      require('bufferline').setup { options = { separator_style = 'thick' } }
    262    end,
    263  },
    264 
    265  -- Hop
    266  {
    267    'phaazon/hop.nvim',
    268    branch = 'v2',
    269    keys = { 'f', 'F', 't', 'T' },
    270    config = function() require('hop').setup {} end,
    271  },
    272 
    273  {
    274  'akinsho/toggleterm.nvim',              -- terminal toggling plugin
    275  version = '*',
    276  keys = { { '<Leader>t', '<cmd>ToggleTerm<CR>', desc = 'Toggle floating terminal' } },
    277  opts = {
    278    size           = 20,                  -- height of split if not floating
    279    open_mapping   = [[<Leader>t]],       -- map <Leader>t to toggle
    280    direction      = 'float',             -- open as floating window
    281    float_opts     = {
    282      border       = 'curved',            -- single, double, rounded, curved, or none
    283      winblend     = 0,
    284      width        = function() return math.floor(vim.o.columns * 0.8) end,
    285      height       = function() return math.floor(vim.o.lines * 0.8) end,
    286      -- row and col will center the float
    287      row          = 0.5,
    288      col          = 0.5,
    289    },
    290    -- hide line numbers and start in insert mode
    291    hide_numbers   = true,
    292    start_in_insert= true,
    293    persist_size   = true,
    294  },
    295  config = function(_, opts)
    296    require('toggleterm').setup(opts)    -- apply settings
    297  end,
    298  },
    299 
    300  -- Notifications
    301  {
    302    'rcarriga/nvim-notify',
    303    event = 'VeryLazy',
    304    config = function()
    305      local notify = require('notify')
    306      notify.setup({
    307        background_colour = '#000000',
    308        stages = 'fade',
    309        timeout = 3000,
    310      })
    311      vim.notify = notify
    312    end,
    313  },
    314 
    315  -- Todo comments
    316  {
    317    'folke/todo-comments.nvim',
    318    event = 'VeryLazy',
    319    dependencies = { 'nvim-lua/plenary.nvim' },
    320    config = function()
    321      require('todo-comments').setup({
    322        signs = true,
    323        sign_priority = 8,
    324        keywords = {
    325          FIX = { icon = ' ', color = 'error' },
    326          TODO = { icon = ' ', color = 'info' },
    327          HACK = { icon = ' ', color = 'warning' },
    328          WARN = { icon = ' ', color = 'warning', alt = { 'WARNING', 'XXX' } },
    329          PERF = { icon = ' ', alt = { 'OPTIM', 'PERFORMANCE', 'OPTIMIZE' } },
    330          NOTE = { icon = ' ', color = 'hint', alt = { 'INFO' } },
    331        },
    332        highlight = {
    333          pattern = [[.*<(KEYWORDS)\s*:]],
    334          keyword = 'wide',
    335        },
    336      })
    337    end,
    338  },
    339 
    340  -- Neogit
    341  {
    342    "NeogitOrg/neogit",
    343    dependencies = {
    344      "nvim-lua/plenary.nvim",
    345      "sindrets/diffview.nvim",
    346      "nvim-telescope/telescope.nvim",
    347    },
    348    opts = {
    349      kind = "tab", -- or "split", "vsplit", "floating"
    350      integrations = { diffview = true, telescope = true },
    351    },
    352    keys = {
    353      { "<leader>gg", function() require("neogit").open() end, desc = "Neogit" },
    354    },
    355  },
    356 
    357  -- Noice UI
    358  {
    359    'folke/noice.nvim',
    360    event = 'VeryLazy',
    361    dependencies = {
    362      'MunifTanjim/nui.nvim',
    363      'rcarriga/nvim-notify',
    364    },
    365    config = function()
    366      require('noice').setup({
    367        lsp = {
    368          override = {
    369            ['vim.lsp.util.convert_input_to_markdown_lines'] = true,
    370            ['vim.lsp.util.stylize_markdown'] = true,
    371            ['cmp.entry.get_documentation'] = true,
    372          },
    373        },
    374        presets = {
    375          bottom_search = true,
    376          command_palette = true,
    377          long_message_to_split = true,
    378          inc_rename = false,
    379          lsp_doc_border = false,
    380        },
    381      })
    382    end,
    383  },
    384 }, {
    385  rocks = { enabled = false },  -- Disable luarocks since no plugins need it
    386 })
    387 
    388 local map = vim.keymap.set
    389 local opts = { silent = true, noremap = true }
    390 
    391 -- Better window navigation
    392 map('n', '<Leader>h', '<C-w>h', { desc = 'Move to left split',    unpack(opts) })
    393 map('n', '<Leader>j', '<C-w>j', { desc = 'Move to below split',   unpack(opts) })
    394 map('n', '<Leader>k', '<C-w>k', { desc = 'Move to above split',   unpack(opts) })
    395 map('n', '<Leader>l', '<C-w>l', { desc = 'Move to right split',   unpack(opts) })
    396 
    397 -- Resize splits with arrows
    398 map('n', '<Leader><Up>',    ':resize -2<CR>',                   { desc = 'Decrease split height', unpack(opts) })
    399 map('n', '<Leader><Down>',  ':resize +2<CR>',                   { desc = 'Increase split height', unpack(opts) })
    400 map('n', '<Leader><Left>',  ':vertical resize -2<CR>',          { desc = 'Decrease split width',  unpack(opts) })
    401 map('n', '<Leader><Right>', ':vertical resize +2<CR>',          { desc = 'Increase split width',  unpack(opts) })
    402 
    403 -- Buffer navigation
    404 map('n', '<Leader>bn', ':bnext<CR>',                              { desc = 'Next buffer',           unpack(opts) })
    405 map('n', '<Leader>bp', ':bprevious<CR>',                          { desc = 'Previous buffer',       unpack(opts) })
    406 map('n', '<Leader>bc', ':bdelete<CR>',                             { desc = 'Close buffer',          unpack(opts) })
    407 
    408 -- Quick save & quit
    409 map('n', '<Leader>w', ':write<CR>',                               { desc = 'Save current file',     unpack(opts) })
    410 map('n', '<Leader>q', ':quit<CR>',                                { desc = 'Quit current window',   unpack(opts) })
    411 map('n', '<Leader>WQ', ':wqall<CR>',                              { desc = 'Save all and quit',     unpack(opts) })
    412 
    413 -- Move lines up/down in visual mode
    414 map('v', '<Leader>j', ":m '>+1<CR>gv=gv",                         { desc = 'Move selection down',   unpack(opts) })
    415 map('v', '<Leader>k', ":m '<-2<CR>gv=gv",                         { desc = 'Move selection up',     unpack(opts) })
    416 
    417 -- Yank to system clipboard
    418 map('n', '<Leader>y', '"+y',                                      { desc = 'Yank to system clipboard',           unpack(opts) })
    419 map('v', '<Leader>y', '"+y',                                      { desc = 'Yank selection to system clipboard', unpack(opts) })
    420 map('n', '<Leader>Y', '"+Y',                                      { desc = 'Yank entire line to clipboard',      unpack(opts) })
    421 
    422 -- Paste over visual selection without losing register
    423 map('v', '<Leader>p', '"_dP',                                     { desc = 'Paste over selection',    unpack(opts) })
    424 
    425 -- Clear search highlights
    426 map('n', '<Leader>c', ':nohlsearch<CR>',                          { desc = 'Clear search highlights',unpack(opts) })
    427 
    428 -- Quick Telescope pickers
    429 map('n', '<Leader>ff', '<cmd>Telescope find_files<CR>',           { desc = 'Find files',            unpack(opts) })
    430 map('n', '<Leader>fg', '<cmd>Telescope live_grep<CR>',            { desc = 'Live grep',             unpack(opts) })
    431 map('n', '<Leader>fb', '<cmd>Telescope buffers<CR>',              { desc = 'List open buffers',     unpack(opts) })
    432 map('n', '<Leader>fh', '<cmd>Telescope help_tags<CR>',            { desc = 'Find help tags',        unpack(opts) })
    433 
    434 -- Toggle NvimTree
    435 map('n', '<Leader>e', ':NvimTreeToggle<CR>',                      { desc = 'Toggle file explorer',  unpack(opts) })
    436 
    437 -- Make ESC faster (jk/ kj in insert mode)
    438 map('i', 'jk', '<Esc>',                                           { desc = 'Exit insert mode',      unpack(opts) })
    439 map('i', 'kj', '<Esc>',                                           { desc = 'Exit insert mode',      unpack(opts) })
    440 
    441 -- Quick comment toggling (using Comment.nvim)
    442 -- map('n', '<Leader>/', '<cmd>CommentToggle<CR>', opts)
    443 -- map('v', '<Leader>/', '<esc><cmd>CommentToggle<CR>', opts)
    444 
    445 
    446 -- End of init.lua