From 72e3217bf1d0fa9be9d85659816926afd8482352 Mon Sep 17 00:00:00 2001
From: Lily Ballard <lily@sb.org>
Date: Thu, 23 Jul 2020 18:01:13 -0700
Subject: [PATCH] macvim: add configuration similar to vim_configurable and
 neovim

vim_configurable and neovim have both supported a mechanism to build
them with a custom vimrc that supports plugins from Nix. This updates
MacVim to support the same sort of configuration using an expression
like

  macvim.configure {
    customRC = ''
      # custom configuration goes here
    '';
    packages.myVimPackage = with pkgs.vimPlugins; {
      start = [ youcompleteme fugitive ];
      opt = [ phpCompletion elm-vim ];
    }
  }

Once configured, .override will allow for editing the configuration.

Like vim_configurable and neovim, configuring macvim does not require
rebuilding it. Also like them, configuring macvim turns off the user
vimrc file.
---
 .../editors/vim/macvim-configurable.nix       | 67 +++++++++++++++++++
 pkgs/top-level/all-packages.nix               |  2 +-
 2 files changed, 68 insertions(+), 1 deletion(-)
 create mode 100644 pkgs/applications/editors/vim/macvim-configurable.nix

diff --git a/pkgs/applications/editors/vim/macvim-configurable.nix b/pkgs/applications/editors/vim/macvim-configurable.nix
new file mode 100644
index 000000000000..087a375c50cc
--- /dev/null
+++ b/pkgs/applications/editors/vim/macvim-configurable.nix
@@ -0,0 +1,67 @@
+{ stdenv, callPackage, vimUtils, buildEnv, makeWrapper }:
+
+let
+  macvim = callPackage ./macvim.nix { inherit stdenv; };
+
+  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_configurable.customize { vimrcConfig = … }
+    #
+    # Note: Like neovim and vim_configurable, 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
+      inherit (stdenv) lib;
+      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"
+        ];
+        buildInputs = [ 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
+  makeCustomizable macvim
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 20090f0f299a..d572a3c8bbb3 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -23812,7 +23812,7 @@ in
 
   vimiv = callPackage ../applications/graphics/vimiv { };
 
-  macvim = callPackage ../applications/editors/vim/macvim.nix { stdenv = clangStdenv; };
+  macvim = callPackage ../applications/editors/vim/macvim-configurable.nix { stdenv = clangStdenv; };
 
   vimHugeX = vim_configurable;