{ lib, stdenv, callPackage, vimUtils, buildEnv, makeWrapper }:

let
  makeCustomizable = macvim: macvim // {
    # configure expects the same args as vimUtils.vimrcFile.
    # This is the same as the value given to neovim.override { configure = … }
    # or the value of vim-full.customize { vimrcConfig = … }
    #
    # Note: Like neovim and vim-full, configuring macvim disables the
    # sourcing of the user's vimrc. Use `customRC = "source $HOME/.vim/vimrc"`
    # if you want to preserve that behavior.
    configure = let
      doConfig = config: let
        vimrcConfig = config // {
          # always source the bundled system vimrc
          beforePlugins = ''
            source $VIM/vimrc
            ${config.beforePlugins or ""}
          '';
        };
      in buildEnv {
        name = macvim.name;
        paths = [ macvim ];
        pathsToLink = [
          "/"
          "/bin"
          "/Applications/MacVim.app/Contents/MacOS"
          "/Applications/MacVim.app/Contents/bin"
        ];
        nativeBuildInputs = [ makeWrapper ];
        # We need to do surgery on the resulting app. We can't just make a wrapper for vim because this
        # is a GUI app. We need to copy the actual GUI executable image as AppKit uses the loaded image's
        # path to locate the bundle. We can use symlinks for other executables and resources though.
        postBuild = ''
          # Replace the Contents/MacOS/MacVim symlink with the original file
          target=$(readlink $out/Applications/MacVim.app/Contents/MacOS/MacVim)
          rm $out/Applications/MacVim.app/Contents/MacOS/MacVim
          cp -a -t $out/Applications/MacVim.app/Contents/MacOS "$target"

          # Wrap the Vim binary for our vimrc
          wrapProgram $out/Applications/MacVim.app/Contents/MacOS/Vim \
            --add-flags "-u ${vimUtils.vimrcFile vimrcConfig}"

          # Replace each symlink in bin/ with the original. Most of them point at other symlinks
          # and we need those original symlinks to point into our new app bundle.
          for prefix in bin Applications/MacVim.app/Contents/bin; do
            for link in $out/$prefix/*; do
              target=$(readlink "$link")
              # don't copy binaries like vimtutor, but we do need mvim
              [ -L "$target" ] || [ "$(basename "$target")" = mvim ] || continue;
              rm "$link"
              cp -a -t $out/$prefix "$target"
            done
          done
        '';
        meta = macvim.meta;
      };
    in lib.makeOverridable (lib.setFunctionArgs doConfig (lib.functionArgs vimUtils.vimrcFile));

    override = f: makeCustomizable (macvim.override f);
    overrideAttrs = f: makeCustomizable (macvim.overrideAttrs f);
  };
in { inherit makeCustomizable; }
