diff --git a/.envrc b/.envrc new file mode 100644 index 00000000000..4f62431e4e9 --- /dev/null +++ b/.envrc @@ -0,0 +1,2 @@ +export PROJECT=$(basename $(pwd)) + diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000000..c73a9c995b1 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# .github/CODEOWNERS +* @dlond diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 120000 index 00000000000..65302d00713 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +/nix/store/sxkaavdlrf0762h3k07j2jm9b7d3656n-home-manager-files/.config/git/templates/.github/ISSUE_TEMPLATE/config.yml \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 120000 index 00000000000..4d77f8e9325 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1 @@ +/nix/store/sxkaavdlrf0762h3k07j2jm9b7d3656n-home-manager-files/.config/git/templates/.github/ISSUE_TEMPLATE/feature_request.md \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/rebase-reminder.md b/.github/ISSUE_TEMPLATE/rebase-reminder.md new file mode 100644 index 00000000000..d5f99fdec68 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/rebase-reminder.md @@ -0,0 +1,33 @@ +--- +name: Rebase Reminder +about: Automated reminder to rebase active worktrees +title: 'โš ๏ธ Rebase Reminder: [PR NUMBER]' +labels: rebase-reminder, automated +assignees: '' +--- + +## Action Required +PR #[NUMBER] has been merged to main. Active worktrees should be rebased. + +## Steps to Rebase + +```bash +# Update main +cd ~/dev/projects/[PROJECT] +git fetch origin main +git pull origin main + +# For each active worktree +cd ~/dev/worktrees/[PROJECT]/[WORKTREE] +git rebase origin/main +git push --force-with-lease +``` + +## Checklist +- [ ] Main branch updated +- [ ] Active worktrees identified +- [ ] Each worktree rebased +- [ ] Changes pushed with --force-with-lease + +--- +*This is an automated reminder. Close this issue once all worktrees are rebased.* diff --git a/.github/hooks/README.md b/.github/hooks/README.md new file mode 100644 index 00000000000..fbc96a8440e --- /dev/null +++ b/.github/hooks/README.md @@ -0,0 +1,2 @@ +# GitHub Hooks +Place webhook processing scripts here diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 00000000000..53c207a9653 --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,48 @@ +name: Claude PR Assistant + +on: + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + issues: + types: [opened, assigned] + pull_request_review: + types: [submitted] + +jobs: + claude-code-action: + if: | + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || + (github.event_name == 'issues' && contains(github.event.issue.body, '@claude')) + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: read + issues: read + id-token: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude PR Action + uses: anthropics/claude-code-action@beta + with: + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + # Or use OAuth token instead: + # claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + timeout_minutes: "60" + # mode: tag # Default: responds to @claude mentions + # Optional: Restrict network access to specific domains only + # experimental_allowed_domains: | + # .anthropic.com + # .github.com + # api.github.com + # .githubusercontent.com + # bun.sh + # registry.npmjs.org + # .blob.core.windows.net diff --git a/.github/workflows/daily-summary.yml b/.github/workflows/daily-summary.yml new file mode 100644 index 00000000000..1f5bf0a57e1 --- /dev/null +++ b/.github/workflows/daily-summary.yml @@ -0,0 +1,59 @@ +name: Daily Activity Summary + +on: + schedule: + - cron: '0 9 * * *' # 9 AM daily + workflow_dispatch: # Allow manual trigger + +jobs: + generate-summary: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: read + + steps: + - name: Generate Activity Summary + id: summary + run: | + echo "# ๐Ÿ“Š Daily Activity Summary" > summary.md + echo "**Date**: $(date -u +"%Y-%m-%d")" >> summary.md + echo "**Repository**: ${{ github.repository }}" >> summary.md + echo "" >> summary.md + + # Get open PRs + echo "## ๐Ÿ”„ Open Pull Requests" >> summary.md + gh pr list --repo ${{ github.repository }} --state open --limit 10 --json number,title,author,createdAt \ + --jq '.[] | "- PR #\(.number): \(.title) by @\(.author.login)"' >> summary.md || echo "- None" >> summary.md + echo "" >> summary.md + + # Get open issues + echo "## ๐Ÿ“ Open Issues" >> summary.md + gh issue list --repo ${{ github.repository }} --state open --limit 10 --json number,title,author,createdAt \ + --jq '.[] | "- Issue #\(.number): \(.title) by @\(.author.login)"' >> summary.md || echo "- None" >> summary.md + echo "" >> summary.md + + # Recent merges (last 24 hours) + echo "## โœ… Recently Merged (24h)" >> summary.md + gh pr list --repo ${{ github.repository }} --state merged --limit 5 --json number,title,mergedAt \ + --jq '.[] | select(.mergedAt > (now - 86400 | strftime("%Y-%m-%dT%H:%M:%SZ"))) | "- PR #\(.number): \(.title)"' >> summary.md || echo "- None" >> summary.md + + cat summary.md + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create Summary Issue + if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' + run: | + # Close previous daily summaries + gh issue list --repo ${{ github.repository }} --label "daily-summary" --state open --json number \ + --jq '.[].number' | xargs -I {} gh issue close {} --repo ${{ github.repository }} || true + + # Create new summary + gh issue create \ + --repo ${{ github.repository }} \ + --title "๐Ÿ“Š Daily Summary: $(date -u +"%Y-%m-%d")" \ + --body-file summary.md \ + --label "daily-summary,automated" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/lead-notifications.yml b/.github/workflows/lead-notifications.yml new file mode 100644 index 00000000000..eb404873166 --- /dev/null +++ b/.github/workflows/lead-notifications.yml @@ -0,0 +1,128 @@ +name: Lead Notifications + +on: + issues: + types: [opened, closed, reopened, assigned, unassigned] + pull_request: + types: [opened, closed, reopened, review_requested, ready_for_review, merged] + pull_request_review: + types: [submitted] + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + push: + branches: [main] + +jobs: + notify-lead: + runs-on: ubuntu-latest + if: github.actor != 'github-actions[bot]' # Don't notify about bot actions + + steps: + - name: Generate Summary + id: summary + run: | + # Determine event description + case "${{ github.event_name }}" in + "issues") + DESCRIPTION="Issue #${{ github.event.issue.number }}: ${{ github.event.action }}" + URL="${{ github.event.issue.html_url }}" + ;; + "pull_request") + DESCRIPTION="PR #${{ github.event.pull_request.number }}: ${{ github.event.action }}" + URL="${{ github.event.pull_request.html_url }}" + ;; + "pull_request_review") + DESCRIPTION="Review on PR #${{ github.event.pull_request.number }}" + URL="${{ github.event.review.html_url }}" + ;; + "issue_comment") + DESCRIPTION="Comment on #${{ github.event.issue.number }}" + URL="${{ github.event.comment.html_url }}" + ;; + "pull_request_review_comment") + DESCRIPTION="Review comment on PR #${{ github.event.pull_request.number }}" + URL="${{ github.event.comment.html_url }}" + ;; + "push") + DESCRIPTION="Push to main by ${{ github.actor }}" + URL="${{ github.event.compare }}" + ;; + *) + DESCRIPTION="${{ github.event_name }} by ${{ github.actor }}" + URL="${{ github.server_url }}/${{ github.repository }}" + ;; + esac + + echo "description=$DESCRIPTION" >> $GITHUB_OUTPUT + echo "url=$URL" >> $GITHUB_OUTPUT + + - name: Create Desktop Notification (macOS) + if: runner.os == 'macOS' + run: | + osascript -e 'display notification "${{ steps.summary.outputs.description }}" with title "[${{ github.repository }}]" sound name "Glass"' + + - name: Log Activity + run: | + echo "๐Ÿ“ข Repository Activity:" + echo "Repository: ${{ github.repository }}" + echo "Event: ${{ github.event_name }}" + echo "Actor: ${{ github.actor }}" + echo "Description: ${{ steps.summary.outputs.description }}" + echo "URL: ${{ steps.summary.outputs.url }}" + echo "Time: $(date -u +"%Y-%m-%d %H:%M:%S UTC")" + + # Optional: Post to Slack + # - name: Slack Notification + # if: github.event_name == 'pull_request' && github.event.action == 'opened' + # uses: slackapi/slack-github-action@v1 + # with: + # payload: | + # { + # "text": "New PR in ${{ github.repository }}", + # "blocks": [{ + # "type": "section", + # "text": { + # "type": "mrkdwn", + # "text": "๐Ÿ”” *${{ steps.summary.outputs.description }}*\n<${{ steps.summary.outputs.url }}|View on GitHub>" + # } + # }] + # } + # env: + # SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + + rebase-reminder: + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true + + steps: + - name: Create Rebase Reminder Issue + run: | + gh issue create \ + --repo ${{ github.repository }} \ + --title "โš ๏ธ Rebase Reminder: PR #${{ github.event.pull_request.number }} merged" \ + --body "PR #${{ github.event.pull_request.number }} was merged to main. + +Active worktrees should be rebased to avoid conflicts: + +\`\`\`bash +# Update main +cd ~/dev/projects/$(basename ${{ github.repository }}) +git fetch origin main +git pull origin main + +# For each active worktree +cd ~/dev/worktrees/$(basename ${{ github.repository }})/ +git rebase origin/main +git push --force-with-lease +\`\`\` + +**Merged PR**: ${{ github.event.pull_request.title }} +**Merged by**: ${{ github.event.pull_request.merged_by.login }} +**Link**: ${{ github.event.pull_request.html_url }} + +This issue can be closed once all active worktrees have been rebased." \ + --label "rebase-reminder,automated" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 005b535b606..b2080743a0c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,25 @@ -tags -test.sh -.luarc.json -nvim +# OS files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Neovim runtime files +.cache/ +.local/ +*.tmp +*.swp +*.swo +*~ -spell/ +# Plugin artifacts lazy-lock.json +.luarc.json + +# Development artifacts +*.disabled +todo.md +CLAUDE.md diff --git a/.tmuxp.nvim.half.json b/.tmuxp.nvim.half.json new file mode 100644 index 00000000000..bc7ab91f65b --- /dev/null +++ b/.tmuxp.nvim.half.json @@ -0,0 +1,14 @@ +{ + "session_name": "nvim", + "tmux_options": "-f /Users/dlond/.config/tmux/tmux.conf", + "windows": [ + { + "window_name": "editor", + "layout": "even-vertical", + "panes": [ + { "shell_command": ["nvim ."] }, + { "shell_command": [] } + ] + } + ] +} diff --git a/README.md b/README.md index 4113950550d..8b328ccee92 100644 --- a/README.md +++ b/README.md @@ -1,241 +1,358 @@ -# kickstart.nvim +# ๐Ÿš€ Modular Neovim Configuration -## Introduction +A clean, fast, and fully-featured Neovim configuration with perfect separation of concerns. Built on modern plugins with LSP, TreeSitter, and Copilot integration. Originally forked from [kickstart.nvim](https://github.com/nvim-lua/kickstart.nvim) and transformed into a maintainable modular structure. -A starting point for Neovim that is: +## โœจ Features -* Small -* Single-file -* Completely Documented +### ๐ŸŽฏ Core Features +- **Modular Architecture** - Clean separation between core settings, plugin specs, and configurations +- **LSP Support** - Full language server integration for C/C++, Python, Nix, LaTeX, and more +- **Intelligent Completion** - [Blink.cmp](https://github.com/saghen/blink.cmp) with Copilot integration +- **Fuzzy Finding** - Telescope with FZF for lightning-fast file and text search +- **Git Integration** - Fugitive + Gitsigns for complete git workflow +- **Syntax Highlighting** - TreeSitter-based highlighting with automatic parser installation +- **Debugging** - Full DAP (Debug Adapter Protocol) support -**NOT** a Neovim distribution, but instead a starting point for your configuration. +### ๐Ÿ”ง Language Support +- **C/C++** - clangd with automatic compile_commands.json detection +- **Python** - Pyright + Ruff for type checking and linting +- **Nix** - Full nixd integration +- **LaTeX** - TeXLab for document preparation +- **CMake** - CMake language server +- **Lua** - Optimized for Neovim config development -## Installation +## ๐Ÿ“ Project Structure -### Install Neovim - -Kickstart.nvim targets *only* the latest -['stable'](https://github.com/neovim/neovim/releases/tag/stable) and latest -['nightly'](https://github.com/neovim/neovim/releases/tag/nightly) of Neovim. -If you are experiencing issues, please make sure you have the latest versions. - -### Install External Dependencies - -External Requirements: -- Basic utils: `git`, `make`, `unzip`, C Compiler (`gcc`) -- [ripgrep](https://github.com/BurntSushi/ripgrep#installation), - [fd-find](https://github.com/sharkdp/fd#installation) -- Clipboard tool (xclip/xsel/win32yank or other depending on the platform) -- A [Nerd Font](https://www.nerdfonts.com/): optional, provides various icons - - if you have it set `vim.g.have_nerd_font` in `init.lua` to true -- Emoji fonts (Ubuntu only, and only if you want emoji!) `sudo apt install fonts-noto-color-emoji` -- Language Setup: - - If you want to write Typescript, you need `npm` - - If you want to write Golang, you will need `go` - - etc. +``` +nvim/ +โ”œโ”€โ”€ init.lua # Minimal bootstrapper +โ”œโ”€โ”€ lua/ +โ”‚ โ”œโ”€โ”€ core/ # Core Neovim settings +โ”‚ โ”‚ โ”œโ”€โ”€ bootstrap.lua # Lazy.nvim installation +โ”‚ โ”‚ โ”œโ”€โ”€ options.lua # Editor options +โ”‚ โ”‚ โ”œโ”€โ”€ keymaps.lua # Core keybindings +โ”‚ โ”‚ โ”œโ”€โ”€ autocmds.lua # Auto commands +โ”‚ โ”‚ โ””โ”€โ”€ health.lua # Health checks +โ”‚ โ””โ”€โ”€ plugins/ +โ”‚ โ”œโ”€โ”€ spec/ # Plugin declarations +โ”‚ โ”‚ โ”œโ”€โ”€ lsp.lua # Language servers +โ”‚ โ”‚ โ”œโ”€โ”€ blink.lua # Completion +โ”‚ โ”‚ โ”œโ”€โ”€ telescope.lua # Fuzzy finder +โ”‚ โ”‚ โ”œโ”€โ”€ treesitter.lua # Syntax highlighting +โ”‚ โ”‚ โ”œโ”€โ”€ git.lua # Git integration +โ”‚ โ”‚ โ””โ”€โ”€ ... # Other plugins +โ”‚ โ””โ”€โ”€ config/ # Plugin configurations +โ”‚ โ”œโ”€โ”€ lsp/ # LSP setup +โ”‚ โ”œโ”€โ”€ blink.lua # Completion config +โ”‚ โ”œโ”€โ”€ telescope.lua # Telescope config +โ”‚ โ””โ”€โ”€ ... # Other configs +``` -> [!NOTE] -> See [Install Recipes](#Install-Recipes) for additional Windows and Linux specific notes -> and quick install snippets +## ๐Ÿš€ Installation + +### Prerequisites + +#### System Requirements +- **Neovim** >= 0.10 +- **Git** - Version control +- **Make** - Build tool +- **C Compiler** - For native extensions +- **ripgrep** - Fast text search +- **fd** - Fast file finder + +#### Language Servers (Install via Nix/Homebrew/Package Manager) +```bash +# Example with Nix +nix-env -iA nixpkgs.clang-tools # clangd +nix-env -iA nixpkgs.pyright # Python LSP +nix-env -iA nixpkgs.ruff # Python linter +nix-env -iA nixpkgs.nixd # Nix LSP +nix-env -iA nixpkgs.texlab # LaTeX LSP +``` -### Install Kickstart +### Install Configuration -> [!NOTE] -> [Backup](#FAQ) your previous configuration (if any exists) +#### Backup Existing Config +```bash +mv ~/.config/nvim ~/.config/nvim.backup +``` -Neovim's configurations are located under the following paths, depending on your OS: +#### Clone This Repository +```bash +git clone https://github.com/yourusername/nvim.git ~/.config/nvim +``` -| OS | PATH | -| :- | :--- | -| Linux, MacOS | `$XDG_CONFIG_HOME/nvim`, `~/.config/nvim` | -| Windows (cmd)| `%localappdata%\nvim\` | -| Windows (powershell)| `$env:LOCALAPPDATA\nvim\` | +#### Launch Neovim +```bash +nvim +``` -#### Recommended Step +The first launch will automatically: +1. Install lazy.nvim plugin manager +2. Download and install all plugins +3. Set up TreeSitter parsers -[Fork](https://docs.github.com/en/get-started/quickstart/fork-a-repo) this repo -so that you have your own copy that you can modify, then install by cloning the -fork to your machine using one of the commands below, depending on your OS. +### Health Check -> [!NOTE] -> Your fork's URL will be something like this: -> `https://github.com//kickstart.nvim.git` +After installation, run `:checkhealth core` to verify: +- Neovim version +- Required executables +- LSP servers +- Formatters -You likely want to remove `lazy-lock.json` from your fork's `.gitignore` file -too - it's ignored in the kickstart repo to make maintenance easier, but it's -[recommended to track it in version control](https://lazy.folke.io/usage/lockfile). +## ๐Ÿ”„ Syncing with Kickstart.nvim -#### Clone kickstart.nvim +This configuration maintains compatibility with upstream kickstart.nvim while keeping all customizations in a modular structure. Here's how to sync with kickstart updates: -> [!NOTE] -> If following the recommended step above (i.e., forking the repo), replace -> `nvim-lua` with `` in the commands below +### Initial Setup (One Time) +```bash +# Add kickstart as a remote +git remote add kickstart https://github.com/nvim-lua/kickstart.nvim +git fetch kickstart +``` -
Linux and Mac +### Checking for Updates +```bash +# See what changed in kickstart +git fetch kickstart +git log kickstart/master --oneline -```sh -git clone https://github.com/nvim-lua/kickstart.nvim.git "${XDG_CONFIG_HOME:-$HOME/.config}"/nvim +# Review specific changes +git diff HEAD kickstart/master -- init.lua ``` -
+### Cherry-Picking Updates +```bash +# Option 1: Cherry-pick specific commits +git cherry-pick -
Windows +# Option 2: Manually review and integrate changes +git diff kickstart/master -- init.lua | less -If you're using `cmd.exe`: - -``` -git clone https://github.com/nvim-lua/kickstart.nvim.git "%localappdata%\nvim" +# Option 3: Check for specific feature updates (e.g., telescope) +git diff kickstart/master -- init.lua | grep -A5 -B5 telescope ``` -If you're using `powershell.exe` +### Update Workflow +1. **Review Changes**: Check kickstart's commit history for interesting updates +2. **Test Locally**: Apply changes in a test branch first +3. **Adapt to Modular Structure**: Move any new plugins/configs to appropriate `lua/plugins/` files +4. **Document**: Update relevant documentation for new features + +### Example: Adding a New Plugin from Kickstart +If kickstart adds a new plugin in their `init.lua`: +1. Create a new spec file: `lua/plugins/spec/newplugin.lua` +2. Add configuration to: `lua/plugins/config/newplugin.lua` (if needed) +3. Update: `lua/plugins/spec/init.lua` to import the new spec + +## โŒจ๏ธ Key Mappings + +### Leader Key +The leader key is set to ``. + +### Essential Keybindings + +#### File Navigation +| Key | Description | +|-----|-------------| +| `sf` | **S**earch **F**iles | +| `sg` | **S**earch by **G**rep | +| `sh` | **S**earch **H**elp | +| `` | Switch buffers | +| `/` | Fuzzy search in current buffer | + +#### LSP Features +| Key | Description | +|-----|-------------| +| `gd` | **G**oto **D**efinition | +| `gr` | **G**oto **R**eferences | +| `gI` | **G**oto **I**mplementation | +| `rn` | **R**e**n**ame symbol | +| `ca` | **C**ode **A**ction | +| `K` | Hover documentation | +| `f` | **F**ormat buffer | + +#### Git Operations +| Key | Description | +|-----|-------------| +| `gs` | Git status (Fugitive) | +| `gd` | Git diff | +| `gc` | Git commit | +| `gb` | Git blame | +| `]c` | Next git change | +| `[c` | Previous git change | +| `hs` | Stage hunk | +| `hr` | Reset hunk | + +#### Debugging +| Key | Description | +|-----|-------------| +| `` | Start/Continue debugging | +| `` | Step over | +| `` | Step into | +| `` | Step out | +| `db` | Toggle breakpoint | +| `` | Toggle debug UI | + +#### Window Navigation (Tmux-aware) +| Key | Description | +|-----|-------------| +| `` | Navigate left | +| `` | Navigate down | +| `` | Navigate up | +| `` | Navigate right | + +### Completion Keybindings +| Key | Description | +|-----|-------------| +| `` | Trigger completion | +| `` | Accept completion | +| `` | Cancel completion | +| `` | Next snippet placeholder | +| `` | Previous snippet placeholder | + +## ๐Ÿ”Œ Installed Plugins + +### Core +- [lazy.nvim](https://github.com/folke/lazy.nvim) - Plugin manager +- [plenary.nvim](https://github.com/nvim-lua/plenary.nvim) - Lua utilities + +### Editor Enhancement +- [mini.nvim](https://github.com/echasnovski/mini.nvim) - Collection of minimal plugins +- [Comment.nvim](https://github.com/numToStr/Comment.nvim) - Smart commenting +- [vim-sleuth](https://github.com/tpope/vim-sleuth) - Auto-detect indentation +- [nvim-autopairs](https://github.com/windwp/nvim-autopairs) - Auto-close brackets +- [indent-blankline.nvim](https://github.com/lukas-reineke/indent-blankline.nvim) - Indent guides +- [vim-illuminate](https://github.com/RRethy/vim-illuminate) - Highlight word under cursor + +### UI/Theme +- [tokyonight.nvim](https://github.com/folke/tokyonight.nvim) - Color scheme +- [which-key.nvim](https://github.com/folke/which-key.nvim) - Keybinding hints +- [todo-comments.nvim](https://github.com/folke/todo-comments.nvim) - Highlight TODO comments + +### Navigation +- [telescope.nvim](https://github.com/nvim-telescope/telescope.nvim) - Fuzzy finder +- [telescope-fzf-native.nvim](https://github.com/nvim-telescope/telescope-fzf-native.nvim) - FZF sorter +- [vim-tmux-navigator](https://github.com/christoomey/vim-tmux-navigator) - Seamless tmux navigation + +### Git +- [vim-fugitive](https://github.com/tpope/vim-fugitive) - Git commands +- [gitsigns.nvim](https://github.com/lewis6991/gitsigns.nvim) - Git gutter signs + +### LSP & Completion +- [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig) - LSP configurations +- [blink.cmp](https://github.com/saghen/blink.cmp) - Completion engine +- [lazydev.nvim](https://github.com/folke/lazydev.nvim) - Lua development +- [fidget.nvim](https://github.com/j-hui/fidget.nvim) - LSP progress + +### Development +- [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) - Syntax highlighting +- [nvim-treesitter-textobjects](https://github.com/nvim-treesitter/nvim-treesitter-textobjects) - Syntax-aware text objects +- [copilot.lua](https://github.com/zbirenbaum/copilot.lua) - GitHub Copilot +- [conform.nvim](https://github.com/stevearc/conform.nvim) - Formatting +- [nvim-dap](https://github.com/mfussenegger/nvim-dap) - Debug Adapter Protocol +- [nvim-dap-ui](https://github.com/rcarriga/nvim-dap-ui) - Debug UI + +## ๐Ÿ› ๏ธ Configuration + +### Customization + +All configuration files are designed to be easily customizable: + +1. **Core Settings**: Edit files in `lua/core/` + - `options.lua` - Vim options + - `keymaps.lua` - Core keybindings + +2. **Add Plugins**: Create new spec files in `lua/plugins/spec/` + ```lua + -- lua/plugins/spec/myplugin.lua + return { + 'username/plugin-name', + opts = { + -- plugin options + } + } + ``` + +3. **Complex Plugin Config**: Add config files to `lua/plugins/config/` + +### LSP Server Configuration + +LSP servers are configured in `lua/plugins/config/lsp/init.lua`. Add new servers to the `servers` table: +```lua +servers = { + myserver = { + settings = { + -- server-specific settings + } + } +} ``` -git clone https://github.com/nvim-lua/kickstart.nvim.git "${env:LOCALAPPDATA}\nvim" -``` - -
-### Post Installation +### Formatter Configuration -Start Neovim +Formatters are configured in `lua/plugins/spec/formatting.lua`: -```sh -nvim +```lua +formatters_by_ft = { + javascript = { "prettier" }, + -- add your formatters here +} ``` -That's it! Lazy will install all the plugins you have. Use `:Lazy` to view -the current plugin status. Hit `q` to close the window. - -#### Read The Friendly Documentation +## ๐Ÿ”ง Commands -Read through the `init.lua` file in your configuration folder for more -information about extending and exploring Neovim. That also includes -examples of adding popularly requested plugins. +### Custom Commands +- `:ReloadLSP` - Restart all LSP servers -> [!NOTE] -> For more information about a particular plugin check its repository's documentation. +### Health Check +- `:checkhealth core` - Run configuration health check +### Plugin Management +- `:Lazy` - Open plugin manager UI +- `:Lazy sync` - Update all plugins +- `:Lazy profile` - Profile startup time -### Getting Started +## ๐Ÿ› Troubleshooting -[The Only Video You Need to Get Started with Neovim](https://youtu.be/m8C0Cq9Uv9o) +### First Steps +1. Run `:checkhealth core` to verify installation +2. Check `:messages` for error messages +3. Ensure all prerequisites are installed -### FAQ +### Common Issues -* What should I do if I already have a pre-existing Neovim configuration? - * You should back it up and then delete all associated files. - * This includes your existing init.lua and the Neovim files in `~/.local` - which can be deleted with `rm -rf ~/.local/share/nvim/` -* Can I keep my existing configuration in parallel to kickstart? - * Yes! You can use [NVIM_APPNAME](https://neovim.io/doc/user/starting.html#%24NVIM_APPNAME)`=nvim-NAME` - to maintain multiple configurations. For example, you can install the kickstart - configuration in `~/.config/nvim-kickstart` and create an alias: - ``` - alias nvim-kickstart='NVIM_APPNAME="nvim-kickstart" nvim' - ``` - When you run Neovim using `nvim-kickstart` alias it will use the alternative - config directory and the matching local directory - `~/.local/share/nvim-kickstart`. You can apply this approach to any Neovim - distribution that you would like to try out. -* What if I want to "uninstall" this configuration: - * See [lazy.nvim uninstall](https://lazy.folke.io/usage#-uninstalling) information -* Why is the kickstart `init.lua` a single file? Wouldn't it make sense to split it into multiple files? - * The main purpose of kickstart is to serve as a teaching tool and a reference - configuration that someone can easily use to `git clone` as a basis for their own. - As you progress in learning Neovim and Lua, you might consider splitting `init.lua` - into smaller parts. A fork of kickstart that does this while maintaining the - same functionality is available here: - * [kickstart-modular.nvim](https://github.com/dam9000/kickstart-modular.nvim) - * Discussions on this topic can be found here: - * [Restructure the configuration](https://github.com/nvim-lua/kickstart.nvim/issues/218) - * [Reorganize init.lua into a multi-file setup](https://github.com/nvim-lua/kickstart.nvim/pull/473) +**Plugins not loading** +- Run `:Lazy sync` to ensure all plugins are installed +- Check for errors in `:messages` -### Install Recipes +**LSP not working** +- Verify language servers are installed (check with `:checkhealth core`) +- Run `:LspInfo` to see active servers +- Try `:ReloadLSP` to restart servers -Below you can find OS specific install instructions for Neovim and dependencies. +**Telescope not finding files** +- Ensure `ripgrep` and `fd` are installed +- Check you're not in a git-ignored directory -After installing all the dependencies continue with the [Install Kickstart](#Install-Kickstart) step. +## ๐Ÿ“ License -#### Windows Installation +This configuration is based on [kickstart.nvim](https://github.com/nvim-lua/kickstart.nvim) and is available under the MIT License. -
Windows with Microsoft C++ Build Tools and CMake -Installation may require installing build tools and updating the run command for `telescope-fzf-native` +## ๐Ÿ™ Acknowledgments -See `telescope-fzf-native` documentation for [more details](https://github.com/nvim-telescope/telescope-fzf-native.nvim#installation) +- [kickstart.nvim](https://github.com/nvim-lua/kickstart.nvim) - Initial configuration structure +- [Neovim](https://neovim.io/) - The best text editor +- All plugin authors for their amazing work -This requires: +## ๐Ÿค Contributing -- Install CMake and the Microsoft C++ Build Tools on Windows +Contributions are welcome! Feel free to: +- Report issues +- Suggest new features +- Submit pull requests -```lua -{'nvim-telescope/telescope-fzf-native.nvim', build = 'cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release && cmake --build build --config Release && cmake --install build --prefix build' } -``` -
-
Windows with gcc/make using chocolatey -Alternatively, one can install gcc and make which don't require changing the config, -the easiest way is to use choco: - -1. install [chocolatey](https://chocolatey.org/install) -either follow the instructions on the page or use winget, -run in cmd as **admin**: -``` -winget install --accept-source-agreements chocolatey.chocolatey -``` - -2. install all requirements using choco, exit the previous cmd and -open a new one so that choco path is set, and run in cmd as **admin**: -``` -choco install -y neovim git ripgrep wget fd unzip gzip mingw make -``` -
-
WSL (Windows Subsystem for Linux) - -``` -wsl --install -wsl -sudo add-apt-repository ppa:neovim-ppa/unstable -y -sudo apt update -sudo apt install make gcc ripgrep unzip git xclip neovim -``` -
- -#### Linux Install -
Ubuntu Install Steps - -``` -sudo add-apt-repository ppa:neovim-ppa/unstable -y -sudo apt update -sudo apt install make gcc ripgrep unzip git xclip neovim -``` -
-
Debian Install Steps - -``` -sudo apt update -sudo apt install make gcc ripgrep unzip git xclip curl - -# Now we install nvim -curl -LO https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.tar.gz -sudo rm -rf /opt/nvim-linux-x86_64 -sudo mkdir -p /opt/nvim-linux-x86_64 -sudo chmod a+rX /opt/nvim-linux-x86_64 -sudo tar -C /opt -xzf nvim-linux-x86_64.tar.gz - -# make it available in /usr/local/bin, distro installs to /usr/bin -sudo ln -sf /opt/nvim-linux-x86_64/bin/nvim /usr/local/bin/ -``` -
-
Fedora Install Steps - -``` -sudo dnf install -y gcc make git ripgrep fd-find unzip neovim -``` -
- -
Arch Install Steps - -``` -sudo pacman -S --noconfirm --needed gcc make git ripgrep fd unzip neovim -``` -
+--- +**Happy Coding!** ๐ŸŽ‰ \ No newline at end of file diff --git a/doc/kickstart.txt b/doc/kickstart.txt deleted file mode 100644 index cb87ac3f1de..00000000000 --- a/doc/kickstart.txt +++ /dev/null @@ -1,24 +0,0 @@ -================================================================================ -INTRODUCTION *kickstart.nvim* - -Kickstart.nvim is a project to help you get started on your neovim journey. - - *kickstart-is-not* -It is not: -- Complete framework for every plugin under the sun -- Place to add every plugin that could ever be useful - - *kickstart-is* -It is: -- Somewhere that has a good start for the most common "IDE" type features: - - autocompletion - - goto-definition - - find references - - fuzzy finding - - and hinting at what more can be done :) -- A place to _kickstart_ your journey. - - You should fork this project and use/modify it so that it matches your - style and preferences. If you don't want to do that, there are probably - other projects that would fit much better for you (and that's great!)! - - vim:tw=78:ts=8:ft=help:norl: diff --git a/doc/modular.txt b/doc/modular.txt new file mode 100644 index 00000000000..9a9c421aa3d --- /dev/null +++ b/doc/modular.txt @@ -0,0 +1,222 @@ +*modular.txt* Modular Neovim Configuration + +============================================================================== +CONTENTS *modular-contents* + + 1. Introduction ................................ |modular-intro| + 2. Quick Start ................................. |modular-quickstart| + 3. Architecture ................................ |modular-architecture| + 4. Keybindings ................................. |modular-keybindings| + 5. Commands .................................... |modular-commands| + 6. Customization ............................... |modular-customization| + 7. Troubleshooting ............................. |modular-troubleshooting| + +============================================================================== +1. INTRODUCTION *modular-intro* + +This is a modular Neovim configuration built for performance and +maintainability. Originally based on kickstart.nvim but restructured with +clean separation of concerns. + +Key features: + โ€ข Modular plugin architecture + โ€ข Full LSP support (C/C++, Python, Nix, LaTeX) + โ€ข Intelligent completion with Blink.cmp + โ€ข Git integration (Fugitive + Gitsigns) + โ€ข Debug support (DAP) + โ€ข Tmux integration + +============================================================================== +2. QUICK START *modular-quickstart* + +Prerequisites: > + - Neovim >= 0.10 + - Git, Make, C compiler + - ripgrep, fd + - Language servers (via Nix/package manager) + +Installation: >bash + # Backup existing config + mv ~/.config/nvim ~/.config/nvim.backup + + # Clone this config + git clone ~/.config/nvim + + # Start Neovim + nvim + +Health check: >vim + :checkhealth core + +============================================================================== +3. ARCHITECTURE *modular-architecture* + +Directory Structure: > + nvim/ + โ”œโ”€โ”€ init.lua # Bootstrap + โ”œโ”€โ”€ lua/ + โ”‚ โ”œโ”€โ”€ core/ # Core settings + โ”‚ โ”‚ โ”œโ”€โ”€ bootstrap.lua # Lazy.nvim + โ”‚ โ”‚ โ”œโ”€โ”€ options.lua # Vim options + โ”‚ โ”‚ โ”œโ”€โ”€ keymaps.lua # Core keymaps + โ”‚ โ”‚ โ””โ”€โ”€ health.lua # Health checks + โ”‚ โ””โ”€โ”€ plugins/ + โ”‚ โ”œโ”€โ”€ spec/ # Plugin specs + โ”‚ โ””โ”€โ”€ config/ # Plugin configs + +Loading Order: + 1. Bootstrap lazy.nvim + 2. Load core options and keymaps + 3. Load plugins via lazy.nvim + 4. Plugin configurations execute + +============================================================================== +4. KEYBINDINGS *modular-keybindings* + +Leader key: + +------------------------------------------------------------------------------ +NAVIGATION *modular-keys-navigation* + + Navigate left (window/tmux) + Navigate down + Navigate up + Navigate right + Clear search highlights + +------------------------------------------------------------------------------ +SEARCH *modular-keys-search* + + sf Search [F]iles + sg Search by [G]rep + sh Search [H]elp + sk Search [K]eymaps + sw Search current [W]ord + sd Search [D]iagnostics + / Fuzzy search in buffer + Find buffers + +------------------------------------------------------------------------------ +LSP *modular-keys-lsp* + + gd Goto Definition + gr Goto References + gI Goto Implementation + K Hover documentation + rn Rename symbol + ca Code action + f Format buffer + lr Reload LSP servers + +------------------------------------------------------------------------------ +GIT *modular-keys-git* + + gs Git status + gd Git diff + gc Git commit + gb Git blame + + ]c Next git change + [c Previous git change + hs Stage hunk + hr Reset hunk + +------------------------------------------------------------------------------ +DEBUG *modular-keys-debug* + + Start/Continue + Step over + Step into + Step out + Toggle UI + db Toggle breakpoint + +------------------------------------------------------------------------------ +COMPLETION *modular-keys-completion* + + Trigger completion + Accept + Cancel + Next snippet placeholder + +============================================================================== +5. COMMANDS *modular-commands* + +Custom Commands: + :ReloadLSP Restart all LSP servers + :checkhealth core Run configuration health check + +Plugin Commands: + :Lazy Plugin manager UI + :Lazy sync Update plugins + :Git Fugitive git status + :Telescope Open telescope + +============================================================================== +6. CUSTOMIZATION *modular-customization* + +------------------------------------------------------------------------------ +ADDING PLUGINS *modular-adding-plugins* + +Create a new spec file: >lua + -- lua/plugins/spec/myplugin.lua + return { + 'author/plugin-name', + event = 'VeryLazy', + opts = { + -- options here + } + } + +Then import it: >lua + -- lua/plugins/spec/init.lua + return { + { import = 'plugins.spec.myplugin' }, + -- other imports... + } + +------------------------------------------------------------------------------ +CONFIGURING LSP *modular-config-lsp* + +Edit `lua/plugins/config/lsp/init.lua`: >lua + local servers = { + myserver = { + settings = { + -- server settings + } + } + } + +------------------------------------------------------------------------------ +CUSTOM KEYMAPS *modular-custom-keymaps* + +Add to `lua/core/keymaps.lua`: >lua + vim.keymap.set('n', 'xx', function() + -- your function + end, { desc = 'My custom action' }) + +============================================================================== +7. TROUBLESHOOTING *modular-troubleshooting* + +Common Issues: + +LSP not working: >vim + :checkhealth core " Check if servers installed + :LspInfo " Check active servers + :ReloadLSP " Restart servers + +Plugins not loading: >vim + :Lazy sync " Update plugins + :messages " Check for errors + +Telescope issues: + โ€ข Ensure ripgrep and fd are installed + โ€ข Check you're not in git-ignored directory + +For more help: + โ€ข Run `:checkhealth core` + โ€ข Check `:messages` for errors + โ€ข See README.md for detailed documentation + +============================================================================== +vim:tw=78:ts=8:ft=help:norl: \ No newline at end of file diff --git a/doc/tags b/doc/tags index 687ae7721d9..38a19774f6a 100644 --- a/doc/tags +++ b/doc/tags @@ -1,3 +1,18 @@ -kickstart-is kickstart.txt /*kickstart-is* -kickstart-is-not kickstart.txt /*kickstart-is-not* -kickstart.nvim kickstart.txt /*kickstart.nvim* +modular-adding-plugins modular.txt /*modular-adding-plugins* +modular-architecture modular.txt /*modular-architecture* +modular-commands modular.txt /*modular-commands* +modular-config-lsp modular.txt /*modular-config-lsp* +modular-contents modular.txt /*modular-contents* +modular-custom-keymaps modular.txt /*modular-custom-keymaps* +modular-customization modular.txt /*modular-customization* +modular-intro modular.txt /*modular-intro* +modular-keybindings modular.txt /*modular-keybindings* +modular-keys-completion modular.txt /*modular-keys-completion* +modular-keys-debug modular.txt /*modular-keys-debug* +modular-keys-git modular.txt /*modular-keys-git* +modular-keys-lsp modular.txt /*modular-keys-lsp* +modular-keys-navigation modular.txt /*modular-keys-navigation* +modular-keys-search modular.txt /*modular-keys-search* +modular-quickstart modular.txt /*modular-quickstart* +modular-troubleshooting modular.txt /*modular-troubleshooting* +modular.txt modular.txt /*modular.txt* \ No newline at end of file diff --git a/init.lua b/init.lua index b98ffc6198a..e054d0c95f0 100644 --- a/init.lua +++ b/init.lua @@ -1,1016 +1,23 @@ ---[[ +-- Bootstrap lazy.nvim +require 'core.bootstrap' -===================================================================== -==================== READ THIS BEFORE CONTINUING ==================== -===================================================================== -======== .-----. ======== -======== .----------------------. | === | ======== -======== |.-""""""""""""""""""-.| |-----| ======== -======== || || | === | ======== -======== || KICKSTART.NVIM || |-----| ======== -======== || || | === | ======== -======== || || |-----| ======== -======== ||:Tutor || |:::::| ======== -======== |'-..................-'| |____o| ======== -======== `"")----------------(""` ___________ ======== -======== /::::::::::| |::::::::::\ \ no mouse \ ======== -======== /:::========| |==hjkl==:::\ \ required \ ======== -======== '""""""""""""' '""""""""""""' '""""""""""' ======== -======== ======== -===================================================================== -===================================================================== +-- Core settings (must be before plugins) +require 'core.options' +require 'core.keymaps' +require 'core.autocmds' -What is Kickstart? - - Kickstart.nvim is *not* a distribution. - - Kickstart.nvim is a starting point for your own configuration. - The goal is that you can read every line of code, top-to-bottom, understand - what your configuration is doing, and modify it to suit your needs. - - Once you've done that, you can start exploring, configuring and tinkering to - make Neovim your own! That might mean leaving Kickstart just the way it is for a while - or immediately breaking it into modular pieces. It's up to you! - - If you don't know anything about Lua, I recommend taking some time to read through - a guide. One possible example which will only take 10-15 minutes: - - https://learnxinyminutes.com/docs/lua/ - - After understanding a bit more about Lua, you can use `:help lua-guide` as a - reference for how Neovim integrates Lua. - - :help lua-guide - - (or HTML version): https://neovim.io/doc/user/lua-guide.html - -Kickstart Guide: - - TODO: The very first thing you should do is to run the command `:Tutor` in Neovim. - - If you don't know what this means, type the following: - - - - : - - Tutor - - - - (If you already know the Neovim basics, you can skip this step.) - - Once you've completed that, you can continue working through **AND READING** the rest - of the kickstart init.lua. - - Next, run AND READ `:help`. - This will open up a help window with some basic information - about reading, navigating and searching the builtin help documentation. - - This should be the first place you go to look when you're stuck or confused - with something. It's one of my favorite Neovim features. - - MOST IMPORTANTLY, we provide a keymap "sh" to [s]earch the [h]elp documentation, - which is very useful when you're not exactly sure of what you're looking for. - - I have left several `:help X` comments throughout the init.lua - These are hints about where to find more information about the relevant settings, - plugins or Neovim features used in Kickstart. - - NOTE: Look for lines like this - - Throughout the file. These are for you, the reader, to help you understand what is happening. - Feel free to delete them once you know what you're doing, but they should serve as a guide - for when you are first encountering a few different constructs in your Neovim config. - -If you experience any errors while trying to install kickstart, run `:checkhealth` for more info. - -I hope you enjoy your Neovim journey, -- TJ - -P.S. You can delete this when you're done too. It's your config now! :) ---]] - --- Set as the leader key --- See `:help mapleader` --- NOTE: Must happen before plugins are loaded (otherwise wrong leader will be used) -vim.g.mapleader = ' ' -vim.g.maplocalleader = ' ' - --- Set to true if you have a Nerd Font installed and selected in the terminal -vim.g.have_nerd_font = false - --- [[ Setting options ]] --- See `:help vim.o` --- NOTE: You can change these options as you wish! --- For more options, you can see `:help option-list` - --- Make line numbers default -vim.o.number = true --- You can also add relative line numbers, to help with jumping. --- Experiment for yourself to see if you like it! --- vim.o.relativenumber = true - --- Enable mouse mode, can be useful for resizing splits for example! -vim.o.mouse = 'a' - --- Don't show the mode, since it's already in the status line -vim.o.showmode = false - --- Sync clipboard between OS and Neovim. --- Schedule the setting after `UiEnter` because it can increase startup-time. --- Remove this option if you want your OS clipboard to remain independent. --- See `:help 'clipboard'` -vim.schedule(function() - vim.o.clipboard = 'unnamedplus' -end) - --- Enable break indent -vim.o.breakindent = true - --- Save undo history -vim.o.undofile = true - --- Case-insensitive searching UNLESS \C or one or more capital letters in the search term -vim.o.ignorecase = true -vim.o.smartcase = true - --- Keep signcolumn on by default -vim.o.signcolumn = 'yes' - --- Decrease update time -vim.o.updatetime = 250 - --- Decrease mapped sequence wait time -vim.o.timeoutlen = 300 - --- Configure how new splits should be opened -vim.o.splitright = true -vim.o.splitbelow = true - --- Sets how neovim will display certain whitespace characters in the editor. --- See `:help 'list'` --- and `:help 'listchars'` --- --- Notice listchars is set using `vim.opt` instead of `vim.o`. --- It is very similar to `vim.o` but offers an interface for conveniently interacting with tables. --- See `:help lua-options` --- and `:help lua-options-guide` -vim.o.list = true -vim.opt.listchars = { tab = 'ยป ', trail = 'ยท', nbsp = 'โฃ' } - --- Preview substitutions live, as you type! -vim.o.inccommand = 'split' - --- Show which line your cursor is on -vim.o.cursorline = true - --- Minimal number of screen lines to keep above and below the cursor. -vim.o.scrolloff = 10 - --- if performing an operation that would fail due to unsaved changes in the buffer (like `:q`), --- instead raise a dialog asking if you wish to save the current file(s) --- See `:help 'confirm'` -vim.o.confirm = true - --- [[ Basic Keymaps ]] --- See `:help vim.keymap.set()` - --- Clear highlights on search when pressing in normal mode --- See `:help hlsearch` -vim.keymap.set('n', '', 'nohlsearch') - --- Diagnostic keymaps -vim.keymap.set('n', 'q', vim.diagnostic.setloclist, { desc = 'Open diagnostic [Q]uickfix list' }) - --- Exit terminal mode in the builtin terminal with a shortcut that is a bit easier --- for people to discover. Otherwise, you normally need to press , which --- is not what someone will guess without a bit more experience. --- --- NOTE: This won't work in all terminal emulators/tmux/etc. Try your own mapping --- or just use to exit terminal mode -vim.keymap.set('t', '', '', { desc = 'Exit terminal mode' }) - --- TIP: Disable arrow keys in normal mode --- vim.keymap.set('n', '', 'echo "Use h to move!!"') --- vim.keymap.set('n', '', 'echo "Use l to move!!"') --- vim.keymap.set('n', '', 'echo "Use k to move!!"') --- vim.keymap.set('n', '', 'echo "Use j to move!!"') - --- Keybinds to make split navigation easier. --- Use CTRL+ to switch between windows --- --- See `:help wincmd` for a list of all window commands -vim.keymap.set('n', '', '', { desc = 'Move focus to the left window' }) -vim.keymap.set('n', '', '', { desc = 'Move focus to the right window' }) -vim.keymap.set('n', '', '', { desc = 'Move focus to the lower window' }) -vim.keymap.set('n', '', '', { desc = 'Move focus to the upper window' }) - --- NOTE: Some terminals have colliding keymaps or are not able to send distinct keycodes --- vim.keymap.set("n", "", "H", { desc = "Move window to the left" }) --- vim.keymap.set("n", "", "L", { desc = "Move window to the right" }) --- vim.keymap.set("n", "", "J", { desc = "Move window to the lower" }) --- vim.keymap.set("n", "", "K", { desc = "Move window to the upper" }) - --- [[ Basic Autocommands ]] --- See `:help lua-guide-autocommands` - --- Highlight when yanking (copying) text --- Try it with `yap` in normal mode --- See `:help vim.hl.on_yank()` -vim.api.nvim_create_autocmd('TextYankPost', { - desc = 'Highlight when yanking (copying) text', - group = vim.api.nvim_create_augroup('kickstart-highlight-yank', { clear = true }), - callback = function() - vim.hl.on_yank() - end, -}) - --- [[ Install `lazy.nvim` plugin manager ]] --- See `:help lazy.nvim.txt` or https://github.com/folke/lazy.nvim for more info -local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim' -if not (vim.uv or vim.loop).fs_stat(lazypath) then - local lazyrepo = 'https://github.com/folke/lazy.nvim.git' - local out = vim.fn.system { 'git', 'clone', '--filter=blob:none', '--branch=stable', lazyrepo, lazypath } - if vim.v.shell_error ~= 0 then - error('Error cloning lazy.nvim:\n' .. out) - end -end - ----@type vim.Option -local rtp = vim.opt.rtp -rtp:prepend(lazypath) - --- [[ Configure and install plugins ]] --- --- To check the current status of your plugins, run --- :Lazy --- --- You can press `?` in this menu for help. Use `:q` to close the window --- --- To update plugins you can run --- :Lazy update --- --- NOTE: Here is where you install your plugins. -require('lazy').setup({ - -- NOTE: Plugins can be added with a link (or for a github repo: 'owner/repo' link). - 'NMAC427/guess-indent.nvim', -- Detect tabstop and shiftwidth automatically - - -- NOTE: Plugins can also be added by using a table, - -- with the first argument being the link and the following - -- keys can be used to configure plugin behavior/loading/etc. - -- - -- Use `opts = {}` to automatically pass options to a plugin's `setup()` function, forcing the plugin to be loaded. - -- - - -- Alternatively, use `config = function() ... end` for full control over the configuration. - -- If you prefer to call `setup` explicitly, use: - -- { - -- 'lewis6991/gitsigns.nvim', - -- config = function() - -- require('gitsigns').setup({ - -- -- Your gitsigns configuration here - -- }) - -- end, - -- } - -- - -- Here is a more advanced example where we pass configuration - -- options to `gitsigns.nvim`. - -- - -- See `:help gitsigns` to understand what the configuration keys do - { -- Adds git related signs to the gutter, as well as utilities for managing changes - 'lewis6991/gitsigns.nvim', - opts = { - signs = { - add = { text = '+' }, - change = { text = '~' }, - delete = { text = '_' }, - topdelete = { text = 'โ€พ' }, - changedelete = { text = '~' }, - }, - }, - }, - - -- NOTE: Plugins can also be configured to run Lua code when they are loaded. - -- - -- This is often very useful to both group configuration, as well as handle - -- lazy loading plugins that don't need to be loaded immediately at startup. - -- - -- For example, in the following configuration, we use: - -- event = 'VimEnter' - -- - -- which loads which-key before all the UI elements are loaded. Events can be - -- normal autocommands events (`:help autocmd-events`). - -- - -- Then, because we use the `opts` key (recommended), the configuration runs - -- after the plugin has been loaded as `require(MODULE).setup(opts)`. - - { -- Useful plugin to show you pending keybinds. - 'folke/which-key.nvim', - event = 'VimEnter', -- Sets the loading event to 'VimEnter' - opts = { - -- delay between pressing a key and opening which-key (milliseconds) - -- this setting is independent of vim.o.timeoutlen - delay = 0, - icons = { - -- set icon mappings to true if you have a Nerd Font - mappings = vim.g.have_nerd_font, - -- If you are using a Nerd Font: set icons.keys to an empty table which will use the - -- default which-key.nvim defined Nerd Font icons, otherwise define a string table - keys = vim.g.have_nerd_font and {} or { - Up = ' ', - Down = ' ', - Left = ' ', - Right = ' ', - C = ' ', - M = ' ', - D = ' ', - S = ' ', - CR = ' ', - Esc = ' ', - ScrollWheelDown = ' ', - ScrollWheelUp = ' ', - NL = ' ', - BS = ' ', - Space = ' ', - Tab = ' ', - F1 = '', - F2 = '', - F3 = '', - F4 = '', - F5 = '', - F6 = '', - F7 = '', - F8 = '', - F9 = '', - F10 = '', - F11 = '', - F12 = '', - }, - }, - - -- Document existing key chains - spec = { - { 's', group = '[S]earch' }, - { 't', group = '[T]oggle' }, - { 'h', group = 'Git [H]unk', mode = { 'n', 'v' } }, - }, - }, - }, - - -- NOTE: Plugins can specify dependencies. - -- - -- The dependencies are proper plugin specifications as well - anything - -- you do for a plugin at the top level, you can do for a dependency. - -- - -- Use the `dependencies` key to specify the dependencies of a particular plugin - - { -- Fuzzy Finder (files, lsp, etc) - 'nvim-telescope/telescope.nvim', - event = 'VimEnter', - dependencies = { - 'nvim-lua/plenary.nvim', - { -- If encountering errors, see telescope-fzf-native README for installation instructions - 'nvim-telescope/telescope-fzf-native.nvim', - - -- `build` is used to run some command when the plugin is installed/updated. - -- This is only run then, not every time Neovim starts up. - build = 'make', - - -- `cond` is a condition used to determine whether this plugin should be - -- installed and loaded. - cond = function() - return vim.fn.executable 'make' == 1 - end, - }, - { 'nvim-telescope/telescope-ui-select.nvim' }, - - -- Useful for getting pretty icons, but requires a Nerd Font. - { 'nvim-tree/nvim-web-devicons', enabled = vim.g.have_nerd_font }, - }, - config = function() - -- Telescope is a fuzzy finder that comes with a lot of different things that - -- it can fuzzy find! It's more than just a "file finder", it can search - -- many different aspects of Neovim, your workspace, LSP, and more! - -- - -- The easiest way to use Telescope, is to start by doing something like: - -- :Telescope help_tags - -- - -- After running this command, a window will open up and you're able to - -- type in the prompt window. You'll see a list of `help_tags` options and - -- a corresponding preview of the help. - -- - -- Two important keymaps to use while in Telescope are: - -- - Insert mode: - -- - Normal mode: ? - -- - -- This opens a window that shows you all of the keymaps for the current - -- Telescope picker. This is really useful to discover what Telescope can - -- do as well as how to actually do it! - - -- [[ Configure Telescope ]] - -- See `:help telescope` and `:help telescope.setup()` - require('telescope').setup { - -- You can put your default mappings / updates / etc. in here - -- All the info you're looking for is in `:help telescope.setup()` - -- - -- defaults = { - -- mappings = { - -- i = { [''] = 'to_fuzzy_refine' }, - -- }, - -- }, - -- pickers = {} - extensions = { - ['ui-select'] = { - require('telescope.themes').get_dropdown(), - }, - }, - } - - -- Enable Telescope extensions if they are installed - pcall(require('telescope').load_extension, 'fzf') - pcall(require('telescope').load_extension, 'ui-select') - - -- See `:help telescope.builtin` - local builtin = require 'telescope.builtin' - vim.keymap.set('n', 'sh', builtin.help_tags, { desc = '[S]earch [H]elp' }) - vim.keymap.set('n', 'sk', builtin.keymaps, { desc = '[S]earch [K]eymaps' }) - vim.keymap.set('n', 'sf', builtin.find_files, { desc = '[S]earch [F]iles' }) - vim.keymap.set('n', 'ss', builtin.builtin, { desc = '[S]earch [S]elect Telescope' }) - vim.keymap.set('n', 'sw', builtin.grep_string, { desc = '[S]earch current [W]ord' }) - vim.keymap.set('n', 'sg', builtin.live_grep, { desc = '[S]earch by [G]rep' }) - vim.keymap.set('n', 'sd', builtin.diagnostics, { desc = '[S]earch [D]iagnostics' }) - vim.keymap.set('n', 'sr', builtin.resume, { desc = '[S]earch [R]esume' }) - vim.keymap.set('n', 's.', builtin.oldfiles, { desc = '[S]earch Recent Files ("." for repeat)' }) - vim.keymap.set('n', '', builtin.buffers, { desc = '[ ] Find existing buffers' }) - - -- Slightly advanced example of overriding default behavior and theme - vim.keymap.set('n', '/', function() - -- You can pass additional configuration to Telescope to change the theme, layout, etc. - builtin.current_buffer_fuzzy_find(require('telescope.themes').get_dropdown { - winblend = 10, - previewer = false, - }) - end, { desc = '[/] Fuzzily search in current buffer' }) - - -- It's also possible to pass additional configuration options. - -- See `:help telescope.builtin.live_grep()` for information about particular keys - vim.keymap.set('n', 's/', function() - builtin.live_grep { - grep_open_files = true, - prompt_title = 'Live Grep in Open Files', - } - end, { desc = '[S]earch [/] in Open Files' }) - - -- Shortcut for searching your Neovim configuration files - vim.keymap.set('n', 'sn', function() - builtin.find_files { cwd = vim.fn.stdpath 'config' } - end, { desc = '[S]earch [N]eovim files' }) - end, - }, - - -- LSP Plugins - { - -- `lazydev` configures Lua LSP for your Neovim config, runtime and plugins - -- used for completion, annotations and signatures of Neovim apis - 'folke/lazydev.nvim', - ft = 'lua', - opts = { - library = { - -- Load luvit types when the `vim.uv` word is found - { path = '${3rd}/luv/library', words = { 'vim%.uv' } }, - }, - }, - }, - { - -- Main LSP Configuration - 'neovim/nvim-lspconfig', - dependencies = { - -- Automatically install LSPs and related tools to stdpath for Neovim - -- Mason must be loaded before its dependents so we need to set it up here. - -- NOTE: `opts = {}` is the same as calling `require('mason').setup({})` - { 'mason-org/mason.nvim', opts = {} }, - 'mason-org/mason-lspconfig.nvim', - 'WhoIsSethDaniel/mason-tool-installer.nvim', - - -- Useful status updates for LSP. - { 'j-hui/fidget.nvim', opts = {} }, - - -- Allows extra capabilities provided by blink.cmp - 'saghen/blink.cmp', - }, - config = function() - -- Brief aside: **What is LSP?** - -- - -- LSP is an initialism you've probably heard, but might not understand what it is. - -- - -- LSP stands for Language Server Protocol. It's a protocol that helps editors - -- and language tooling communicate in a standardized fashion. - -- - -- In general, you have a "server" which is some tool built to understand a particular - -- language (such as `gopls`, `lua_ls`, `rust_analyzer`, etc.). These Language Servers - -- (sometimes called LSP servers, but that's kind of like ATM Machine) are standalone - -- processes that communicate with some "client" - in this case, Neovim! - -- - -- LSP provides Neovim with features like: - -- - Go to definition - -- - Find references - -- - Autocompletion - -- - Symbol Search - -- - and more! - -- - -- Thus, Language Servers are external tools that must be installed separately from - -- Neovim. This is where `mason` and related plugins come into play. - -- - -- If you're wondering about lsp vs treesitter, you can check out the wonderfully - -- and elegantly composed help section, `:help lsp-vs-treesitter` - - -- This function gets run when an LSP attaches to a particular buffer. - -- That is to say, every time a new file is opened that is associated with - -- an lsp (for example, opening `main.rs` is associated with `rust_analyzer`) this - -- function will be executed to configure the current buffer - vim.api.nvim_create_autocmd('LspAttach', { - group = vim.api.nvim_create_augroup('kickstart-lsp-attach', { clear = true }), - callback = function(event) - -- 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. - -- - -- 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 map = function(keys, func, desc, mode) - mode = mode or 'n' - vim.keymap.set(mode, keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc }) - end - - -- Rename the variable under your cursor. - -- Most Language Servers support renaming across files, etc. - map('grn', vim.lsp.buf.rename, '[R]e[n]ame') - - -- Execute a code action, usually your cursor needs to be on top of an error - -- or a suggestion from your LSP for this to activate. - map('gra', vim.lsp.buf.code_action, '[G]oto Code [A]ction', { 'n', 'x' }) - - -- Find references for the word under your cursor. - map('grr', require('telescope.builtin').lsp_references, '[G]oto [R]eferences') - - -- Jump to the implementation of the word under your cursor. - -- Useful when your language has ways of declaring types without an actual implementation. - map('gri', require('telescope.builtin').lsp_implementations, '[G]oto [I]mplementation') - - -- Jump to the definition of the word under your cursor. - -- This is where a variable was first declared, or where a function is defined, etc. - -- To jump back, press . - map('grd', require('telescope.builtin').lsp_definitions, '[G]oto [D]efinition') - - -- WARN: This is not Goto Definition, this is Goto Declaration. - -- For example, in C this would take you to the header. - map('grD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') - - -- Fuzzy find all the symbols in your current document. - -- Symbols are things like variables, functions, types, etc. - map('gO', require('telescope.builtin').lsp_document_symbols, 'Open Document Symbols') - - -- Fuzzy find all the symbols in your current workspace. - -- Similar to document symbols, except searches over your entire project. - map('gW', require('telescope.builtin').lsp_dynamic_workspace_symbols, 'Open Workspace Symbols') - - -- Jump to the type of the word under your cursor. - -- Useful when you're not sure what type a variable is and you want to see - -- the definition of its *type*, not where it was *defined*. - map('grt', require('telescope.builtin').lsp_type_definitions, '[G]oto [T]ype Definition') - - -- This function resolves a difference between neovim nightly (version 0.11) and stable (version 0.10) - ---@param client vim.lsp.Client - ---@param method vim.lsp.protocol.Method - ---@param bufnr? integer some lsp support methods only in specific files - ---@return boolean - local function client_supports_method(client, method, bufnr) - if vim.fn.has 'nvim-0.11' == 1 then - return client:supports_method(method, bufnr) - else - return client.supports_method(method, { bufnr = bufnr }) - end - end - - -- The following two autocommands are used to highlight references of the - -- word under your cursor when your cursor rests there for a little while. - -- See `:help CursorHold` for information about when this is executed - -- - -- When you move your cursor, the highlights will be cleared (the second autocommand). - local client = vim.lsp.get_client_by_id(event.data.client_id) - if client and client_supports_method(client, vim.lsp.protocol.Methods.textDocument_documentHighlight, event.buf) then - local highlight_augroup = vim.api.nvim_create_augroup('kickstart-lsp-highlight', { clear = false }) - vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, { - buffer = event.buf, - group = highlight_augroup, - callback = vim.lsp.buf.document_highlight, - }) - - vim.api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI' }, { - buffer = event.buf, - group = highlight_augroup, - callback = vim.lsp.buf.clear_references, - }) - - vim.api.nvim_create_autocmd('LspDetach', { - group = vim.api.nvim_create_augroup('kickstart-lsp-detach', { clear = true }), - callback = function(event2) - vim.lsp.buf.clear_references() - vim.api.nvim_clear_autocmds { group = 'kickstart-lsp-highlight', buffer = event2.buf } - end, - }) - end - - -- The following code creates a keymap to toggle inlay hints in your - -- code, if the language server you are using supports them - -- - -- This may be unwanted, since they displace some of your code - if client and client_supports_method(client, vim.lsp.protocol.Methods.textDocument_inlayHint, event.buf) then - map('th', function() - vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled { bufnr = event.buf }) - end, '[T]oggle Inlay [H]ints') - end - end, - }) - - -- Diagnostic Config - -- See :help vim.diagnostic.Opts - vim.diagnostic.config { - severity_sort = true, - float = { border = 'rounded', source = 'if_many' }, - underline = { severity = vim.diagnostic.severity.ERROR }, - signs = vim.g.have_nerd_font and { - text = { - [vim.diagnostic.severity.ERROR] = '๓ฐ…š ', - [vim.diagnostic.severity.WARN] = '๓ฐ€ช ', - [vim.diagnostic.severity.INFO] = '๓ฐ‹ฝ ', - [vim.diagnostic.severity.HINT] = '๓ฐŒถ ', - }, - } or {}, - virtual_text = { - source = 'if_many', - spacing = 2, - format = function(diagnostic) - local diagnostic_message = { - [vim.diagnostic.severity.ERROR] = diagnostic.message, - [vim.diagnostic.severity.WARN] = diagnostic.message, - [vim.diagnostic.severity.INFO] = diagnostic.message, - [vim.diagnostic.severity.HINT] = diagnostic.message, - } - return diagnostic_message[diagnostic.severity] - end, - }, - } - - -- LSP servers and clients are able to communicate to each other what features they support. - -- By default, Neovim doesn't support everything that is in the LSP specification. - -- When you add blink.cmp, luasnip, etc. Neovim now has *more* capabilities. - -- So, we create new capabilities with blink.cmp, and then broadcast that to the servers. - local capabilities = require('blink.cmp').get_lsp_capabilities() - - -- 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. Available keys are: - -- - cmd (table): Override the default command used to start the server - -- - filetypes (table): Override the default list of associated filetypes for the server - -- - capabilities (table): Override fields in capabilities. Can be used to disable certain LSP features. - -- - settings (table): Override the default settings passed when initializing the server. - -- For example, to see the options for `lua_ls`, you could go to: https://luals.github.io/wiki/settings/ - local servers = { - -- clangd = {}, - -- gopls = {}, - -- pyright = {}, - -- rust_analyzer = {}, - -- ... etc. See `:help lspconfig-all` for a list of all the pre-configured LSPs - -- - -- Some languages (like typescript) have entire language plugins that can be useful: - -- https://github.com/pmizio/typescript-tools.nvim - -- - -- But for many setups, the LSP (`ts_ls`) will work just fine - -- ts_ls = {}, - -- - - lua_ls = { - -- cmd = { ... }, - -- filetypes = { ... }, - -- capabilities = {}, - settings = { - Lua = { - completion = { - callSnippet = 'Replace', - }, - -- You can toggle below to ignore Lua_LS's noisy `missing-fields` warnings - -- diagnostics = { disable = { 'missing-fields' } }, - }, - }, - }, - } - - -- Ensure the servers and tools above are installed - -- - -- To check the current status of installed tools and/or manually install - -- other tools, you can run - -- :Mason - -- - -- You can press `g?` for help in this menu. - -- - -- `mason` had to be setup earlier: to configure its options see the - -- `dependencies` table for `nvim-lspconfig` above. - -- - -- You can add other tools here that you want Mason to install - -- for you, so that they are available from within Neovim. - local ensure_installed = vim.tbl_keys(servers or {}) - vim.list_extend(ensure_installed, { - 'stylua', -- Used to format Lua code - }) - require('mason-tool-installer').setup { ensure_installed = ensure_installed } - - require('mason-lspconfig').setup { - ensure_installed = {}, -- explicitly set to an empty table (Kickstart populates installs via mason-tool-installer) - automatic_installation = false, - handlers = { - function(server_name) - local server = servers[server_name] or {} - -- This handles overriding only values explicitly passed - -- by the server configuration above. Useful when disabling - -- certain features of an LSP (for example, turning off formatting for ts_ls) - server.capabilities = vim.tbl_deep_extend('force', {}, capabilities, server.capabilities or {}) - require('lspconfig')[server_name].setup(server) - end, - }, - } - end, - }, - - { -- Autoformat - 'stevearc/conform.nvim', - event = { 'BufWritePre' }, - cmd = { 'ConformInfo' }, - keys = { - { - 'f', - function() - require('conform').format { async = true, lsp_format = 'fallback' } - end, - mode = '', - desc = '[F]ormat buffer', - }, - }, - opts = { - notify_on_error = false, - format_on_save = function(bufnr) - -- Disable "format_on_save lsp_fallback" for languages that don't - -- have a well standardized coding style. You can add additional - -- languages here or re-enable it for the disabled ones. - local disable_filetypes = { c = true, cpp = true } - if disable_filetypes[vim.bo[bufnr].filetype] then - return nil - else - return { - timeout_ms = 500, - lsp_format = 'fallback', - } - end - end, - formatters_by_ft = { - lua = { 'stylua' }, - -- Conform can also run multiple formatters sequentially - -- python = { "isort", "black" }, - -- - -- You can use 'stop_after_first' to run the first available formatter from the list - -- javascript = { "prettierd", "prettier", stop_after_first = true }, - }, - }, - }, - - { -- Autocompletion - 'saghen/blink.cmp', - event = 'VimEnter', - version = '1.*', - dependencies = { - -- Snippet Engine - { - 'L3MON4D3/LuaSnip', - version = '2.*', - build = (function() - -- Build Step is needed for regex support in snippets. - -- This step is not supported in many windows environments. - -- Remove the below condition to re-enable on windows. - if vim.fn.has 'win32' == 1 or vim.fn.executable 'make' == 0 then - return - end - return 'make install_jsregexp' - end)(), - dependencies = { - -- `friendly-snippets` contains a variety of premade snippets. - -- See the README about individual language/framework/plugin snippets: - -- https://github.com/rafamadriz/friendly-snippets - -- { - -- 'rafamadriz/friendly-snippets', - -- config = function() - -- require('luasnip.loaders.from_vscode').lazy_load() - -- end, - -- }, - }, - opts = {}, - }, - 'folke/lazydev.nvim', - }, - --- @module 'blink.cmp' - --- @type blink.cmp.Config - opts = { - keymap = { - -- 'default' (recommended) for mappings similar to built-in completions - -- to accept ([y]es) the completion. - -- This will auto-import if your LSP supports it. - -- This will expand snippets if the LSP sent a snippet. - -- 'super-tab' for tab to accept - -- 'enter' for enter to accept - -- 'none' for no mappings - -- - -- For an understanding of why the 'default' preset is recommended, - -- you will need to read `:help ins-completion` - -- - -- No, but seriously. Please read `:help ins-completion`, it is really good! - -- - -- All presets have the following mappings: - -- /: move to right/left of your snippet expansion - -- : Open menu or open docs if already open - -- / or /: Select next/previous item - -- : Hide menu - -- : Toggle signature help - -- - -- See :h blink-cmp-config-keymap for defining your own keymap - preset = 'default', - - -- For more advanced Luasnip keymaps (e.g. selecting choice nodes, expansion) see: - -- https://github.com/L3MON4D3/LuaSnip?tab=readme-ov-file#keymaps - }, - - appearance = { - -- 'mono' (default) for 'Nerd Font Mono' or 'normal' for 'Nerd Font' - -- Adjusts spacing to ensure icons are aligned - nerd_font_variant = 'mono', - }, - - completion = { - -- By default, you may press `` to show the documentation. - -- Optionally, set `auto_show = true` to show the documentation after a delay. - documentation = { auto_show = false, auto_show_delay_ms = 500 }, - }, - - sources = { - default = { 'lsp', 'path', 'snippets', 'lazydev' }, - providers = { - lazydev = { module = 'lazydev.integrations.blink', score_offset = 100 }, - }, - }, - - snippets = { preset = 'luasnip' }, - - -- Blink.cmp includes an optional, recommended rust fuzzy matcher, - -- which automatically downloads a prebuilt binary when enabled. - -- - -- By default, we use the Lua implementation instead, but you may enable - -- the rust implementation via `'prefer_rust_with_warning'` - -- - -- See :h blink-cmp-config-fuzzy for more information - fuzzy = { implementation = 'lua' }, - - -- Shows a signature help window while you type arguments for a function - signature = { enabled = true }, - }, - }, - - { -- You can easily change to a different colorscheme. - -- Change the name of the colorscheme plugin below, and then - -- change the command in the config to whatever the name of that colorscheme is. - -- - -- If you want to see what colorschemes are already installed, you can use `:Telescope colorscheme`. - 'folke/tokyonight.nvim', - priority = 1000, -- Make sure to load this before all the other start plugins. - config = function() - ---@diagnostic disable-next-line: missing-fields - require('tokyonight').setup { - styles = { - comments = { italic = false }, -- Disable italics in comments - }, - } - - -- Load the colorscheme here. - -- Like many other themes, this one has different styles, and you could load - -- any other, such as 'tokyonight-storm', 'tokyonight-moon', or 'tokyonight-day'. - vim.cmd.colorscheme 'tokyonight-night' - end, - }, - - -- Highlight todo, notes, etc in comments - { 'folke/todo-comments.nvim', event = 'VimEnter', dependencies = { 'nvim-lua/plenary.nvim' }, opts = { signs = false } }, - - { -- Collection of various small independent plugins/modules - 'echasnovski/mini.nvim', - config = function() - -- Better Around/Inside textobjects - -- - -- Examples: - -- - va) - [V]isually select [A]round [)]paren - -- - yinq - [Y]ank [I]nside [N]ext [Q]uote - -- - ci' - [C]hange [I]nside [']quote - require('mini.ai').setup { n_lines = 500 } - - -- Add/delete/replace surroundings (brackets, quotes, etc.) - -- - -- - saiw) - [S]urround [A]dd [I]nner [W]ord [)]Paren - -- - sd' - [S]urround [D]elete [']quotes - -- - sr)' - [S]urround [R]eplace [)] ['] - require('mini.surround').setup() - - -- Simple and easy statusline. - -- You could remove this setup call if you don't like it, - -- and try some other statusline plugin - local statusline = require 'mini.statusline' - -- set use_icons to true if you have a Nerd Font - statusline.setup { use_icons = vim.g.have_nerd_font } - - -- You can configure sections in the statusline by overriding their - -- default behavior. For example, here we set the section for - -- cursor location to LINE:COLUMN - ---@diagnostic disable-next-line: duplicate-set-field - statusline.section_location = function() - return '%2l:%-2v' - end - - -- ... and there is more! - -- Check out: https://github.com/echasnovski/mini.nvim - end, - }, - { -- Highlight, edit, and navigate code - 'nvim-treesitter/nvim-treesitter', - build = ':TSUpdate', - main = 'nvim-treesitter.configs', -- Sets main module to use for opts - -- [[ Configure Treesitter ]] See `:help nvim-treesitter` - opts = { - ensure_installed = { 'bash', 'c', 'diff', 'html', 'lua', 'luadoc', 'markdown', 'markdown_inline', 'query', 'vim', 'vimdoc' }, - -- Autoinstall languages that are not installed - auto_install = true, - highlight = { - enable = true, - -- Some languages depend on vim's regex highlighting system (such as Ruby) for indent rules. - -- If you are experiencing weird indenting issues, add the language to - -- the list of additional_vim_regex_highlighting and disabled languages for indent. - additional_vim_regex_highlighting = { 'ruby' }, +-- Load plugins via lazy.nvim +require('lazy').setup('plugins.spec', { + change_detection = { enabled = true, notify = false }, + performance = { + rtp = { + disabled_plugins = { + 'gzip', + 'tarPlugin', + 'tohtml', + 'tutor', + 'zipPlugin', }, - indent = { enable = true, disable = { 'ruby' } }, - }, - -- There are additional nvim-treesitter modules that you can use to interact - -- with nvim-treesitter. You should go explore a few and see what interests you: - -- - -- - Incremental selection: Included, see `:help nvim-treesitter-incremental-selection-mod` - -- - Show your current context: https://github.com/nvim-treesitter/nvim-treesitter-context - -- - Treesitter + textobjects: https://github.com/nvim-treesitter/nvim-treesitter-textobjects - }, - - -- The following comments only work if you have downloaded the kickstart repo, not just copy pasted the - -- init.lua. If you want these files, they are in the repository, so you can just download them and - -- place them in the correct locations. - - -- NOTE: Next step on your Neovim journey: Add/Configure additional plugins for Kickstart - -- - -- Here are some example plugins that I've included in the Kickstart repository. - -- Uncomment any of the lines below to enable them (you will need to restart nvim). - -- - -- require 'kickstart.plugins.debug', - -- require 'kickstart.plugins.indent_line', - -- require 'kickstart.plugins.lint', - -- require 'kickstart.plugins.autopairs', - -- require 'kickstart.plugins.neo-tree', - -- require 'kickstart.plugins.gitsigns', -- adds gitsigns recommend keymaps - - -- NOTE: The import below can automatically add your own plugins, configuration, etc from `lua/custom/plugins/*.lua` - -- This is the easiest way to modularize your config. - -- - -- Uncomment the following line and add your plugins to `lua/custom/plugins/*.lua` to get going. - -- { import = 'custom.plugins' }, - -- - -- For additional information with loading, sourcing and examples see `:help lazy.nvim-๐Ÿ”Œ-plugin-spec` - -- Or use telescope! - -- In normal mode type `sh` then write `lazy.nvim-plugin` - -- you can continue same window with `sr` which resumes last telescope search -}, { - ui = { - -- If you are using a Nerd Font: set icons to an empty table which will use the - -- default lazy.nvim defined Nerd Font icons, otherwise define a unicode icons table - icons = vim.g.have_nerd_font and {} or { - cmd = 'โŒ˜', - config = '๐Ÿ› ', - event = '๐Ÿ“…', - ft = '๐Ÿ“‚', - init = 'โš™', - keys = '๐Ÿ—', - plugin = '๐Ÿ”Œ', - runtime = '๐Ÿ’ป', - require = '๐ŸŒ™', - source = '๐Ÿ“„', - start = '๐Ÿš€', - task = '๐Ÿ“Œ', - lazy = '๐Ÿ’ค ', }, }, }) - --- The line beneath this is called `modeline`. See `:help modeline` --- vim: ts=2 sts=2 sw=2 et diff --git a/lua/core/autocmds.lua b/lua/core/autocmds.lua new file mode 100644 index 00000000000..5a0f38c7ca0 --- /dev/null +++ b/lua/core/autocmds.lua @@ -0,0 +1,49 @@ +-- [[ Basic Autocommands ]] +-- See `:help lua-guide-autocommands` + +-- Highlight when yanking (copying) text +-- Try it with `yap` in normal mode +-- See `:help vim.hl.on_yank()` +vim.api.nvim_create_autocmd('TextYankPost', { + desc = 'Highlight when yanking (copying) text', + group = vim.api.nvim_create_augroup('highlight-yank', { clear = true }), + callback = function() + vim.hl.on_yank() + end, +}) + +-- Warn when trying to quit a shared tmux session +local function is_shared_session() + local tmux = vim.env.TMUX + if not tmux or tmux == '' then + return false + end + + -- Check if session name contains "-nvim-shared" + local handle = io.popen "tmux display-message -p '#{session_name}' 2>/dev/null" + if handle then + local session_name = handle:read('*a'):gsub('\n', '') + handle:close() + return session_name:match '%-nvim%-shared$' ~= nil + end + return false +end + +-- Create an autocommand group for shared session warning +local shared_session_group = vim.api.nvim_create_augroup("SharedSessionWarning", { clear = true }) + + +-- Override quit commands for shared sessions +vim.api.nvim_create_autocmd('VimLeavePre', { + group = shared_session_group, + callback = function() + if is_shared_session() then + local response = vim.fn.input("โš ๏ธ Closing shared nvim session! Confirm with y/Y: ") + if response:lower() ~= "y" then + -- Cancel the quit by throwing an error + error("Quit cancelled") + end + end + end, +}) + diff --git a/lua/core/bootstrap.lua b/lua/core/bootstrap.lua new file mode 100644 index 00000000000..e21b1f46afc --- /dev/null +++ b/lua/core/bootstrap.lua @@ -0,0 +1,13 @@ +-- Lazy.nvim installation +local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim' +if not (vim.uv or vim.loop).fs_stat(lazypath) then + vim.fn.system { + 'git', + 'clone', + '--filter=blob:none', + 'https://github.com/folke/lazy.nvim.git', + '--branch=stable', + lazypath, + } +end +vim.opt.rtp:prepend(lazypath) \ No newline at end of file diff --git a/lua/core/health.lua b/lua/core/health.lua new file mode 100644 index 00000000000..5e2697a93b5 --- /dev/null +++ b/lua/core/health.lua @@ -0,0 +1,98 @@ +-- Health check for the modular Neovim configuration + +local M = {} + +local check_version = function() + local verstr = tostring(vim.version()) + if not vim.version.ge then + vim.health.error(string.format("Neovim out of date: '%s'. Upgrade to latest stable or nightly", verstr)) + return + end + + if vim.version.ge(vim.version(), '0.10-dev') then + vim.health.ok(string.format("Neovim version is: '%s'", verstr)) + else + vim.health.error(string.format("Neovim out of date: '%s'. Upgrade to latest stable or nightly", verstr)) + end +end + +local check_external_reqs = function() + -- Basic utils + for _, exe in ipairs { 'git', 'make', 'unzip' } do + local is_executable = vim.fn.executable(exe) == 1 + if is_executable then + vim.health.ok(string.format("Found executable: '%s'", exe)) + else + vim.health.warn(string.format("Could not find executable: '%s'", exe)) + end + end + + -- Search tools + for _, exe in ipairs { 'rg', 'fd' } do + local is_executable = vim.fn.executable(exe) == 1 + if is_executable then + vim.health.ok(string.format("Found search tool: '%s'", exe)) + else + vim.health.warn(string.format("Could not find search tool: '%s' (required for Telescope)", exe)) + end + end +end + +local check_lsp_servers = function() + -- Check for LSP servers installed via Nix + local servers = { + { name = 'clangd', desc = 'C/C++ language server' }, + { name = 'pyright', desc = 'Python language server' }, + { name = 'ruff', desc = 'Python linter/formatter' }, + { name = 'nixd', desc = 'Nix language server' }, + { name = 'texlab', desc = 'LaTeX language server' }, + { name = 'cmake-language-server', desc = 'CMake language server' }, + } + + vim.health.start('LSP Servers (via Nix/Home Manager)') + for _, server in ipairs(servers) do + local is_executable = vim.fn.executable(server.name) == 1 + if is_executable then + vim.health.ok(string.format("Found %s: '%s'", server.desc, server.name)) + else + vim.health.info(string.format("Not found: '%s' (%s) - install via Nix if needed", server.name, server.desc)) + end + end +end + +local check_formatters = function() + -- Check for formatters installed via Nix + local formatters = { + { name = 'stylua', filetype = 'lua' }, + { name = 'clang-format', filetype = 'c/cpp' }, + { name = 'alejandra', filetype = 'nix' }, + } + + vim.health.start('Formatters (via Nix/Home Manager)') + for _, formatter in ipairs(formatters) do + local is_executable = vim.fn.executable(formatter.name) == 1 + if is_executable then + vim.health.ok(string.format("Found formatter for %s: '%s'", formatter.filetype, formatter.name)) + else + vim.health.info(string.format("Not found: '%s' (%s) - install via Nix if needed", formatter.name, formatter.filetype)) + end + end +end + +function M.check() + vim.health.start('Modular Neovim Configuration') + + vim.health.info [[NOTE: Not every warning needs to be fixed. +Only install tools for languages you actually use. +All language servers and formatters should be installed via Nix/Home Manager.]] + + local uv = vim.uv or vim.loop + vim.health.info('System Information: ' .. vim.inspect(uv.os_uname())) + + check_version() + check_external_reqs() + check_lsp_servers() + check_formatters() +end + +return M \ No newline at end of file diff --git a/lua/core/keymaps.lua b/lua/core/keymaps.lua new file mode 100644 index 00000000000..a77f4763bba --- /dev/null +++ b/lua/core/keymaps.lua @@ -0,0 +1,68 @@ +-- [[ Basic Keymaps ]] +-- See `:help vim.keymap.set()` + +-- Clear search highlights with Escape in normal mode +vim.keymap.set('n', '', 'nohlsearch') + +-- Diagnostic keymaps +vim.keymap.set('n', 'q', vim.diagnostic.setloclist, { desc = 'Open diagnostic [Q]uickfix list' }) + +-- Exit terminal mode with double Escape +vim.keymap.set('t', '', '', { desc = 'Exit terminal mode' }) + +-- NOTE: Window navigation is handled by nvim-tmux-navigator plugin +-- which provides seamless navigation between vim splits and tmux panes + +-- LSP reload function +local function reload_lsp() + local clients = vim.lsp.get_clients() + if #clients == 0 then + print('No LSP clients running') + return + end + + for _, client in ipairs(clients) do + vim.lsp.stop_client(client.id) + end + + vim.defer_fn(function() + vim.cmd('LspStart') + print('LSP servers reloaded') + end, 500) +end + +-- Reload LSP keybind +vim.keymap.set('n', 'lr', reload_lsp, { desc = '[L]SP [R]eload all servers' }) + +-- Buffer management keymaps +vim.keymap.set('n', 'bb', 'Telescope buffers', { desc = '[B]rowse [B]uffers' }) +vim.keymap.set('n', '[b', 'bprevious', { desc = 'Previous buffer' }) +vim.keymap.set('n', ']b', 'bnext', { desc = 'Next buffer' }) +vim.keymap.set('n', 'bd', 'bdelete', { desc = '[B]uffer [D]elete' }) +vim.keymap.set('n', 'ba', '%bd|e#', { desc = '[B]uffers close [A]ll but current' }) +vim.keymap.set('n', 'bn', 'enew', { desc = '[B]uffer [N]ew' }) + +-- Quick buffer switching with numbers +for i = 1, 9 do + vim.keymap.set('n', '' .. i, 'buffer ' .. i .. '', { desc = 'Switch to buffer ' .. i }) +end + +-- Alternate file (toggle between two most recent files) +vim.keymap.set('n', '', '', { desc = 'Toggle alternate file' }) + +-- Window management keymaps +vim.keymap.set('n', 'ws', 'split', { desc = '[W]indow [S]plit horizontal' }) +vim.keymap.set('n', 'wv', 'vsplit', { desc = '[W]indow [V]ertical split' }) +vim.keymap.set('n', 'wc', 'close', { desc = '[W]indow [C]lose' }) +vim.keymap.set('n', 'wo', 'only', { desc = '[W]indow [O]nly (close others)' }) +vim.keymap.set('n', 'ww', 'w', { desc = '[W]indow cycle' }) +vim.keymap.set('n', 'w=', '=', { desc = '[W]indow balance sizes' }) + +-- Window resizing with arrow keys +vim.keymap.set('n', '', 'resize +2', { desc = 'Increase window height' }) +vim.keymap.set('n', '', 'resize -2', { desc = 'Decrease window height' }) +vim.keymap.set('n', '', 'vertical resize -2', { desc = 'Decrease window width' }) +vim.keymap.set('n', '', 'vertical resize +2', { desc = 'Increase window width' }) + +-- Standard practice for Lua modules that don't need to return complex data +return {} diff --git a/lua/core/options.lua b/lua/core/options.lua new file mode 100644 index 00000000000..2047b71fd73 --- /dev/null +++ b/lua/core/options.lua @@ -0,0 +1,68 @@ +-- Set as the leader key +-- See `:help mapleader` +-- NOTE: Must happen before plugins are loaded (otherwise wrong leader will be used) +vim.g.mapleader = ' ' +vim.g.maplocalleader = ' ' + +-- Load Nix-controlled settings if available +pcall(require, 'nix-settings') + +-- Place custom vim options here + +-- Set based on your font installation +vim.g.have_nerd_font = true + +-- [[ Essential Options from Kickstart ]] +-- These MUST be set since we're not loading kickstart's defaults + +-- Line numbers +vim.opt.number = true +vim.opt.relativenumber = true + +-- Mouse and interaction +vim.opt.mouse = 'a' -- Enable mouse mode +vim.opt.showmode = false -- Don't show mode since we have a statusline + +-- Clipboard - sync with system clipboard +vim.opt.clipboard = 'unnamedplus' + +-- Indentation settings +vim.opt.breakindent = true -- Enable break indent +vim.opt.smartindent = true +vim.opt.autoindent = true +vim.opt.expandtab = true +vim.opt.tabstop = 2 +vim.opt.shiftwidth = 2 +vim.opt.softtabstop = 2 + +-- Save undo history +vim.opt.undofile = true + +-- Search settings +vim.opt.ignorecase = true -- Case insensitive searching +vim.opt.smartcase = true -- Unless capital in search +vim.opt.hlsearch = true -- Highlight search results + +-- Keep signcolumn on by default +vim.opt.signcolumn = 'yes' + +-- Decrease update time +vim.opt.updatetime = 250 +vim.opt.timeoutlen = 300 -- Time to wait for mapped sequence + +-- Configure how new splits should be opened +vim.opt.splitright = true +vim.opt.splitbelow = true + +-- Sets how neovim will display certain whitespace characters +vim.opt.list = true +vim.opt.listchars = { tab = 'ยป ', trail = 'ยท', nbsp = 'โฃ' } + +-- Preview substitutions live +vim.opt.inccommand = 'split' + +-- Show which line your cursor is on +vim.opt.cursorline = true + +-- Minimal number of screen lines to keep above and below the cursor +vim.opt.scrolloff = 10 diff --git a/lua/custom/plugins/init.lua b/lua/custom/plugins/init.lua deleted file mode 100644 index be0eb9d8d7a..00000000000 --- a/lua/custom/plugins/init.lua +++ /dev/null @@ -1,5 +0,0 @@ --- You can add your own plugins here or in other files in this directory! --- I promise not to create any merge conflicts in this directory :) --- --- See the kickstart.nvim README for more information -return {} diff --git a/lua/kickstart/health.lua b/lua/kickstart/health.lua deleted file mode 100644 index b59d08649af..00000000000 --- a/lua/kickstart/health.lua +++ /dev/null @@ -1,52 +0,0 @@ ---[[ --- --- This file is not required for your own configuration, --- but helps people determine if their system is setup correctly. --- ---]] - -local check_version = function() - local verstr = tostring(vim.version()) - if not vim.version.ge then - vim.health.error(string.format("Neovim out of date: '%s'. Upgrade to latest stable or nightly", verstr)) - return - end - - if vim.version.ge(vim.version(), '0.10-dev') then - vim.health.ok(string.format("Neovim version is: '%s'", verstr)) - else - vim.health.error(string.format("Neovim out of date: '%s'. Upgrade to latest stable or nightly", verstr)) - end -end - -local check_external_reqs = function() - -- Basic utils: `git`, `make`, `unzip` - for _, exe in ipairs { 'git', 'make', 'unzip', 'rg' } do - local is_executable = vim.fn.executable(exe) == 1 - if is_executable then - vim.health.ok(string.format("Found executable: '%s'", exe)) - else - vim.health.warn(string.format("Could not find executable: '%s'", exe)) - end - end - - return true -end - -return { - check = function() - vim.health.start 'kickstart.nvim' - - vim.health.info [[NOTE: Not every warning is a 'must-fix' in `:checkhealth` - - Fix only warnings for plugins and languages you intend to use. - Mason will give warnings for languages that are not installed. - You do not need to install, unless you want to use those languages!]] - - local uv = vim.uv or vim.loop - vim.health.info('System Information: ' .. vim.inspect(uv.os_uname())) - - check_version() - check_external_reqs() - end, -} diff --git a/lua/kickstart/plugins/autopairs.lua b/lua/kickstart/plugins/autopairs.lua deleted file mode 100644 index 386d392e7ad..00000000000 --- a/lua/kickstart/plugins/autopairs.lua +++ /dev/null @@ -1,8 +0,0 @@ --- autopairs --- https://github.com/windwp/nvim-autopairs - -return { - 'windwp/nvim-autopairs', - event = 'InsertEnter', - opts = {}, -} diff --git a/lua/kickstart/plugins/debug.lua b/lua/kickstart/plugins/debug.lua deleted file mode 100644 index 8e332bf2ff9..00000000000 --- a/lua/kickstart/plugins/debug.lua +++ /dev/null @@ -1,148 +0,0 @@ --- debug.lua --- --- Shows how to use the DAP plugin to debug your code. --- --- Primarily focused on configuring the debugger for Go, but can --- be extended to other languages as well. That's why it's called --- kickstart.nvim and not kitchen-sink.nvim ;) - -return { - -- NOTE: Yes, you can install new plugins here! - 'mfussenegger/nvim-dap', - -- NOTE: And you can specify dependencies as well - dependencies = { - -- Creates a beautiful debugger UI - 'rcarriga/nvim-dap-ui', - - -- Required dependency for nvim-dap-ui - 'nvim-neotest/nvim-nio', - - -- Installs the debug adapters for you - 'mason-org/mason.nvim', - 'jay-babu/mason-nvim-dap.nvim', - - -- Add your own debuggers here - 'leoluz/nvim-dap-go', - }, - keys = { - -- Basic debugging keymaps, feel free to change to your liking! - { - '', - function() - require('dap').continue() - end, - desc = 'Debug: Start/Continue', - }, - { - '', - function() - require('dap').step_into() - end, - desc = 'Debug: Step Into', - }, - { - '', - function() - require('dap').step_over() - end, - desc = 'Debug: Step Over', - }, - { - '', - function() - require('dap').step_out() - end, - desc = 'Debug: Step Out', - }, - { - 'b', - function() - require('dap').toggle_breakpoint() - end, - desc = 'Debug: Toggle Breakpoint', - }, - { - 'B', - function() - require('dap').set_breakpoint(vim.fn.input 'Breakpoint condition: ') - end, - desc = 'Debug: Set Breakpoint', - }, - -- Toggle to see last session result. Without this, you can't see session output in case of unhandled exception. - { - '', - function() - require('dapui').toggle() - end, - desc = 'Debug: See last session result.', - }, - }, - config = function() - local dap = require 'dap' - local dapui = require 'dapui' - - require('mason-nvim-dap').setup { - -- Makes a best effort to setup the various debuggers with - -- reasonable debug configurations - automatic_installation = true, - - -- You can provide additional configuration to the handlers, - -- see mason-nvim-dap README for more information - handlers = {}, - - -- You'll need to check that you have the required things installed - -- online, please don't ask me how to install them :) - ensure_installed = { - -- Update this to ensure that you have the debuggers for the langs you want - 'delve', - }, - } - - -- Dap UI setup - -- For more information, see |:help nvim-dap-ui| - dapui.setup { - -- Set icons to characters that are more likely to work in every terminal. - -- Feel free to remove or use ones that you like more! :) - -- Don't feel like these are good choices. - icons = { expanded = 'โ–พ', collapsed = 'โ–ธ', current_frame = '*' }, - controls = { - icons = { - pause = 'โธ', - play = 'โ–ถ', - step_into = 'โŽ', - step_over = 'โญ', - step_out = 'โฎ', - step_back = 'b', - run_last = 'โ–ถโ–ถ', - terminate = 'โน', - disconnect = 'โ', - }, - }, - } - - -- Change breakpoint icons - -- vim.api.nvim_set_hl(0, 'DapBreak', { fg = '#e51400' }) - -- vim.api.nvim_set_hl(0, 'DapStop', { fg = '#ffcc00' }) - -- local breakpoint_icons = vim.g.have_nerd_font - -- and { Breakpoint = '๎ฉฑ', BreakpointCondition = '๎ชง', BreakpointRejected = '๎ฎŒ', LogPoint = '๎ชซ', Stopped = '๎ฎ‹' } - -- or { Breakpoint = 'โ—', BreakpointCondition = 'โŠœ', BreakpointRejected = 'โŠ˜', LogPoint = 'โ—†', Stopped = 'โญ”' } - -- for type, icon in pairs(breakpoint_icons) do - -- local tp = 'Dap' .. type - -- local hl = (type == 'Stopped') and 'DapStop' or 'DapBreak' - -- vim.fn.sign_define(tp, { text = icon, texthl = hl, numhl = hl }) - -- end - - dap.listeners.after.event_initialized['dapui_config'] = dapui.open - dap.listeners.before.event_terminated['dapui_config'] = dapui.close - dap.listeners.before.event_exited['dapui_config'] = dapui.close - - -- Install golang specific config - require('dap-go').setup { - delve = { - -- On Windows delve must be run attached or it crashes. - -- See https://github.com/leoluz/nvim-dap-go/blob/main/README.md#configuring - detached = vim.fn.has 'win32' == 0, - }, - } - end, -} diff --git a/lua/kickstart/plugins/gitsigns.lua b/lua/kickstart/plugins/gitsigns.lua deleted file mode 100644 index cbbd22d24fc..00000000000 --- a/lua/kickstart/plugins/gitsigns.lua +++ /dev/null @@ -1,61 +0,0 @@ --- Adds git related signs to the gutter, as well as utilities for managing changes --- NOTE: gitsigns is already included in init.lua but contains only the base --- config. This will add also the recommended keymaps. - -return { - { - 'lewis6991/gitsigns.nvim', - opts = { - on_attach = function(bufnr) - local gitsigns = require 'gitsigns' - - local function map(mode, l, r, opts) - opts = opts or {} - opts.buffer = bufnr - vim.keymap.set(mode, l, r, opts) - end - - -- Navigation - map('n', ']c', function() - if vim.wo.diff then - vim.cmd.normal { ']c', bang = true } - else - gitsigns.nav_hunk 'next' - end - end, { desc = 'Jump to next git [c]hange' }) - - map('n', '[c', function() - if vim.wo.diff then - vim.cmd.normal { '[c', bang = true } - else - gitsigns.nav_hunk 'prev' - end - end, { desc = 'Jump to previous git [c]hange' }) - - -- Actions - -- visual mode - map('v', 'hs', function() - gitsigns.stage_hunk { vim.fn.line '.', vim.fn.line 'v' } - end, { desc = 'git [s]tage hunk' }) - map('v', 'hr', function() - gitsigns.reset_hunk { vim.fn.line '.', vim.fn.line 'v' } - end, { desc = 'git [r]eset hunk' }) - -- normal mode - map('n', 'hs', gitsigns.stage_hunk, { desc = 'git [s]tage hunk' }) - map('n', 'hr', gitsigns.reset_hunk, { desc = 'git [r]eset hunk' }) - map('n', 'hS', gitsigns.stage_buffer, { desc = 'git [S]tage buffer' }) - map('n', 'hu', gitsigns.stage_hunk, { desc = 'git [u]ndo stage hunk' }) - map('n', 'hR', gitsigns.reset_buffer, { desc = 'git [R]eset buffer' }) - map('n', 'hp', gitsigns.preview_hunk, { desc = 'git [p]review hunk' }) - map('n', 'hb', gitsigns.blame_line, { desc = 'git [b]lame line' }) - map('n', 'hd', gitsigns.diffthis, { desc = 'git [d]iff against index' }) - map('n', 'hD', function() - gitsigns.diffthis '@' - end, { desc = 'git [D]iff against last commit' }) - -- Toggles - map('n', 'tb', gitsigns.toggle_current_line_blame, { desc = '[T]oggle git show [b]lame line' }) - map('n', 'tD', gitsigns.preview_hunk_inline, { desc = '[T]oggle git show [D]eleted' }) - end, - }, - }, -} diff --git a/lua/kickstart/plugins/indent_line.lua b/lua/kickstart/plugins/indent_line.lua deleted file mode 100644 index ed7f269399f..00000000000 --- a/lua/kickstart/plugins/indent_line.lua +++ /dev/null @@ -1,9 +0,0 @@ -return { - { -- Add indentation guides even on blank lines - 'lukas-reineke/indent-blankline.nvim', - -- Enable `lukas-reineke/indent-blankline.nvim` - -- See `:help ibl` - main = 'ibl', - opts = {}, - }, -} diff --git a/lua/kickstart/plugins/lint.lua b/lua/kickstart/plugins/lint.lua deleted file mode 100644 index dec42f097c6..00000000000 --- a/lua/kickstart/plugins/lint.lua +++ /dev/null @@ -1,60 +0,0 @@ -return { - - { -- Linting - 'mfussenegger/nvim-lint', - event = { 'BufReadPre', 'BufNewFile' }, - config = function() - local lint = require 'lint' - lint.linters_by_ft = { - markdown = { 'markdownlint' }, - } - - -- To allow other plugins to add linters to require('lint').linters_by_ft, - -- instead set linters_by_ft like this: - -- lint.linters_by_ft = lint.linters_by_ft or {} - -- lint.linters_by_ft['markdown'] = { 'markdownlint' } - -- - -- However, note that this will enable a set of default linters, - -- which will cause errors unless these tools are available: - -- { - -- clojure = { "clj-kondo" }, - -- dockerfile = { "hadolint" }, - -- inko = { "inko" }, - -- janet = { "janet" }, - -- json = { "jsonlint" }, - -- markdown = { "vale" }, - -- rst = { "vale" }, - -- ruby = { "ruby" }, - -- terraform = { "tflint" }, - -- text = { "vale" } - -- } - -- - -- You can disable the default linters by setting their filetypes to nil: - -- lint.linters_by_ft['clojure'] = nil - -- lint.linters_by_ft['dockerfile'] = nil - -- lint.linters_by_ft['inko'] = nil - -- lint.linters_by_ft['janet'] = nil - -- lint.linters_by_ft['json'] = nil - -- lint.linters_by_ft['markdown'] = nil - -- lint.linters_by_ft['rst'] = nil - -- lint.linters_by_ft['ruby'] = nil - -- lint.linters_by_ft['terraform'] = nil - -- lint.linters_by_ft['text'] = nil - - -- Create autocommand which carries out the actual linting - -- on the specified events. - local lint_augroup = vim.api.nvim_create_augroup('lint', { clear = true }) - vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost', 'InsertLeave' }, { - group = lint_augroup, - callback = function() - -- Only run the linter in buffers that you can modify in order to - -- avoid superfluous noise, notably within the handy LSP pop-ups that - -- describe the hovered symbol using Markdown. - if vim.bo.modifiable then - lint.try_lint() - end - end, - }) - end, - }, -} diff --git a/lua/kickstart/plugins/neo-tree.lua b/lua/kickstart/plugins/neo-tree.lua deleted file mode 100644 index c7067891df0..00000000000 --- a/lua/kickstart/plugins/neo-tree.lua +++ /dev/null @@ -1,25 +0,0 @@ --- Neo-tree is a Neovim plugin to browse the file system --- https://github.com/nvim-neo-tree/neo-tree.nvim - -return { - 'nvim-neo-tree/neo-tree.nvim', - version = '*', - dependencies = { - 'nvim-lua/plenary.nvim', - 'nvim-tree/nvim-web-devicons', -- not strictly required, but recommended - 'MunifTanjim/nui.nvim', - }, - lazy = false, - keys = { - { '\\', ':Neotree reveal', desc = 'NeoTree reveal', silent = true }, - }, - opts = { - filesystem = { - window = { - mappings = { - ['\\'] = 'close_window', - }, - }, - }, - }, -} diff --git a/lua/plugins/config/blink.lua b/lua/plugins/config/blink.lua new file mode 100644 index 00000000000..bf8311a18bc --- /dev/null +++ b/lua/plugins/config/blink.lua @@ -0,0 +1,126 @@ +-- Blink.cmp Configuration +local M = {} + +function M.setup() + require('blink.cmp').setup({ + -- Keymap configuration + keymap = { + preset = 'default', + [''] = { 'show', 'show_documentation', 'hide_documentation' }, + [''] = { 'hide' }, + [''] = { 'select_and_accept' }, + + [''] = { 'select_prev', 'fallback' }, + [''] = { 'select_next', 'fallback' }, + + [''] = { 'scroll_documentation_up', 'fallback' }, + [''] = { 'scroll_documentation_down', 'fallback' }, + + [''] = { 'snippet_forward', 'fallback' }, + [''] = { 'snippet_backward', 'fallback' }, + }, + + -- Appearance configuration + appearance = { + use_nvim_cmp_as_default = true, + nerd_font_variant = 'mono', + }, + + -- Sources configuration with Copilot integration + sources = { + default = { 'lsp', 'path', 'snippets', 'buffer', 'copilot' }, + providers = { + copilot = { + name = 'copilot', + module = 'blink-cmp-copilot', + score_offset = 100, + async = true, + transform_items = function(_, items) + -- Add copilot icon to copilot suggestions + for _, item in ipairs(items) do + item.kind = 'Copilot' + end + return items + end, + }, + }, + }, + + -- Command line configuration (new API) + cmdline = { + enabled = false, -- Disable cmdline completion for now + }, + + -- Signature help configuration + signature = { + enabled = true, + window = { + border = 'rounded', + }, + }, + + -- Completion configuration + completion = { + accept = { + -- Auto-insert brackets for functions + auto_brackets = { + enabled = true, + }, + }, + menu = { + draw = { + columns = { + { 'label', 'label_description', gap = 1 }, + { 'kind_icon', 'kind' } + }, + }, + border = 'rounded', + winblend = 0, + }, + documentation = { + auto_show = true, + auto_show_delay_ms = 200, + window = { + border = 'rounded', + }, + }, + ghost_text = { + enabled = true, + }, + }, + + -- Fuzzy matching configuration + fuzzy = { + -- Use Rust implementation for better performance + implementation = 'prefer_rust_with_warning', + -- Allow typos based on keyword length + max_typos = function(keyword) + return math.floor(#keyword / 4) + end, + -- Track frequently/recently used items + use_frecency = true, + -- Boost items matching nearby words + use_proximity = true, + -- Prebuilt binaries configuration + prebuilt_binaries = { + download = true, + }, + }, + + -- Snippet configuration + snippets = { + expand = function(snippet) + -- Use native snippet expansion if available + if vim.snippet then + vim.snippet.expand(snippet) + else + -- Fallback to basic expansion + local insert = string.gsub(snippet, '%$%d+', '') + vim.api.nvim_put({ insert }, 'c', true, true) + end + end, + }, + }) +end + +return M \ No newline at end of file diff --git a/lua/plugins/config/compile-commands-picker.lua b/lua/plugins/config/compile-commands-picker.lua new file mode 100644 index 00000000000..ecd095d3b89 --- /dev/null +++ b/lua/plugins/config/compile-commands-picker.lua @@ -0,0 +1,142 @@ +-- Telescope picker for selecting compile_commands.json +local M = {} + +local function find_compile_commands() + local root = vim.fn.getcwd() + local cmd = string.format('find "%s" -name compile_commands.json -type f 2>/dev/null', root) + local handle = io.popen(cmd) + if not handle then + return {} + end + + local result = handle:read('*a') + handle:close() + + local files = {} + for line in result:gmatch('[^\n]+') do + -- Get relative path for display + local relative = line:gsub('^' .. vim.pesc(root) .. '/', '') + table.insert(files, { + path = line, + display = relative, + dir = vim.fn.fnamemodify(line, ':h'), + relative_dir = vim.fn.fnamemodify(relative, ':h'), + }) + end + + return files +end + +function M.pick_compile_commands() + local files = find_compile_commands() + + if #files == 0 then + vim.notify('No compile_commands.json files found', vim.log.levels.WARN) + return + elseif #files == 1 then + vim.notify('Using: ' .. files[1].display, vim.log.levels.INFO) + M.set_compile_commands(files[1]) + return + end + + -- Use Telescope's built-in find_files with custom settings + local builtin = require('telescope.builtin') + local actions = require('telescope.actions') + local action_state = require('telescope.actions.state') + + builtin.find_files({ + prompt_title = 'Select compile_commands.json', + cwd = vim.fn.getcwd(), + find_command = { 'find', '.', '-name', 'compile_commands.json', '-type', 'f' }, + attach_mappings = function(prompt_bufnr, map) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + if selection then + -- Convert the selection to our file_info format + local path = selection[1] + local relative = path:gsub('^%./', '') + local file_info = { + path = vim.fn.getcwd() .. '/' .. relative, + display = relative, + dir = vim.fn.fnamemodify(path, ':h'), + relative_dir = vim.fn.fnamemodify(relative, ':h'), + } + M.set_compile_commands(file_info) + end + end) + return true + end, + }) +end + +function M.set_compile_commands(file_info) + local clangd_config = string.format([[ +CompileFlags: + CompilationDatabase: %s +]], file_info.relative_dir) + + -- Write .clangd file + local clangd_file = vim.fn.getcwd() .. '/.clangd' + local file = io.open(clangd_file, 'w') + if file then + file:write(clangd_config) + file:close() + vim.notify('Created .clangd pointing to: ' .. file_info.relative_dir, vim.log.levels.INFO) + + -- Restart LSP if clangd is running + local clients = vim.lsp.get_clients({ name = 'clangd' }) + if #clients > 0 then + vim.notify('Restarting clangd...', vim.log.levels.INFO) + -- Stop and start clangd to pick up new config + for _, client in ipairs(clients) do + client.stop() + end + vim.defer_fn(function() + vim.cmd('LspStart clangd') + vim.notify('Clangd restarted with new configuration', vim.log.levels.INFO) + end, 100) + end + else + vim.notify('Failed to create .clangd file', vim.log.levels.ERROR) + end +end + +-- Auto-detect multiple compile_commands.json on startup +function M.auto_detect() + local files = find_compile_commands() + + if #files > 1 then + -- Check if .clangd already exists + local clangd_file = vim.fn.getcwd() .. '/.clangd' + if vim.fn.filereadable(clangd_file) == 0 then + vim.notify( + string.format('Found %d compile_commands.json files. Use :CompileCommandsPicker to select one.', #files), + vim.log.levels.INFO + ) + end + end +end + +-- Setup function to create command +function M.setup() + vim.api.nvim_create_user_command('CompileCommandsPicker', function() + M.pick_compile_commands() + end, { desc = 'Select compile_commands.json for clangd' }) + + -- Auto-detect on entering a C/C++ file + vim.api.nvim_create_autocmd('FileType', { + pattern = { 'c', 'cpp', 'objc', 'objcpp' }, + callback = function() + -- Only run once per session + if not vim.g.compile_commands_detected then + vim.g.compile_commands_detected = true + vim.defer_fn(function() + M.auto_detect() + end, 100) + end + end, + }) +end + +return M \ No newline at end of file diff --git a/lua/plugins/config/debug/adapters.lua b/lua/plugins/config/debug/adapters.lua new file mode 100644 index 00000000000..93629e5d113 --- /dev/null +++ b/lua/plugins/config/debug/adapters.lua @@ -0,0 +1,148 @@ +-- Debug Adapters Configuration +local M = {} + +-- Helper function to find Python executable +-- In Nix environments, use whatever Python is in PATH +local function get_python_path() + -- Use the Python from current environment (Nix or system) + if vim.fn.executable('python3') == 1 then + return vim.fn.exepath('python3') + elseif vim.fn.executable('python') == 1 then + return vim.fn.exepath('python') + else + -- Fallback to system Python + return '/usr/bin/python3' + end +end + +function M.setup() + local dap = require('dap') + + -- Setup all language-specific adapters + M.setup_python(dap) + M.setup_cpp(dap) + + -- Add more adapters as needed + -- M.setup_rust(dap) + -- M.setup_go(dap) + -- M.setup_javascript(dap) +end + +-- Python debugger configuration +function M.setup_python(dap) + dap.adapters.python = { + type = 'executable', + command = vim.fn.exepath('python3') ~= '' and vim.fn.exepath('python3') or 'python', + args = { '-m', 'debugpy.adapter' }, + } + + dap.configurations.python = { + { + type = 'python', + request = 'launch', + name = 'Launch file', + program = '${file}', + pythonPath = get_python_path, + }, + { + type = 'python', + request = 'launch', + name = 'Launch file with arguments', + program = '${file}', + args = function() + local args_string = vim.fn.input('Arguments: ') + return vim.split(args_string, ' ') + end, + pythonPath = get_python_path, + }, + { + type = 'python', + request = 'attach', + name = 'Attach to running process', + processId = require('dap.utils').pick_process, + pythonPath = get_python_path, + }, + } +end + +-- C/C++/Rust debugger configuration (using lldb-dap) +function M.setup_cpp(dap) + -- LLDB-DAP adapter (modern LLDB with DAP support) + dap.adapters.lldb = { + type = 'executable', + command = 'lldb-dap', -- Will use lldb-dap from PATH (Nix environment) + name = 'lldb', + } + + -- C++ configuration + dap.configurations.cpp = { + { + name = 'Launch', + type = 'lldb', + request = 'launch', + program = function() + return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/', 'file') + end, + cwd = '${workspaceFolder}', + stopOnEntry = false, + args = {}, + runInTerminal = false, + }, + { + name = 'Launch with arguments', + type = 'lldb', + request = 'launch', + program = function() + return vim.fn.input('Path to executable: ', vim.fn.getcwd() .. '/', 'file') + end, + cwd = '${workspaceFolder}', + stopOnEntry = false, + args = function() + local args_string = vim.fn.input('Arguments: ') + return vim.split(args_string, ' ') + end, + runInTerminal = false, + }, + { + name = 'Attach to process', + type = 'lldb', + request = 'attach', + pid = require('dap.utils').pick_process, + args = {}, + }, + } + + -- Share C++ configuration with C and Rust + dap.configurations.c = dap.configurations.cpp + dap.configurations.rust = dap.configurations.cpp +end + +-- Example: Go debugger configuration (commented out) +-- function M.setup_go(dap) +-- dap.adapters.delve = { +-- type = 'server', +-- port = '${port}', +-- executable = { +-- command = 'dlv', +-- args = { 'dap', '-l', '127.0.0.1:${port}' }, +-- }, +-- } +-- +-- dap.configurations.go = { +-- { +-- type = 'delve', +-- name = 'Debug', +-- request = 'launch', +-- program = '${file}', +-- }, +-- { +-- type = 'delve', +-- name = 'Debug test', +-- request = 'launch', +-- mode = 'test', +-- program = '${file}', +-- }, +-- } +-- end + +return M \ No newline at end of file diff --git a/lua/plugins/config/debug/init.lua b/lua/plugins/config/debug/init.lua new file mode 100644 index 00000000000..69fbcd2b588 --- /dev/null +++ b/lua/plugins/config/debug/init.lua @@ -0,0 +1,38 @@ +-- Debug Configuration (DAP) +local M = {} + +function M.setup() + local dap = require('dap') + local dapui = require('dapui') + + -- Setup DAP UI with icons and controls + dapui.setup({ + icons = { expanded = 'โ–พ', collapsed = 'โ–ธ', current_frame = '*' }, + controls = { + icons = { + pause = 'โธ', + play = 'โ–ถ', + step_into = 'โŽ', + step_over = 'โญ', + step_out = 'โฎ', + step_back = 'b', + run_last = 'โ–ถโ–ถ', + terminate = 'โน', + disconnect = 'โ', + }, + }, + }) + + -- Automatically open/close DAP UI on debug events + dap.listeners.after.event_initialized['dapui_config'] = dapui.open + dap.listeners.before.event_terminated['dapui_config'] = dapui.close + dap.listeners.before.event_exited['dapui_config'] = dapui.close + + -- Configure debug adapters for different languages + require('plugins.config.debug.adapters').setup() + + -- Setup debug keymaps + require('plugins.config.debug.keymaps').setup() +end + +return M \ No newline at end of file diff --git a/lua/plugins/config/debug/keymaps.lua b/lua/plugins/config/debug/keymaps.lua new file mode 100644 index 00000000000..7c55b282b20 --- /dev/null +++ b/lua/plugins/config/debug/keymaps.lua @@ -0,0 +1,59 @@ +-- Debug Keymaps Configuration +local M = {} + +function M.setup() + local dap = require('dap') + local dapui = require('dapui') + + -- Function key mappings for common debug operations + vim.keymap.set('n', '', dap.continue, { desc = 'Debug: Start/Continue' }) + vim.keymap.set('n', '', dap.step_over, { desc = 'Debug: Step Over' }) + vim.keymap.set('n', '', dap.step_into, { desc = 'Debug: Step Into' }) + vim.keymap.set('n', '', dap.step_out, { desc = 'Debug: Step Out' }) + + -- Breakpoint management + vim.keymap.set('n', 'db', dap.toggle_breakpoint, { desc = 'Debug: Toggle Breakpoint' }) + vim.keymap.set('n', 'dB', function() + dap.set_breakpoint(vim.fn.input 'Breakpoint condition: ') + end, { desc = 'Debug: Set Conditional Breakpoint' }) + vim.keymap.set('n', 'lp', function() + dap.set_breakpoint(nil, nil, vim.fn.input('Log point message: ')) + end, { desc = 'Debug: Set Log Point' }) + + -- DAP UI controls + vim.keymap.set('n', '', dapui.toggle, { desc = 'Debug: Toggle UI' }) + vim.keymap.set('n', 'de', dapui.eval, { desc = 'Debug: Eval under cursor' }) + vim.keymap.set('v', 'de', dapui.eval, { desc = 'Debug: Eval selection' }) + + -- REPL and additional features + vim.keymap.set('n', 'dr', dap.repl.open, { desc = 'Debug: Open REPL' }) + vim.keymap.set('n', 'dl', dap.run_last, { desc = 'Debug: Run Last' }) + + -- Widget-based inspections + vim.keymap.set('n', 'dh', function() + require('dap.ui.widgets').hover() + end, { desc = 'Debug: Hover Variables' }) + + vim.keymap.set('n', 'ds', function() + local widgets = require('dap.ui.widgets') + widgets.centered_float(widgets.scopes) + end, { desc = 'Debug: View Scopes' }) + + vim.keymap.set('n', 'df', function() + local widgets = require('dap.ui.widgets') + widgets.centered_float(widgets.frames) + end, { desc = 'Debug: View Frames' }) + + -- Session management + vim.keymap.set('n', 'dt', dap.terminate, { desc = 'Debug: Terminate Session' }) + vim.keymap.set('n', 'dc', dap.run_to_cursor, { desc = 'Debug: Continue to Cursor' }) + + -- Create visual indicators for breakpoints + vim.fn.sign_define('DapBreakpoint', { text = '๐Ÿ”ด', texthl = 'DapBreakpoint', linehl = '', numhl = '' }) + vim.fn.sign_define('DapBreakpointCondition', { text = '๐ŸŸก', texthl = 'DapBreakpoint', linehl = '', numhl = '' }) + vim.fn.sign_define('DapBreakpointRejected', { text = 'โญ•', texthl = 'DapBreakpoint', linehl = '', numhl = '' }) + vim.fn.sign_define('DapLogPoint', { text = '๐Ÿ“', texthl = 'DapLogPoint', linehl = '', numhl = '' }) + vim.fn.sign_define('DapStopped', { text = 'โ–ถ๏ธ', texthl = 'DapStopped', linehl = 'DapStopped', numhl = 'DapStopped' }) +end + +return M \ No newline at end of file diff --git a/lua/plugins/config/editor.lua b/lua/plugins/config/editor.lua new file mode 100644 index 00000000000..f905e914c0b --- /dev/null +++ b/lua/plugins/config/editor.lua @@ -0,0 +1,59 @@ +-- Editor Enhancement Configuration +local M = {} + +function M.setup_mini() + -- Better Around/Inside textobjects + require('mini.ai').setup { n_lines = 500 } + + -- Add/delete/replace surroundings (brackets, quotes, etc.) + require('mini.surround').setup() + + -- Simple and easy statusline + local statusline = require 'mini.statusline' + statusline.setup { use_icons = vim.g.have_nerd_font } + + -- Custom statusline location section + ---@diagnostic disable-next-line: duplicate-set-field + statusline.section_location = function() + return '%2l:%-2v' + end +end + +function M.setup_illuminate() + require('illuminate').configure({ + delay = 200, + large_file_cutoff = 2000, + large_file_overrides = { + providers = { 'lsp' }, + }, + providers = { + 'lsp', + 'treesitter', + 'regex', + }, + filetypes_denylist = { + 'dirbuf', + 'dirvish', + 'fugitive', + 'alpha', + 'NvimTree', + 'lazy', + 'neogitstatus', + 'Trouble', + 'lir', + 'Outline', + 'spectre_panel', + 'toggleterm', + 'DressingSelect', + 'TelescopePrompt', + }, + under_cursor = true, + }) +end + +function M.setup() + M.setup_mini() + M.setup_illuminate() +end + +return M \ No newline at end of file diff --git a/lua/plugins/config/git.lua b/lua/plugins/config/git.lua new file mode 100644 index 00000000000..166cf725220 --- /dev/null +++ b/lua/plugins/config/git.lua @@ -0,0 +1,69 @@ +-- Git Configuration +local M = {} + +function M.setup_gitsigns() + require('gitsigns').setup({ + signs = { + add = { text = '+' }, + change = { text = '~' }, + delete = { text = '_' }, + topdelete = { text = 'โ€พ' }, + changedelete = { text = '~' }, + }, + on_attach = function(bufnr) + local gitsigns = require('gitsigns') + + local function map(mode, l, r, opts) + opts = opts or {} + opts.buffer = bufnr + vim.keymap.set(mode, l, r, opts) + end + + -- Navigation + map('n', ']c', function() + if vim.wo.diff then + vim.cmd.normal({']c', bang = true}) + else + gitsigns.nav_hunk('next') + end + end, { desc = 'Jump to next git [c]hange' }) + + map('n', '[c', function() + if vim.wo.diff then + vim.cmd.normal({'[c', bang = true}) + else + gitsigns.nav_hunk('prev') + end + end, { desc = 'Jump to previous git [c]hange' }) + + -- Actions + map('n', 'hs', gitsigns.stage_hunk, { desc = 'Git [s]tage hunk' }) + map('n', 'hr', gitsigns.reset_hunk, { desc = 'Git [r]eset hunk' }) + map('v', 'hs', function() + gitsigns.stage_hunk({vim.fn.line('.'), vim.fn.line('v')}) + end, { desc = 'Git [s]tage hunk' }) + map('v', 'hr', function() + gitsigns.reset_hunk({vim.fn.line('.'), vim.fn.line('v')}) + end, { desc = 'Git [r]eset hunk' }) + + map('n', 'hS', gitsigns.stage_buffer, { desc = 'Git [S]tage buffer' }) + map('n', 'hu', gitsigns.undo_stage_hunk, { desc = 'Git [u]ndo stage hunk' }) + map('n', 'hR', gitsigns.reset_buffer, { desc = 'Git [R]eset buffer' }) + map('n', 'hp', gitsigns.preview_hunk, { desc = 'Git [p]review hunk' }) + map('n', 'hb', gitsigns.blame_line, { desc = 'Git [b]lame line' }) + map('n', 'hd', gitsigns.diffthis, { desc = 'Git [d]iff against index' }) + map('n', 'hD', function() + gitsigns.diffthis('@') + end, { desc = 'Git [D]iff against last commit' }) + + -- Toggles + map('n', 'tb', gitsigns.toggle_current_line_blame, { desc = '[T]oggle git show [b]lame line' }) + map('n', 'tD', gitsigns.toggle_deleted, { desc = '[T]oggle git show [D]eleted' }) + + -- Text object + map({'o', 'x'}, 'ih', ':Gitsigns select_hunk', { desc = 'Select git hunk' }) + end, + }) +end + +return M \ No newline at end of file diff --git a/lua/plugins/config/harpoon.lua b/lua/plugins/config/harpoon.lua new file mode 100644 index 00000000000..1a7efb631df --- /dev/null +++ b/lua/plugins/config/harpoon.lua @@ -0,0 +1,106 @@ +local M = {} + +function M.setup() + local harpoon = require 'harpoon' + harpoon:setup { + settings = { + save_on_toggle = false, + sync_on_ui_close = false, + key = function() + return vim.loop.cwd() + end, + }, + } + + -- Add current file to list + vim.keymap.set('n', 'ma', function() + harpoon:list():add() + vim.notify('Added to Harpoon', vim.log.levels.INFO) + end, { desc = '[M]ark [A]dd file (Harpoon)' }) + + -- Toggle quick menu + vim.keymap.set('n', '', function() + harpoon.ui:toggle_quick_menu(harpoon:list()) + end, { desc = 'Toggle Harpoon menu' }) + + -- Quick navigation to files 1-4 using leader+m prefix + vim.keymap.set('n', 'm1', function() + harpoon:list():select(1) + end, { desc = 'Jump to mark 1' }) + + vim.keymap.set('n', 'm2', function() + harpoon:list():select(2) + end, { desc = 'Jump to mark 2' }) + + vim.keymap.set('n', 'm3', function() + harpoon:list():select(3) + end, { desc = 'Jump to mark 3' }) + + vim.keymap.set('n', 'm4', function() + harpoon:list():select(4) + end, { desc = 'Jump to mark 4' }) + + -- Alternative quick access with Alt/Option key (doesn't conflict) + vim.keymap.set('n', '', function() + harpoon:list():select(1) + end, { desc = 'Harpoon file 1' }) + + vim.keymap.set('n', '', function() + harpoon:list():select(2) + end, { desc = 'Harpoon file 2' }) + + vim.keymap.set('n', '', function() + harpoon:list():select(3) + end, { desc = 'Harpoon file 3' }) + + vim.keymap.set('n', '', function() + harpoon:list():select(4) + end, { desc = 'Harpoon file 4' }) + + -- Navigate between harpoon files + vim.keymap.set('n', '[m', function() + harpoon:list():prev() + end, { desc = 'Previous marked file' }) + + vim.keymap.set('n', ']m', function() + harpoon:list():next() + end, { desc = 'Next marked file' }) + + -- Show harpoon files in Telescope + local conf = require('telescope.config').values + local function toggle_telescope(harpoon_files) + local file_paths = {} + for _, item in ipairs(harpoon_files.items) do + table.insert(file_paths, item.value) + end + + require('telescope.pickers') + .new({}, { + prompt_title = 'Harpoon', + finder = require('telescope.finders').new_table { + results = file_paths, + }, + previewer = conf.file_previewer {}, + sorter = conf.generic_sorter {}, + }) + :find() + end + + vim.keymap.set('n', 'mm', function() + toggle_telescope(harpoon:list()) + end, { desc = '[M]arked files in Telescope' }) + + -- Clear all marks + vim.keymap.set('n', 'mc', function() + harpoon:list():clear() + vim.notify('Cleared all Harpoon marks', vim.log.levels.INFO) + end, { desc = '[M]arks [C]lear all' }) + + -- Remove current file from harpoon + vim.keymap.set('n', 'mr', function() + harpoon:list():remove() + vim.notify('Removed from Harpoon', vim.log.levels.INFO) + end, { desc = '[M]ark [R]emove current file' }) +end + +return M \ No newline at end of file diff --git a/lua/plugins/config/lsp/init.lua b/lua/plugins/config/lsp/init.lua new file mode 100644 index 00000000000..5a723471d53 --- /dev/null +++ b/lua/plugins/config/lsp/init.lua @@ -0,0 +1,31 @@ +-- LSP Configuration Module +local M = {} + +function M.setup() + local lspconfig = require 'lspconfig' + + -- Get capabilities from blink.cmp if available + local capabilities = vim.lsp.protocol.make_client_capabilities() + + local ok, blink_cmp = pcall(require, 'blink.cmp') + if ok then + capabilities = blink_cmp.get_lsp_capabilities(capabilities) + end + -- + -- Set global position encoding preference + capabilities.general.positionEncodings = { 'utf-16' } + + -- Load server configurations + local servers = require('plugins.config.lsp.servers').get_servers() + + -- Setup each server with capabilities + for name, config in pairs(servers) do + config.capabilities = vim.tbl_deep_extend('force', {}, capabilities, config.capabilities or {}) + lspconfig[name].setup(config) + end + + -- Setup LSP keymaps + require('plugins.config.lsp.keymaps').setup() +end + +return M diff --git a/lua/plugins/config/lsp/keymaps.lua b/lua/plugins/config/lsp/keymaps.lua new file mode 100644 index 00000000000..aac80735ad9 --- /dev/null +++ b/lua/plugins/config/lsp/keymaps.lua @@ -0,0 +1,57 @@ +-- LSP Keymaps Configuration +local M = {} + +function M.setup() + -- Setup keymaps when LSP attaches to a buffer + vim.api.nvim_create_autocmd('LspAttach', { + group = vim.api.nvim_create_augroup('lsp-attach-keymaps', { clear = true }), + callback = function(event) + -- Helper function to define keymaps + local map = function(keys, func, desc, mode) + mode = mode or 'n' + vim.keymap.set(mode, keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc }) + end + + -- Navigation keymaps (using kickstart.nvim patterns) + map('gd', require('telescope.builtin').lsp_definitions, '[G]oto [D]efinition') + map('grr', require('telescope.builtin').lsp_references, '[G]oto [R]eferences') + map('gri', require('telescope.builtin').lsp_implementations, '[G]oto [I]mplementation') + map('grt', require('telescope.builtin').lsp_type_definitions, '[G]oto [T]ype definition') + map('grD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') + + -- Symbol operations + map('grn', vim.lsp.buf.rename, '[G]oto [R]e[n]ame') + map('gra', vim.lsp.buf.code_action, '[G]oto code [A]ction', { 'n', 'x' }) + map('gO', require('telescope.builtin').lsp_document_symbols, '[G]oto [O]pen document symbols') + map('gW', require('telescope.builtin').lsp_dynamic_workspace_symbols, '[G]oto [W]orkspace symbols') + + -- Documentation + map('K', vim.lsp.buf.hover, 'Hover Documentation') + + -- Formatting + map('f', function() + vim.lsp.buf.format { async = true } + end, '[F]ormat buffer') + + -- The following keymaps are available but not mapped by default: + -- vim.lsp.buf.signature_help - Show function signature help + -- vim.lsp.buf.add_workspace_folder - Add workspace folder + -- vim.lsp.buf.remove_workspace_folder - Remove workspace folder + -- vim.lsp.buf.list_workspace_folders - List workspace folders + + -- Optional: Add a message when LSP attaches + local client = vim.lsp.get_client_by_id(event.data.client_id) + if client then + vim.notify('LSP attached: ' .. client.name, vim.log.levels.INFO) + end + end, + }) + + -- Diagnostic keymaps (available globally, not just when LSP attaches) + vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, { desc = 'Go to previous [D]iagnostic message' }) + vim.keymap.set('n', ']d', vim.diagnostic.goto_next, { desc = 'Go to next [D]iagnostic message' }) + vim.keymap.set('n', 'e', vim.diagnostic.open_float, { desc = 'Show diagnostic [E]rror messages' }) + vim.keymap.set('n', 'q', vim.diagnostic.setloclist, { desc = 'Open diagnostic [Q]uickfix list' }) +end + +return M \ No newline at end of file diff --git a/lua/plugins/config/lsp/servers.lua b/lua/plugins/config/lsp/servers.lua new file mode 100644 index 00000000000..a64c21c139a --- /dev/null +++ b/lua/plugins/config/lsp/servers.lua @@ -0,0 +1,156 @@ +-- LSP Server Configurations +local M = {} + +local util = require 'lspconfig.util' + +-- Get clang-wrapper resource-root for Nix environments +local function get_clang_resource_dir() + -- Try to find clang-wrapper's resource-root + local handle = io.popen 'ls -d /nix/store/*clang-wrapper*/resource-root 2>/dev/null | head -1' + if handle then + local resource_root = handle:read '*l' + handle:close() + if resource_root and resource_root ~= '' then + return resource_root + end + end + return nil -- Let clangd use its default +end + +function M.get_servers() + -- Build clangd command + local clangd_cmd = { + 'clangd', + '--query-driver=/nix/store/*/bin/clang*', + '--background-index', + '--clang-tidy', + '--enable-config', + '--fallback-style=llvm', + '--function-arg-placeholders', + '--header-insertion-decorators', + '--header-insertion=iwyu', + } + + -- Add resource-dir if in Nix environment + local resource_dir = get_clang_resource_dir() + if resource_dir then + table.insert(clangd_cmd, '--resource-dir=' .. resource_dir) + end + + return { + -- C/C++ Language Server + clangd = { + cmd = clangd_cmd, + filetypes = { 'c', 'cpp', 'objc', 'objcpp', 'cuda' }, + -- Look for project markers - clangd will find compile_commands.json itself + root_dir = util.root_pattern( + -- First check for any compile_commands.json anywhere + 'compile_commands.json', + -- Then check common build directories + 'build/compile_commands.json', + 'Debug/compile_commands.json', + 'Release/compile_commands.json', + -- Project markers + '.clangd', + 'compile_flags.txt', + 'CMakeLists.txt', + 'Makefile', + '.git' + ), + single_file_support = true, + }, + + -- Python Language Server + basedpyright = { + settings = { + basedpyright = { + analysis = { + autoSearchPaths = true, + diagnosticMode = 'openFilesOnly', + typeCheckingMode = 'basic', + useLibraryCodeForTypes = true, + + diagnosticSeverityOverrides = { + reportOptionalCall = 'none', + reportOptionalSubscript = 'none', + reportOptionalMemberAccess = 'none', + reportOptionalIterable = 'none', + reportAttributeAccessIssue = 'none', + reportUnknownMemberType = 'none', + reportUnknownVariableType = 'none', + reportUnknownArgumentType = 'none', + reportUnknownParameterType = 'none', + reportUnknownAssignmentType = 'none', + reportMissingTypeStubs = 'none', + }, + }, + }, + }, + }, + + -- Python Linter/Formatter + ruff = {}, + + -- Nix Language Server + nixd = {}, + + -- LaTeX Language Server + texlab = {}, + + -- CMake Language Server + cmake = { + cmd = { 'cmake-language-server' }, + filetypes = { 'cmake' }, + root_dir = util.root_pattern('CMakeLists.txt', '.git'), + }, + + -- Lua Language Server + lua_ls = { + settings = { + Lua = { + runtime = { version = 'LuaJIT' }, + diagnostics = { + globals = { 'vim' }, + }, + workspace = { + library = vim.api.nvim_get_runtime_file('', true), + checkThirdParty = false, + }, + telemetry = { enable = false }, + }, + }, + }, + + -- Bash Language Server + bashls = {}, + + -- YAML Language Server + yamlls = {}, + + -- JSON Language Server + jsonls = {}, + + -- Markdown Language Server + marksman = {}, + + -- TOML Language Server + taplo = {}, + + -- SQL Language Server + sqls = {}, + + -- Add more servers here as needed + -- Example: + -- rust_analyzer = { + -- settings = { + -- ['rust-analyzer'] = { + -- checkOnSave = { + -- command = 'clippy', + -- }, + -- }, + -- }, + -- }, + } +end + +return M diff --git a/lua/plugins/config/telescope.lua b/lua/plugins/config/telescope.lua new file mode 100644 index 00000000000..60275b80e23 --- /dev/null +++ b/lua/plugins/config/telescope.lua @@ -0,0 +1,88 @@ +-- Telescope Configuration +local M = {} + +function M.setup() + local telescope = require('telescope') + local builtin = require('telescope.builtin') + + telescope.setup({ + defaults = { + prompt_prefix = '> ', + selection_caret = '> ', + path_display = { 'truncate' }, + sorting_strategy = 'ascending', + layout_config = { + horizontal = { + prompt_position = 'top', + preview_width = 0.55, + }, + vertical = { + mirror = false, + }, + width = 0.87, + height = 0.80, + preview_cutoff = 120, + }, + }, + pickers = { + find_files = { + -- Use rg for finding files (ensure rg is installed via Nix/Home Manager) + find_command = { 'rg', '--files', '--hidden', '-g', '!.git' }, + }, + }, + extensions = { + ['ui-select'] = { + require('telescope.themes').get_dropdown(), + }, + fzf = { + fuzzy = true, + override_generic_sorter = true, + override_file_sorter = true, + case_mode = 'smart_case', + }, + }, + }) + + -- Load extensions + pcall(telescope.load_extension, 'fzf') + pcall(telescope.load_extension, 'ui-select') + + -- Setup keymaps + vim.keymap.set('n', 'sf', builtin.find_files, { desc = '[S]earch [F]iles' }) + vim.keymap.set('n', 'sg', builtin.live_grep, { desc = '[S]earch by [G]rep' }) + vim.keymap.set('n', 'sh', builtin.help_tags, { desc = '[S]earch [H]elp' }) + vim.keymap.set('n', 'sk', builtin.keymaps, { desc = '[S]earch [K]eymaps' }) + vim.keymap.set('n', 'ss', builtin.builtin, { desc = '[S]earch [S]elect Telescope' }) + vim.keymap.set('n', 'sw', builtin.grep_string, { desc = '[S]earch current [W]ord' }) + vim.keymap.set('n', 'sd', builtin.diagnostics, { desc = '[S]earch [D]iagnostics' }) + vim.keymap.set('n', 'sr', builtin.resume, { desc = '[S]earch [R]esume' }) + vim.keymap.set('n', 's.', builtin.oldfiles, { desc = '[S]earch Recent Files ("." for repeat)' }) + vim.keymap.set('n', '', builtin.buffers, { desc = '[ ] Find existing buffers' }) + + -- Fuzzy search in current buffer + vim.keymap.set('n', '/', function() + builtin.current_buffer_fuzzy_find(require('telescope.themes').get_dropdown { + winblend = 10, + previewer = false, + }) + end, { desc = '[/] Fuzzily search in current buffer' }) + + -- Search in open files + vim.keymap.set('n', 's/', function() + builtin.live_grep { + grep_open_files = true, + prompt_title = 'Live Grep in Open Files', + } + end, { desc = '[S]earch [/] in Open Files' }) + + -- Search in neovim config + vim.keymap.set('n', 'sn', function() + builtin.find_files { cwd = vim.fn.stdpath 'config' } + end, { desc = '[S]earch [N]eovim files' }) + + -- C/C++ compile_commands.json picker + vim.keymap.set('n', 'sc', 'CompileCommandsPicker', + { desc = '[S]earch [C]ompile commands.json' }) +end + +return M \ No newline at end of file diff --git a/lua/plugins/config/training.lua b/lua/plugins/config/training.lua new file mode 100644 index 00000000000..598e61becb1 --- /dev/null +++ b/lua/plugins/config/training.lua @@ -0,0 +1,278 @@ +local M = {} + +-- Statistics tracking +local stats = { + inefficient_moves = 0, + efficient_moves = 0, + start_time = os.time(), +} + +-- Training mode state +local training_enabled = false + +-- Movement key counters for spam detection +local key_counts = { h = 0, j = 0, k = 0, l = 0 } + +-- Hard mode: Disable inefficient keys +local function setup_hard_mode() + -- Disable arrow keys completely + vim.keymap.set({ 'n', 'v', 'i' }, '', '', { desc = 'Use k instead!' }) + vim.keymap.set({ 'n', 'v', 'i' }, '', '', { desc = 'Use j instead!' }) + vim.keymap.set({ 'n', 'v', 'i' }, '', '', { desc = 'Use h instead!' }) + vim.keymap.set({ 'n', 'v', 'i' }, '', '', { desc = 'Use l instead!' }) + + -- Make holding j/k/h/l painful (warns after 5 repeats) + for _, key in ipairs { 'h', 'j', 'k', 'l' } do + vim.keymap.set('n', key, function() + key_counts[key] = key_counts[key] + 1 + if key_counts[key] > 5 then + vim.notify(string.format('Stop spamming %s! Use counts (5%s) or better navigation!', key, key), vim.log.levels.WARN) + key_counts[key] = 0 + end + return key + end, { expr = true }) + end + + -- Reset counter when using other movements + for _, good_move in ipairs { '', '', '}', '{', 'gg', 'G' } do + vim.keymap.set('n', good_move, function() + key_counts = { h = 0, j = 0, k = 0, l = 0 } + stats.efficient_moves = stats.efficient_moves + 1 + return good_move + end, { expr = true }) + end +end + +-- Smart search helpers +local function setup_smart_search() + -- Search word under cursor + vim.keymap.set('n', '*', '*N', { desc = 'Search word under cursor' }) + + -- Search selected text + vim.keymap.set('v', '//', [[y/\V=escape(@",'/\')]], { desc = 'Search selection' }) + + -- Replace word under cursor (the smart way) + vim.keymap.set('n', 'R', function() + local word = vim.fn.expand '' + vim.ui.input({ prompt = 'Replace "' .. word .. '" with: ' }, function(replacement) + if replacement then + vim.cmd(':%s/\\<' .. word .. '\\>/' .. replacement .. '/g') + vim.notify(string.format('Replaced all instances of "%s" with "%s"', word, replacement)) + end + end) + end, { desc = 'Replace word under cursor globally' }) + + -- cgn workflow helper + vim.keymap.set('n', 'C', '*Ncgn', { desc = 'Change word under cursor (cgn workflow)' }) +end + +-- Efficiency helpers +local function setup_efficiency_helpers() + -- Movement reminder + vim.keymap.set('n', 'tm', function() + local hints = { + '=== VERTICAL MOVEMENT ===', + 'gg/G - Top/bottom of file', + '50G or 50% - Go to line 50', + '{ } - Paragraph jumps', + '[[ ]] - Function/section jumps', + 'H M L - High/Middle/Low of screen', + '', + '=== HORIZONTAL MOVEMENT ===', + 'f / F - Find forward/backward', + 't / T - Till forward/backward', + '; , - Repeat f/t forward/backward', + '0 $ - Start/end of line', + '^ g_ - First/last non-blank', + '', + '=== WORD MOVEMENT ===', + 'w/W - Next word/WORD', + 'b/B - Back word/WORD', + 'e/E - End of word/WORD', + 'ge/gE - End of previous word/WORD', + '', + '=== SEARCH MOVEMENT ===', + '* # - Search word forward/backward', + 'g* g# - Search partial word', + 'n N - Next/previous match', + } + vim.notify(table.concat(hints, '\n'), vim.log.levels.INFO) + end, { desc = '[T]raining [M]ovement hints' }) + + -- Text object practice + vim.keymap.set('n', 'ti', function() + local hints = { + '=== TEXT OBJECTS ===', + 'ciw - Change inside word', + 'ci" - Change inside quotes', + 'ci( or cib - Change inside parentheses', + 'ci{ or ciB - Change inside braces', + 'cit - Change inside tags', + 'cip - Change inside paragraph', + '', + '=== VARIATIONS ===', + 'c - Change', + 'd - Delete', + 'y - Yank', + 'v - Visual select', + '', + 'i - Inside (excludes delimiters)', + 'a - Around (includes delimiters)', + } + vim.notify(table.concat(hints, '\n'), vim.log.levels.INFO) + end, { desc = '[T]ext object [I]nfo' }) +end + +-- Track statistics +local function setup_statistics() + -- Track efficient movements + local efficient_patterns = { '*', '#', 'cgn', 'ciw', 'ci"', "ci'", 'cib', 'ciB', 'f', 'F', 't', 'T', '}', '{', ']]', '[[' } + + for _, pattern in ipairs(efficient_patterns) do + vim.keymap.set('n', pattern, function() + stats.efficient_moves = stats.efficient_moves + 1 + return pattern + end, { expr = true, silent = true }) + end +end + +-- Visual feedback for good movements +local function setup_visual_feedback() + vim.api.nvim_create_autocmd('CursorMoved', { + group = vim.api.nvim_create_augroup('TrainingMode', { clear = true }), + callback = function() + if not training_enabled then + return + end + + local col = vim.fn.col '.' + local line = vim.fn.line '.' + + -- Check if cursor moved significantly (likely used good navigation) + if math.abs(line - (vim.b.last_line or line)) > 5 then + -- Don't notify, just track it + stats.efficient_moves = stats.efficient_moves + 1 + end + + vim.b.last_line = line + end, + }) +end + +-- Disable hard mode +local function disable_hard_mode() + -- Remove hard mode restrictions + pcall(vim.keymap.del, { 'n', 'v', 'i' }, '') + pcall(vim.keymap.del, { 'n', 'v', 'i' }, '') + pcall(vim.keymap.del, { 'n', 'v', 'i' }, '') + pcall(vim.keymap.del, { 'n', 'v', 'i' }, '') + + -- Remove hjkl spam detection + for _, key in ipairs { 'h', 'j', 'k', 'l' } do + pcall(vim.keymap.del, 'n', key) + end +end + +-- Main setup function +function M.setup() + -- Always setup smart search helpers (they're just helpful) + setup_smart_search() + setup_efficiency_helpers() + setup_visual_feedback() + + vim.notify('Training mode available! Press tt to toggle', vim.log.levels.INFO) +end + +-- Toggle training mode +function M.toggle() + training_enabled = not training_enabled + + if training_enabled then + setup_hard_mode() + setup_statistics() + stats.start_time = os.time() -- Reset timer + vim.notify('Training mode ENABLED! ๐Ÿ’ช\nArrows disabled, hjkl spam detection on!', vim.log.levels.INFO) + else + disable_hard_mode() + vim.notify('Training mode DISABLED. Keep practicing those efficient movements!', vim.log.levels.INFO) + end +end + +-- Show statistics +function M.show_stats() + local time_elapsed = os.time() - stats.start_time + local total_moves = stats.efficient_moves + stats.inefficient_moves + local efficiency = total_moves > 0 and (stats.efficient_moves / total_moves * 100) or 0 + + vim.notify( + string.format( + '๐Ÿ“Š Session Statistics:\n' .. + 'Time: %d min\n' .. + 'Efficient moves: %d\n' .. + 'Inefficient moves: %d\n' .. + 'Efficiency: %.1f%%\n\n' .. + 'Keep practicing! ๐ŸŽฏ', + time_elapsed / 60, + stats.efficient_moves, + stats.inefficient_moves, + efficiency + ), + vim.log.levels.INFO + ) +end + +-- Random challenge +function M.challenge() + local challenges = { + 'Jump to line 50 without counting lines (use 50G)', + 'Find the next "function" (use /function)', + 'Change the word in quotes (use ci")', + 'Delete until the next comma (use dt,)', + 'Jump to matching bracket (use %)', + 'Select entire paragraph (use vap)', + 'Change word and repeat with . (use *cgn)', + 'Jump to next blank line (use })', + 'Delete entire function (use dap or di{)', + 'Find and change next "TODO" (use /TODOcgn)', + } + + local challenge = challenges[math.random(#challenges)] + vim.notify('๐ŸŽฎ Challenge: ' .. challenge, vim.log.levels.INFO) +end + +-- Show cheatsheet +function M.cheatsheet() + local cheatsheet = [[ +=== STOP DOING === | === START DOING === +jjjjjjjj | 10j, }, +wwwww | 3w, f +manually typing search | *, viw/, sg +:%s/old/new/g | *cgn then . +:q then git | :Git (Fugitive) +arrow keys | hjkl with counts + +=== POWER MOVES === +cgn - Change next occurrence (use with *) +. - Repeat last change +* - Search word under cursor +ciw - Change inside word +f/t - Find/till character +% - Jump to matching bracket + - Half page down + - Half page up + +=== TRAINING COMMANDS === +tt - Toggle training mode +ts - Show statistics +tg - Get random challenge +tm - Movement hints +ti - Text object info +* - Search word under cursor +R - Replace word globally +C - Start cgn workflow +]] + + vim.notify(cheatsheet, vim.log.levels.INFO) +end + +return M \ No newline at end of file diff --git a/lua/plugins/config/ui.lua b/lua/plugins/config/ui.lua new file mode 100644 index 00000000000..1e16b2cf0e6 --- /dev/null +++ b/lua/plugins/config/ui.lua @@ -0,0 +1,57 @@ +-- UI Configuration +local M = {} + +function M.setup_which_key() + local wk = require 'which-key' + + wk.setup({ + delay = 0, + icons = { + mappings = vim.g.have_nerd_font, + keys = vim.g.have_nerd_font and {} or { + Up = ' ', + Down = ' ', + Left = ' ', + Right = ' ', + C = ' ', + M = ' ', + D = ' ', + S = ' ', + CR = ' ', + Esc = ' ', + ScrollWheelDown = ' ', + ScrollWheelUp = ' ', + NL = ' ', + BS = ' ', + Space = ' ', + Tab = ' ', + F1 = '', + F2 = '', + F3 = '', + F4 = '', + F5 = '', + F6 = '', + F7 = '', + F8 = '', + F9 = '', + F10 = '', + F11 = '', + F12 = '', + }, + }, + }) + + -- Document existing key chains + wk.add { + { 'c', group = '[C]ode' }, + { 'd', group = '[D]ocument/[D]ebug' }, + { 'r', group = '[R]ename' }, + { 's', group = '[S]earch' }, + { 'w', group = '[W]orkspace' }, + { 't', group = '[T]oggle' }, + { 'g', group = '[G]it' }, + { 'h', group = 'Git [H]unk', mode = { 'n', 'v' } }, + } +end + +return M \ No newline at end of file diff --git a/lua/plugins/spec/autopairs.lua b/lua/plugins/spec/autopairs.lua new file mode 100644 index 00000000000..c11d19d1bc5 --- /dev/null +++ b/lua/plugins/spec/autopairs.lua @@ -0,0 +1,24 @@ +-- Auto-pairs - Automatically close brackets, quotes, etc. +return { + 'windwp/nvim-autopairs', + event = 'InsertEnter', + opts = { + check_ts = true, + ts_config = { + lua = { 'string', 'source' }, + javascript = { 'string', 'template_string' }, + }, + disable_filetype = { 'TelescopePrompt', 'spectre_panel' }, + fast_wrap = { + map = '', + chars = { '{', '[', '(', '"', "'" }, + pattern = string.gsub([[ [%'%"%)%>%]%)%}%,] ]], '%s+', ''), + offset = 0, + end_key = '$', + keys = 'qwertyuiopzxcvbnmasdfghjkl', + check_comma = true, + highlight = 'PmenuSel', + highlight_grey = 'LineNr', + }, + }, +} \ No newline at end of file diff --git a/lua/plugins/spec/blink.lua b/lua/plugins/spec/blink.lua new file mode 100644 index 00000000000..0c3acd86b32 --- /dev/null +++ b/lua/plugins/spec/blink.lua @@ -0,0 +1,12 @@ +-- Blink.cmp - Modern completion plugin +return { + 'saghen/blink.cmp', + lazy = false, -- Lazy loading handled internally + dependencies = { + 'giuxtaposition/blink-cmp-copilot', + }, + version = 'v0.*', -- Use stable releases + config = function() + require('plugins.config.blink').setup() + end, +} \ No newline at end of file diff --git a/lua/plugins/spec/copilot.lua b/lua/plugins/spec/copilot.lua new file mode 100644 index 00000000000..2f54b453510 --- /dev/null +++ b/lua/plugins/spec/copilot.lua @@ -0,0 +1,21 @@ +-- GitHub Copilot integration +return { + 'zbirenbaum/copilot.lua', + cmd = 'Copilot', + event = 'InsertEnter', + opts = { + suggestion = { enabled = false }, -- Disable inline ghost text (handled by blink.cmp) + panel = { enabled = false }, -- Disable panel view + filetypes = { + yaml = false, + markdown = false, + help = false, + gitcommit = false, + gitrebase = false, + hgcommit = false, + svn = false, + cvs = false, + ['.'] = false, + }, + }, +} \ No newline at end of file diff --git a/lua/plugins/spec/debug.lua b/lua/plugins/spec/debug.lua new file mode 100644 index 00000000000..77f6e70eac8 --- /dev/null +++ b/lua/plugins/spec/debug.lua @@ -0,0 +1,20 @@ +-- Debug Adapter Protocol (DAP) support +return { + 'mfussenegger/nvim-dap', + dependencies = { + -- DAP UI + { + 'rcarriga/nvim-dap-ui', + dependencies = { 'nvim-neotest/nvim-nio' }, + }, + + -- Virtual text for debugging + { + 'theHamsta/nvim-dap-virtual-text', + opts = {}, + }, + }, + config = function() + require('plugins.config.debug').setup() + end, +} \ No newline at end of file diff --git a/lua/plugins/spec/editor.lua b/lua/plugins/spec/editor.lua new file mode 100644 index 00000000000..0a3cd5c310b --- /dev/null +++ b/lua/plugins/spec/editor.lua @@ -0,0 +1,36 @@ +-- Editor enhancement plugins +return { + -- Collection of various small independent plugins/modules + { + 'echasnovski/mini.nvim', + config = function() + require('plugins.config.editor').setup_mini() + end, + }, + + -- Highlight, edit, and navigate code + { + 'nvim-treesitter/nvim-treesitter-textobjects', + event = 'VeryLazy', + dependencies = { 'nvim-treesitter/nvim-treesitter' }, + }, + + -- Detect tabstop and shiftwidth automatically + { 'tpope/vim-sleuth' }, + + -- Comment plugin + { + 'numToStr/Comment.nvim', + event = 'VeryLazy', + opts = {}, + }, + + -- Highlight word under cursor + { + 'RRethy/vim-illuminate', + event = { 'BufReadPost', 'BufNewFile' }, + config = function() + require('plugins.config.editor').setup_illuminate() + end, + }, +} \ No newline at end of file diff --git a/lua/plugins/spec/formatting.lua b/lua/plugins/spec/formatting.lua new file mode 100644 index 00000000000..3bbc7eacbc4 --- /dev/null +++ b/lua/plugins/spec/formatting.lua @@ -0,0 +1,40 @@ +-- Formatter configuration + +return { + -- ======================================== + -- Formatter Configuration (conform.nvim) + -- ======================================== + { + 'stevearc/conform.nvim', + event = 'BufWritePre', -- Format on save + -- cmd = { 'ConformInfo' }, -- Optional: If you want the command available + -- keys = { ... } -- Optional: Define keys if needed + opts = { + formatters_by_ft = { + lua = { 'stylua' }, + c = { 'clang_format' }, + cpp = { 'clang_format' }, + python = { 'ruff_organize_imports', 'ruff_format', 'ruff_fix' }, + nix = { 'alejandra' }, -- Add nix formatter + -- Add other filetypes and formatters, e.g.: + javascript = { 'prettier' }, + typescript = { 'prettier' }, + css = { 'prettier' }, + html = { 'prettier' }, + json = { 'prettier' }, + yaml = { 'prettier' }, + markdown = { 'prettier' }, + bash = { 'shfmt' }, + sh = { 'shfmt' }, + cmake = { 'cmake_format' }, + sql = { 'sqlfluff' }, + }, + -- Configure format_on_save behavior + format_on_save = { + -- I recommend these options, but adjust to your liking + timeout_ms = 500, -- Stop formatting if it takes too long + lsp_fallback = true, -- Fallback to LSP formatting if conform fails + }, + }, + }, +} diff --git a/lua/plugins/spec/git.lua b/lua/plugins/spec/git.lua new file mode 100644 index 00000000000..f362cdba948 --- /dev/null +++ b/lua/plugins/spec/git.lua @@ -0,0 +1,26 @@ +-- Git integration plugins +return { + -- Fugitive - Git integration + { + 'tpope/vim-fugitive', + cmd = { 'Git', 'G', 'Gdiff', 'Gread', 'Gwrite', 'Ggrep', 'GMove', 'GDelete', 'GBrowse', 'GRemove' }, + keys = { + { 'gs', 'Git', desc = 'Git status' }, + { 'gd', 'Gdiff', desc = 'Git diff' }, + { 'gc', 'Git commit', desc = 'Git commit' }, + { 'gb', 'Git blame', desc = 'Git blame' }, + { 'gl', 'Git log', desc = 'Git log' }, + { 'gp', 'Git push', desc = 'Git push' }, + { 'gf', 'Git fetch', desc = 'Git fetch' }, + }, + }, + + -- Gitsigns - Git gutter and hunk operations + { + 'lewis6991/gitsigns.nvim', + event = 'VeryLazy', + config = function() + require('plugins.config.git').setup_gitsigns() + end, + }, +} \ No newline at end of file diff --git a/lua/plugins/spec/harpoon.lua b/lua/plugins/spec/harpoon.lua new file mode 100644 index 00000000000..0e0871be911 --- /dev/null +++ b/lua/plugins/spec/harpoon.lua @@ -0,0 +1,10 @@ +-- Harpoon - Quick file navigation +return { + 'ThePrimeagen/harpoon', + branch = 'harpoon2', + dependencies = { 'nvim-lua/plenary.nvim' }, + event = 'VeryLazy', + config = function() + require('plugins.config.harpoon').setup() + end, +} \ No newline at end of file diff --git a/lua/plugins/spec/indent-line.lua b/lua/plugins/spec/indent-line.lua new file mode 100644 index 00000000000..d594e1b0d10 --- /dev/null +++ b/lua/plugins/spec/indent-line.lua @@ -0,0 +1,33 @@ +-- Indent guides - Show vertical lines at indentation levels +return { + 'lukas-reineke/indent-blankline.nvim', + event = { 'BufReadPost', 'BufNewFile' }, + main = 'ibl', + opts = { + indent = { + char = 'โ”‚', + tab_char = 'โ”‚', + }, + scope = { + enabled = true, + show_start = true, + show_end = false, + injected_languages = false, + highlight = { 'Function', 'Label' }, + }, + exclude = { + filetypes = { + 'help', + 'alpha', + 'dashboard', + 'neo-tree', + 'Trouble', + 'lazy', + 'mason', + 'notify', + 'toggleterm', + 'lazyterm', + }, + }, + }, +} \ No newline at end of file diff --git a/lua/plugins/spec/init.lua b/lua/plugins/spec/init.lua new file mode 100644 index 00000000000..ae57ac1c719 --- /dev/null +++ b/lua/plugins/spec/init.lua @@ -0,0 +1,25 @@ +-- Main plugin loader - imports all plugin specifications +return { + -- UI and Theme + { import = 'plugins.spec.ui' }, + { import = 'plugins.spec.editor' }, + { import = 'plugins.spec.autopairs' }, + { import = 'plugins.spec.indent-line' }, + + -- Core functionality + { import = 'plugins.spec.lsp' }, + { import = 'plugins.spec.treesitter' }, + { import = 'plugins.spec.telescope' }, + { import = 'plugins.spec.blink' }, + + -- Git integration + { import = 'plugins.spec.git' }, + + -- Development tools + { import = 'plugins.spec.copilot' }, + { import = 'plugins.spec.debug' }, + { import = 'plugins.spec.formatting' }, + + -- Navigation + { import = 'plugins.spec.nvim-tmux-navigator' }, +} \ No newline at end of file diff --git a/lua/plugins/spec/lsp.lua b/lua/plugins/spec/lsp.lua new file mode 100644 index 00000000000..b83a20989d6 --- /dev/null +++ b/lua/plugins/spec/lsp.lua @@ -0,0 +1,26 @@ +-- LSP Plugin Specification +return { + { + 'neovim/nvim-lspconfig', + event = { 'BufReadPost', 'BufNewFile' }, + dependencies = { + { 'j-hui/fidget.nvim', opts = {} }, + 'folke/lazydev.nvim', + }, + config = function() + require('plugins.config.lsp').setup() + end, + }, + + -- LazyDev for better Neovim Lua development + { + 'folke/lazydev.nvim', + ft = 'lua', + opts = { + library = { + { path = 'luvit-meta/library', words = { 'vim%.uv' } }, + }, + }, + }, +} + diff --git a/lua/plugins/spec/nvim-tmux-navigator.lua b/lua/plugins/spec/nvim-tmux-navigator.lua new file mode 100644 index 00000000000..653ae519b93 --- /dev/null +++ b/lua/plugins/spec/nvim-tmux-navigator.lua @@ -0,0 +1,11 @@ +-- Tmux navigation integration +return { + 'christoomey/vim-tmux-navigator', + keys = { + { '', ':TmuxNavigateLeft', desc = 'Navigate to left tmux pane' }, + { '', ':TmuxNavigateDown', desc = 'Navigate to down tmux pane' }, + { '', ':TmuxNavigateUp', desc = 'Navigate to up tmux pane' }, + { '', ':TmuxNavigateRight', desc = 'Navigate to right tmux pane' }, + { '', ':TmuxNavigatePrevious', desc = 'Navigate to previous tmux pane' }, + }, +} \ No newline at end of file diff --git a/lua/plugins/spec/telescope.lua b/lua/plugins/spec/telescope.lua new file mode 100644 index 00000000000..e6759e6d0c4 --- /dev/null +++ b/lua/plugins/spec/telescope.lua @@ -0,0 +1,23 @@ +-- Telescope - Fuzzy finder +return { + 'nvim-telescope/telescope.nvim', + event = 'VimEnter', + branch = '0.1.x', + dependencies = { + 'nvim-lua/plenary.nvim', + { + 'nvim-telescope/telescope-fzf-native.nvim', + build = 'make', + cond = function() + return vim.fn.executable 'make' == 1 + end, + }, + { 'nvim-telescope/telescope-ui-select.nvim' }, + { 'nvim-tree/nvim-web-devicons', enabled = vim.g.have_nerd_font }, + }, + config = function() + require('plugins.config.telescope').setup() + -- Setup compile_commands.json picker for C/C++ projects + require('plugins.config.compile-commands-picker').setup() + end, +} \ No newline at end of file diff --git a/lua/plugins/spec/training.lua b/lua/plugins/spec/training.lua new file mode 100644 index 00000000000..13e4767facc --- /dev/null +++ b/lua/plugins/spec/training.lua @@ -0,0 +1,19 @@ +-- Neovim Training Wheels - Build better vim habits +-- Load nix settings if available +pcall(require, 'nix-settings') + +return { + 'dlond/training.nvim', + enabled = vim.g.training_mode_enabled or false, -- Controlled by Nix + lazy = false, + dir = vim.fn.stdpath('config') .. '/lua/plugins/training', -- Local "plugin" + config = function() + require('plugins.config.training').setup() + end, + keys = { + { 'tt', function() require('plugins.config.training').toggle() end, desc = '[T]raining [T]oggle' }, + { 'ts', function() require('plugins.config.training').show_stats() end, desc = '[T]raining [S]tats' }, + { 'tg', function() require('plugins.config.training').challenge() end, desc = '[T]raining [G]ame' }, + { '?', function() require('plugins.config.training').cheatsheet() end, desc = 'Show efficiency cheatsheet' }, + }, +} \ No newline at end of file diff --git a/lua/plugins/spec/treesitter.lua b/lua/plugins/spec/treesitter.lua new file mode 100644 index 00000000000..0c3cf5de506 --- /dev/null +++ b/lua/plugins/spec/treesitter.lua @@ -0,0 +1,45 @@ +-- Treesitter - Syntax highlighting and text objects +return { + 'nvim-treesitter/nvim-treesitter', + event = { 'BufReadPost', 'BufNewFile' }, + build = ':TSUpdate', + main = 'nvim-treesitter.configs', + opts = { + ensure_installed = { + 'bash', + 'c', + 'cmake', + 'cpp', + 'diff', + 'html', + 'lua', + 'luadoc', + 'make', + 'markdown', + 'markdown_inline', + 'nix', + 'python', + 'query', + 'vim', + 'vimdoc', + 'yaml', + }, + auto_install = true, + highlight = { + enable = true, + additional_vim_regex_highlighting = false, + }, + indent = { + enable = true, + }, + incremental_selection = { + enable = true, + keymaps = { + init_selection = '', + node_incremental = '', + scope_incremental = false, + node_decremental = '', + }, + }, + }, +} \ No newline at end of file diff --git a/lua/plugins/spec/ui.lua b/lua/plugins/spec/ui.lua new file mode 100644 index 00000000000..479c72f12b8 --- /dev/null +++ b/lua/plugins/spec/ui.lua @@ -0,0 +1,29 @@ +-- UI and Theme plugins +return { + -- Color scheme + { + 'folke/tokyonight.nvim', + priority = 1000, + init = function() + vim.cmd.colorscheme 'tokyonight-night' + vim.cmd.hi 'Comment gui=none' + end, + }, + + -- Which-key for keybind hints + { + 'folke/which-key.nvim', + event = 'VimEnter', + config = function() + require('plugins.config.ui').setup_which_key() + end, + }, + + -- Todo comments highlighting + { + 'folke/todo-comments.nvim', + event = 'VimEnter', + dependencies = { 'nvim-lua/plenary.nvim' }, + opts = { signs = false } + }, +} \ No newline at end of file