diff --git a/nvim/.github/ISSUE_TEMPLATE/bug_report.yml b/nvim/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..4906f93 --- /dev/null +++ b/nvim/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,121 @@ +name: Bug Report +description: File a bug report +labels: [bug] +body: + - type: markdown + attributes: + value: | + _Before reporting:_ Search [existing issues](https://github.com/ayamir/nvimdots/issues) and check the [FAQ](https://github.com/ayamir/nvimdots/wiki/Issues). Thank you for helping us improve! + > [!IMPORTANT] + > The `0.11` branch is intended for nightly Neovim builds and is **not** stable. It typically harbors subtle issues scattered throughout. Therefore, refrain from submitting issues if you happen to encounter them. They will be closed directly unless a viable solution is proposed or included. + - type: checkboxes + id: is-latest-commit + attributes: + label: "Version confirmation" + description: "The local configuration is up-to-date in the current branch and this issue _persists_." + options: + - label: "Confirm" + required: true + - type: checkboxes + id: prerequisites-done + attributes: + label: "Following prerequisites" + description: "I've checked everything mentioned in [Wiki: Prerequisites](https://github.com/ayamir/nvimdots/wiki/Prerequisites)." + options: + - label: "Confirm" + required: true + - type: checkboxes + id: not-user-config-issue + attributes: + label: "Not a user config issue" + description: "This issue _persists_ after removing ALL user configs. If this is not the case, you should open a [Custom (User) Config Issue](https://github.com/ayamir/nvimdots/issues/new?assignees=&labels=usage&projects=&template=custom_config.yml) instead." + options: + - label: "Confirm" + required: true + + - type: input + id: nvim-version + attributes: + label: "Neovim version" + description: "Paste the output of `nvim --version` here" + placeholder: "NVIM v0.11.0-dev-194+g6c7677e5d" + validations: + required: true + - type: input + id: system-version + attributes: + label: "Operating system/version" + placeholder: "macOS 12.6.1" + validations: + required: true + - type: input + id: terminal-version + attributes: + label: "Terminal name/version" + placeholder: "iTerm2 Build 3.4.17" + validations: + required: true + - type: input + id: term-env + attributes: + label: "$TERM environment variable" + placeholder: "xterm-256color" + validations: + required: false + - type: dropdown + id: branch + attributes: + label: "Branch info" + description: "Which branch are you currently on? If you are not sure, check the output of `git rev-parse --abbrev-ref HEAD`" + options: + - main (Default/Latest) + - 0.9 (Legacy) + - 0.8 (Deprecated) + - 0.11 (Nightly) + validations: + required: true + - type: dropdown + id: fetch-pref + attributes: + label: "Fetch Preferences" + description: "In what way do you fetch resources? If you are not sure, check the value of `use_ssh` in `lua/user/settings.lua`" + options: + - SSH (use_ssh = true) + - HTTPS (use_ssh = false) + validations: + required: true + + - type: textarea + id: repro-steps + attributes: + label: "How to reproduce the issue" + description: "Note: Issues without any information will be closed directly" + placeholder: | + Steps to reproduce the behavior: + 1. Go to '...' + 2. Click on '....' + 3. Scroll down to '....' + 4. See error + validations: + required: true + + - type: textarea + id: expected-behavior + attributes: + label: "Expected behavior" + description: "Describe the behavior you expect" + validations: + required: true + - type: textarea + id: actual-behavior + attributes: + label: "Actual behavior" + validations: + required: false + - type: textarea + id: extras + attributes: + label: Additional information + description: If applicable, you may include logs, images, or videos to help explain your problem + validations: + required: false diff --git a/nvim/.github/ISSUE_TEMPLATE/config.yml b/nvim/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..1c7e924 --- /dev/null +++ b/nvim/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: GitHub Discussions + url: https://github.com/ayamir/nvimdots/discussions/new/choose + about: Any issue that does not fall into the above categories shall go here + - name: GitHub Wiki + url: https://github.com/ayamir/nvimdots/wiki + about: Make sure you have checked our documentation first. To be explicit, the "Issues" section \ No newline at end of file diff --git a/nvim/.github/ISSUE_TEMPLATE/custom_config.yml b/nvim/.github/ISSUE_TEMPLATE/custom_config.yml new file mode 100644 index 0000000..6a95d39 --- /dev/null +++ b/nvim/.github/ISSUE_TEMPLATE/custom_config.yml @@ -0,0 +1,111 @@ +name: Custom (User) Config Issue +description: Problems when trying to implement your custom config +labels: [usage] +body: + - type: markdown + attributes: + value: | + _Before requesting:_ Make sure you've read through our [Wiki: Usage](https://github.com/ayamir/nvimdots/wiki/Usage) before you start to add things to nvimdots! + > [!IMPORTANT] + > The `0.11` branch is intended for nightly Neovim builds and is **not** stable. It typically harbors subtle issues scattered throughout. Therefore, refrain from submitting issues if you happen to encounter them. They will be closed directly unless a viable solution is proposed or included. + - type: checkboxes + id: is-latest-commit + attributes: + label: "Version confirmation" + description: "The local configuration is up-to-date in the current branch and this issue _persists_." + options: + - label: "Confirm" + required: true + - type: checkboxes + id: prerequisites-done + attributes: + label: "Following prerequisites" + description: "I've checked everything mentioned in [Wiki: Prerequisites](https://github.com/ayamir/nvimdots/wiki/Prerequisites)." + options: + - label: "Confirm" + required: true + + - type: input + id: nvim-version + attributes: + label: "Neovim version" + description: "Paste the output of `nvim --version` here" + placeholder: "NVIM v0.11.0-dev-194+g6c7677e5d" + validations: + required: true + - type: dropdown + id: branch-info + attributes: + label: "Branch info" + description: "This issue template mainly targets `main` branch. Check the output of `git rev-parse --abbrev-ref HEAD` if you're not sure." + options: + - main (Default/Latest) + - 0.9 (Legacy) + - 0.8 (Deprecated) + - 0.11 (Nightly) + validations: + required: true + + - type: textarea + id: folder-structure-ta + attributes: + label: "Minimal (user) folder structure required to reproduce the issue" + description: "Note: You only need to describe where the *new/modified files* are. This section will be automatically formatted." + render: console + placeholder: | + └── lua/ + ├── core/ + ├── keymap/ default keymaps + ├── modules/ default plugins and plugin configs + └── user custom configs root directory + ├── configs/ custom plugin config folder + │ ├── dap-clients/ custom dap client config folder + │ ├── lsp-servers/ custom lsp server config folder + │ └── your-config.lua your plugin configs (if applicable) + ├── keymap/ custom keymap folder + │ └── your-config.lua your keymap overrides (if applicable) + ├── plugins/ custom plugin folder + │ └── your-config.lua your plugins (if applicable) + ├── event.lua custom `core/events.lua` overrides + ├── options.lua custom `core/options.lua` overrides + └── settings.lua custom `core/settings.lua` overrides + validations: + required: true + + - type: textarea + id: repro-steps + attributes: + label: "Minimal config with steps on how to reproduce the issue" + description: "Note: Issues without any information will be closed directly" + placeholder: | + This is my custom config (`specs.lua`): + ```lua + return { + popup = { + delay_ms = 20, + } + } + ``` + + Steps to reproduce the behavior: + 1. Go to '...' + 2. Click on '....' + 3. Scroll down to '....' + 4. See error + validations: + required: true + + - type: textarea + id: expected-behavior + attributes: + label: "Expected behavior" + description: "Describe the behavior you expect" + validations: + required: true + - type: textarea + id: extras + attributes: + label: Additional information + description: If applicable, you may include logs, images, or videos to help explain your problem + validations: + required: false diff --git a/nvim/.github/ISSUE_TEMPLATE/feature_request.yml b/nvim/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..47fc1ae --- /dev/null +++ b/nvim/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,22 @@ +name: Feature Request +description: Request an enhancement for this project +labels: [enhancement] +body: + - type: markdown + attributes: + value: | + _Before requesting:_ Search [existing issues](https://github.com/ayamir/nvimdots/labels/enhancement) and check the [FAQ](https://github.com/ayamir/nvimdots/wiki/Issues). Thank you for helping us improve! + + - type: textarea + id: feat-desc + attributes: + label: "Feature description" + validations: + required: true + - type: textarea + id: extras + attributes: + label: "Additional information" + description: "If applicable, you may include images or videos to help explain your request" + validations: + required: false diff --git a/nvim/.github/ISSUE_TEMPLATE/lsp_issue_report.yml b/nvim/.github/ISSUE_TEMPLATE/lsp_issue_report.yml new file mode 100644 index 0000000..0997861 --- /dev/null +++ b/nvim/.github/ISSUE_TEMPLATE/lsp_issue_report.yml @@ -0,0 +1,148 @@ +name: LSP Issue +description: File a bug report related to LSPs +labels: [bug, lsp] +body: + - type: markdown + attributes: + value: | + _Before reporting:_ Search [existing issues](https://github.com/ayamir/nvimdots/issues) and check the [FAQ](https://github.com/ayamir/nvimdots/wiki/Issues). Thank you for helping us improve! + > [!IMPORTANT] + > The `0.11` branch is intended for nightly Neovim builds and is **not** stable. It typically harbors subtle issues scattered throughout. Therefore, refrain from submitting issues if you happen to encounter them. They will be closed directly unless a viable solution is proposed or included. + - type: checkboxes + id: is-latest-commit + attributes: + label: "Version confirmation" + description: "The local configuration is up-to-date in the current branch and this issue _persists_." + options: + - label: "Confirm" + required: true + - type: checkboxes + id: prerequisites-done + attributes: + label: "Following prerequisites" + description: "I've checked everything mentioned in [Wiki: Prerequisites](https://github.com/ayamir/nvimdots/wiki/Prerequisites)." + options: + - label: "Confirm" + required: true + - type: checkboxes + id: not-user-config-issue + attributes: + label: "Not a user config issue" + description: "This issue _persists_ after removing ALL user configs. If this is not the case, you should open a [Custom (User) Config Issue](https://github.com/ayamir/nvimdots/issues/new?assignees=&labels=usage&projects=&template=custom_config.yml) instead." + options: + - label: "Confirm" + required: true + + - type: input + id: nvim-version + attributes: + label: "Neovim version" + description: "Paste the output of `nvim --version` here" + placeholder: "NVIM v0.11.0-dev-194+g6c7677e5d" + validations: + required: true + - type: input + id: system-version + attributes: + label: "Operating system/version" + placeholder: "macOS 12.6.1" + validations: + required: true + - type: input + id: terminal-version + attributes: + label: "Terminal name/version" + placeholder: "iTerm2 Build 3.4.17" + validations: + required: true + - type: input + id: term-env + attributes: + label: "$TERM environment variable" + placeholder: "xterm-256color" + validations: + required: false + - type: dropdown + id: branch + attributes: + label: "Branch info" + description: "Which branch are you currently on? If you are not sure, check the output of `git rev-parse --abbrev-ref HEAD`" + options: + - main (Default/Latest) + - 0.9 (Legacy) + - 0.8 (Deprecated) + - 0.11 (Nightly) + validations: + required: true + - type: dropdown + id: fetch-pref + attributes: + label: "Fetch Preferences" + description: "In what way do you fetch resources? If you are not sure, check the value of `use_ssh` in `lua/user/settings.lua`" + options: + - SSH (use_ssh = true) + - HTTPS (use_ssh = false) + validations: + required: true + - type: input + id: servers + attributes: + label: "Affected language servers" + description: "If this issue is specific to one or more language servers, list them here. If not, write `any`" + placeholder: "lua-language-server, clangd" + validations: + required: true + + - type: textarea + id: repro-steps + attributes: + label: "How to reproduce the issue" + description: "Note: Issues without any information will be closed directly" + placeholder: | + Steps to reproduce the behavior: + 1. Go to '...' + 2. Click on '....' + 3. Scroll down to '....' + 4. See error + validations: + required: true + + - type: textarea + id: actual-behavior + attributes: + label: "Actual behavior" + description: "Briefly describe what you've observed" + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: "Expected behavior" + description: "Describe the behavior you expect" + validations: + required: false + - type: textarea + id: support-info + attributes: + label: "Support info" + description: "Plase include information (screenshots) from `:LspInfo` and `:Mason`" + placeholder: | + :LspInfo + :Mason + validations: + required: true + - type: textarea + id: lsp-logs + attributes: + label: "Logs" + description: "Please copy and paste any relevant log output (e.g., `${HOME}/.local/state/nvim/lsp.log` and `${HOME}/.cache/nvim/lsp.log`). This section will be automatically formatted" + render: console + validations: + required: false + - type: textarea + id: extras + attributes: + label: "Additional information" + description: "If applicable, you may include images or videos to help explain your problem" + validations: + required: false diff --git a/nvim/.github/workflows/lint_code.yml b/nvim/.github/workflows/lint_code.yml new file mode 100644 index 0000000..71d11c5 --- /dev/null +++ b/nvim/.github/workflows/lint_code.yml @@ -0,0 +1,11 @@ +name: lint code +on: [push, pull_request] + +jobs: + luacheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: lunarmodules/luacheck@v1 + with: + args: . --std luajit --globals vim _debugging _command_panel _flash_esc_or_noh _telescope_collections _toggle_lazygit --max-line-length 150 --no-config diff --git a/nvim/.github/workflows/style_check.yml b/nvim/.github/workflows/style_check.yml new file mode 100644 index 0000000..3c7936d --- /dev/null +++ b/nvim/.github/workflows/style_check.yml @@ -0,0 +1,13 @@ +name: style check +on: [push, pull_request] + +jobs: + stylua: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: JohnnyMorganz/stylua-action@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + version: latest + args: --check --config-path=stylua.toml . diff --git a/nvim/.github/workflows/update_flake.yml b/nvim/.github/workflows/update_flake.yml new file mode 100644 index 0000000..9d9e31c --- /dev/null +++ b/nvim/.github/workflows/update_flake.yml @@ -0,0 +1,26 @@ +name: update flake.lock +on: + # Scheduled update (1st of every month) + schedule: [{ cron: "30 02 1 * *" }] + +jobs: + update-lockfile: + if: github.repository_owner == 'ayamir' + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v26 + with: + nix_path: nixpkgs=channel:nixos-unstable + - name: Run flake-update + run: | + nix flake update + - uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: "chore(lockfile): auto update flake.lock" + commit_user_name: "github-actions[bot]" + commit_user_email: "41898282+github-actions[bot]@users.noreply.github.com" + commit_author: "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>" + file_pattern: "flake.lock" diff --git a/nvim/.github/workflows/update_lockfile.yml b/nvim/.github/workflows/update_lockfile.yml new file mode 100644 index 0000000..200e019 --- /dev/null +++ b/nvim/.github/workflows/update_lockfile.yml @@ -0,0 +1,41 @@ +name: update lockfile +on: + # Scheduled update (each day) + schedule: [{ cron: "30 01 * * *" }] + +jobs: + update-lockfile: + if: github.repository_owner == 'ayamir' + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Required to count the commits + - uses: andstor/file-existence-action@v3 + id: check_lockfile + with: + files: "lazy-lock.json" + - name: Run count-new-commits + run: | + echo "NEW_COMMIT_COUNT=$(git log --oneline --since '24 hours ago' --perl-regexp --author='^((?!github-actions).*)$' | wc -l)" >> "$GITHUB_ENV" + - uses: rhysd/action-setup-vim@v1 + if: ${{ steps.check_lockfile.outputs.files_exists == 'true' && env.NEW_COMMIT_COUNT > 0 }} + with: + neovim: true + - name: Run lockfile-autoupdate + if: ${{ steps.check_lockfile.outputs.files_exists == 'true' && env.NEW_COMMIT_COUNT > 0 }} + timeout-minutes: 5 + run: | + ./scripts/install.sh + nvim --headless "+Lazy! update" +qa + cp -pv "${HOME}/.config/nvim/lazy-lock.json" . + - uses: stefanzweifel/git-auto-commit-action@v5 + if: ${{ steps.check_lockfile.outputs.files_exists == 'true' && env.NEW_COMMIT_COUNT > 0 }} + with: + commit_message: "chore(lockfile): auto update lazy-lock.json" + commit_user_name: "github-actions[bot]" + commit_user_email: "41898282+github-actions[bot]@users.noreply.github.com" + commit_author: "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>" + file_pattern: "lazy-lock.json" diff --git a/nvim/.gitignore b/nvim/.gitignore new file mode 100644 index 0000000..51c6018 --- /dev/null +++ b/nvim/.gitignore @@ -0,0 +1,4 @@ +lua/modules/plugins/custom.lua +lua/modules/configs/custom +lua/user +result diff --git a/nvim/.nixd.json b/nvim/.nixd.json new file mode 100644 index 0000000..f8bee3e --- /dev/null +++ b/nvim/.nixd.json @@ -0,0 +1,7 @@ +{ + "formatting": { + "command": [ + "nixpkgs-fmt" + ] + } +} diff --git a/nvim/LICENSE b/nvim/LICENSE new file mode 100644 index 0000000..33895b6 --- /dev/null +++ b/nvim/LICENSE @@ -0,0 +1,30 @@ +BSD 3-Clause License + +Copyright (c) 2021 ayamir +Copyright (c) 2022 Jint-lzxy, CharlesChiuGit +Copyright (c) 2023 aarnphm, misumisumi + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/nvim/README.md b/nvim/README.md new file mode 100644 index 0000000..f4af58f --- /dev/null +++ b/nvim/README.md @@ -0,0 +1,216 @@ +
See Wiki: Keybindings for details
+See Wiki: Plugins for details
(You can also find a deps diagram there!)
See Wiki: Usage for details
+See Wiki: NixOS Support for details
+See Wiki: FAQ for details
+ +## ✨ Features + ++ +
+ ++ +
+ +> Tested with [rhysd/vim-startuptime](https://github.com/rhysd/vim-startuptime) + ++ + Dashboard +
++ + Telescope +
++ + Coding +
++ + Code Action +
++ + Debugging +
++ + Lazygit with built-in Terminal +
++ + Command quickref +
+ +## 👐 Contributing + +- If you find anything that needs improving, do not hesitate to point it out or create a PR. +- If you come across an issue, you can first use `:checkhealth` command provided by nvim to trouble-shoot yourself. + - If you still have such problems, feel free to open a new issue! + +## ❤️ Thanks to + +- [ayamir](https://github.com/ayamir) +- [Jint-lzxy](https://github.com/Jint-lzxy) +- [CharlesChiuGit](https://github.com/CharlesChiuGit) +- [aarnphm](https://github.com/aarnphm) +- [misumisumi](https://github.com/misumisumi) + +## 🎉 Acknowledgement + +- [glepnir/nvim](https://github.com/glepnir/nvim) + +## 📜 License + +This Neovim configuration is released under the BSD 3-Clause license, which grants the following permissions: + +- Commercial use +- Distribution +- Modification +- Private use + +For more convoluted language, see the [LICENSE](https://github.com/ayamir/nvimdots/blob/main/LICENSE). diff --git a/nvim/flake.lock b/nvim/flake.lock new file mode 100644 index 0000000..c62dd92 --- /dev/null +++ b/nvim/flake.lock @@ -0,0 +1,148 @@ +{ + "nodes": { + "devshell": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1717408969, + "narHash": "sha256-Q0OEFqe35fZbbRPPRdrjTUUChKVhhWXz3T9ZSKmaoVY=", + "owner": "numtide", + "repo": "devshell", + "rev": "1ebbe68d57457c8cae98145410b164b5477761f4", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1719745305, + "narHash": "sha256-xwgjVUpqSviudEkpQnioeez1Uo2wzrsMaJKJClh+Bls=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "c3c5ecc05edc7dafba779c6c1a61cd08ac6583e9", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719677234, + "narHash": "sha256-qO9WZsj/0E6zcK4Ht1y/iJ8XfwbBzq7xdqhBh44OP/M=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "36317d4d38887f7629876b0e43c8d9593c5cc48d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1704161960, + "narHash": "sha256-QGua89Pmq+FBAro8NriTuoO/wNaUtugt29/qqA8zeeM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "63143ac2c9186be6d9da6035fa22620018c85932", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1717284937, + "narHash": "sha256-lIbdfCsf8LMFloheeE6N31+BMIeixqyQWbSr2vk79EQ=", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1719468428, + "narHash": "sha256-vN5xJAZ4UGREEglh3lfbbkIj+MPEYMuqewMn4atZFaQ=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "1e3deb3d8a86a870d925760db1a5adecc64d329d", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "devshell": "devshell", + "flake-parts": "flake-parts", + "home-manager": "home-manager", + "nixpkgs": "nixpkgs_2" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/nvim/flake.nix b/nvim/flake.nix new file mode 100644 index 0000000..9dd3840 --- /dev/null +++ b/nvim/flake.nix @@ -0,0 +1,105 @@ +{ + # This provides only NixOS module + # As of 2023/08/19, you need to depend on nixpkgs-unstable. + # because "doq" is not included in the stable version. + description = "Provide nixosModules for ayamir/nvimdots"; + + inputs = { + flake-parts.url = "github:hercules-ci/flake-parts"; + devshell.url = "github:numtide/devshell"; + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = inputs @ { self, flake-parts, ... }: + flake-parts.lib.mkFlake { inherit inputs; } + { + imports = [ + inputs.devshell.flakeModule + ]; + flake = { + homeManagerModules = { + nvimdots = ./nixos; + }; + }; + systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; + perSystem = { pkgs, system, ... }: { + packages = { + testEnv = (import ./nixos/testEnv.nix { inherit inputs pkgs; }).activationPackage; + check-linker = pkgs.writeShellApplication { + name = "check-linker"; + text = + let + ldd_cmd = if pkgs.stdenv.isDarwin then "xcrun otool -L" else "${pkgs.glibc.bin}/bin/ldd"; + in + '' + #shellcheck disable=SC1090 + source <(sed -ne :1 -e 'N;1,1b1' -e 'P;D' "${self.packages.${system}.testEnv}/home-path/bin/nvim") + echo "Checking files under ''${XDG_DATA_HOME}/''${NVIM_APPNAME:-nvim}/mason/bin..." + find "''${XDG_DATA_HOME}/''${NVIM_APPNAME:-nvim}/mason/bin" -type l | while read -r link; do + "${ldd_cmd}" "$(readlink -f "$link")" > /dev/zero 2>&1 || continue + linkers=$("${ldd_cmd}" "$(readlink -f "$link")" | tail -n+2) + echo "$linkers" | while read -r line; do + [ -z "$line" ] && continue + echo "$line" | grep -q "/nix/store" || printf '%s: %s does not link to /nix/store \n' "$(basename "$link")" "$line" + done + done + echo "*** Done ***" + ''; + }; + }; + devshells.default = { + commands = [ + { + help = "neovim linked to testEnv."; + name = "nvim"; + command = '' + ${self.packages.${system}.testEnv}/home-path/bin/nvim + ''; + } + { + help = "check-linker"; + package = self.packages.${system}.check-linker; + } + ]; + devshell = { + motd = '' + {202}🔨 Welcome to devshell{reset} + Symlink configs to "''${XDG_CONFIG_HOME}"/nvimdots! + And NVIM_APPNAME=nvimdots is already configured, so neovim will put files under "\$XDG_xxx_HOME"/nvimdots. + To uninstall, remove "\$XDG_xxx_HOME"/nvimdots. + + $(type -p menu &>/dev/null && menu) + ''; + startup = { + mkNvimDir = { + text = '' + mkdir -p "''${XDG_CONFIG_HOME}"/nvimdots + for path in lazy-lock.json init.lua lua snips tutor; do + ln -sf "''${PWD}/''${path}" "''${XDG_CONFIG_HOME}"/nvimdots/ + done + ''; + }; + }; + }; + env = [ + { + name = "NVIM_APPNAME"; + value = "nvimdots"; + } + { + name = "PATH"; + prefix = "${self.packages.${system}.testEnv}/home-path/bin"; + } + ]; + packages = with pkgs; [ + nixd + nixpkgs-fmt + ]; + }; + }; + }; +} diff --git a/nvim/init.lua b/nvim/init.lua new file mode 100644 index 0000000..1544509 --- /dev/null +++ b/nvim/init.lua @@ -0,0 +1,3 @@ +if not vim.g.vscode then + require("core") +end diff --git a/nvim/init.vim b/nvim/init.vim deleted file mode 100644 index 7aeaed9..0000000 --- a/nvim/init.vim +++ /dev/null @@ -1,43 +0,0 @@ -" _ _ _ -" | \ | | ___ _____ _(_)_ __ ___ -" | \| |/ _ \/ _ \ \ / / | '_ ` _ \ -" | |\ | __/ (_) \ V /| | | | | | | -" |_| \_|\___|\___/ \_/ |_|_| |_| |_| -" -" by Stephan Raabe (2023) -" ----------------------------------------------------- - -set nocompatible " disable compatibility to old-time vi -set showmatch " show matching -set ignorecase " case insensitive -set mouse=v " middle-click paste with -set hlsearch " highlight search -set incsearch " incremental search -set tabstop=4 " number of columns occupied by a tab -set softtabstop=4 " see multiple spaces as tabstops so+vim.api.nvim_create_autocmd("FileType", { + pattern = { + "qf", + "help", + "man", + "notify", + "nofile", + "lspinfo", + "terminal", + "prompt", + "toggleterm", + "copilot", + "startuptime", + "tsplayground", + "PlenaryTestPopup", + }, + callback = function(event) + vim.bo[event.buf].buflisted = false + vim.api.nvim_buf_set_keymap(event.buf, "n", "q", "close ", { silent = true }) + end, +}) + +function autocmd.load_autocmds() + local definitions = { + lazy = {}, + bufs = { + -- Reload vim config automatically + { + "BufWritePost", + [[$VIM_PATH/{*.vim,*.yaml,vimrc} nested source $MYVIMRC | redraw]], + }, + -- Reload Vim script automatically if setlocal autoread + { + "BufWritePost,FileWritePost", + "*.vim", + [[nested if &l:autoread > 0 | source | echo 'source ' . bufname('%') | endif]], + }, + { "BufWritePre", "/tmp/*", "setlocal noundofile" }, + { "BufWritePre", "COMMIT_EDITMSG", "setlocal noundofile" }, + { "BufWritePre", "MERGE_MSG", "setlocal noundofile" }, + { "BufWritePre", "*.tmp", "setlocal noundofile" }, + { "BufWritePre", "*.bak", "setlocal noundofile" }, + -- auto place to last edit + { + "BufReadPost", + "*", + [[if line("'\"") > 1 && line("'\"") <= line("$") | execute "normal! g'\"" | endif]], + }, + -- Auto toggle fcitx5 + -- {"InsertLeave", "* :silent", "!fcitx5-remote -c"}, + -- {"BufCreate", "*", ":silent !fcitx5-remote -c"}, + -- {"BufEnter", "*", ":silent !fcitx5-remote -c "}, + -- {"BufLeave", "*", ":silent !fcitx5-remote -c "} + }, + wins = { + -- Highlight current line only on focused window + { + "WinEnter,BufEnter,InsertLeave", + "*", + [[if ! &cursorline && &filetype !~# '^\(dashboard\|clap_\)' && ! &pvw | setlocal cursorline | endif]], + }, + { + "WinLeave,BufLeave,InsertEnter", + "*", + [[if &cursorline && &filetype !~# '^\(dashboard\|clap_\)' && ! &pvw | setlocal nocursorline | endif]], + }, + -- Attempt to write shada when leaving nvim + { + "VimLeave", + "*", + [[if has('nvim') | wshada | else | wviminfo! | endif]], + }, + -- Check if file changed when its window is focus, more eager than 'autoread' + { "FocusGained", "* checktime" }, + -- Equalize window dimensions when resizing vim window + { "VimResized", "*", [[tabdo wincmd =]] }, + }, + ft = { + { "FileType", "*", "setlocal formatoptions-=cro" }, + { "FileType", "alpha", "setlocal showtabline=0" }, + { "FileType", "markdown", "setlocal wrap" }, + { "FileType", "dap-repl", "lua require('dap.ext.autocompl').attach()" }, + { + "FileType", + "c,cpp", + "nnoremap h :ClangdSwitchSourceHeaderVSplit ", + }, + }, + yank = { + { + "TextYankPost", + "*", + [[silent! lua vim.highlight.on_yank({higroup="IncSearch", timeout=300})]], + }, + }, + } + autocmd.nvim_create_augroups(require("modules.utils").extend_config(definitions, "user.event")) +end + +autocmd.load_autocmds() diff --git a/nvim/lua/core/global.lua b/nvim/lua/core/global.lua new file mode 100644 index 0000000..0f01edc --- /dev/null +++ b/nvim/lua/core/global.lua @@ -0,0 +1,18 @@ +local global = {} +local os_name = vim.uv.os_uname().sysname + +function global:load_variables() + self.is_mac = os_name == "Darwin" + self.is_linux = os_name == "Linux" + self.is_windows = os_name == "Windows_NT" + self.is_wsl = vim.fn.has("wsl") == 1 + self.vim_path = vim.fn.stdpath("config") + self.cache_dir = vim.fn.stdpath("cache") + self.data_dir = string.format("%s/site/", vim.fn.stdpath("data")) + self.modules_dir = self.vim_path .. "/modules" + self.home = self.is_windows and os.getenv("USERPROFILE") or os.getenv("HOME") +end + +global:load_variables() + +return global diff --git a/nvim/lua/core/init.lua b/nvim/lua/core/init.lua new file mode 100644 index 0000000..a5fa328 --- /dev/null +++ b/nvim/lua/core/init.lua @@ -0,0 +1,169 @@ +local settings = require("core.settings") +local global = require("core.global") + +-- Create cache dir and data dirs +local createdir = function() + local data_dirs = { + global.cache_dir .. "/backup", + global.cache_dir .. "/session", + global.cache_dir .. "/swap", + global.cache_dir .. "/tags", + global.cache_dir .. "/undo", + } + -- Only check whether cache_dir exists, this would be enough. + if vim.fn.isdirectory(global.cache_dir) == 0 then + ---@diagnostic disable-next-line: param-type-mismatch + vim.fn.mkdir(global.cache_dir, "p") + for _, dir in pairs(data_dirs) do + if vim.fn.isdirectory(dir) == 0 then + vim.fn.mkdir(dir, "p") + end + end + end +end + +local disable_distribution_plugins = function() + -- Disable menu loading + vim.g.did_install_default_menus = 1 + vim.g.did_install_syntax_menu = 1 + + -- Comment this if you define your own filetypes in `after/ftplugin` + -- vim.g.did_load_filetypes = 1 + + -- Do not load native syntax completion + vim.g.loaded_syntax_completion = 1 + + -- Do not load spell files + vim.g.loaded_spellfile_plugin = 1 + + -- Whether to load netrw by default + -- vim.g.loaded_netrw = 1 + -- vim.g.loaded_netrwFileHandlers = 1 + -- vim.g.loaded_netrwPlugin = 1 + -- vim.g.loaded_netrwSettings = 1 + -- newtrw liststyle: https://medium.com/usevim/the-netrw-style-options-3ebe91d42456 + vim.g.netrw_liststyle = 3 + + -- Do not load tohtml.vim + vim.g.loaded_2html_plugin = 1 + + -- Do not load zipPlugin.vim, gzip.vim and tarPlugin.vim (all of these plugins are + -- related to reading files inside compressed containers) + vim.g.loaded_gzip = 1 + vim.g.loaded_tar = 1 + vim.g.loaded_tarPlugin = 1 + vim.g.loaded_vimball = 1 + vim.g.loaded_vimballPlugin = 1 + vim.g.loaded_zip = 1 + vim.g.loaded_zipPlugin = 1 + + -- Do not use builtin matchit.vim and matchparen.vim because we're using vim-matchup + vim.g.loaded_matchit = 1 + vim.g.loaded_matchparen = 1 + + -- Disable sql omni completion + vim.g.loaded_sql_completion = 1 + + -- Set this to 0 in order to disable native EditorConfig support + vim.g.editorconfig = 1 + + -- Disable remote plugins + -- NOTE: + -- > Disabling rplugin.vim will make `wilder.nvim` complain about missing rplugins during :checkhealth, + -- > but since it's config doesn't require python rtp (strictly), it's fine to ignore that for now. + -- vim.g.loaded_remote_plugins = 1 +end + +local leader_map = function() + vim.g.mapleader = " " + -- NOTE: + -- > Uncomment the following if you're using a other than , and you wish + -- > to disable advancing one character by pressing in normal/visual mode. + -- vim.api.nvim_set_keymap("n", " ", "", { noremap = true }) + -- vim.api.nvim_set_keymap("x", " ", "", { noremap = true }) +end + +local gui_config = function() + vim.api.nvim_set_option_value("guifont", settings.gui_config.font_name .. ":h" .. settings.gui_config.font_size, {}) +end + +local neovide_config = function() + for name, config in pairs(settings.neovide_config) do + vim.g["neovide_" .. name] = config + end +end + +local clipboard_config = function() + if global.is_mac then + vim.g.clipboard = { + name = "macOS-clipboard", + copy = { ["+"] = "pbcopy", ["*"] = "pbcopy" }, + paste = { ["+"] = "pbpaste", ["*"] = "pbpaste" }, + cache_enabled = 0, + } + elseif global.is_wsl then + vim.g.clipboard = { + name = "win32yank-wsl", + copy = { + ["+"] = "win32yank.exe -i --crlf", + ["*"] = "win32yank.exe -i --crlf", + }, + paste = { + ["+"] = "win32yank.exe -o --lf", + ["*"] = "win32yank.exe -o --lf", + }, + cache_enabled = 0, + } + end +end + +local shell_config = function() + if global.is_windows then + if not (vim.fn.executable("pwsh") == 1 or vim.fn.executable("powershell") == 1) then + vim.notify( + [[ +Failed to setup terminal config + +PowerShell is either not installed, missing from PATH, or not executable; +cmd.exe will be used instead for `:!` (shell bang) and toggleterm.nvim. + +You're recommended to install PowerShell for better experience.]], + vim.log.levels.WARN, + { title = "[core] Runtime Warning" } + ) + return + end + + local basecmd = "-NoLogo -MTA -ExecutionPolicy RemoteSigned" + local ctrlcmd = "-Command [console]::InputEncoding = [console]::OutputEncoding = [System.Text.Encoding]::UTF8" + local set_opts = vim.api.nvim_set_option_value + set_opts("shell", vim.fn.executable("pwsh") == 1 and "pwsh" or "powershell", {}) + set_opts("shellcmdflag", string.format("%s %s;", basecmd, ctrlcmd), {}) + set_opts("shellredir", "-RedirectStandardOutput %s -NoNewWindow -Wait", {}) + set_opts("shellpipe", "2>&1 | Out-File -Encoding UTF8 %s; exit $LastExitCode", {}) + set_opts("shellquote", "", {}) + set_opts("shellxquote", "", {}) + end +end + +local load_core = function() + createdir() + disable_distribution_plugins() + leader_map() + + gui_config() + neovide_config() + clipboard_config() + shell_config() + + require("core.options") + require("core.mapping") + require("core.event") + require("core.pack") + require("keymap") + + vim.api.nvim_set_option_value("background", settings.background, {}) + vim.cmd.colorscheme(settings.colorscheme) +end + +load_core() diff --git a/nvim/lua/core/mapping.lua b/nvim/lua/core/mapping.lua new file mode 100644 index 0000000..3512169 --- /dev/null +++ b/nvim/lua/core/mapping.lua @@ -0,0 +1,65 @@ +local bind = require("keymap.bind") +local map_cr = bind.map_cr +local map_cu = bind.map_cu +local map_cmd = bind.map_cmd +local map_callback = bind.map_callback + +local core_map = { + -- Suckless + ["n| "] = map_cr("normal za"):with_noremap():with_silent():with_desc("edit: Toggle code fold"), + ["n| "] = map_cu("write"):with_noremap():with_silent():with_desc("edit: Save file"), + ["n|Y"] = map_cmd("y$"):with_desc("edit: Yank text to EOL"), + ["n|D"] = map_cmd("d$"):with_desc("edit: Delete text to EOL"), + ["n|n"] = map_cmd("nzzzv"):with_noremap():with_desc("edit: Next search result"), + ["n|N"] = map_cmd("Nzzzv"):with_noremap():with_desc("edit: Prev search result"), + ["n|J"] = map_cmd("mzJ`z"):with_noremap():with_desc("edit: Join next line"), + ["n| "] = map_callback(function() + _flash_esc_or_noh() + end) + :with_noremap() + :with_silent() + :with_desc("edit: Clear search highlight"), + ["n| "] = map_cmd(" h"):with_noremap():with_desc("window: Focus left"), + ["n| "] = map_cmd(" l"):with_noremap():with_desc("window: Focus right"), + ["n| "] = map_cmd(" j"):with_noremap():with_desc("window: Focus down"), + ["n| "] = map_cmd(" k"):with_noremap():with_desc("window: Focus up"), + ["t| h"] = map_cmd(" wincmd h "):with_silent():with_noremap():with_desc("window: Focus left"), + ["t| l"] = map_cmd(" wincmd l "):with_silent():with_noremap():with_desc("window: Focus right"), + ["t| j"] = map_cmd(" wincmd j "):with_silent():with_noremap():with_desc("window: Focus down"), + ["t| k"] = map_cmd(" wincmd k "):with_silent():with_noremap():with_desc("window: Focus up"), + ["n| "] = map_cr("vertical resize -3"):with_silent():with_desc("window: Resize -3 vertically"), + ["n| "] = map_cr("vertical resize +3"):with_silent():with_desc("window: Resize +3 vertically"), + ["n| "] = map_cr("resize -3"):with_silent():with_desc("window: Resize -3 horizontally"), + ["n| "] = map_cr("resize +3"):with_silent():with_desc("window: Resize +3 horizontally"), + ["n| "] = map_cr("wq"):with_desc("edit: Save file and quit"), + ["n| "] = map_cr("q!"):with_desc("edit: Force quit"), + ["n| o"] = map_cr("setlocal spell! spelllang=en_us"):with_desc("edit: Toggle spell check"), + ["n| bn"] = map_cu("enew"):with_noremap():with_silent():with_desc("buffer: New"), + ["n|tn"] = map_cr("tabnew"):with_noremap():with_silent():with_desc("tab: Create a new tab"), + ["n|tk"] = map_cr("tabnext"):with_noremap():with_silent():with_desc("tab: Move to next tab"), + ["n|tj"] = map_cr("tabprevious"):with_noremap():with_silent():with_desc("tab: Move to previous tab"), + ["n|to"] = map_cr("tabonly"):with_noremap():with_silent():with_desc("tab: Only keep current tab"), + -- Insert mode + ["i| "] = map_cmd(" u "):with_noremap():with_desc("edit: Delete previous block"), + ["i| "] = map_cmd(" "):with_noremap():with_desc("edit: Move cursor to left"), + ["i| "] = map_cmd(" ^i"):with_noremap():with_desc("edit: Move cursor to line start"), + ["i| "] = map_cmd(" :w "):with_desc("edit: Save file"), + ["i| "] = map_cmd(" :wq "):with_desc("edit: Save file and quit"), + -- Command mode + ["c| "] = map_cmd(" "):with_noremap():with_desc("edit: Left"), + ["c| "] = map_cmd(" "):with_noremap():with_desc("edit: Right"), + ["c| "] = map_cmd(" "):with_noremap():with_desc("edit: Home"), + ["c| "] = map_cmd(" "):with_noremap():with_desc("edit: End"), + ["c| "] = map_cmd(" "):with_noremap():with_desc("edit: Delete"), + ["c|"] = map_cmd(" "):with_noremap():with_desc("edit: Backspace"), + ["c| "] = map_cmd([[ =expand("%:p:h") . "/" ]]) + :with_noremap() + :with_desc("edit: Complete path of current file"), + -- Visual mode + ["v|J"] = map_cmd(":m '>+1 gv=gv"):with_desc("edit: Move this line down"), + ["v|K"] = map_cmd(":m '<-2 gv=gv"):with_desc("edit: Move this line up"), + ["v|<"] = map_cmd(" "] = map_cmd(">gv"):with_desc("edit: Increase indent"), +} + +bind.nvim_load_mapping(core_map) diff --git a/nvim/lua/core/options.lua b/nvim/lua/core/options.lua new file mode 100644 index 0000000..d025abf --- /dev/null +++ b/nvim/lua/core/options.lua @@ -0,0 +1,128 @@ +local global = require("core.global") + +local function load_options() + local global_local = { + -- backupdir = global.cache_dir .. "/backup/", + -- directory = global.cache_dir .. "/swap/", + -- spellfile = global.cache_dir .. "/spell/en.uft-8.add", + -- viewdir = global.cache_dir .. "/view/", + autoindent = true, + autoread = true, + autowrite = true, + backspace = "indent,eol,start", + backup = false, + backupskip = "/tmp/*,$TMPDIR/*,$TMP/*,$TEMP/*,*/shm/*,/private/var/*,.vault.vim", + breakat = [[\ \ ;:,!?]], + breakindentopt = "shift:2,min:20", + clipboard = "unnamedplus", + cmdheight = 1, -- 0, 1, 2 + cmdwinheight = 5, + complete = ".,w,b,k,kspell", + completeopt = "menuone,noselect,popup", + concealcursor = "niv", + conceallevel = 0, + cursorcolumn = true, + cursorline = true, + diffopt = "filler,iwhite,internal,linematch:60,algorithm:patience", + display = "lastline", + encoding = "utf-8", + equalalways = false, + errorbells = true, + fileformats = "unix,mac,dos", + foldenable = true, + foldlevelstart = 99, + formatoptions = "1jcroql", + grepformat = "%f:%l:%c:%m", + grepprg = "rg --hidden --vimgrep --smart-case --", + helpheight = 12, + hidden = true, + history = 2000, + ignorecase = true, + inccommand = "nosplit", + incsearch = true, + infercase = true, + jumpoptions = "stack", + laststatus = 3, + linebreak = true, + list = true, + listchars = "tab:»·,nbsp:+,trail:·,extends:→,precedes:←", + magic = true, + mousescroll = "ver:3,hor:6", + number = true, + previewheight = 12, + -- Do NOT adjust the following option (pumblend) if you're using transparent background + pumblend = 0, + pumheight = 15, + redrawtime = 1500, + relativenumber = true, + ruler = true, + scrolloff = 2, + sessionoptions = "buffers,curdir,folds,help,tabpages,winpos,winsize", + shada = "!,'500,<50,@100,s10,h", + shiftround = true, + shiftwidth = 4, + shortmess = "aoOTIcF", + showbreak = "↳ ", + showcmd = false, + showmode = false, + showtabline = 2, + sidescrolloff = 5, + signcolumn = "yes", + smartcase = true, + smarttab = true, + smoothscroll = true, + splitbelow = true, + splitkeep = "screen", + splitright = true, + startofline = false, + swapfile = false, + switchbuf = "usetab,uselast", + synmaxcol = 2500, + tabstop = 4, + termguicolors = true, + timeout = true, + timeoutlen = 300, + ttimeout = true, + ttimeoutlen = 0, + undodir = global.cache_dir .. "/undo/", + undofile = true, + -- Please do NOT set `updatetime` to above 500, otherwise most plugins may not function correctly + updatetime = 200, + viewoptions = "folds,cursor,curdir,slash,unix", + virtualedit = "block", + visualbell = true, + whichwrap = "h,l,<,>,[,],~", + wildignore = ".git,.hg,.svn,*.pyc,*.o,*.out,*.jpg,*.jpeg,*.png,*.gif,*.zip,**/tmp/**,*.DS_Store,**/node_modules/**,**/bower_modules/**", + wildignorecase = true, + -- Do NOT adjust the following option (winblend) if you're using transparent background + winblend = 0, + winminwidth = 10, + winwidth = 30, + wrap = false, + wrapscan = true, + writebackup = false, + } + + local function isempty(s) + return s == nil or s == "" + end + local function use_if_defined(val, fallback) + return val ~= nil and val or fallback + end + + -- custom python provider + local conda_prefix = os.getenv("CONDA_PREFIX") + if not isempty(conda_prefix) then + vim.g.python_host_prog = use_if_defined(vim.g.python_host_prog, conda_prefix .. "/bin/python") + vim.g.python3_host_prog = use_if_defined(vim.g.python3_host_prog, conda_prefix .. "/bin/python") + else + vim.g.python_host_prog = use_if_defined(vim.g.python_host_prog, "python") + vim.g.python3_host_prog = use_if_defined(vim.g.python3_host_prog, "python3") + end + + for name, value in pairs(require("modules.utils").extend_config(global_local, "user.options")) do + vim.api.nvim_set_option_value(name, value, {}) + end +end + +load_options() diff --git a/nvim/lua/core/pack.lua b/nvim/lua/core/pack.lua new file mode 100644 index 0000000..326bf3d --- /dev/null +++ b/nvim/lua/core/pack.lua @@ -0,0 +1,138 @@ +local fn, api = vim.fn, vim.api +local global = require("core.global") +local is_mac = global.is_mac +local vim_path = global.vim_path +local data_dir = global.data_dir +local lazy_path = data_dir .. "lazy/lazy.nvim" +local modules_dir = vim_path .. "/lua/modules" +local user_config_dir = vim_path .. "/lua/user" + +local settings = require("core.settings") +local use_ssh = settings.use_ssh + +local icons = { + kind = require("modules.utils.icons").get("kind"), + documents = require("modules.utils.icons").get("documents"), + ui = require("modules.utils.icons").get("ui"), + ui_sep = require("modules.utils.icons").get("ui", true), + misc = require("modules.utils.icons").get("misc"), +} + +local Lazy = {} + +function Lazy:load_plugins() + self.modules = {} + + local append_nativertp = function() + package.path = package.path + .. string.format( + ";%s;%s;%s", + modules_dir .. "/configs/?.lua", + modules_dir .. "/configs/?/init.lua", + user_config_dir .. "/?.lua" + ) + end + + local get_plugins_list = function() + local list = {} + local plugins_list = vim.split(fn.glob(modules_dir .. "/plugins/*.lua"), "\n") + local user_plugins_list = vim.split(fn.glob(user_config_dir .. "/plugins/*.lua"), "\n", { trimempty = true }) + vim.list_extend(plugins_list, user_plugins_list) + for _, f in ipairs(plugins_list) do + -- aggregate the plugins from `/plugins/*.lua` and `/user/plugins/*.lua` to a plugin list of a certain field for later `require` action. + -- current fields contains: completion, editor, lang, tool, ui + list[#list + 1] = f:find(modules_dir) and f:sub(#modules_dir - 6, -1) or f:sub(#user_config_dir - 3, -1) + end + return list + end + + append_nativertp() + + for _, m in ipairs(get_plugins_list()) do + -- require modules returned from `get_plugins_list()` function. + local modules = require(m:sub(0, #m - 4)) + if type(modules) == "table" then + for name, conf in pairs(modules) do + self.modules[#self.modules + 1] = vim.tbl_extend("force", { name }, conf) + end + end + end + for _, name in ipairs(settings.disabled_plugins) do + self.modules[#self.modules + 1] = { name, enabled = false } + end +end + +function Lazy:load_lazy() + if not vim.uv.fs_stat(lazy_path) then + local lazy_repo = use_ssh and "git@github.com:folke/lazy.nvim.git " or "https://github.com/folke/lazy.nvim.git " + api.nvim_command("!git clone --filter=blob:none --branch=stable " .. lazy_repo .. lazy_path) + end + self:load_plugins() + + local clone_prefix = use_ssh and "git@github.com:%s.git" or "https://github.com/%s.git" + local lazy_settings = { + root = data_dir .. "lazy", -- directory where plugins will be installed + git = { + -- log = { "-10" }, -- show the last 10 commits + timeout = 300, + url_format = clone_prefix, + }, + install = { + -- install missing plugins on startup. This doesn't increase startup time. + missing = true, + colorscheme = { settings.colorscheme }, + }, + ui = { + -- a number <1 is a percentage., >1 is a fixed size + size = { width = 0.88, height = 0.8 }, + wrap = true, -- wrap the lines in the ui + -- The border to use for the UI window. Accepts same border values as |nvim_open_win()|. + border = "rounded", + icons = { + cmd = icons.misc.Code, + config = icons.ui.Gear, + event = icons.kind.Event, + ft = icons.documents.Files, + init = icons.misc.ManUp, + import = icons.documents.Import, + keys = icons.ui.Keyboard, + loaded = icons.ui.Check, + not_loaded = icons.misc.Ghost, + plugin = icons.ui.Package, + runtime = icons.misc.Vim, + source = icons.kind.StaticMethod, + start = icons.ui.Play, + list = { + icons.ui_sep.BigCircle, + icons.ui_sep.BigUnfilledCircle, + icons.ui_sep.Square, + icons.ui_sep.ChevronRight, + }, + }, + }, + performance = { + cache = { + enabled = true, + path = vim.fn.stdpath("cache") .. "/lazy/cache", + -- Once one of the following events triggers, caching will be disabled. + -- To cache all modules, set this to `{}`, but that is not recommended. + disable_events = { "UIEnter", "BufReadPre" }, + ttl = 3600 * 24 * 2, -- keep unused modules for up to 2 days + }, + reset_packpath = true, -- reset the package path to improve startup time + rtp = { + reset = true, -- reset the runtime path to $VIMRUNTIME and the config directory + ---@type string[] + paths = {}, -- add any custom paths here that you want to include in the rtp + }, + }, + } + if is_mac then + lazy_settings.concurrency = 20 + end + + vim.opt.rtp:prepend(lazy_path) + require("lazy").setup(self.modules, lazy_settings) +end + +Lazy:load_lazy() diff --git a/nvim/lua/core/settings.lua b/nvim/lua/core/settings.lua new file mode 100644 index 0000000..1254160 --- /dev/null +++ b/nvim/lua/core/settings.lua @@ -0,0 +1,225 @@ +local settings = {} + +-- Set it to false if you want to use https to update plugins and treesitter parsers. +---@type boolean +settings["use_ssh"] = true + +-- Set it to false if you don't use copilot +---@type boolean +settings["use_copilot"] = true + +-- Set it to false if there is no need to format on save. +---@type boolean +settings["format_on_save"] = true + +-- Set format timeout here (in ms). +---@type number +settings["format_timeout"] = 1000 + +-- Set it to false if the notification after formatting is annoying. +---@type boolean +settings["format_notify"] = true + +-- Set it to true if you prefer formatting ONLY the *changed lines* as defined by your version control system. +-- NOTE: This entry will only be respected if: +-- > The buffer to be formatted is under version control (Git or Mercurial); +-- > Any of the server attached to that buffer supports |DocumentRangeFormattingProvider| server capability. +-- Otherwise Neovim would fall back to format the whole buffer, and a warning will be issued. +---@type boolean +settings["format_modifications_only"] = false + +-- Set the format disabled directories here, files under these dirs won't be formatted on save. +--- NOTE: Directories may contain regular expressions (grammar: vim). |regexp| +--- NOTE: Directories are automatically normalized. |vim.fs.normalize()| +---@type string[] +settings["format_disabled_dirs"] = { + -- Example + "~/format_disabled_dir", +} + +-- Filetypes in this list will skip lsp formatting if rhs is true. +---@type table +settings["formatter_block_list"] = { + lua = false, -- example +} + +-- Servers in this list will skip setting formatting capabilities if rhs is true. +---@type table +settings["server_formatting_block_list"] = { + lua_ls = true, + tsserver = true, + clangd = true, +} + +-- Set it to false if you want to turn off LSP Inlay Hints +---@type boolean +settings["lsp_inlayhints"] = true + +-- Set it to false if diagnostics virtual text is annoying. +-- If disabled, you may browse lsp diagnostics using trouble.nvim (press `gt` to toggle it). +---@type boolean +settings["diagnostics_virtual_text"] = true + +-- Set it to one of the values below if you want to change the visible severity level of lsp diagnostics. +-- Priority: `Error` > `Warning` > `Information` > `Hint`. +-- > e.g. if you set this option to `Warning`, only lsp warnings and errors will be shown. +-- NOTE: This entry only works when `diagnostics_virtual_text` is true. +---@type "ERROR"|"WARN"|"INFO"|"HINT" +settings["diagnostics_level"] = "HINT" + +-- Set the plugins to disable here. +-- Example: "Some-User/A-Repo" +---@type string[] +settings["disabled_plugins"] = {} + +-- Set it to false if you don't use nvim to open big files. +---@type boolean +settings["load_big_files_faster"] = true + +-- Change the colors of the global palette here. +-- Settings will complete their replacement at initialization. +-- Parameters will be automatically completed as you type. +-- Example: { sky = "#04A5E5" } +---@type palette[] +settings["palette_overwrite"] = {} + +-- Set the colorscheme to use here. +-- Available values are: `catppuccin`, `catppuccin-latte`, `catppucin-mocha`, `catppuccin-frappe`, `catppuccin-macchiato`. +---@type string +settings["colorscheme"] = "catppuccin" + +-- Set it to true if your terminal has transparent background. +---@type boolean +settings["transparent_background"] = false + +-- Set background color to use here. +-- Useful if you would like to use a colorscheme that has a light and dark variant like `edge`. +-- Valid values are: `dark`, `light`. +---@type "dark"|"light" +settings["background"] = "dark" + +-- Set the command for handling external URLs here. The executable must be available on your $PATH. +-- This entry is IGNORED on Windows and macOS, which have their default handlers builtin. +---@type string +settings["external_browser"] = "chrome-cli open" + +-- Set the language servers that will be installed during bootstrap here. +-- check the below link for all the supported LSPs: +-- https://github.com/neovim/nvim-lspconfig/tree/master/lua/lspconfig/server_configurations +---@type string[] +settings["lsp_deps"] = { + "bashls", + "clangd", + "html", + "jsonls", + "lua_ls", + "pylsp", + "gopls", +} + +-- Set the general-purpose servers that will be installed during bootstrap here. +-- Check the below link for all supported sources. +-- in `code_actions`, `completion`, `diagnostics`, `formatting`, `hover` folders: +-- https://github.com/nvimtools/none-ls.nvim/tree/main/lua/null-ls/builtins +---@type string[] +settings["null_ls_deps"] = { + "clang_format", + "gofumpt", + "goimports", + "prettier", + "shfmt", + "stylua", + "vint", +} + +-- Set the Debug Adapter Protocol (DAP) clients that will be installed and configured during bootstrap here. +-- Check the below link for all supported DAPs: +-- https://github.com/jay-babu/mason-nvim-dap.nvim/blob/main/lua/mason-nvim-dap/mappings/source.lua +---@type string[] +settings["dap_deps"] = { + "codelldb", -- C-Family + "delve", -- Go + "python", -- Python (debugpy) +} + +-- Set the Treesitter parsers that will be installed during bootstrap here. +-- Check the below link for all supported languages: +-- https://github.com/nvim-treesitter/nvim-treesitter#supported-languages +---@type string[] +settings["treesitter_deps"] = { + "bash", + "c", + "cpp", + "css", + "go", + "gomod", + "html", + "javascript", + "json", + "jsonc", + "latex", + "lua", + "make", + "markdown", + "markdown_inline", + "python", + "rust", + "typescript", + "vimdoc", + "vue", + "yaml", +} + +-- Set the options for neovim's gui clients like `neovide` and `neovim-qt` here. +-- NOTE: Currently, only the following options related to the GUI are supported. Other entries will be IGNORED. +---@type { font_name: string, font_size: number } +settings["gui_config"] = { + font_name = "JetBrainsMono Nerd Font", + font_size = 12, +} + +-- Set the options specific to `neovide` here. +-- NOTE: You should remove the `neovide_` prefix (with trailing underscore) from all your entries below. +-- Check the below link for all supported entries: +-- https://neovide.dev/configuration.html +---@type table +settings["neovide_config"] = { + no_idle = true, + refresh_rate = 120, + cursor_vfx_mode = "railgun", + cursor_vfx_opacity = 200.0, + cursor_antialiasing = true, + cursor_trail_length = 0.05, + cursor_animation_length = 0.03, + cursor_vfx_particle_speed = 20.0, + cursor_vfx_particle_density = 5.0, + cursor_vfx_particle_lifetime = 1.2, +} + +-- Set the dashboard startup image here +-- You can generate the ascii image using: https://github.com/TheZoraiz/ascii-image-converter +-- More info: https://github.com/ayamir/nvimdots/wiki/Issues#change-dashboard-startup-image +---@type string[] +settings["dashboard_image"] = { + [[⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿]], + [[⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⣠⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿]], + [[⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣡⣾⣿⣿⣿⣿⣿⢿⣿⣿⣿⣿⣿⣿⣟⠻⣿⣿⣿⣿⣿⣿⣿⣿]], + [[⣿⣿⣿⣿⣿⣿⣿⣿⡿⢫⣷⣿⣿⣿⣿⣿⣿⣿⣾⣯⣿⡿⢧⡚⢷⣌⣽⣿⣿⣿⣿⣿⣶⡌⣿⣿⣿⣿⣿⣿]], + [[⣿⣿⣿⣿⣿⣿⣿⣿⠇⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣮⣇⣘⠿⢹⣿⣿⣿⣿⣿⣻⢿⣿⣿⣿⣿⣿]], + [[⣿⣿⣿⣿⣿⣿⣿⣿⠀⢸⣿⣿⡇⣿⣿⣿⣿⣿⣿⣿⣿⡟⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣻⣿⣿⣿⣿]], + [[⣿⣿⣿⣿⣿⣿⣿⡇⠀⣬⠏⣿⡇⢻⣿⣿⣿⣿⣿⣿⣿⣷⣼⣿⣿⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⢻⣿⣿⣿⣿]], + [[⣿⣿⣿⣿⣿⣿⣿⠀⠈⠁⠀⣿⡇⠘⡟⣿⣿⣿⣿⣿⣿⣿⣿⡏⠿⣿⣟⣿⣿⣿⣿⣿⣿⣿⣿⣇⣿⣿⣿⣿]], + [[⣿⣿⣿⣿⣿⣿⡏⠀⠀⠐⠀⢻⣇⠀⠀⠹⣿⣿⣿⣿⣿⣿⣩⡶⠼⠟⠻⠞⣿⡈⠻⣟⢻⣿⣿⣿⣿⣿⣿⣿]], + [[⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⢿⠀⡆⠀⠘⢿⢻⡿⣿⣧⣷⢣⣶⡃⢀⣾⡆⡋⣧⠙⢿⣿⣿⣟⣿⣿⣿⣿]], + [[⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀⠀⡥⠂⡐⠀⠁⠑⣾⣿⣿⣾⣿⣿⣿⡿⣷⣷⣿⣧⣾⣿⣿⣿⣿⣿⣿⣿]], + [[⣿⣿⡿⣿⣍⡴⠆⠀⠀⠀⠀⠀⠀⠀⠀⣼⣄⣀⣷⡄⣙⢿⣿⣿⣿⣿⣯⣶⣿⣿⢟⣾⣿⣿⢡⣿⣿⣿⣿⣿]], + [[⣿⡏⣾⣿⣿⣿⣷⣦⠀⠀⠀⢀⡀⠀⠀⠠⣭⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⣡⣾⣿⣿⢏⣾⣿⣿⣿⣿⣿]], + [[⣿⣿⣿⣿⣿⣿⣿⣿⡴⠀⠀⠀⠀⠀⠠⠀⠰⣿⣿⣿⣷⣿⠿⠿⣿⣿⣭⡶⣫⠔⢻⢿⢇⣾⣿⣿⣿⣿⣿⣿]], + [[⣿⣿⣿⡿⢫⣽⠟⣋⠀⠀⠀⠀⣶⣦⠀⠀⠀⠈⠻⣿⣿⣿⣾⣿⣿⣿⣿⡿⣣⣿⣿⢸⣾⣿⣿⣿⣿⣿⣿⣿]], + [[⡿⠛⣹⣶⣶⣶⣾⣿⣷⣦⣤⣤⣀⣀⠀⠀⠀⠀⠀⠀⠉⠛⠻⢿⣿⡿⠫⠾⠿⠋⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿]], + [[⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣀⡆⣠⢀⣴⣏⡀⠀⠀⠀⠉⠀⠀⢀⣠⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿]], + [[⠿⠛⠛⠛⠛⠛⠛⠻⢿⣿⣿⣿⣿⣯⣟⠷⢷⣿⡿⠋⠀⠀⠀⠀⣵⡀⢠⡿⠋⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿]], + [[⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠛⢿⣿⣿⠂⠀⠀⠀⠀⠀⢀⣽⣿⣿⣿⣿⣿⣿⣿⣍⠛⠿⣿⣿⣿⣿⣿⣿]], +} + +return require("modules.utils").extend_config(settings, "user.settings") diff --git a/nvim/lua/keymap/bind.lua b/nvim/lua/keymap/bind.lua new file mode 100644 index 0000000..a5c4b8d --- /dev/null +++ b/nvim/lua/keymap/bind.lua @@ -0,0 +1,169 @@ +---@class map_rhs +---@field cmd string +---@field options table +---@field options.noremap boolean +---@field options.silent boolean +---@field options.expr boolean +---@field options.nowait boolean +---@field options.callback function +---@field options.desc string +---@field buffer boolean|number +local rhs_options = {} + +function rhs_options:new() + local instance = { + cmd = "", + options = { + noremap = false, + silent = false, + expr = false, + nowait = false, + callback = nil, + desc = "", + }, + buffer = false, + } + setmetatable(instance, self) + self.__index = self + return instance +end + +---@param cmd_string string +---@return map_rhs +function rhs_options:map_cmd(cmd_string) + self.cmd = cmd_string + return self +end + +---@param cmd_string string +---@return map_rhs +function rhs_options:map_cr(cmd_string) + self.cmd = (":%s "):format(cmd_string) + return self +end + +---@param cmd_string string +---@return map_rhs +function rhs_options:map_args(cmd_string) + self.cmd = (":%s "):format(cmd_string) + return self +end + +---@param cmd_string string +---@return map_rhs +function rhs_options:map_cu(cmd_string) + -- to eliminate the automatically inserted range in visual mode + self.cmd = (": %s "):format(cmd_string) + return self +end + +---@param callback fun():nil +--- Takes a callback that will be called when the key is pressed +---@return map_rhs +function rhs_options:map_callback(callback) + self.cmd = "" + self.options.callback = callback + return self +end + +---@return map_rhs +function rhs_options:with_silent() + self.options.silent = true + return self +end + +---@param description_string string +---@return map_rhs +function rhs_options:with_desc(description_string) + self.options.desc = description_string + return self +end + +---@return map_rhs +function rhs_options:with_noremap() + self.options.noremap = true + return self +end + +---@return map_rhs +function rhs_options:with_expr() + self.options.expr = true + return self +end + +---@return map_rhs +function rhs_options:with_nowait() + self.options.nowait = true + return self +end + +---@param num number +---@return map_rhs +function rhs_options:with_buffer(num) + self.buffer = num + return self +end + +local bind = {} + +---@param cmd_string string +---@return map_rhs +function bind.map_cr(cmd_string) + local ro = rhs_options:new() + return ro:map_cr(cmd_string) +end + +---@param cmd_string string +---@return map_rhs +function bind.map_cmd(cmd_string) + local ro = rhs_options:new() + return ro:map_cmd(cmd_string) +end + +---@param cmd_string string +---@return map_rhs +function bind.map_cu(cmd_string) + local ro = rhs_options:new() + return ro:map_cu(cmd_string) +end + +---@param cmd_string string +---@return map_rhs +function bind.map_args(cmd_string) + local ro = rhs_options:new() + return ro:map_args(cmd_string) +end + +---@param callback fun():nil +---@return map_rhs +function bind.map_callback(callback) + local ro = rhs_options:new() + return ro:map_callback(callback) +end + +---@param cmd_string string +---@return string escaped_string +function bind.escape_termcode(cmd_string) + return vim.api.nvim_replace_termcodes(cmd_string, true, true, true) +end + +---@param mapping table +function bind.nvim_load_mapping(mapping) + for key, value in pairs(mapping) do + local modes, keymap = key:match("([^|]*)|?(.*)") + if type(value) == "table" then + for _, mode in ipairs(vim.split(modes, "")) do + local rhs = value.cmd + local options = value.options + local buf = value.buffer + if buf and type(buf) == "number" then + vim.api.nvim_buf_set_keymap(buf, mode, keymap, rhs, options) + else + vim.api.nvim_set_keymap(mode, keymap, rhs, options) + end + end + end + end +end + +return bind diff --git a/nvim/lua/keymap/completion.lua b/nvim/lua/keymap/completion.lua new file mode 100644 index 0000000..ae67e2a --- /dev/null +++ b/nvim/lua/keymap/completion.lua @@ -0,0 +1,74 @@ +local bind = require("keymap.bind") +local map_cr = bind.map_cr +local map_cmd = bind.map_cmd +local map_callback = bind.map_callback + +local plug_map = { + ["n| "] = map_cmd(" FormatToggle "):with_noremap():with_desc("formatter: Toggle format on save"), +} +bind.nvim_load_mapping(plug_map) + +local mapping = {} + +function mapping.lsp(buf) + local map = { + -- LSP-related keymaps, ONLY effective in buffers with LSP(s) attached + ["n| li"] = map_cr("LspInfo"):with_silent():with_buffer(buf):with_desc("lsp: Info"), + ["n| lr"] = map_cr("LspRestart"):with_silent():with_buffer(buf):with_nowait():with_desc("lsp: Restart"), + ["n|go"] = map_cr("AerialToggle!"):with_silent():with_buffer(buf):with_desc("lsp: Toggle outline"), + ["n|gto"] = map_callback(function() + require("telescope").extensions.aerial.aerial() + end) + :with_silent() + :with_buffer(buf) + :with_desc("lsp: Toggle outline in Telescope"), + ["n|g["] = map_cr("Lspsaga diagnostic_jump_prev") + :with_silent() + :with_buffer(buf) + :with_desc("lsp: Prev diagnostic"), + ["n|g]"] = map_cr("Lspsaga diagnostic_jump_next") + :with_silent() + :with_buffer(buf) + :with_desc("lsp: Next diagnostic"), + ["n| lx"] = map_cr("Lspsaga show_line_diagnostics ++unfocus") + :with_silent() + :with_buffer(buf) + :with_desc("lsp: Line diagnostic"), + ["n|gs"] = map_callback(function() + vim.lsp.buf.signature_help() + end):with_desc("lsp: Signature help"), + ["n|gr"] = map_cr("Lspsaga rename"):with_silent():with_buffer(buf):with_desc("lsp: Rename in file range"), + ["n|gR"] = map_cr("Lspsaga rename ++project") + :with_silent() + :with_buffer(buf) + :with_desc("lsp: Rename in project range"), + ["n|K"] = map_cr("Lspsaga hover_doc"):with_silent():with_buffer(buf):with_desc("lsp: Show doc"), + ["nv|ga"] = map_cr("Lspsaga code_action") + :with_silent() + :with_buffer(buf) + :with_desc("lsp: Code action for cursor"), + ["n|gd"] = map_cr("Glance definitions"):with_silent():with_buffer(buf):with_desc("lsp: Preview definition"), + ["n|gD"] = map_cr("Lspsaga goto_definition"):with_silent():with_buffer(buf):with_desc("lsp: Goto definition"), + ["n|gh"] = map_cr("Glance references"):with_silent():with_buffer(buf):with_desc("lsp: Show reference"), + ["n|gm"] = map_cr("Glance implementations") + :with_silent() + :with_buffer(buf) + :with_desc("lsp: Show implementation"), + ["n|gci"] = map_cr("Lspsaga incoming_calls") + :with_silent() + :with_buffer(buf) + :with_desc("lsp: Show incoming calls"), + ["n|gco"] = map_cr("Lspsaga outgoing_calls") + :with_silent() + :with_buffer(buf) + :with_desc("lsp: Show outgoing calls"), + } + bind.nvim_load_mapping(map) + + local ok, user_mappings = pcall(require, "user.keymap.completion") + if ok and type(user_mappings.lsp) == "function" then + require("modules.utils.keymap").replace(user_mappings.lsp(buf)) + end +end + +return mapping diff --git a/nvim/lua/keymap/editor.lua b/nvim/lua/keymap/editor.lua new file mode 100644 index 0000000..9b0271c --- /dev/null +++ b/nvim/lua/keymap/editor.lua @@ -0,0 +1,109 @@ +local bind = require("keymap.bind") +local map_cr = bind.map_cr +local map_cu = bind.map_cu +local map_cmd = bind.map_cmd +local map_callback = bind.map_callback +local et = bind.escape_termcode + +local plug_map = { + -- Plugin persisted.nvim + ["n| ss"] = map_cu("SessionSave"):with_noremap():with_silent():with_desc("session: Save"), + ["n| sl"] = map_cu("SessionLoad"):with_noremap():with_silent():with_desc("session: Load current"), + ["n| sd"] = map_cu("SessionDelete"):with_noremap():with_silent():with_desc("session: Delete"), + + -- Plugin: nvim-bufdel + ["n| "] = map_cr("BufDel"):with_noremap():with_silent():with_desc("buffer: Close current"), + + -- Plugin: comment.nvim + ["n|gcc"] = map_callback(function() + return vim.v.count == 0 and et(" (comment_toggle_linewise_current)") + or et(" (comment_toggle_linewise_count)") + end) + :with_silent() + :with_noremap() + :with_expr() + :with_desc("edit: Toggle comment for line"), + ["n|gbc"] = map_callback(function() + return vim.v.count == 0 and et(" (comment_toggle_blockwise_current)") + or et(" (comment_toggle_blockwise_count)") + end) + :with_silent() + :with_noremap() + :with_expr() + :with_desc("edit: Toggle comment for block"), + ["n|gc"] = map_cmd(" (comment_toggle_linewise)") + :with_silent() + :with_noremap() + :with_desc("edit: Toggle comment for line with operator"), + ["n|gb"] = map_cmd(" (comment_toggle_blockwise)") + :with_silent() + :with_noremap() + :with_desc("edit: Toggle comment for block with operator"), + ["x|gc"] = map_cmd(" (comment_toggle_linewise_visual)") + :with_silent() + :with_noremap() + :with_desc("edit: Toggle comment for line with selection"), + ["x|gb"] = map_cmd(" (comment_toggle_blockwise_visual)") + :with_silent() + :with_noremap() + :with_desc("edit: Toggle comment for block with selection"), + + -- Plugin: diffview.nvim + ["n| gd"] = map_cr("DiffviewOpen"):with_silent():with_noremap():with_desc("git: Show diff"), + ["n| gD"] = map_cr("DiffviewClose"):with_silent():with_noremap():with_desc("git: Close diff"), + + -- Plugin: hop.nvim + ["nv| w"] = map_cmd(" HopWordMW "):with_noremap():with_desc("jump: Goto word"), + ["nv| j"] = map_cmd(" HopLineMW "):with_noremap():with_desc("jump: Goto line"), + ["nv| k"] = map_cmd(" HopLineMW "):with_noremap():with_desc("jump: Goto line"), + ["nv| c"] = map_cmd(" HopChar1MW "):with_noremap():with_desc("jump: Goto one char"), + ["nv| C"] = map_cmd(" HopChar2MW "):with_noremap():with_desc("jump: Goto two chars"), + + -- Plugin: smart-splits.nvim + ["n| "] = map_cu("SmartResizeLeft"):with_silent():with_noremap():with_desc("window: Resize -3 horizontally"), + ["n| "] = map_cu("SmartResizeDown"):with_silent():with_noremap():with_desc("window: Resize -3 vertically"), + ["n| "] = map_cu("SmartResizeUp"):with_silent():with_noremap():with_desc("window: Resize +3 vertically"), + ["n| "] = map_cu("SmartResizeRight"):with_silent():with_noremap():with_desc("window: Resize +3 horizontally"), + ["n| "] = map_cu("SmartCursorMoveLeft"):with_silent():with_noremap():with_desc("window: Focus left"), + ["n| "] = map_cu("SmartCursorMoveDown"):with_silent():with_noremap():with_desc("window: Focus down"), + ["n| "] = map_cu("SmartCursorMoveUp"):with_silent():with_noremap():with_desc("window: Focus up"), + ["n| "] = map_cu("SmartCursorMoveRight"):with_silent():with_noremap():with_desc("window: Focus right"), + ["n| Wh"] = map_cu("SmartSwapLeft"):with_silent():with_noremap():with_desc("window: Move window leftward"), + ["n| Wj"] = map_cu("SmartSwapDown"):with_silent():with_noremap():with_desc("window: Move window downward"), + ["n| Wk"] = map_cu("SmartSwapUp"):with_silent():with_noremap():with_desc("window: Move window upward"), + ["n| Wl"] = map_cu("SmartSwapRight"):with_silent():with_noremap():with_desc("window: Move window rightward"), + + -- Plugin: nvim-spectre + ["n| Ss"] = map_callback(function() + require("spectre").toggle() + end) + :with_silent() + :with_noremap() + :with_desc("editn: Toggle search & replace panel"), + ["n| Sp"] = map_callback(function() + require("spectre").open_visual({ select_word = true }) + end) + :with_silent() + :with_noremap() + :with_desc("editn: search&replace current word (project)"), + ["v| Sp"] = map_callback(function() + require("spectre").open_visual() + end) + :with_silent() + :with_noremap() + :with_desc("edit: search & replace current word (project)"), + ["n| Sf"] = map_callback(function() + require("spectre").open_file_search({ select_word = true }) + end) + :with_silent() + :with_noremap() + :with_desc("editn: search & replace current word (file)"), + + -- Plugin: nvim-treehopper + ["o|m"] = map_cu("lua require('tsht').nodes()"):with_silent():with_desc("jump: Operate across syntax tree"), + + -- Plugin suda.vim + ["n| "] = map_cu("SudaWrite"):with_silent():with_noremap():with_desc("editn: Save file using sudo"), +} + +bind.nvim_load_mapping(plug_map) diff --git a/nvim/lua/keymap/helpers.lua b/nvim/lua/keymap/helpers.lua new file mode 100644 index 0000000..60d99e4 --- /dev/null +++ b/nvim/lua/keymap/helpers.lua @@ -0,0 +1,67 @@ +_G._command_panel = function() + require("telescope.builtin").keymaps({ + lhs_filter = function(lhs) + return not string.find(lhs, "Þ") + end, + layout_config = { + width = 0.6, + height = 0.6, + prompt_position = "top", + }, + }) +end + +_G._telescope_collections = function(picker_type) + local actions = require("telescope.actions") + local action_state = require("telescope.actions.state") + local conf = require("telescope.config").values + local finder = require("telescope.finders") + local pickers = require("telescope.pickers") + picker_type = picker_type or {} + + local collections = vim.tbl_keys(require("search.tabs").collections) + pickers + .new(picker_type, { + prompt_title = "Telescope Collections", + finder = finder.new_table({ results = collections }), + sorter = conf.generic_sorter(picker_type), + attach_mappings = function(bufnr) + actions.select_default:replace(function() + actions.close(bufnr) + local selection = action_state.get_selected_entry() + require("search").open({ collection = selection[1] }) + end) + + return true + end, + }) + :find() +end + +_G._flash_esc_or_noh = function() + local flash_active, state = pcall(function() + return require("flash.plugins.char").state + end) + if flash_active and state then + state:hide() + else + pcall(vim.cmd.noh) + end +end + +local _lazygit = nil +_G._toggle_lazygit = function() + if vim.fn.executable("lazygit") == 1 then + if not _lazygit then + _lazygit = require("toggleterm.terminal").Terminal:new({ + cmd = "lazygit", + direction = "float", + close_on_exit = true, + hidden = true, + }) + end + _lazygit:toggle() + else + vim.notify("Command [lazygit] not found!", vim.log.levels.ERROR, { title = "toggleterm.nvim" }) + end +end diff --git a/nvim/lua/keymap/init.lua b/nvim/lua/keymap/init.lua new file mode 100644 index 0000000..dfef620 --- /dev/null +++ b/nvim/lua/keymap/init.lua @@ -0,0 +1,35 @@ +require("keymap.helpers") +local bind = require("keymap.bind") +local map_cr = bind.map_cr +-- local map_cu = bind.map_cu +-- local map_cmd = bind.map_cmd +-- local map_callback = bind.map_callback + +local plug_map = { + -- Package manager: lazy.nvim + ["n| ph"] = map_cr("Lazy"):with_silent():with_noremap():with_nowait():with_desc("package: Show"), + ["n| ps"] = map_cr("Lazy sync"):with_silent():with_noremap():with_nowait():with_desc("package: Sync"), + ["n| pu"] = map_cr("Lazy update"):with_silent():with_noremap():with_nowait():with_desc("package: Update"), + ["n| pi"] = map_cr("Lazy install"):with_silent():with_noremap():with_nowait():with_desc("package: Install"), + ["n| pl"] = map_cr("Lazy log"):with_silent():with_noremap():with_nowait():with_desc("package: Log"), + ["n| pc"] = map_cr("Lazy check"):with_silent():with_noremap():with_nowait():with_desc("package: Check"), + ["n| pd"] = map_cr("Lazy debug"):with_silent():with_noremap():with_nowait():with_desc("package: Debug"), + ["n| pp"] = map_cr("Lazy profile"):with_silent():with_noremap():with_nowait():with_desc("package: Profile"), + ["n| pr"] = map_cr("Lazy restore"):with_silent():with_noremap():with_nowait():with_desc("package: Restore"), + ["n| px"] = map_cr("Lazy clean"):with_silent():with_noremap():with_nowait():with_desc("package: Clean"), +} + +bind.nvim_load_mapping(plug_map) + +-- Plugin keymaps +require("keymap.completion") +require("keymap.editor") +require("keymap.lang") +require("keymap.tool") +require("keymap.ui") + +-- User keymaps +local ok, mappings = pcall(require, "user.keymap.init") +if ok then + require("modules.utils.keymap").replace(mappings) +end diff --git a/nvim/lua/keymap/lang.lua b/nvim/lua/keymap/lang.lua new file mode 100644 index 0000000..46ec703 --- /dev/null +++ b/nvim/lua/keymap/lang.lua @@ -0,0 +1,12 @@ +local bind = require("keymap.bind") +local map_cr = bind.map_cr +-- local map_cu = bind.map_cu +-- local map_cmd = bind.map_cmd +-- local map_callback = bind.map_callback + +local plug_map = { + -- Plugin MarkdownPreview + ["n| "] = map_cr("MarkdownPreviewToggle"):with_noremap():with_silent():with_desc("tool: Preview markdown"), +} + +bind.nvim_load_mapping(plug_map) diff --git a/nvim/lua/keymap/tool.lua b/nvim/lua/keymap/tool.lua new file mode 100644 index 0000000..617a2d0 --- /dev/null +++ b/nvim/lua/keymap/tool.lua @@ -0,0 +1,191 @@ +local bind = require("keymap.bind") +local map_cr = bind.map_cr +local map_cu = bind.map_cu +local map_cmd = bind.map_cmd +local map_callback = bind.map_callback +require("keymap.helpers") + +local plug_map = { + -- Plugin: vim-fugitive + ["n|gps"] = map_cr("G push"):with_noremap():with_silent():with_desc("git: Push"), + ["n|gpl"] = map_cr("G pull"):with_noremap():with_silent():with_desc("git: Pull"), + ["n| gG"] = map_cu("Git"):with_noremap():with_silent():with_desc("git: Open git-fugitive"), + + -- Plugin: nvim-tree + ["n| "] = map_cr("NvimTreeToggle"):with_noremap():with_silent():with_desc("filetree: Toggle"), + ["n| nf"] = map_cr("NvimTreeFindFile"):with_noremap():with_silent():with_desc("filetree: Find file"), + ["n| nr"] = map_cr("NvimTreeRefresh"):with_noremap():with_silent():with_desc("filetree: Refresh"), + + -- Plugin: sniprun + ["v| r"] = map_cr("SnipRun"):with_noremap():with_silent():with_desc("tool: Run code by range"), + ["n| r"] = map_cu([[%SnipRun]]):with_noremap():with_silent():with_desc("tool: Run code by file"), + + -- Plugin: toggleterm + ["t| "] = map_cmd([[ ]]):with_noremap():with_silent(), -- switch to normal mode in terminal. + ["n| "] = map_cr("ToggleTerm direction=horizontal") + :with_noremap() + :with_silent() + :with_desc("terminal: Toggle horizontal"), + ["i| "] = map_cmd(" ToggleTerm direction=horizontal ") + :with_noremap() + :with_silent() + :with_desc("terminal: Toggle horizontal"), + ["t| "] = map_cmd(" ToggleTerm "):with_noremap():with_silent():with_desc("terminal: Toggle horizontal"), + ["n| "] = map_cr("ToggleTerm direction=vertical") + :with_noremap() + :with_silent() + :with_desc("terminal: Toggle vertical"), + ["i| "] = map_cmd(" ToggleTerm direction=vertical ") + :with_noremap() + :with_silent() + :with_desc("terminal: Toggle vertical"), + ["t| "] = map_cmd(" ToggleTerm "):with_noremap():with_silent():with_desc("terminal: Toggle vertical"), + ["n| "] = map_cr("ToggleTerm direction=vertical") + :with_noremap() + :with_silent() + :with_desc("terminal: Toggle vertical"), + ["i| "] = map_cmd(" ToggleTerm direction=vertical ") + :with_noremap() + :with_silent() + :with_desc("terminal: Toggle vertical"), + ["t| "] = map_cmd(" ToggleTerm "):with_noremap():with_silent():with_desc("terminal: Toggle vertical"), + ["n| "] = map_cr("ToggleTerm direction=float"):with_noremap():with_silent():with_desc("terminal: Toggle float"), + ["i| "] = map_cmd(" ToggleTerm direction=float ") + :with_noremap() + :with_silent() + :with_desc("terminal: Toggle float"), + ["t| "] = map_cmd(" ToggleTerm "):with_noremap():with_silent():with_desc("terminal: Toggle float"), + ["n| gg"] = map_callback(function() + _toggle_lazygit() + end) + :with_noremap() + :with_silent() + :with_desc("git: Toggle lazygit"), + + -- Plugin: trouble + ["n|gt"] = map_cr("Trouble diagnostics toggle"):with_noremap():with_silent():with_desc("lsp: Toggle trouble list"), + ["n| lw"] = map_cr("Trouble diagnostics toggle") + :with_noremap() + :with_silent() + :with_desc("lsp: Show workspace diagnostics"), + ["n| lp"] = map_cr("Trouble project_diagnostics toggle") + :with_noremap() + :with_silent() + :with_desc("lsp: Show project diagnostics"), + ["n| ld"] = map_cr("Trouble diagnostics toggle filter.buf=0") + :with_noremap() + :with_silent() + :with_desc("lsp: Show document diagnostics"), + + -- Plugin: telescope + ["n| "] = map_callback(function() + _command_panel() + end) + :with_noremap() + :with_silent() + :with_desc("tool: Toggle command panel"), + ["n| fc"] = map_callback(function() + _telescope_collections(require("telescope.themes").get_dropdown()) + end) + :with_noremap() + :with_silent() + :with_desc("tool: Open Telescope collections"), + ["n| ff"] = map_callback(function() + require("search").open({ collection = "file" }) + end) + :with_noremap() + :with_silent() + :with_desc("tool: Find files"), + ["n| fp"] = map_callback(function() + require("search").open({ collection = "pattern" }) + end) + :with_noremap() + :with_silent() + :with_desc("tool: Find patterns"), + ["v| fs"] = map_cu("Telescope grep_string") + :with_noremap() + :with_silent() + :with_desc("tool: Find word under cursor"), + ["n| fg"] = map_callback(function() + require("search").open({ collection = "git" }) + end) + :with_noremap() + :with_silent() + :with_desc("tool: Locate Git objects"), + ["n| fd"] = map_callback(function() + require("search").open({ collection = "dossier" }) + end) + :with_noremap() + :with_silent() + :with_desc("tool: Retrieve dossiers"), + ["n| fm"] = map_callback(function() + require("search").open({ collection = "misc" }) + end) + :with_noremap() + :with_silent() + :with_desc("tool: Miscellaneous"), + + -- Plugin: dap + ["n| "] = map_callback(function() + require("dap").continue() + end) + :with_noremap() + :with_silent() + :with_desc("debug: Run/Continue"), + ["n| "] = map_callback(function() + require("dap").terminate() + end) + :with_noremap() + :with_silent() + :with_desc("debug: Stop"), + ["n| "] = map_callback(function() + require("dap").toggle_breakpoint() + end) + :with_noremap() + :with_silent() + :with_desc("debug: Toggle breakpoint"), + ["n| "] = map_callback(function() + require("dap").step_into() + end) + :with_noremap() + :with_silent() + :with_desc("debug: Step into"), + ["n| "] = map_callback(function() + require("dap").step_out() + end) + :with_noremap() + :with_silent() + :with_desc("debug: Step out"), + ["n| "] = map_callback(function() + require("dap").step_over() + end) + :with_noremap() + :with_silent() + :with_desc("debug: Step over"), + ["n| db"] = map_callback(function() + require("dap").set_breakpoint(vim.fn.input("Breakpoint condition: ")) + end) + :with_noremap() + :with_silent() + :with_desc("debug: Set breakpoint with condition"), + ["n| dc"] = map_callback(function() + require("dap").run_to_cursor() + end) + :with_noremap() + :with_silent() + :with_desc("debug: Run to cursor"), + ["n| dl"] = map_callback(function() + require("dap").run_last() + end) + :with_noremap() + :with_silent() + :with_desc("debug: Run last"), + ["n| do"] = map_callback(function() + require("dap").repl.open() + end) + :with_noremap() + :with_silent() + :with_desc("debug: Open REPL"), +} + +bind.nvim_load_mapping(plug_map) diff --git a/nvim/lua/keymap/ui.lua b/nvim/lua/keymap/ui.lua new file mode 100644 index 0000000..77df22d --- /dev/null +++ b/nvim/lua/keymap/ui.lua @@ -0,0 +1,105 @@ +local bind = require("keymap.bind") +local map_cr = bind.map_cr +-- local map_cu = bind.map_cu +-- local map_cmd = bind.map_cmd +-- local map_callback = bind.map_callback + +local plug_map = { + -- Plugin: bufferline.nvim + ["n| "] = map_cr("BufferLineCycleNext"):with_noremap():with_silent():with_desc("buffer: Switch to next"), + ["n| "] = map_cr("BufferLineCyclePrev"):with_noremap():with_silent():with_desc("buffer: Switch to prev"), + ["n| "] = map_cr("BufferLineMoveNext"):with_noremap():with_silent():with_desc("buffer: Move current to next"), + ["n| "] = map_cr("BufferLineMovePrev"):with_noremap():with_silent():with_desc("buffer: Move current to prev"), + ["n| be"] = map_cr("BufferLineSortByExtension"):with_noremap():with_desc("buffer: Sort by extension"), + ["n| bd"] = map_cr("BufferLineSortByDirectory"):with_noremap():with_desc("buffer: Sort by directory"), + ["n| "] = map_cr("BufferLineGoToBuffer 1"):with_noremap():with_silent():with_desc("buffer: Goto buffer 1"), + ["n| "] = map_cr("BufferLineGoToBuffer 2"):with_noremap():with_silent():with_desc("buffer: Goto buffer 2"), + ["n| "] = map_cr("BufferLineGoToBuffer 3"):with_noremap():with_silent():with_desc("buffer: Goto buffer 3"), + ["n| "] = map_cr("BufferLineGoToBuffer 4"):with_noremap():with_silent():with_desc("buffer: Goto buffer 4"), + ["n| "] = map_cr("BufferLineGoToBuffer 5"):with_noremap():with_silent():with_desc("buffer: Goto buffer 5"), + ["n| "] = map_cr("BufferLineGoToBuffer 6"):with_noremap():with_silent():with_desc("buffer: Goto buffer 6"), + ["n| "] = map_cr("BufferLineGoToBuffer 7"):with_noremap():with_silent():with_desc("buffer: Goto buffer 7"), + ["n| "] = map_cr("BufferLineGoToBuffer 8"):with_noremap():with_silent():with_desc("buffer: Goto buffer 8"), + ["n| "] = map_cr("BufferLineGoToBuffer 9"):with_noremap():with_silent():with_desc("buffer: Goto buffer 9"), +} + +bind.nvim_load_mapping(plug_map) + +local mapping = {} + +function mapping.gitsigns(buf) + local actions = require("gitsigns.actions") + local map = { + ["n|]g"] = bind.map_callback(function() + if vim.wo.diff then + return "]g" + end + vim.schedule(function() + actions.next_hunk() + end) + return " " + end) + :with_buffer(buf) + :with_expr() + :with_desc("git: Goto next hunk"), + ["n|[g"] = bind.map_callback(function() + if vim.wo.diff then + return "[g" + end + vim.schedule(function() + actions.prev_hunk() + end) + return " " + end) + :with_buffer(buf) + :with_expr() + :with_desc("git: Goto prev hunk"), + ["n| gs"] = bind.map_callback(function() + actions.stage_hunk() + end) + :with_buffer(buf) + :with_desc("git: Stage hunk"), + ["v| gs"] = bind.map_callback(function() + actions.stage_hunk({ vim.fn.line("."), vim.fn.line("v") }) + end) + :with_buffer(buf) + :with_desc("git: Stage hunk"), + ["n| gu"] = bind.map_callback(function() + actions.undo_stage_hunk() + end) + :with_buffer(buf) + :with_desc("git: Undo stage hunk"), + ["n| gr"] = bind.map_callback(function() + actions.reset_hunk() + end) + :with_buffer(buf) + :with_desc("git: Reset hunk"), + ["v| gr"] = bind.map_callback(function() + actions.reset_hunk({ vim.fn.line("."), vim.fn.line("v") }) + end) + :with_buffer(buf) + :with_desc("git: Reset hunk"), + ["n| gR"] = bind.map_callback(function() + actions.reset_buffer() + end) + :with_buffer(buf) + :with_desc("git: Reset buffer"), + ["n| gp"] = bind.map_callback(function() + actions.preview_hunk() + end) + :with_buffer(buf) + :with_desc("git: Preview hunk"), + ["n| gb"] = bind.map_callback(function() + actions.blame_line({ full = true }) + end) + :with_buffer(buf) + :with_desc("git: Blame line"), + -- Text objects + ["ox|ih"] = bind.map_callback(function() + actions.text_object() + end):with_buffer(buf), + } + bind.nvim_load_mapping(map) +end + +return mapping diff --git a/nvim/lua/modules/configs/completion/aerial.lua b/nvim/lua/modules/configs/completion/aerial.lua new file mode 100644 index 0000000..4c89afd --- /dev/null +++ b/nvim/lua/modules/configs/completion/aerial.lua @@ -0,0 +1,80 @@ +return function() + require("modules.utils").load_plugin("aerial", { + lazy_load = false, + close_on_select = true, + highlight_on_jump = false, + disable_max_lines = 8500, + disable_max_size = 1000000, + ignore = { filetypes = { "NvimTree", "terminal", "nofile" } }, + -- Use symbol tree for folding. Set to true or false to enable/disable + -- Set to "auto" to manage folds if your previous foldmethod was 'manual' + -- This can be a filetype map (see :help aerial-filetype-map) + manage_folds = "auto", + layout = { + -- Determines the default direction to open the aerial window. The 'prefer' + -- options will open the window in the other direction *if* there is a + -- different buffer in the way of the preferred direction + -- Enum: prefer_right, prefer_left, right, left, float + default_direction = "prefer_right", + }, + -- Keymaps in aerial window. Can be any value that `vim.keymap.set` accepts OR a table of keymap + -- options with a `callback` (e.g. { callback = function() ... end, desc = "", nowait = true }) + -- Additionally, if it is a string that matches "actions. ", + -- it will use the mapping at require("aerial.actions"). + -- Set to `false` to remove a keymap + keymaps = { + ["?"] = "actions.show_help", + ["g?"] = "actions.show_help", + [" "] = "actions.jump", + ["<2-LeftMouse>"] = "actions.jump", + [" "] = "actions.jump_vsplit", + [" "] = "actions.jump_split", + [" "] = "actions.down_and_scroll", + [" "] = "actions.up_and_scroll", + ["{"] = "actions.prev", + ["}"] = "actions.next", + ["[["] = "actions.prev_up", + ["]]"] = "actions.next_up", + ["q"] = "actions.close", + ["o"] = "actions.tree_toggle", + ["O"] = "actions.tree_toggle_recursive", + ["zr"] = "actions.tree_increase_fold_level", + ["zR"] = "actions.tree_open_all", + ["zm"] = "actions.tree_decrease_fold_level", + ["zM"] = "actions.tree_close_all", + ["zx"] = "actions.tree_sync_folds", + ["zX"] = "actions.tree_sync_folds", + }, + -- A list of all symbols to display. Set to false to display all symbols. + -- This can be a filetype map (see :help aerial-filetype-map) + -- To see all available values, see :help SymbolKind + filter_kind = { + "Array", + "Boolean", + "Class", + "Constant", + "Constructor", + "Enum", + "EnumMember", + "Event", + "Field", + "File", + "Function", + "Interface", + "Key", + "Method", + "Module", + "Namespace", + "Null", + -- "Number", + "Object", + "Operator", + "Package", + -- "Property", + -- "String", + "Struct", + -- "TypeParameter", + -- "Variable", + }, + }) +end diff --git a/nvim/lua/modules/configs/completion/cmp.lua b/nvim/lua/modules/configs/completion/cmp.lua new file mode 100644 index 0000000..f20e7b6 --- /dev/null +++ b/nvim/lua/modules/configs/completion/cmp.lua @@ -0,0 +1,199 @@ +return function() + local icons = { + kind = require("modules.utils.icons").get("kind"), + type = require("modules.utils.icons").get("type"), + cmp = require("modules.utils.icons").get("cmp"), + } + + local border = function(hl) + return { + { "┌", hl }, + { "─", hl }, + { "┐", hl }, + { "│", hl }, + { "┘", hl }, + { "─", hl }, + { "└", hl }, + { "│", hl }, + } + end + + local compare = require("cmp.config.compare") + compare.lsp_scores = function(entry1, entry2) + local diff + if entry1.completion_item.score and entry2.completion_item.score then + diff = (entry2.completion_item.score * entry2.score) - (entry1.completion_item.score * entry1.score) + else + diff = entry2.score - entry1.score + end + return (diff < 0) + end + + local use_copilot = require("core.settings").use_copilot + local comparators = use_copilot == true + and { + require("copilot_cmp.comparators").prioritize, + require("copilot_cmp.comparators").score, + -- require("cmp_tabnine.compare"), + compare.offset, -- Items closer to cursor will have lower priority + compare.exact, + -- compare.scopes, + compare.lsp_scores, + compare.sort_text, + compare.score, + compare.recently_used, + -- compare.locality, -- Items closer to cursor will have higher priority, conflicts with `offset` + require("cmp-under-comparator").under, + compare.kind, + compare.length, + compare.order, + } + or { + -- require("cmp_tabnine.compare"), + compare.offset, -- Items closer to cursor will have lower priority + compare.exact, + -- compare.scopes, + compare.lsp_scores, + compare.sort_text, + compare.score, + compare.recently_used, + -- compare.locality, -- Items closer to cursor will have higher priority, conflicts with `offset` + require("cmp-under-comparator").under, + compare.kind, + compare.length, + compare.order, + } + + local cmp = require("cmp") + require("modules.utils").load_plugin("cmp", { + preselect = cmp.PreselectMode.None, + window = { + completion = { + border = border("PmenuBorder"), + winhighlight = "Normal:Pmenu,CursorLine:PmenuSel,Search:PmenuSel", + scrollbar = false, + }, + documentation = { + border = border("CmpDocBorder"), + winhighlight = "Normal:CmpDoc", + }, + }, + sorting = { + priority_weight = 2, + comparators = comparators, + }, + formatting = { + fields = { "abbr", "kind", "menu" }, + format = function(entry, vim_item) + local lspkind_icons = vim.tbl_deep_extend("force", icons.kind, icons.type, icons.cmp) + -- load lspkind icons + vim_item.kind = + string.format(" %s %s", lspkind_icons[vim_item.kind] or icons.cmp.undefined, vim_item.kind or "") + + vim_item.menu = setmetatable({ + cmp_tabnine = "[TN]", + copilot = "[CPLT]", + buffer = "[BUF]", + orgmode = "[ORG]", + nvim_lsp = "[LSP]", + nvim_lua = "[LUA]", + path = "[PATH]", + tmux = "[TMUX]", + treesitter = "[TS]", + latex_symbols = "[LTEX]", + luasnip = "[SNIP]", + spell = "[SPELL]", + }, { + __index = function() + return "[BTN]" -- builtin/unknown source names + end, + })[entry.source.name] + + local label = vim_item.abbr + local truncated_label = vim.fn.strcharpart(label, 0, 80) + if truncated_label ~= label then + vim_item.abbr = truncated_label .. "..." + end + + return vim_item + end, + }, + matching = { + disallow_partial_fuzzy_matching = false, + }, + performance = { + async_budget = 1, + max_view_entries = 120, + }, + -- You can set mappings if you want + mapping = cmp.mapping.preset.insert({ + [" "] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Select }), + [" "] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Select }), + [" "] = cmp.mapping.scroll_docs(-4), + [" "] = cmp.mapping.scroll_docs(4), + [" "] = cmp.mapping.abort(), + [" "] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_next_item({ behavior = cmp.SelectBehavior.Select }) + elseif require("luasnip").expand_or_locally_jumpable() then + require("luasnip").expand_or_jump() + else + fallback() + end + end, { "i", "s" }), + [" "] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_prev_item({ behavior = cmp.SelectBehavior.Select }) + elseif require("luasnip").jumpable(-1) then + require("luasnip").jump(-1) + else + fallback() + end + end, { "i", "s" }), + [" "] = cmp.mapping({ + i = function(fallback) + if cmp.visible() and cmp.get_active_entry() then + cmp.confirm({ behavior = cmp.ConfirmBehavior.Insert, select = false }) + else + fallback() + end + end, + s = cmp.mapping.confirm({ select = true }), + c = cmp.mapping.confirm({ behavior = cmp.ConfirmBehavior.Insert, select = true }), + }), + }), + snippet = { + expand = function(args) + require("luasnip").lsp_expand(args.body) + end, + }, + -- You should specify your *installed* sources. + sources = { + { name = "nvim_lsp", max_item_count = 350 }, + { name = "nvim_lua" }, + { name = "luasnip" }, + { name = "path" }, + { name = "treesitter" }, + { name = "spell" }, + { name = "tmux" }, + { name = "orgmode" }, + { + name = "buffer", + option = { + get_bufnrs = function() + return vim.api.nvim_buf_line_count(0) < 7500 and vim.api.nvim_list_bufs() or {} + end, + }, + }, + { name = "latex_symbols" }, + { name = "copilot" }, + -- { name = "codeium" }, + -- { name = "cmp_tabnine" }, + }, + experimental = { + ghost_text = { + hl_group = "Whitespace", + }, + }, + }) +end diff --git a/nvim/lua/modules/configs/completion/codeium.lua b/nvim/lua/modules/configs/completion/codeium.lua new file mode 100644 index 0000000..229eab6 --- /dev/null +++ b/nvim/lua/modules/configs/completion/codeium.lua @@ -0,0 +1,3 @@ +return function() + require("modules.utils").load_plugin("codeium", {}) +end diff --git a/nvim/lua/modules/configs/completion/copilot-cmp.lua b/nvim/lua/modules/configs/completion/copilot-cmp.lua new file mode 100644 index 0000000..26d1dad --- /dev/null +++ b/nvim/lua/modules/configs/completion/copilot-cmp.lua @@ -0,0 +1,3 @@ +return function() + require("modules.utils").load_plugin("copilot_cmp", {}) +end diff --git a/nvim/lua/modules/configs/completion/copilot.lua b/nvim/lua/modules/configs/completion/copilot.lua new file mode 100644 index 0000000..a6ea78c --- /dev/null +++ b/nvim/lua/modules/configs/completion/copilot.lua @@ -0,0 +1,28 @@ +return function() + vim.defer_fn(function() + require("modules.utils").load_plugin("copilot", { + cmp = { + enabled = true, + method = "getCompletionsCycling", + }, + panel = { + -- if true, it can interfere with completions in copilot-cmp + enabled = false, + }, + suggestion = { + -- if true, it can interfere with completions in copilot-cmp + enabled = false, + }, + filetypes = { + ["bigfile"] = false, + ["dap-repl"] = false, + ["fugitive"] = false, + ["fugitiveblame"] = false, + ["git"] = false, + ["gitcommit"] = false, + ["log"] = false, + ["toggleterm"] = false, + }, + }) + end, 100) +end diff --git a/nvim/lua/modules/configs/completion/formatters/clang_format.lua b/nvim/lua/modules/configs/completion/formatters/clang_format.lua new file mode 100644 index 0000000..a0f81bf --- /dev/null +++ b/nvim/lua/modules/configs/completion/formatters/clang_format.lua @@ -0,0 +1 @@ +return { "-style={BasedOnStyle: LLVM, IndentWidth: 4}" } diff --git a/nvim/lua/modules/configs/completion/formatting.lua b/nvim/lua/modules/configs/completion/formatting.lua new file mode 100644 index 0000000..0368efe --- /dev/null +++ b/nvim/lua/modules/configs/completion/formatting.lua @@ -0,0 +1,198 @@ +local M = {} + +local settings = require("core.settings") +local disabled_workspaces = settings.format_disabled_dirs +local format_on_save = settings.format_on_save +local format_notify = settings.format_notify +local format_modifications_only = settings.format_modifications_only +local server_formatting_block_list = settings.server_formatting_block_list +local format_timeout = settings.format_timeout + +vim.api.nvim_create_user_command("FormatToggle", function() + M.toggle_format_on_save() +end, {}) + +local block_list = settings.formatter_block_list +vim.api.nvim_create_user_command("FormatterToggleFt", function(opts) + if block_list[opts.args] == nil then + vim.notify( + string.format("[LSP] Formatter for [%s] has been recorded in list and disabled.", opts.args), + vim.log.levels.WARN, + { title = "LSP Formatter Warning" } + ) + block_list[opts.args] = true + else + block_list[opts.args] = not block_list[opts.args] + vim.notify( + string.format( + "[LSP] Formatter for [%s] has been %s.", + opts.args, + not block_list[opts.args] and "enabled" or "disabled" + ), + not block_list[opts.args] and vim.log.levels.INFO or vim.log.levels.WARN, + { title = string.format("LSP Formatter %s", not block_list[opts.args] and "Info" or "Warning") } + ) + end +end, { nargs = 1, complete = "filetype" }) + +function M.enable_format_on_save(is_configured) + local opts = { pattern = "*", timeout = format_timeout } + vim.api.nvim_create_augroup("format_on_save", { clear = true }) + vim.api.nvim_create_autocmd("BufWritePre", { + group = "format_on_save", + pattern = opts.pattern, + callback = function() + require("completion.formatting").format({ + timeout_ms = opts.timeout, + filter = M.format_filter, + }) + end, + }) + if not is_configured then + vim.notify( + "Successfully enabled format-on-save", + vim.log.levels.INFO, + { title = "Settings modification success" } + ) + end +end + +function M.disable_format_on_save(is_configured) + pcall(vim.api.nvim_del_augroup_by_name, "format_on_save") + if not is_configured then + vim.notify( + "Successfully disabled format-on-save", + vim.log.levels.INFO, + { title = "Settings modification success" } + ) + end +end + +function M.configure_format_on_save() + if format_on_save then + M.enable_format_on_save(true) + else + M.disable_format_on_save(true) + end +end + +function M.toggle_format_on_save() + local status = pcall(vim.api.nvim_get_autocmds, { + group = "format_on_save", + event = "BufWritePre", + }) + if not status then + M.enable_format_on_save(false) + else + M.disable_format_on_save(false) + end +end + +function M.format_filter(clients) + return vim.tbl_filter(function(client) + local status_ok, formatting_supported = pcall(function() + return client.supports_method("textDocument/formatting") + end) + if status_ok and formatting_supported and client.name == "null-ls" then + return "null-ls" + elseif not server_formatting_block_list[client.name] and status_ok and formatting_supported then + return client.name + end + end, clients) +end + +function M.format(opts) + local filedir = vim.fn.expand("%:p:h") + for i = 1, #disabled_workspaces do + if vim.regex(vim.fs.normalize(disabled_workspaces[i])):match_str(filedir) ~= nil then + vim.notify( + string.format( + "[LSP] Formatting for all files under [%s] has been disabled.", + vim.fs.normalize(disabled_workspaces[i]) + ), + vim.log.levels.WARN, + { title = "LSP Formatter Warning" } + ) + return + end + end + + local bufnr = opts.bufnr or vim.api.nvim_get_current_buf() + local clients = vim.lsp.get_clients({ buffer = bufnr }) + + if opts.filter then + clients = opts.filter(clients) + elseif opts.id then + clients = vim.tbl_filter(function(client) + return client.id == opts.id + end, clients) + elseif opts.name then + clients = vim.tbl_filter(function(client) + return client.name == opts.name + end, clients) + end + + clients = vim.tbl_filter(function(client) + return client.supports_method("textDocument/formatting") + end, clients) + + if #clients == 0 then + vim.notify( + "[LSP] Format request failed, no matching language servers.", + vim.log.levels.WARN, + { title = "Formatting Failed" } + ) + end + + local timeout_ms = opts.timeout_ms + for _, client in pairs(clients) do + if block_list[vim.bo.filetype] == true then + vim.notify( + string.format( + "[LSP][%s] Formatting for [%s] has been disabled. This file is not being processed.", + client.name, + vim.bo.filetype + ), + vim.log.levels.WARN, + { title = "LSP Formatter Warning" } + ) + return + end + + if + format_modifications_only + and require("lsp-format-modifications").format_modifications(client, bufnr).success + then + if format_notify then + vim.notify( + string.format("[LSP] Format changed lines successfully with %s!", client.name), + vim.log.levels.INFO, + { title = "LSP Range Format Success" } + ) + end + return + end + + -- Fall back to format the whole buffer (even if partial formatting failed) + local params = vim.lsp.util.make_formatting_params(opts.formatting_options) + local result, err = client.request_sync("textDocument/formatting", params, timeout_ms, bufnr) + if result and result.result then + vim.lsp.util.apply_text_edits(result.result, bufnr, client.offset_encoding) + if format_notify then + vim.notify( + string.format("[LSP] Format successfully with %s!", client.name), + vim.log.levels.INFO, + { title = "LSP Format Success" } + ) + end + elseif err then + vim.notify( + string.format("[LSP][%s] %s", client.name, err), + vim.log.levels.ERROR, + { title = "LSP Format Error" } + ) + end + end +end + +return M diff --git a/nvim/lua/modules/configs/completion/glance.lua b/nvim/lua/modules/configs/completion/glance.lua new file mode 100644 index 0000000..f2950de --- /dev/null +++ b/nvim/lua/modules/configs/completion/glance.lua @@ -0,0 +1,83 @@ +return function() + local icons = { ui = require("modules.utils.icons").get("ui", true) } + local actions = require("glance").actions + + require("modules.utils").load_plugin("glance", { + height = 20, + zindex = 50, + preview_win_opts = { + cursorline = true, + number = true, + wrap = true, + }, + border = { + enable = require("core.settings").transparent_background, + top_char = "―", + bottom_char = "―", + }, + list = { + position = "right", + width = 0.33, -- 33% width relative to the active window, min 0.1, max 0.5 + }, + folds = { + folded = true, -- Automatically fold list on startup + fold_closed = icons.ui.ArrowClosed, + fold_open = icons.ui.ArrowOpen, + }, + indent_lines = { enable = true }, + winbar = { enable = true }, + mappings = { + list = { + ["k"] = actions.previous, + ["j"] = actions.next, + [" "] = actions.previous, + [" "] = actions.next, + [" "] = actions.previous_location, -- Bring the cursor to the previous location skipping groups in the list + [" "] = actions.next_location, -- Bring the cursor to the next location skipping groups in the list + [" "] = actions.preview_scroll_win(8), + ["