From 39baab230264f72660b8f467f0ce24ecc9858a51 Mon Sep 17 00:00:00 2001 From: punkfairie Date: Wed, 27 Nov 2024 20:38:07 -0800 Subject: [PATCH] Pull in kickstart-nix.nvim --- .envrc | 1 + .gitignore | 3 + .stylua.toml | 6 + README.md | 332 +++++++++++++++++++++++++++++++++++ flake.lock | 223 +++++++++++++++++++++++ flake.nix | 73 ++++++++ nix/mkNeovim.nix | 214 ++++++++++++++++++++++ nix/neovim-overlay.nix | 118 +++++++++++++ nvim-nix.svg | 317 +++++++++++++++++++++++++++++++++ nvim/after/README.md | 8 + nvim/ftplugin/lua.lua | 55 ++++++ nvim/ftplugin/nix.lua | 18 ++ nvim/init.lua | 104 +++++++++++ nvim/lua/user/lsp.lua | 23 +++ nvim/plugin/autocommands.lua | 148 ++++++++++++++++ nvim/plugin/commands.lua | 9 + nvim/plugin/completion.lua | 163 +++++++++++++++++ nvim/plugin/diffview.lua | 11 ++ nvim/plugin/eyeliner.lua | 10 ++ nvim/plugin/gitsigns.lua | 66 +++++++ nvim/plugin/keymaps.lua | 200 +++++++++++++++++++++ nvim/plugin/lualine.lua | 87 +++++++++ nvim/plugin/neogit.lua | 29 +++ nvim/plugin/plugins.lua | 9 + nvim/plugin/statuscol.lua | 18 ++ nvim/plugin/telescope.lua | 159 +++++++++++++++++ nvim/plugin/treesitter.lua | 97 ++++++++++ nvim/plugin/which-key.lua | 3 + 28 files changed, 2504 insertions(+) create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 .stylua.toml create mode 100644 README.md create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 nix/mkNeovim.nix create mode 100644 nix/neovim-overlay.nix create mode 100644 nvim-nix.svg create mode 100644 nvim/after/README.md create mode 100644 nvim/ftplugin/lua.lua create mode 100644 nvim/ftplugin/nix.lua create mode 100644 nvim/init.lua create mode 100644 nvim/lua/user/lsp.lua create mode 100644 nvim/plugin/autocommands.lua create mode 100644 nvim/plugin/commands.lua create mode 100644 nvim/plugin/completion.lua create mode 100644 nvim/plugin/diffview.lua create mode 100644 nvim/plugin/eyeliner.lua create mode 100644 nvim/plugin/gitsigns.lua create mode 100644 nvim/plugin/keymaps.lua create mode 100644 nvim/plugin/lualine.lua create mode 100644 nvim/plugin/neogit.lua create mode 100644 nvim/plugin/plugins.lua create mode 100644 nvim/plugin/statuscol.lua create mode 100644 nvim/plugin/telescope.lua create mode 100644 nvim/plugin/treesitter.lua create mode 100644 nvim/plugin/which-key.lua diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..a1d3540 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake . -Lv diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a8b6a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +result +.direnv +.luarc.json diff --git a/.stylua.toml b/.stylua.toml new file mode 100644 index 0000000..4fe0607 --- /dev/null +++ b/.stylua.toml @@ -0,0 +1,6 @@ +line_endings = "Unix" +indent_type = "Spaces" +indent_width = 2 +quote_style = "AutoPreferSingle" +call_parentheses = "NoSingleTable" +# collapse_simple_statement = "Never" diff --git a/README.md b/README.md new file mode 100644 index 0000000..54fb994 --- /dev/null +++ b/README.md @@ -0,0 +1,332 @@ + +
+
+ + kickstart-nix.nvim + + + + + + + + + + + + + + +

❄️

+

+ + A dead simple Nix flake template repository
+ for Neovim +
+

+ +[![Neovim][neovim-shield]][neovim-url] +[![Nix][nix-shield]][nix-url] +[![Lua][lua-shield]][lua-url] + +[![GPL2 License][license-shield]][license-url] +[![Issues][issues-shield]][issues-url] +
+ + +![](https://github.com/nix-community/kickstart-nix.nvim/assets/12857160/84faa268-82de-4401-acf3-efddc26dd58a) + +## :grey_question: Why kickstart-nix.nvim + +If Nix and Neovim have one thing in common, +it's that many new users don't know where to get started. +Most Nix-based Neovim setups assume deep expertise in both realms, +abstracting away Neovim's core functionalities +as well as the Nix internals used to build a Neovim config. +Frameworks and module-based DSLs are opinionated and difficult to diverge from +with one's own modifications. + +`kickstart-nix.nvim` is different: +It's geared for users of all levels, +making the migration of Neovim configurations to Nix straightforward. +This project aims to be as simple as possible, while allowing +for maximum flexibility. + +> [!NOTE] +> +> Similar to [`kickstart.nvim`](https://github.com/nvim-lua/kickstart.nvim), +> this repository is meant to be used by **you** to begin your +> **Nix**/Neovim journey; remove the things you don't use and add what you miss. + +## :milky_way: Philosophy + +- KISS principle with sane defaults. +- Manage plugins + external dependencies using Nix + (managing plugins shouldn't be the responsibility of a plugin). +- Configuration entirely in Lua[^1] (Vimscript is also possible). + This makes it easy to migrate from non-nix dotfiles. +- Use Neovim's built-in loading mechanisms. See: + - [`:h initialization`](https://neovim.io/doc/user/starting.html#initialization) + - [`:h runtimepath`](https://neovim.io/doc/user/options.html#'runtimepath') + - [`:h packadd`](https://neovim.io/doc/user/repeat.html#%3Apackadd) +- Use Neovim's built-in LSP client, with Nix managing language servers. + +[^1]: The absence of a Nix module DSL for Neovim configuration is deliberate. + If you were to copy the `nvim` directory to `$XDG_CONFIG_HOME`, + and install the plugins, it would work out of the box. + +## :star2: Features + +- Use either nixpkgs or flake inputs as plugin sources. +- Usable on any device with Neovim and Nix installed. +- Create multiple derivations with different sets of plugins, + and simple regex filters to exclude config files. +- Uses Nix to generate a `.luarc.json` in the devShell's `shellHook`. + This sets up lua-language-server to recognize all plugins + and the Neovim API. + +## :bicyclist: Test drive + +If you have Nix installed (with [flakes](https://wiki.nixos.org/wiki/Flakes) enabled), +you can test drive this by running: + +```console +nix run "github:nix-community/kickstart-nix.nvim" +``` + +## :books: Usage + +1. Click on [Use this template](https://github.com/nix-community/kickstart-nix.nvim/generate) +to start a repo based on this template. **Do _not_ fork it**. +1. Add/remove plugins to/from the [Neovim overlay](./nix/neovim-overlay.nix). +1. Add/remove plugin configs to/from the `nvim/plugin` directory. +1. Modify as you wish (you will probably want to add a color theme, ...). + See: [Design](#robot-design). +1. You can create more than one package using the `mkNeovim` function by + - Passing different plugin lists. + - Adding `ignoreConfigRegexes` (e.g. `= [ "^ftplugin/.*.lua" ]`). + +> [!TIP] +> +> The nix and lua files contain comments explaining +> what everything does in detail. + +## :zap: Installation + +### :snowflake: NixOS (with flakes) + +1. Add your flake to you NixOS flake inputs. +1. Add the overlay provided by this flake. + +```nix +nixpkgs.overlays = [ + # replace with the name you chose + .overlays.default +]; +``` + +You can then add the overlay's output(s) to the `systemPackages`: + +```nix +environment.systemPackages = with pkgs; [ + nvim-pkg # The default package added by the overlay +]; +``` + +> [!IMPORTANT] +> +> This flake uses `nixpkgs.wrapNeovimUnstable`, which has an +> unstable signature. If you set `nixpkgs.follows = "nixpkgs";` +> when importing this into your flake.nix, it may break. +> Especially if your nixpkgs input pins a different branch. + +### :penguin: Non-NixOS + +With Nix installed (flakes enabled), from the repo root: + +```console +nix profile install .#nvim +``` + +## :robot: Design + +Directory structure: + +```sh +── flake.nix +── nvim # Neovim configs (lua), equivalent to ~/.config/nvim +── nix # Nix configs +``` + +### :open_file_folder: Neovim configs + +- Set options in `init.lua`. +- Source autocommands, user commands, keymaps, + and configure plugins in individual files within the `plugin` directory. +- Filetype-specific scripts (e.g. start LSP clients) in the `ftplugin` directory. +- Library modules in the `lua/user` directory. + +Directory structure: + +```sh +── nvim + ├── ftplugin # Sourced when opening a file type + │ └── .lua + ├── init.lua # Always sourced + ├── lua # Shared library modules + │ └── user + │ └── .lua + ├── plugin # Automatically sourced at startup + │ ├── autocommands.lua + │ ├── commands.lua + │ ├── keymaps.lua + │ ├── plugins.lua # Plugins that require a `setup` call + │ └── .lua # Plugin configurations + └── after # Empty in this template + ├── plugin # Sourced at the very end of startup (rarely needed) + └── ftplugin # Sourced when opening a filetype, after sourcing ftplugin scripts +``` + +> [!IMPORTANT] +> +> - Configuration variables (e.g. `vim.g.`) should go in `nvim/init.lua` +> or a module that is `require`d in `init.lua`. +> - Configurations for plugins that require explicit initialization +> (e.g. via a call to a `setup()` function) should go in `nvim/plugin/.lua` +> or `nvim/plugin/plugins.lua`. +> - See [Initialization order](#initialization-order) for details. + +### :open_file_folder: Nix + +You can declare Neovim derivations in `nix/neovim-overlay.nix`. + +There are two ways to add plugins: + +- The traditional way, using `nixpkgs` as the source. +- By adding plugins as flake inputs (if you like living on the bleeding-edge). + Plugins added as flake inputs must be built in `nix/plugin-overlay.nix`. + +Directory structure: + +```sh +── flake.nix +── nix + ├── mkNeovim.nix # Function for creating the Neovim derivation + └── neovim-overlay.nix # Overlay that adds Neovim derivation +``` + +### :mag: Initialization order + +This derivation creates an `init.lua` as follows: + +1. Add `nvim/lua` to the `runtimepath`. +1. Add the content of `nvim/init.lua`. +1. Add `nvim/*` to the `runtimepath`. +1. Add `nvim/after` to the `runtimepath`. + +This means that modules in `nvim/lua` can be `require`d in `init.lua` and `nvim/*/*.lua`. + +Modules in `nvim/plugin/` are sourced automatically, as if they were plugins. +Because they are added to the runtime path at the end of the resulting `init.lua`, +Neovim sources them _after_ loading plugins. + +## :electric_plug: Pre-configured plugins + +This configuration comes with [a few plugins pre-configured](./nix/neovim-overlay.nix). + +You can add or remove plugins by + +- Adding/Removing them in the [Nix list](./nix/neovim-overlay.nix). +- Adding/Removing the config in `nvim/plugin/.lua`. + +## :anchor: Syncing updates + +If you have used this template and would like to fetch updates +that were added later... + +Add this template as a remote: + +```console +git remote add upstream git@github.com:nix-community/kickstart-nix.nvim.git +``` + +Fetch and merge changes: + +```console +git fetch upstream +git merge upstream/main --allow-unrelated-histories +``` + +## :pencil: Editing your config + +When your neovim setup is a nix derivation, editing your config +demands a different workflow than you are used to without nix. +Here is how I usually do it: + +- Perform modifications and stage any new files[^2]. +- Run `nix run /path/to/neovim/#nvim` + or `nix run /path/to/neovim/#nvim -- ` + +[^2]: When adding new files, nix flakes won't pick them up unless they + have been committed or staged. + +This requires a rebuild of the `nvim` derivation, but has the advantage +that if anything breaks, it's only broken during your test run. + +If you want an impure, but faster feedback loop, +you can use `$XDG_CONFIG_HOME/$NVIM_APPNAME`[^3], where `$NVIM_APPNAME` +defaults to `nvim` if the `appName` attribute is not set +in the `mkNeovim` function. + +[^3]: Assuming Linux. Refer to `:h initialization` for Darwin. + +This has one caveat: The wrapper which nix generates for the derivation +calls `nvim` with `-u /nix/store/path/to/generated-init.lua`. +So it won't source a local `init.lua` file. +To work around this, you can put scripts in the `plugin` or `after/plugin` directory. + +> [!TIP] +> +> If you are starting out, and want to test things without having to +> stage or commit new files for changes to take effect, +> you can remove the `.git` directory and re-initialize it (`git init`) +> when you are done. + +## :link: Alternative / similar projects + +- [`kickstart.nvim`](https://github.com/nvim-lua/kickstart.nvim): + Single-file Neovim configuration template with a similar philosophy to this project. + Does not use Nix to manage plugins. +- [`neovim-flake`](https://github.com/jordanisaacs/neovim-flake): + Configured using a Nix module DSL. +- [`NixVim`](https://github.com/nix-community/nixvim): + A module system for Neovim, with a focus on plugin configs. +- [`nixCats-nvim`](https://github.com/BirdeeHub/nixCats-nvim): + A project that organises plugins into categories. + It also separates lua and nix configuration. +- [`lz.n`](https://github.com/nvim-neorocks/lz.n): + A plugin-manager agnostic Lua library for lazy-loading plugins. + Can be used with Nix. + +> [!NOTE] +> +> When comparing with projects in the "non-Nix world", this +> repository would be more comparable to `kickstart.nvim` (hence the name), +> while the philosophies of `neovim-flake` and `NixVim` are more in line with +> a Neovim distribution like [`LunarVim`](https://www.lunarvim.org/) +> or [`LazyVim`](https://www.lazyvim.org/) +> (though they are far more minimal by default). + + +[neovim-shield]: https://img.shields.io/badge/NeoVim-%2357A143.svg?&style=for-the-badge&logo=neovim&logoColor=white +[neovim-url]: https://neovim.io/ +[nix-shield]: https://img.shields.io/badge/nix-0175C2?style=for-the-badge&logo=NixOS&logoColor=white +[nix-url]: https://nixos.org/ +[lua-shield]: https://img.shields.io/badge/lua-%232C2D72.svg?style=for-the-badge&logo=lua&logoColor=white +[lua-url]: https://www.lua.org/ +[license-shield]: https://img.shields.io/github/license/nix-community/kickstart-nix.nvim.svg?style=for-the-badge +[license-url]: https://github.com/nix-community/kickstart-nix.nvim/blob/master/LICENSE +[issues-shield]: https://img.shields.io/github/issues/nix-community/kickstart-nix.nvim.svg?style=for-the-badge +[issues-url]: https://github.com/nix-community/kickstart-nix.nvim/issues +[license-shield]: https://img.shields.io/github/license/nix-community/kickstart-nix.nvim.svg?style=for-the-badge +[license-url]: https://github.com/nix-community/kickstart-nix.nvim/blob/master/LICENSE diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..f8bb672 --- /dev/null +++ b/flake.lock @@ -0,0 +1,223 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1717285511, + "narHash": "sha256-iKzJcpdXih14qYVcZ9QC9XuZYnPc6T8YImb6dX166kw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "2a55567fcf15b1b1c7ed712a2c6fadaec7412ea8", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "gen-luarc": { + "inputs": { + "flake-parts": "flake-parts", + "git-hooks": "git-hooks", + "luvit-meta": "luvit-meta", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1724097937, + "narHash": "sha256-Q4tgm8ZHAQUdvsNft86MqIbHQAm7OF7RT/wwYWXqSdY=", + "owner": "mrcjkb", + "repo": "nix-gen-luarc-json", + "rev": "b36b69c4ded9f31b079523bc452e23458734cf00", + "type": "github" + }, + "original": { + "owner": "mrcjkb", + "repo": "nix-gen-luarc-json", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": [ + "gen-luarc", + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1723803910, + "narHash": "sha256-yezvUuFiEnCFbGuwj/bQcqg7RykIEqudOy/RBrId0pc=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "bfef0ada09e2c8ac55bbcd0831bd0c9d42e651ba", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "gen-luarc", + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "luvit-meta": { + "flake": false, + "locked": { + "lastModified": 1705776742, + "narHash": "sha256-zAAptV/oLuLAAsa2zSB/6fxlElk4+jNZd/cPr9oxFig=", + "owner": "Bilal2453", + "repo": "luvit-meta", + "rev": "ce76f6f6cdc9201523a5875a4471dcfe0186eb60", + "type": "github" + }, + "original": { + "owner": "Bilal2453", + "repo": "luvit-meta", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1718714799, + "narHash": "sha256-FUZpz9rg3gL8NVPKbqU8ei1VkPLsTIfAJ2fdAf5qjak=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "c00d587b1a1afbf200b1d8f0b0e4ba9deb1c7f0e", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-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-stable": { + "locked": { + "lastModified": 1720386169, + "narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "194846768975b7ad2c4988bdb82572c00222c0d7", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1731319897, + "narHash": "sha256-PbABj4tnbWFMfBp6OcUK5iGy1QY+/Z96ZcLpooIbuEI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "dc460ec76cbff0e66e269457d7b728432263166c", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "gen-luarc": "gen-luarc", + "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/flake.nix b/flake.nix new file mode 100644 index 0000000..7f03010 --- /dev/null +++ b/flake.nix @@ -0,0 +1,73 @@ +{ + description = "Neovim derivation"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + gen-luarc.url = "github:mrcjkb/nix-gen-luarc-json"; + + # Add bleeding-edge plugins here. + # They can be updated with `nix flake update` (make sure to commit the generated flake.lock) + # wf-nvim = { + # url = "github:Cassin01/wf.nvim"; + # flake = false; + # }; + }; + + outputs = inputs @ { + self, + nixpkgs, + flake-utils, + gen-luarc, + ... + }: let + supportedSystems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + + # This is where the Neovim derivation is built. + neovim-overlay = import ./nix/neovim-overlay.nix {inherit inputs;}; + in + flake-utils.lib.eachSystem supportedSystems (system: let + pkgs = import nixpkgs { + inherit system; + overlays = [ + # Import the overlay, so that the final Neovim derivation(s) can be accessed via pkgs. + neovim-overlay + # This adds a function can be used to generate a .luarc.json + # containing the Neovim API all plugins in the workspace directory. + # The generated file can be symlinked in the devShell's shellHook. + gen-luarc.overlays.default + ]; + }; + shell = pkgs.mkShell { + name = "nvim-devShell"; + buildInputs = with pkgs; [ + # Tools for Lua and Nix development, useful for editing files in this repo + lua-language-server + nil + stylua + luajitPackages.luacheck + ]; + shellHook = '' + # symlink the .luarc.json generated in the overlay + ln -fs ${pkgs.nvim-luarc-json} .luarc.json + ''; + }; + in { + packages = rec { + default = nvim; + nvim = pkgs.nvim-pkg; + }; + devShells = { + default = shell; + }; + }) + // { + # You can add this overlay to your NixOS configuration + overlays.default = neovim-overlay; + }; +} diff --git a/nix/mkNeovim.nix b/nix/mkNeovim.nix new file mode 100644 index 0000000..efd41c9 --- /dev/null +++ b/nix/mkNeovim.nix @@ -0,0 +1,214 @@ +# Function for creating a Neovim derivation +{ + pkgs, + lib, + stdenv, + # Set by the overlay to ensure we use a compatible version of `wrapNeovimUnstable` + pkgs-wrapNeovim ? pkgs, +}: +with lib; + { + # NVIM_APPNAME - Defaults to 'nvim' if not set. + # If set to something else, this will also rename the binary. + appName ? null, + # The Neovim package to wrap + neovim-unwrapped ? pkgs-wrapNeovim.neovim-unwrapped, + plugins ? [], # List of plugins + # List of dev plugins (will be bootstrapped) - useful for plugin developers + # { name = ; url = ; } + devPlugins ? [], + # Regexes for config files to ignore, relative to the nvim directory. + # e.g. [ "^plugin/neogit.lua" "^ftplugin/.*.lua" ] + ignoreConfigRegexes ? [], + extraPackages ? [], # Extra runtime dependencies (e.g. ripgrep, ...) + # The below arguments can typically be left as their defaults + # Additional lua packages (not plugins), e.g. from luarocks.org. + # e.g. p: [p.jsregexp] + extraLuaPackages ? p: [], + extraPython3Packages ? p: [], # Additional python 3 packages + withPython3 ? true, # Build Neovim with Python 3 support? + withRuby ? false, # Build Neovim with Ruby support? + withNodeJs ? false, # Build Neovim with NodeJS support? + withSqlite ? true, # Add sqlite? This is a dependency for some plugins + # You probably don't want to create vi or vim aliases + # if the appName is something different than "nvim" + # Add a "vi" binary to the build output as an alias? + viAlias ? appName == null || appName == "nvim", + # Add a "vim" binary to the build output as an alias? + vimAlias ? appName == null || appName == "nvim", + }: let + # This is the structure of a plugin definition. + # Each plugin in the `plugins` argument list can also be defined as this attrset + defaultPlugin = { + plugin = null; # e.g. nvim-lspconfig + config = null; # plugin config + # If `optional` is set to `false`, the plugin is installed in the 'start' packpath + # set to `true`, it is installed in the 'opt' packpath, and can be lazy loaded with + # ':packadd! {plugin-name} + optional = false; + runtime = {}; + }; + + externalPackages = extraPackages ++ (optionals withSqlite [pkgs.sqlite]); + + # Map all plugins to an attrset { plugin = ; config = ; optional = ; ... } + normalizedPlugins = map (x: + defaultPlugin + // ( + if x ? plugin + then x + else {plugin = x;} + )) + plugins; + + # This nixpkgs util function creates an attrset + # that pkgs.wrapNeovimUnstable uses to configure the Neovim build. + neovimConfig = pkgs-wrapNeovim.neovimUtils.makeNeovimConfig { + inherit extraPython3Packages withPython3 withRuby withNodeJs viAlias vimAlias; + plugins = normalizedPlugins; + }; + + # This uses the ignoreConfigRegexes list to filter + # the nvim directory + nvimRtpSrc = let + src = ../nvim; + in + lib.cleanSourceWith { + inherit src; + name = "nvim-rtp-src"; + filter = path: tyoe: let + srcPrefix = toString src + "/"; + relPath = lib.removePrefix srcPrefix (toString path); + in + lib.all (regex: builtins.match regex relPath == null) ignoreConfigRegexes; + }; + + # Split runtimepath into 3 directories: + # - lua, to be prepended to the rtp at the beginning of init.lua + # - nvim, containing plugin, ftplugin, ... subdirectories + # - after, to be sourced last in the startup initialization + # See also: https://neovim.io/doc/user/starting.html + nvimRtp = stdenv.mkDerivation { + name = "nvim-rtp"; + src = nvimRtpSrc; + + buildPhase = '' + mkdir -p $out/nvim + mkdir -p $out/lua + rm init.lua + ''; + + installPhase = '' + cp -r lua $out/lua + rm -r lua + # Copy nvim/after only if it exists + if [ -d "after" ]; then + cp -r after $out/after + rm -r after + fi + # Copy rest of nvim/ subdirectories only if they exist + if [ ! -z "$(ls -A)" ]; then + cp -r -- * $out/nvim + fi + ''; + }; + + # The final init.lua content that we pass to the Neovim wrapper. + # It wraps the user init.lua, prepends the lua lib directory to the RTP + # and prepends the nvim and after directory to the RTP + # It also adds logic for bootstrapping dev plugins (for plugin developers) + initLua = + '' + vim.loader.enable() + -- prepend lua directory + vim.opt.rtp:prepend('${nvimRtp}/lua') + '' + # Wrap init.lua + + (builtins.readFile ../nvim/init.lua) + # Bootstrap/load dev plugins + + optionalString (devPlugins != []) ( + '' + local dev_pack_path = vim.fn.stdpath('data') .. '/site/pack/dev' + local dev_plugins_dir = dev_pack_path .. '/opt' + local dev_plugin_path + '' + + strings.concatMapStringsSep + "\n" + (plugin: '' + dev_plugin_path = dev_plugins_dir .. '/${plugin.name}' + if vim.fn.empty(vim.fn.glob(dev_plugin_path)) > 0 then + vim.notify('Bootstrapping dev plugin ${plugin.name} ...', vim.log.levels.INFO) + vim.cmd('!${pkgs.git}/bin/git clone ${plugin.url} ' .. dev_plugin_path) + end + vim.cmd('packadd! ${plugin.name}') + '') + devPlugins + ) + # Prepend nvim and after directories to the runtimepath + # NOTE: This is done after init.lua, + # because of a bug in Neovim that can cause filetype plugins + # to be sourced prematurely, see https://github.com/neovim/neovim/issues/19008 + # We prepend to ensure that user ftplugins are sourced before builtin ftplugins. + + '' + vim.opt.rtp:prepend('${nvimRtp}/nvim') + vim.opt.rtp:prepend('${nvimRtp}/after') + ''; + + # Add arguments to the Neovim wrapper script + extraMakeWrapperArgs = builtins.concatStringsSep " " ( + # Set the NVIM_APPNAME environment variable + (optional (appName != "nvim" && appName != null && appName != "") + ''--set NVIM_APPNAME "${appName}"'') + # Add external packages to the PATH + ++ (optional (externalPackages != []) + ''--prefix PATH : "${makeBinPath externalPackages}"'') + # Set the LIBSQLITE_CLIB_PATH if sqlite is enabled + ++ (optional withSqlite + ''--set LIBSQLITE_CLIB_PATH "${pkgs.sqlite.out}/lib/libsqlite3.so"'') + # Set the LIBSQLITE environment variable if sqlite is enabled + ++ (optional withSqlite + ''--set LIBSQLITE "${pkgs.sqlite.out}/lib/libsqlite3.so"'') + ); + + luaPackages = neovim-unwrapped.lua.pkgs; + resolvedExtraLuaPackages = extraLuaPackages luaPackages; + + # Native Lua libraries + extraMakeWrapperLuaCArgs = + optionalString (resolvedExtraLuaPackages != []) + ''--suffix LUA_CPATH ";" "${concatMapStringsSep ";" luaPackages.getLuaCPath resolvedExtraLuaPackages}"''; + + # Lua libraries + extraMakeWrapperLuaArgs = + optionalString (resolvedExtraLuaPackages != []) + ''--suffix LUA_PATH ";" "${concatMapStringsSep ";" luaPackages.getLuaPath resolvedExtraLuaPackages}"''; + + # wrapNeovimUnstable is the nixpkgs utility function for building a Neovim derivation. + neovim-wrapped = pkgs-wrapNeovim.wrapNeovimUnstable neovim-unwrapped (neovimConfig + // { + luaRcContent = initLua; + wrapperArgs = + escapeShellArgs neovimConfig.wrapperArgs + + " " + + extraMakeWrapperArgs + + " " + + extraMakeWrapperLuaCArgs + + " " + + extraMakeWrapperLuaArgs; + wrapRc = true; + }); + + isCustomAppName = appName != null && appName != "nvim"; + in + neovim-wrapped.overrideAttrs (oa: { + buildPhase = + oa.buildPhase + # If a custom NVIM_APPNAME has been set, rename the `nvim` binary + + lib.optionalString isCustomAppName '' + mv $out/bin/nvim $out/bin/${lib.escapeShellArg appName} + ''; + meta.mainProgram + = if isCustomAppName + then appName + else oa.meta.mainProgram; + }) diff --git a/nix/neovim-overlay.nix b/nix/neovim-overlay.nix new file mode 100644 index 0000000..4c300d3 --- /dev/null +++ b/nix/neovim-overlay.nix @@ -0,0 +1,118 @@ +# This overlay, when applied to nixpkgs, adds the final neovim derivation to nixpkgs. +{inputs}: final: prev: +with final.pkgs.lib; let + pkgs = final; + + # Use this to create a plugin from a flake input + mkNvimPlugin = src: pname: + pkgs.vimUtils.buildVimPlugin { + inherit pname src; + version = src.lastModifiedDate; + }; + + # Make sure we use the pinned nixpkgs instance for wrapNeovimUnstable, + # otherwise it could have an incompatible signature when applying this overlay. + pkgs-wrapNeovim = inputs.nixpkgs.legacyPackages.${pkgs.system}; + + # This is the helper function that builds the Neovim derivation. + mkNeovim = pkgs.callPackage ./mkNeovim.nix { inherit pkgs-wrapNeovim; }; + + # A plugin can either be a package or an attrset, such as + # { plugin = ; # the package, e.g. pkgs.vimPlugins.nvim-cmp + # config = ; # String; a config that will be loaded with the plugin + # # Boolean; Whether to automatically load the plugin as a 'start' plugin, + # # or as an 'opt' plugin, that can be loaded with `:packadd!` + # optional = ; # Default: false + # ... + # } + all-plugins = with pkgs.vimPlugins; [ + # plugins from nixpkgs go in here. + # https://search.nixos.org/packages?channel=unstable&from=0&size=50&sort=relevance&type=packages&query=vimPlugins + nvim-treesitter.withAllGrammars + luasnip # snippets | https://github.com/l3mon4d3/luasnip/ + # nvim-cmp (autocompletion) and extensions + nvim-cmp # https://github.com/hrsh7th/nvim-cmp + cmp_luasnip # snippets autocompletion extension for nvim-cmp | https://github.com/saadparwaiz1/cmp_luasnip/ + lspkind-nvim # vscode-like LSP pictograms | https://github.com/onsails/lspkind.nvim/ + cmp-nvim-lsp # LSP as completion source | https://github.com/hrsh7th/cmp-nvim-lsp/ + cmp-nvim-lsp-signature-help # https://github.com/hrsh7th/cmp-nvim-lsp-signature-help/ + cmp-buffer # current buffer as completion source | https://github.com/hrsh7th/cmp-buffer/ + cmp-path # file paths as completion source | https://github.com/hrsh7th/cmp-path/ + cmp-nvim-lua # neovim lua API as completion source | https://github.com/hrsh7th/cmp-nvim-lua/ + cmp-cmdline # cmp command line suggestions + cmp-cmdline-history # cmp command line history suggestions + # ^ nvim-cmp extensions + # git integration plugins + diffview-nvim # https://github.com/sindrets/diffview.nvim/ + neogit # https://github.com/TimUntersberger/neogit/ + gitsigns-nvim # https://github.com/lewis6991/gitsigns.nvim/ + vim-fugitive # https://github.com/tpope/vim-fugitive/ + # ^ git integration plugins + # telescope and extensions + telescope-nvim # https://github.com/nvim-telescope/telescope.nvim/ + telescope-fzy-native-nvim # https://github.com/nvim-telescope/telescope-fzy-native.nvim + # telescope-smart-history-nvim # https://github.com/nvim-telescope/telescope-smart-history.nvim + # ^ telescope and extensions + # UI + lualine-nvim # Status line | https://github.com/nvim-lualine/lualine.nvim/ + nvim-navic # Add LSP location to lualine | https://github.com/SmiteshP/nvim-navic + statuscol-nvim # Status column | https://github.com/luukvbaal/statuscol.nvim/ + nvim-treesitter-context # nvim-treesitter-context + # ^ UI + # language support + # ^ language support + # navigation/editing enhancement plugins + vim-unimpaired # predefined ] and [ navigation keymaps | https://github.com/tpope/vim-unimpaired/ + eyeliner-nvim # Highlights unique characters for f/F and t/T motions | https://github.com/jinh0/eyeliner.nvim + nvim-surround # https://github.com/kylechui/nvim-surround/ + nvim-treesitter-textobjects # https://github.com/nvim-treesitter/nvim-treesitter-textobjects/ + nvim-ts-context-commentstring # https://github.com/joosepalviste/nvim-ts-context-commentstring/ + # ^ navigation/editing enhancement plugins + # Useful utilities + nvim-unception # Prevent nested neovim sessions | nvim-unception + # ^ Useful utilities + # libraries that other plugins depend on + sqlite-lua + plenary-nvim + nvim-web-devicons + vim-repeat + # ^ libraries that other plugins depend on + # bleeding-edge plugins from flake inputs + # (mkNvimPlugin inputs.wf-nvim "wf.nvim") # (example) keymap hints | https://github.com/Cassin01/wf.nvim + # ^ bleeding-edge plugins from flake inputs + which-key-nvim + ]; + + extraPackages = with pkgs; [ + # language servers, etc. + lua-language-server + nil # nix LSP + ]; +in { + # This is the neovim derivation + # returned by the overlay + nvim-pkg = mkNeovim { + plugins = all-plugins; + inherit extraPackages; + }; + + # This can be symlinked in the devShell's shellHook + nvim-luarc-json = final.mk-luarc-json { + plugins = all-plugins; + }; + + # You can add as many derivations as you like. + # Use `ignoreConfigRegexes` to filter out config + # files you would not like to include. + # + # For example: + # + # nvim-pkg-no-telescope = mkNeovim { + # plugins = []; + # ignoreConfigRegexes = [ + # "^plugin/telescope.lua" + # "^ftplugin/.*.lua" + # ]; + # inherit extraPackages; + # }; +} diff --git a/nvim-nix.svg b/nvim-nix.svg new file mode 100644 index 0000000..882567a --- /dev/null +++ b/nvim-nix.svg @@ -0,0 +1,317 @@ + + + + neovim-mark@2x + Created with Sketch (http://www.bohemiancoding.com/sketch) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + neovim-mark@2x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nvim/after/README.md b/nvim/after/README.md new file mode 100644 index 0000000..a4b4ff2 --- /dev/null +++ b/nvim/after/README.md @@ -0,0 +1,8 @@ +## `after` directory + +Scripts put in + +- `after/plugin` will be sourced *after* init.lua + or any other scripts are sourced during startup. +- `after/ftplugin` will be sourced when opening a + filetype, *after* any other `ftplugin` scripts are sourced. diff --git a/nvim/ftplugin/lua.lua b/nvim/ftplugin/lua.lua new file mode 100644 index 0000000..125c422 --- /dev/null +++ b/nvim/ftplugin/lua.lua @@ -0,0 +1,55 @@ +vim.bo.comments = ':---,:--' + +local lua_ls_cmd = 'lua-language-server' + +-- Check if lua-language-server is available +if vim.fn.executable(lua_ls_cmd) ~= 1 then + return +end + +local root_files = { + '.luarc.json', + '.luarc.jsonc', + '.luacheckrc', + '.stylua.toml', + 'stylua.toml', + 'selene.toml', + 'selene.yml', + '.git', +} + +vim.lsp.start { + name = 'luals', + cmd = { lua_ls_cmd }, + root_dir = vim.fs.dirname(vim.fs.find(root_files, { upward = true })[1]), + capabilities = require('user.lsp').make_client_capabilities(), + settings = { + Lua = { + runtime = { + version = 'LuaJIT', + }, + diagnostics = { + -- Get the language server to recognize the `vim` global, etc. + globals = { + 'vim', + 'describe', + 'it', + 'assert', + 'stub', + }, + disable = { + 'duplicate-set-field', + }, + }, + workspace = { + checkThirdParty = false, + }, + telemetry = { + enable = false, + }, + hint = { -- inlay hints (supported in Neovim >= 0.10) + enable = true, + }, + }, + }, +} diff --git a/nvim/ftplugin/nix.lua b/nvim/ftplugin/nix.lua new file mode 100644 index 0000000..8691e2a --- /dev/null +++ b/nvim/ftplugin/nix.lua @@ -0,0 +1,18 @@ +-- Exit if the language server isn't available +if vim.fn.executable('nil') ~= 1 then + return +end + +local root_files = { + 'flake.nix', + 'default.nix', + 'shell.nix', + '.git', +} + +vim.lsp.start { + name = 'nil_ls', + cmd = { 'nil' }, + root_dir = vim.fs.dirname(vim.fs.find(root_files, { upward = true })[1]), + capabilities = require('user.lsp').make_client_capabilities(), +} diff --git a/nvim/init.lua b/nvim/init.lua new file mode 100644 index 0000000..ecd6583 --- /dev/null +++ b/nvim/init.lua @@ -0,0 +1,104 @@ +local cmd = vim.cmd +local fn = vim.fn +local opt = vim.o +local g = vim.g + +-- key. Defaults to `\`. Some people prefer space. +-- g.mapleader = ' ' +-- g.maplocalleader = ' ' + +opt.compatible = false + +-- Enable true colour support +if fn.has('termguicolors') then + opt.termguicolors = true +end + +-- See :h