diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..a43af69 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,135 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +This is a personal Neovim configuration built on lazy.nvim with a focus on LSP, testing, and modern plugin management. The configuration emphasizes a clean, modular structure with separate plugin files. + +## Architecture + +### Core Structure +- **init.lua**: Entry point that sets up vim options, loads lazy.nvim, and initializes core modules +- **lua/keybinds.lua**: Global keybindings (ALT navigation, terminal toggle, C# namespace helper) +- **lua/diagnostic.lua**: Diagnostic display configuration with custom signs and virtual text +- **lua/snippets.lua**: LuaSnip snippets (currently contains C# namespace/class generation) +- **lua/plugins/**: Modular plugin configurations, each file returns a lazy.nvim plugin spec + +### Plugin Architecture Pattern +Each plugin file follows lazy.nvim's structure: +```lua +return { + 'author/plugin-name', + dependencies = { ... }, + opts = { ... }, + config = function() ... end, +} +``` + +## Key Plugins & Configuration + +### LSP (lua/plugins/lsp.lua) +- Uses mason.nvim with custom registry including Crashdummyy's registry +- Configured servers: lua_ls, vtsls, jsonls (with schemastore), bashls, zls, cssls, prismals, intelephense, html, yamlls, eslint, tailwindcss, gopls, rust_analyzer, roslyn +- Auto-installs tools: stylua, prettierd, php-cs-fixer, cspell +- Blink.cmp integration for completion capabilities +- Keybindings set on LspAttach: + - `a`: Code actions + - `gd`, `gr`, `gi`: Definition/references/implementation via Telescope + - ``: Rename + - `d`: Show diagnostics float + - `D`: Jump to next diagnostic + +### Formatting (lua/plugins/conform.lua) +- Format-on-save enabled (3s timeout) +- Formatters: stylua (Lua), prettierd/prettier (JS/TS/CSS/JSON/Markdown), php-cs-fixer (PHP), gofmt (Go), csharpierd (C#) +- Manual format: `f` + +### Testing (lua/plugins/neotest.lua) +- Adapters: neotest-jest, neotest-bun +- Jest config auto-detection from project root +- Keybindings: + - `tt`: Run nearest test + - `tf`: Run all tests in current file + - `td`: Display test output + +### Fuzzy Finding (lua/plugins/telescope.lua) +- Keybindings (all start with `f`): + - `ff`: Find files + - `fg`: Live grep + - `fb`: Buffers + - `fd`: Diagnostics + - `fw`: Grep string under cursor + - `fh/fk/fs/fr/f.`: Help/keymaps/builtin/resume/oldfiles + - `ft`: Todo comments + +### C# Development +- Roslyn LSP configured +- Custom namespace insertion: `n` (reads .csproj, constructs namespace from path) +- C# class snippet: `csc` (auto-generates namespace and class from filename) +- csharpierd formatter integration + +## Development Workflow + +### Testing JavaScript/TypeScript +```bash +# Run nearest test (with cursor on test) +tt + +# Run all tests in file +tf + +# View test output +td +``` + +### Formatting +- Auto-formats on save (configured in conform.lua) +- Manual format: `f` + +### LSP Operations +- Jump to definition: `gd` (opens in Telescope) +- Find references: `gr` (opens in Telescope) +- Rename symbol: `` +- Code actions: `a` +- Show diagnostics: `d` +- Next diagnostic: `D` +- Workspace symbols: `fs` + +## Special Configurations + +### Clipboard +Uses xclip for clipboard integration on Linux (configured in init.lua with vim.schedule) + +### Theme +TokyoNight theme with transparency disabled on WSL, terminal colors disabled + +### Tab Behavior +2-space indentation, tabs converted to spaces globally + +### Window Navigation +- ALT + Arrow keys to navigate between splits +- `` mapped to `` for jump forward + +### Terminal +- ``: Open terminal in insert mode +- ``: Exit terminal mode to normal mode + +## Plugin Management + +### Installing/Updating Plugins +Lazy.nvim auto-bootstraps on first run. To manage plugins: +- Add new plugin specs to lua/plugins/ or directly in init.lua's require('lazy').setup() +- Lazy will auto-install on next startup + +### Mason Tool Management +LSP servers and formatters are auto-installed via mason-tool-installer based on the ensure_installed list in lua/plugins/lsp.lua + +## Important Notes + +- Leader key is Space +- Nerd Font required (vim.g.have_nerd_font = true) +- Swap and backup files disabled +- Relative line numbers enabled +- 10-line scrolloff for cursor positioning +- The configuration uses Neovim 0.10+ APIs with compatibility shim for 0.11 (see client_supports_method in lsp.lua) diff --git a/README.md b/README.md new file mode 100644 index 0000000..6759565 --- /dev/null +++ b/README.md @@ -0,0 +1,88 @@ +# Neovim Configuration + +Personal Neovim configuration built with [lazy.nvim](https://github.com/folke/lazy.nvim) for modern plugin management. + +## Requirements + +- Neovim >= 0.10 +- [Nerd Font](https://www.nerdfonts.com/) (for icons) +- [xclip](https://github.com/astrand/xclip) (for clipboard support on Linux) +- [ripgrep](https://github.com/BurntSushi/ripgrep) (for Telescope live grep) +- [make](https://www.gnu.org/software/make/) (for building Telescope fzf-native) + +## Installation + +1. Backup your existing Neovim configuration if you have one +2. Clone this repository to your Neovim config directory: + ```bash + git clone ~/.config/nvim + ``` +3. Start Neovim - lazy.nvim will automatically bootstrap and install all plugins: + ```bash + nvim + ``` + +## Features + +- **LSP Support**: Pre-configured language servers for TypeScript, Lua, Go, Rust, C#, PHP, and more +- **Auto-formatting**: Format-on-save with conform.nvim +- **Testing**: Integrated test runner with neotest (Jest and Bun support) +- **Fuzzy Finding**: Telescope for files, grep, LSP symbols, and more +- **Syntax Highlighting**: Tree-sitter based highlighting +- **Git Integration**: Gitsigns for inline git blame and hunks +- **Completions**: Blink.cmp for fast autocompletion +- **File Explorer**: Neo-tree for file navigation +- **Status Line**: Custom Heirline configuration + +## Key Bindings + +Leader key: `Space` + +### File Navigation +- `ff` - Find files +- `fg` - Live grep +- `fb` - Browse buffers + +### LSP +- `gd` - Go to definition +- `gr` - Find references +- `` - Rename symbol +- `a` - Code actions +- `d` - Show diagnostics + +### Testing +- `tt` - Run nearest test +- `tf` - Run tests in current file +- `td` - Display test output + +### Formatting +- `f` - Format buffer (also auto-formats on save) + +### Other +- `` - Open terminal +- `n` - Insert C# namespace (C# files only) + +## Structure + +``` +. +├── init.lua # Entry point +├── lua/ +│ ├── keybinds.lua # Global keybindings +│ ├── diagnostic.lua # Diagnostic configuration +│ ├── snippets.lua # Custom snippets +│ └── plugins/ # Plugin configurations +│ ├── lsp.lua +│ ├── telescope.lua +│ ├── conform.lua +│ ├── neotest.lua +│ └── ... +└── CLAUDE.md # AI assistant context +``` + +## Customization + +- Edit plugin configurations in `lua/plugins/` +- Add new plugins to the `require('lazy').setup()` call in `init.lua` +- Modify keybindings in `lua/keybinds.lua` or plugin-specific files +- LSP servers and formatters are managed in `lua/plugins/lsp.lua` and `lua/plugins/conform.lua` diff --git a/init.lua b/init.lua index 6e947b0..bdcd520 100644 --- a/init.lua +++ b/init.lua @@ -42,6 +42,7 @@ vim.cmd([[filetype plugin indent on]]) vim.o.tabstop = 2 vim.o.shiftwidth = 2 vim.o.expandtab = true +vim.o.winborder = 'rounded' vim.filetype.add({ extension = { @@ -109,7 +110,6 @@ require('lazy').setup({ require('plugins/pairs'), require('plugins/ccc'), require('plugins/heirline'), - require('plugins/lspsaga'), { 'folke/ts-comments.nvim', opts = {}, event = 'VeryLazy' }, { 'folke/todo-comments.nvim', @@ -136,14 +136,14 @@ require('lazy').setup({ opts = {}, }, 'jghauser/mkdir.nvim', - { - 'supermaven-inc/supermaven-nvim', - config = function() - if not (vim.fn.has_key(vim.fn.environ(), 'LOAD_SUPERMAVEN') == 0) then - require('supermaven-nvim').setup({}) - end - end, - }, + -- { + -- 'supermaven-inc/supermaven-nvim', + -- config = function() + -- if not (vim.fn.has_key(vim.fn.environ(), 'LOAD_SUPERMAVEN') == 0) then + -- require('supermaven-nvim').setup({}) + -- end + -- end, + -- }, { 'folke/todo-comments.nvim', dependencies = 'nvim-lua/plenary.nvim', diff --git a/kitty/kitty.conf b/kitty/kitty.conf index 5497d33..473350d 100644 --- a/kitty/kitty.conf +++ b/kitty/kitty.conf @@ -43,6 +43,7 @@ map ctrl+shift+p set_background_opacity 1 map super+t set_background_opacity default map ctrl+shift+enter new_window_with_cwd map ctrl+shift+n new_window_with_cwd +map ctrl+shift+u kitten unicode_input map ctrl+shift+wheel_up change_font_size all +0.5 map ctrl+shift+wheel_down change_font_size all -0.5 diff --git a/lazy-lock.json b/lazy-lock.json index 7542c8c..ea62f52 100644 --- a/lazy-lock.json +++ b/lazy-lock.json @@ -1,45 +1,43 @@ { "FixCursorHold.nvim": { "branch": "master", "commit": "1900f89dc17c603eec29960f57c00bd9ae696495" }, - "LuaSnip": { "branch": "master", "commit": "21e9fecfc07fb2cd707b6c7c3fa148550a34d053" }, - "blink.cmp": { "branch": "main", "commit": "327fff91fe6af358e990be7be1ec8b78037d2138" }, + "LuaSnip": { "branch": "master", "commit": "dae4f5aaa3574bd0c2b9dd20fb9542a02c10471c" }, + "blink.cmp": { "branch": "main", "commit": "4b18c32adef2898f95cdef6192cbd5796c1a332d" }, "ccc.nvim": { "branch": "main", "commit": "9d1a256e006decc574789dfc7d628ca11644d4c2" }, - "conform.nvim": { "branch": "master", "commit": "fbcb4fa7f34bfea9be702ffff481a8e336ebf6ed" }, - "cspell.nvim": { "branch": "main", "commit": "07d75238648ef99c0c5c05f4cfd83093d0a01dd4" }, - "fidget.nvim": { "branch": "main", "commit": "3f5475949679953af6d78654db29b944fa826e6a" }, - "friendly-snippets": { "branch": "main", "commit": "572f5660cf05f8cd8834e096d7b4c921ba18e175" }, - "gitsigns.nvim": { "branch": "main", "commit": "1ee5c1fd068c81f9dd06483e639c2aa4587dc197" }, - "grug-far.nvim": { "branch": "main", "commit": "2e991081c0e653e151fc9e659514d7c2fc31d22a" }, + "conform.nvim": { "branch": "master", "commit": "e969e302bced7ffb9a0a0323629f31feb0ca35a6" }, + "cspell.nvim": { "branch": "main", "commit": "5feecef8d109f5460c576596aba44a6253127aa4" }, + "fidget.nvim": { "branch": "main", "commit": "7fa433a83118a70fe24c1ce88d5f0bd3453c0970" }, + "friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" }, + "gitsigns.nvim": { "branch": "main", "commit": "9f3c6dd7868bcc116e9c1c1929ce063b978fa519" }, + "grug-far.nvim": { "branch": "main", "commit": "9370422e5cdd55321c0b8c4880082c5fd4e52e99" }, "heirline.nvim": { "branch": "master", "commit": "fae936abb5e0345b85c3a03ecf38525b0828b992" }, - "lazy.nvim": { "branch": "main", "commit": "1ea3c4085785f460fb0e46d2fe1ee895f5f9e7c1" }, + "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, "leetcode.nvim": { "branch": "master", "commit": "fdd3f91800b3983e27bc9fcfb99cfa7293d7f11a" }, - "lspsaga.nvim": { "branch": "main", "commit": "8efe00d6aed9db6449969f889170f1a7e43101a1" }, - "mason-lspconfig.nvim": { "branch": "main", "commit": "6bdb14f230de0904229ec367b410fb817e59b072" }, - "mason-tool-installer.nvim": { "branch": "main", "commit": "517ef5994ef9d6b738322664d5fdd948f0fdeb46" }, - "mason.nvim": { "branch": "main", "commit": "ad7146aa61dcaeb54fa900144d768f040090bff0" }, - "mini.pairs": { "branch": "main", "commit": "b9aada8c0e59f2b938e98fbf4eae0799eba96ad9" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "a324581a3c83fdacdb9804b79de1cbe00ce18550" }, + "mason-tool-installer.nvim": { "branch": "main", "commit": "443f1ef8b5e6bf47045cb2217b6f748a223cf7dc" }, + "mason.nvim": { "branch": "main", "commit": "44d1e90e1f66e077268191e3ee9d2ac97cc18e65" }, + "mini.pairs": { "branch": "main", "commit": "b7fde3719340946feb75017ef9d75edebdeb0566" }, "mkdir.nvim": { "branch": "main", "commit": "c55d1dee4f099528a1853b28bb28caa802eba217" }, - "neo-tree.nvim": { "branch": "main", "commit": "20244beec28b9d79ffb75fe1b1606f4dd8d476fc" }, - "neotest": { "branch": "master", "commit": "7166dc36af2760a76479e021e0521e23f62165f1" }, - "neotest-bun": { "branch": "main", "commit": "453759015c4c87792a720fa3cc7b643cebe9d4cf" }, - "neotest-jest": { "branch": "main", "commit": "2f657403aabab7d68eaa2cb9181dc4bb7fdd8a08" }, - "none-ls.nvim": { "branch": "main", "commit": "a96172f673f720cd4f3572e1fcd08400ed3eb25d" }, + "neo-tree.nvim": { "branch": "main", "commit": "9d6826582a3e8c84787bd7355df22a2812a1ad59" }, + "neotest": { "branch": "master", "commit": "deadfb1af5ce458742671ad3a013acb9a6b41178" }, + "neotest-bun": { "branch": "main", "commit": "af0f8684cd00a96f1e0359f1aeff2b9bf7a0ec88" }, + "neotest-jest": { "branch": "main", "commit": "3f0cc2cff1ee05394081805c622dc2551b54d8c4" }, + "none-ls.nvim": { "branch": "main", "commit": "f61f46ded0ca9edce7a09b674f8e162d10921426" }, "nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" }, - "nvim-lspconfig": { "branch": "master", "commit": "ac98db2f9f06a56498ec890a96928774eae412c3" }, + "nvim-lspconfig": { "branch": "master", "commit": "ead0f5f342d8d323441e7d4b88f0fc436a81ad5f" }, "nvim-nio": { "branch": "master", "commit": "21f5324bfac14e22ba26553caf69ec76ae8a7662" }, "nvim-treesitter": { "branch": "master", "commit": "42fc28ba918343ebfd5565147a42a26580579482" }, - "nvim-ts-autotag": { "branch": "main", "commit": "c4ca798ab95b316a768d51eaaaee48f64a4a46bc" }, - "nvim-web-devicons": { "branch": "master", "commit": "b8221e42cf7287c4dcde81f232f58d7b947c210d" }, + "nvim-ts-autotag": { "branch": "main", "commit": "8e1c0a389f20bf7f5b0dd0e00306c1247bda2595" }, + "nvim-web-devicons": { "branch": "master", "commit": "737cf6c657898d0c697311d79d361288a1343d50" }, "nvim-window-picker": { "branch": "main", "commit": "6382540b2ae5de6c793d4aa2e3fe6dbb518505ec" }, "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, - "roslyn.nvim": { "branch": "main", "commit": "7d8819239c5e2c4a0d8150da1c00fa583f761704" }, - "schemastore.nvim": { "branch": "main", "commit": "667eaa5da8f66f1dd97c905a12dd1eb544a2d259" }, - "snacks.nvim": { "branch": "main", "commit": "454ba02d69347c0735044f159b95d2495fc79a73" }, - "supermaven-nvim": { "branch": "main", "commit": "07d20fce48a5629686aefb0a7cd4b25e33947d50" }, - "telescope-fzf-native.nvim": { "branch": "main", "commit": "1f08ed60cafc8f6168b72b80be2b2ea149813e55" }, + "roslyn.nvim": { "branch": "main", "commit": "7deb9bb5b6afcb3c03c70741c6d364ffd8b59bda" }, + "schemastore.nvim": { "branch": "main", "commit": "2c2f2d3fb568bbff1a5e1344e87a979b7edf50a8" }, + "snacks.nvim": { "branch": "main", "commit": "9912042fc8bca2209105526ac7534e9a0c2071b2" }, + "telescope-fzf-native.nvim": { "branch": "main", "commit": "6fea601bd2b694c6f2ae08a6c6fab14930c60e2c" }, "telescope-ui-select.nvim": { "branch": "master", "commit": "6e51d7da30bd139a6950adf2a47fda6df9fa06d2" }, - "telescope.nvim": { "branch": "master", "commit": "b4da76be54691e854d3e0e02c36b0245f945c2c7" }, - "template-string.nvim": { "branch": "main", "commit": "da5f326b65fb74fd068aa1d8b55461b64c8fb23b" }, - "todo-comments.nvim": { "branch": "main", "commit": "19d461ddd543e938eb22505fb03fa878800270b6" }, - "tokyonight.nvim": { "branch": "main", "commit": "d14614cbfc63b6037bfccd48bb982d2ad2003352" }, - "ts-comments.nvim": { "branch": "main", "commit": "217ab9cc137fceb6659b53790bd25e608219abe1" } + "telescope.nvim": { "branch": "master", "commit": "5255aa27c422de944791318024167ad5d40aad20" }, + "template-string.nvim": { "branch": "main", "commit": "d3a26d3c449a97c44891a31736a101b60b64cf2b" }, + "todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" }, + "tokyonight.nvim": { "branch": "main", "commit": "5da1b76e64daf4c5d410f06bcb6b9cb640da7dfd" }, + "ts-comments.nvim": { "branch": "main", "commit": "123a9fb12e7229342f807ec9e6de478b1102b041" } } diff --git a/lua/keybinds.lua b/lua/keybinds.lua index d993b87..e14fd79 100644 --- a/lua/keybinds.lua +++ b/lua/keybinds.lua @@ -8,23 +8,4 @@ vim.api.nvim_set_keymap('', '', '', { silent = true }) vim.api.nvim_set_keymap('', '', '', { silent = true }) vim.api.nvim_set_keymap('', '', '', { silent = true, noremap = true }) -local print_namespace = function() - local cmd = 'bash -c "xq *.csproj -q RootNamespace"' - -- insert namespace NAMESPACE.PATH.TO.FILE; at the start of the file - local output = vim.fn.system(cmd):gsub('\n', '') - local relative_path = vim.fn.expand('%:h') - local short_path = relative_path:gsub('/', '.') - local namespace = output .. '.' .. short_path - if relative_path == '.' then - namespace = output - end - vim.cmd([[normal! gg]]) - vim.cmd([[normal! }]]) - vim.cmd([[normal! o]]) - vim.api.nvim_put({ 'namespace ' .. namespace .. ';' }, 'c', true, true) - vim.cmd([[normal! o]]) -end - -vim.keymap.set('n', 'n', print_namespace, { silent = true }) - vim.api.nvim_set_keymap('n', '', 'terminali', { silent = true }) diff --git a/lua/plugins/blink.lua b/lua/plugins/blink.lua index 856c7a8..1234e5d 100644 --- a/lua/plugins/blink.lua +++ b/lua/plugins/blink.lua @@ -20,9 +20,10 @@ return { }, completion = { - documentation = { auto_show = true }, + documentation = { auto_show = true, window = { border = 'none' } }, menu = { max_height = 24, + border = 'none', }, }, diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua index 00908ad..06afd23 100644 --- a/lua/plugins/lsp.lua +++ b/lua/plugins/lsp.lua @@ -129,11 +129,11 @@ return { yamlls = {}, eslint = {}, tailwindcss = {}, - -- vtsls = { - -- settings = { - -- vtsls = { autoUseWorkspaceTsdk = true }, - -- }, - -- }, + vtsls = { + settings = { + vtsls = { autoUseWorkspaceTsdk = true }, + }, + }, jsonls = { settings = { json = { @@ -144,8 +144,12 @@ return { }, gopls = {}, rust_analyzer = {}, + -- C# roslyn = {}, - tsgo = {}, + -- F# + fsautocomplete = {}, + -- tsgo = {}, + clangd = {}, } local ensure_installed = vim.tbl_keys(servers or {}) vim.list_extend(ensure_installed, { diff --git a/lua/plugins/lspsaga.lua b/lua/plugins/lspsaga.lua deleted file mode 100644 index 8092810..0000000 --- a/lua/plugins/lspsaga.lua +++ /dev/null @@ -1,31 +0,0 @@ -return { - 'nvimdev/lspsaga.nvim', - config = function() - require('lspsaga').setup({ - symbol_in_winbar = { - enable = false, - }, - lightbulb = { - enable = false, - }, - beacon = { - enable = false, - }, - rename = { - keys = { - quit = '', - }, - }, - code_action = { - keys = { - quit = '', - }, - }, - }) - vim.keymap.set('n', 'K', 'Lspsaga hover_doc') - end, - dependencies = { - 'nvim-treesitter/nvim-treesitter', -- optional - 'nvim-tree/nvim-web-devicons', -- optional - }, -} diff --git a/lua/plugins/web-devicons.lua b/lua/plugins/web-devicons.lua index 2f68cbc..fea1862 100644 --- a/lua/plugins/web-devicons.lua +++ b/lua/plugins/web-devicons.lua @@ -52,6 +52,11 @@ return { color = '#FFFFFF', name = 'Jar', }, + ['fsproj'] = { + icon = '󰪮', + color = '#66b2b2', + name = 'FsProj', + }, }) end, } diff --git a/lua/snippets.lua b/lua/snippets.lua index 583833a..0b5665a 100644 --- a/lua/snippets.lua +++ b/lua/snippets.lua @@ -52,13 +52,69 @@ local function get_classname() return vim.fn.expand('%:t:r') end --- C# class snippet +-- C# snippets ls.add_snippets('cs', { - s('csc', { + -- C# class snippet + s('class', { t('namespace '), - f(function() return get_namespace() end), + f(function() + return get_namespace() + end), t({ ';', '', 'public class ' }), - f(function() return get_classname() end), + f(function() + return get_classname() + end), + t({ '', '{', '\t' }), + i(0), + t({ '', '}' }), + }), + -- C# property snippet + s('prop', { + t('public '), + i(1, 'string'), + t(' '), + i(2, 'Name'), + t(' { get; set; }'), + i(0), + }), + -- C# constructor snippet + s('ctor', { + t('public '), + f(function() + return get_classname() + end), + t('('), + i(1), + t({ ')', '{', '\t' }), + i(0), + t({ '', '}' }), + }), + -- C# enum snippet + s('enum', { + t('namespace '), + f(function() + return get_namespace() + end), + t({ ';', '', 'public enum ' }), + f(function() + return get_classname() + end), + t({ '', '{', '\t' }), + i(1, 'Value1'), + t({ ',', '\t' }), + i(0), + t({ '', '}' }), + }), + -- C# interface snippet + s('interface', { + t('namespace '), + f(function() + return get_namespace() + end), + t({ ';', '', 'public interface I' }), + f(function() + return get_classname() + end), t({ '', '{', '\t' }), i(0), t({ '', '}' }),