{
  pkgs,
  sqlformat
}:

let

  # The folder contains the expected `~/.config/nvim/` structure
  # This structure is the same for plugins.
  # I therefore just load this folder as plugin.
  configuration = pkgs.vimUtils.buildVimPlugin {
    pname = "configuration";
    version = "1.0.0";
    src = ./neovim/configuration;
  };

  colorscheme-smyckblue = pkgs.vimUtils.buildVimPlugin rec {
    pname = "colorscheme-smyckblue";
    version = "1.6.0";
    src = pkgs.fetchgit {
      url = "https://git.daniel-siepmann.de/danielsiepmann/vim-${pname}.git";
      rev = "v${version}";
      sha256 = "pQKP/SWwesRyu98R0JQ//NZIPuMkPWjF1D+08EbOGNA=";
    };
  };

  neotags = pkgs.vimUtils.buildVimPlugin rec {
    pname = "neotags";
    version = "0.3.0";
    src = pkgs.fetchgit {
      url = "https://git.daniel-siepmann.de/danielsiepmann/${pname}.git";
      rev = "v${version}";
      sha256 = "uJ7cl+1Ngff0FKzjmh1i7O/PkNjPvPT+ZEHgceeZcz0=";
    };

    nativeBuildInputs = [
      pkgs.python3
    ];

    preInstall = ''
      rm -rf Dockerfile readme.rst .gitlab-ci.yml rplugin/test
      python -m compileall rplugin
    '';
  };

  syntax-typoscript = pkgs.vimUtils.buildVimPlugin rec {
    pname = "syntax-typoscript";
    version = "2.0.0";
    src = pkgs.fetchgit {
      url = "https://git.daniel-siepmann.de/danielsiepmann/vim-${pname}.git";
      rev = "v${version}";
      sha256 = "fCB+ikDmkfEP/W0pFYGrsZiH30vT0g3z6GZpRGk0Rhc=";
    };
  };

  syntax-fluid = pkgs.vimUtils.buildVimPlugin rec {
    pname = "syntax-fluid";
    version = "2016-06-22";
    src = pkgs.fetchFromGitHub {
      owner = "mipmip";
      repo = "vim-fluid";
      rev =  "cedc4ad871941e8f7134d1d71f9434f1bc3d93d5";
      sha256 = "LiS2Dqw1K1Fu5VfHQnxIBDxDzEarmSAUUavQcwHRDsQ=";
    };
  };

  syntax-mustache = pkgs.vimUtils.buildVimPlugin rec {
    pname = "syntax-mustache-handlebars";
    version = "2021-11-30";
    src = pkgs.fetchFromGitHub {
      owner = "mustache";
      repo = "vim-mustache-handlebars";
      rev = "0153fe03a919add2d6cf2d41b2d5b6e1188bc0e0";
      sha256 = "lmYt+GKuXhbOhu3HufqIFE2DvzUYlk5vGqU6tpJ2yjY=";
    };
  };

  rg = pkgs.vimUtils.buildVimPlugin rec {
    pname = "rg";
    version = "2023-08-12";
    src = pkgs.fetchFromGitHub {
      owner = "duane9";
      repo = "nvim-rg";
      rev = "c24e37093929a60e61761bdfa591af6984e49b51";
      sha256 = "PBDdkhZq5OnYpWSbLRG8krMTcuaCRn0mSpRLCqnEgLk=";
    };
  };

  vdebug = pkgs.vimUtils.buildVimPlugin rec {
    pname = "vdebug";
    version = "2022-02-27";
    src = pkgs.fetchFromGitHub {
      owner = "joonty";
      repo = pname;
      rev = "f979cc065e63796bdf60f014ae2280ce8e72cded";
      sha256 = "0pvRdqogxYs2QMH1uHTJzLY5QtvenSyowcqkGhtauLY=";
    };
  };

  # TODO: Check changes of forks: https://github.com/sgeb/vim-diff-fold/network
  diff-fold = pkgs.vimUtils.buildVimPlugin rec {
    pname = "diff-fold";
    version = "2012-09-14";
    src = pkgs.fetchFromGitHub {
      owner = "sgeb";
      repo = "vim-${pname}";
      rev = "48b4505c1b6f14ceb4e4be732aad337147ef36cd";
      sha256 = "M3CAUueEhLD0J6sLUpRkFv+vK4aGYO+Xnokxmn+VxqU=";
    };
  };

  neoterm = pkgs.vimUtils.buildVimPlugin rec {
    pname = "neoterm";
    version = "2023-03-09";
    src = pkgs.fetchFromGitHub {
      owner = "kassio";
      repo = pname;
      rev = "eca22dc90a9db5e52d8baf91f31991ad540ffe36";
      sha256 = "0w962xfcgigdw41wblrv1l55xki0kl5vwkdbm6jlr44hzii0nhgz";
    };
    patches = [
      ./neovim/patches/disable_neoterm_repl.patch
    ];
  };

  tagbar = pkgs.vimUtils.buildVimPlugin rec {
    pname = "tagbar";
    version = "2.7";
    src = pkgs.fetchFromGitHub {
      owner = "majutsushi";
      repo = pname;
      rev = "v${version}";
      sha256 = "Eg6xRwisopmBexqkWjRbSi9aQC4uCXbFO6SCK1LY+Ow=";
    };
  };

  # Use `let g:test#last_command="<command>"` to set a test to execute when repeating last.
  # Note that you need to set further variables, or execute a matching test beforehand.
  test = pkgs.vimUtils.buildVimPlugin rec {
    pname = "test";
    version = "2023-10-28";
    src = pkgs.fetchFromGitHub {
      owner = "vim-${pname}";
      repo = "vim-${pname}";
      rev = "5880b17c3baf31a22077538dad5d88c658874303";
      sha256 = "f6T5L3x2T6EwHoRmcH1zmrBX1FDqhlfsePB8InLTgsg=";
    };
    patches = [
      ./neovim/patches/disable_test_paratest.patch
      ./neovim/patches/test_fix_codeception_nearest.patch
      ./neovim/patches/test_limit_codeception.patch
    ];
  };

  telescope-ctags-outline = pkgs.vimUtils.buildVimPlugin rec {
    pname = "telescope-ctags-outline";
    version = "2023-08-21";
    src = pkgs.fetchFromGitHub {
      owner = "fcying";
      repo = "${pname}.nvim";
      rev = "74745d8c08617f68ad88fd08ea4d342ca8549d8d";
      sha256 = "JOD36DukgJzqtNqAveQpc/LbsihYw6OgaX+bMXbSc8o=";
    };
  };

in {
  enable = true;

  # TODO: Check out these plugins as additions / replacements:

  # - https://github.com/NTBBloodbath/rest.nvim recommended by Sascha, allows to write and execute requests

  # - https://github.com/glacambre/firenvim Give it another try, integrates neovim into firefox
  # - https://github.com/sindrets/diffview.nvim/ 

  # - https://github.com/weilbith/nvim-code-action-menu/ Check again in future, right now not of much useness on my setup.
  #
  # Alternatives:
  # - https://github.com/mfussenegger/nvim-dap Alternative to Vdebug, more modern and should work with firefox as well? But needs node …)
  # - https://github.com/nvim-neo-tree/neo-tree.nvim (General tree, not only filesystem, alternative to nerdtree but can also be used for buffers etc.)
  # - https://github.com/simrat39/symbols-outline.nvim/ Replacement for tagbar using lsp, combine with https://github.com/jose-elias-alvarez/null-ls.nvim once it supports Workspace Symbols / Document Symbol

  plugins = with pkgs.vimPlugins; [

    # My own plugins

    colorscheme-smyckblue
    neotags
    {
      plugin = configuration;
      config = ''
        au FileType sql setlocal formatprg=${sqlformat}/bin/sqlformat
      '';
    }
    syntax-typoscript

    # More UI related

    {
      plugin = nerdtree;
      config = builtins.readFile(./neovim/plugins/nerdtree.vim);
    }

    {
      # Use pinned to 2.7 as I don't need any of the new features.
      # Instead they make it hard to only show what I'm interested in within PHP files.
      # As they changed the building with nested structures.
      plugin = tagbar;
      config = builtins.readFile(./neovim/plugins/tagbar.vim);
    }

    {
      plugin = telescope-nvim;
      type = "lua";
      config = builtins.readFile(./neovim/plugins/telescope.lua);
    }

    {
      plugin = telescope-ctags-outline;
      type = "lua";
      config = builtins.readFile(./neovim/plugins/telescope-ctags-outline.lua);
    }

    dressing-nvim

    # Syntax

    syntax-mustache
    i3config-vim
    typescript-vim
    syntax-fluid
    vim-twig
    # PHP Syntax is loaded via xdg config file.
    # This is necessary as Vim provides a native syntax which would be loaded before the one defined here.
    # See: https://github.com/NixOS/nixpkgs/commit/cda1f8ae46869c429971323717d622d5b17d9854 where runtimepath is not set.

    # Adding features

    rg
    diff-fold
    BufOnly-vim

    {
      plugin = vim-snipmate;
      # I didn't migrate snippets to new format, yet.
      config = ''
        let g:snipMate = { 'snippet_version' : 0 }
      '';
    }

    fugitive

    vim-commentary
    vim-indent-object
    vim-textobj-comment

    {
      plugin = vdebug;
      config = builtins.readFile(./neovim/plugins/vdebug.vim);
    }

    {
      # Seems to be broken: https://github.com/kassio/neoterm/issues/338
      # Therefore I install my own version where this bug is disabled
      plugin = neoterm;
      config = builtins.readFile(./neovim/plugins/neoterm.vim);
    }

    {
      plugin = phpactor;
      config = ''
        " Make empty, as we have a full blown wrapper thanks to nix.
        " Adding a php in front would interpret the wrapper via PHP.
        let g:phpactorPhpBin = ""
        let g:phpactorOmniError = v:true
      '';
    }

    # LSP (=Language Server Protocol)

    # I remove diagnostics as I use ale instead.
    # Maybe some day I need both or use lsp for some languages, docs:
    # - https://neovim.io/doc/user/diagnostic.html#diagnostic-api
    # - https://github.com/neovim/nvim-lspconfig/issues/662
    # Add nix: https://discourse.nixos.org/t/nixd-1-1-0-released/29416
    {
      plugin = nvim-lspconfig;
      type = "lua";
      config = ''
        vim.diagnostic.config({
          virtual_text = true,
          underline = false,
        })

        require('lspconfig').phpactor.setup({
          cmd = {
            '${pkgs.phpactor}/bin/phpactor',
            'language-server',
          },
        })
      '';
    }

    {
      plugin = lsp_signature-nvim;
      type = "lua";
      config = builtins.readFile(./neovim/plugins/lsp-signature.lua);
    }

    # Tree Sitter (Syntax, Parsing, …)

    {
      plugin = pkgs.vimPlugins.nvim-treesitter.withPlugins (p: with p; [
          bash
          dockerfile
          html
          javascript
          json
          lua
          markdown
          nix
          php
          phpdoc
          rst
          scss
          css
          sql
          typescript
          vim
          vimdoc
          yaml
      ]);
      type = "lua";
      config = builtins.readFile(./neovim/plugins/treesitter.lua);
    }

    {
      # Used to inspect node types to extend colorscheme
      # Installed for ":TSHighlightCapturesUnderCursor"
      plugin = playground;
      type = "lua";
      config = ''
        require("nvim-treesitter.configs").setup({
          playground = {
            enable = true,
          },
        })
      '';
    }


    # More related to testing, linting, …

    {
      plugin = ale;
      config = builtins.readFile(./neovim/plugins/ale.vim)
        # Keep line break as fileContents strips last EOL
        + ''

          let g:ale_yaml_yamllint_executable = '${pkgs.yamllint}/bin/yamllint'
          let g:ale_xml_xmllint_executable = '${pkgs.libxml2}/bin/xmllint'
          let g:ale_gitcommit_gitlint_executable = '${pkgs.gitlint}/bin/gitlint'
          let g:ale_nix_statix_check_executable = '${pkgs.statix}/bin/statix'
          let g:ale_languagetool_executable = '${pkgs.languagetool}/bin/languagetool-commandline'
          let g:ale_sh_shellcheck_executable = '${pkgs.shellcheck}/bin/shellcheck'
        '';
    }

    {
      plugin = test;
      config = builtins.readFile(./neovim/plugins/test.vim);
    }

    # Presentations
    presenting-vim
    goyo-vim

    # Dependencies for other plugins

    vim-addon-mw-utils
    vim-textobj-user
    plenary-nvim
  ];
}
