From 550389392a54a81e750aabb54b69a77c9e5d18af Mon Sep 17 00:00:00 2001 From: Daniel Gorin Date: Mon, 29 Jun 2020 21:25:16 +0100 Subject: [PATCH 1/2] kakoune: rework plugin support The previous implementation of plugin-support for the kakoune derivation was based on generating, at build time, a `plugins.kak` file that would source all .kak files in the list of plugins, and wrap the `kak` binary in a script that would add some command-line arguments so that this file gets loaded on start-up. The main problem with this approach is that the plugins' code get executed *after* the user's configuration file is loaded, so effectively one cannot automatically activate/configure these plugins. The idiomatic way of loading plugins is ensuring they end up installed somwhere under `share/kak/autoload`. Because plugins are already being packaged to have their code in `share/kak/autoload/plugins/`, we can obtain a derivation that includes the plugins simply by doing a `symlinkJoin` of `kakoune-unwrapped` and all the requested plugins. For this to work, we need to fix two issues: 1. By default, kakoune makes `share/kak/autoload` a symbolic link to `share/kak/rc`, which contains all builtin definitions. We need to patch this to put the symlink under `share/kak/autoload/rc`, so that the join works. 2. By default kakoune expects the `autoload` directory to be in `../share/kak/autoload` relative to the location of the `kak` binary. We need to set the `KAKOUNE_RUNTIME` to point the symlinked share/kak for this to work. --- doc/builders/packages/kakoune.xml | 4 +- pkgs/applications/editors/kakoune/default.nix | 9 ++++ pkgs/applications/editors/kakoune/wrapper.nix | 54 ++++++------------- pkgs/applications/editors/kakoune/wrapper.sh | 30 ----------- pkgs/top-level/all-packages.nix | 6 ++- 5 files changed, 31 insertions(+), 72 deletions(-) delete mode 100644 pkgs/applications/editors/kakoune/wrapper.sh diff --git a/doc/builders/packages/kakoune.xml b/doc/builders/packages/kakoune.xml index 728d40dacc9..045dbd0a653 100644 --- a/doc/builders/packages/kakoune.xml +++ b/doc/builders/packages/kakoune.xml @@ -6,9 +6,7 @@ Kakoune can be built to autoload plugins: (kakoune.override { - configure = { - plugins = with pkgs.kakounePlugins; [ parinfer-rust ]; - }; + plugins = with pkgs.kakounePlugins; [ parinfer-rust ]; }) diff --git a/pkgs/applications/editors/kakoune/default.nix b/pkgs/applications/editors/kakoune/default.nix index eec14f286ba..f1f81106659 100644 --- a/pkgs/applications/editors/kakoune/default.nix +++ b/pkgs/applications/editors/kakoune/default.nix @@ -30,6 +30,15 @@ stdenv.mkDerivation rec { $out/bin/kak -ui json -E "kill 0" ''; + postInstall = '' + # make share/kak/autoload a directory, so we can use symlinkJoin with plugins + cd "$out/share/kak" + autoload_target=$(readlink autoload) + rm autoload + mkdir autoload + ln -s --relative "$autoload_target" autoload + ''; + meta = { homepage = "http://kakoune.org/"; description = "A vim inspired text editor"; diff --git a/pkgs/applications/editors/kakoune/wrapper.nix b/pkgs/applications/editors/kakoune/wrapper.nix index b4cc823880e..6d6e23f1dac 100644 --- a/pkgs/applications/editors/kakoune/wrapper.nix +++ b/pkgs/applications/editors/kakoune/wrapper.nix @@ -1,44 +1,24 @@ -{ stdenv, bash }: -with stdenv.lib; - -kakoune: +{ symlinkJoin, makeWrapper, kakoune, plugins ? [], configure ? {} }: let - getPlugins = { plugins ? [] }: plugins; + # "plugins" is the preferred way, but some configurations may be + # using "configure.plugins", so accept both + requestedPlugins = plugins ++ (configure.plugins or []); - wrapper = { configure ? {} }: - stdenv.mkDerivation rec { - pname = "kakoune"; - version = getVersion kakoune; +in + symlinkJoin { + name = "kakoune-${kakoune.version}"; - src = ./.; - buildCommand = '' - mkdir -p $out/share/kak - for plugin in ${strings.escapeShellArgs (getPlugins configure)}; do - if [[ -d $plugin/share/kak/autoload ]]; then - find "$plugin/share/kak/autoload" -type f -name '*.kak'| while read rcfile; do - printf 'source "%s"\n' "$rcfile" - done - fi - done >>$out/share/kak/plugins.kak + buildInputs = [ makeWrapper ]; - mkdir -p $out/bin - substitute ${src}/wrapper.sh $out/bin/kak \ - --subst-var-by bash "${bash}" \ - --subst-var-by kakoune "${kakoune}" \ - --subst-var-by out "$out" - chmod +x $out/bin/kak + paths = [ kakoune ] ++ requestedPlugins; + + postBuild = '' + # location of kak binary is used to find ../share/kak/autoload, + # unless explicitly overriden with KAKOUNE_RUNTIME + rm "$out/bin/kak" + makeWrapper "${kakoune}/bin/kak" "$out/bin/kak" --set KAKOUNE_RUNTIME "$out/share/kak" ''; - preferLocalBuild = true; - buildInputs = [ bash kakoune ]; - passthru = { unwrapped = kakoune; }; - - meta = kakoune.meta // { - # prefer wrapper over the package - priority = (kakoune.meta.priority or 0) - 1; - hydraPlatforms = []; - }; - }; -in - makeOverridable wrapper + meta = kakoune.meta // { priority = (kakoune.meta.priority or 0) - 1; }; + } diff --git a/pkgs/applications/editors/kakoune/wrapper.sh b/pkgs/applications/editors/kakoune/wrapper.sh deleted file mode 100644 index 48a971a10c6..00000000000 --- a/pkgs/applications/editors/kakoune/wrapper.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!@bash@/bin/bash - -# We use the -E option to load plugins. This only makes sense when we are -# starting a new session, so we detect that. Also, Kakoune can only handle -# one -E option, so we prepend loading plugins to an existing one. -args=( "$@" ) -loadPlugins=true -EValueOffset=-1 -pluginScript='@out@/share/kak/plugins.kak' - -for (( i = 0; i < ${#args[@]}; i++ )); do - case "${args[i]}" in - -n|-c|-l|-p|-clear|-version) loadPlugins=false;; - -E) EValueOffset=$(( i + 1 ));; - --) break;; - esac - case "${args[i]}" in - -E|-c|-e|-s|-p|-f|-i|-ui|-debug) i=$(( i + 1 ));; - esac -done - -if [[ $loadPlugins = true ]]; then - if (( EValueOffset >= 0 )); then - args[EValueOffset]="source '$pluginScript'"$'\n'"${args[EValueOffset]}" - else - args=( "-E" "source '$pluginScript'" "${args[@]}" ) - fi -fi - -exec @kakoune@/bin/kak "${args[@]}" diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 4226f35c7fa..eba6da07d07 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -4905,10 +4905,12 @@ in kalibrate-hackrf = callPackage ../applications/radio/kalibrate-hackrf { }; - wrapKakoune = callPackage ../applications/editors/kakoune/wrapper.nix { }; + wrapKakoune = kakoune: attrs: callPackage ../applications/editors/kakoune/wrapper.nix (attrs // { inherit kakoune; }); kakounePlugins = callPackage ../applications/editors/kakoune/plugins { }; kakoune-unwrapped = callPackage ../applications/editors/kakoune { }; - kakoune = wrapKakoune kakoune-unwrapped { }; + kakoune = wrapKakoune kakoune-unwrapped { + plugins = [ ]; # override with the list of desired plugins + }; kak-lsp = callPackage ../tools/misc/kak-lsp { }; From 464804b43f6e414d4a6eadcf220a43040640cc34 Mon Sep 17 00:00:00 2001 From: Daniel Gorin Date: Sun, 18 Oct 2020 16:19:09 +0100 Subject: [PATCH 2/2] kakoune: Fix :doc when using plugins So, kakoune takes the documentation shown for `:doc` from `$KAKOUNE_RUNTIME/share/kak/doc`. Unfortunately, it seems that it will ignore files that are symlinks. This is arguably a bug in kakoune, we workaround it for now by copying the content of the docfiles. --- pkgs/applications/editors/kakoune/wrapper.nix | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pkgs/applications/editors/kakoune/wrapper.nix b/pkgs/applications/editors/kakoune/wrapper.nix index 6d6e23f1dac..7ac56d9cb1e 100644 --- a/pkgs/applications/editors/kakoune/wrapper.nix +++ b/pkgs/applications/editors/kakoune/wrapper.nix @@ -18,6 +18,13 @@ in # unless explicitly overriden with KAKOUNE_RUNTIME rm "$out/bin/kak" makeWrapper "${kakoune}/bin/kak" "$out/bin/kak" --set KAKOUNE_RUNTIME "$out/share/kak" + + # currently kakoune ignores doc files if they are symlinks, so workaround by + # copying doc files over, so they become regular files... + mkdir "$out/DELETE_ME" + mv "$out/share/kak/doc" "$out/DELETE_ME" + cp -r --dereference "$out/DELETE_ME/doc" "$out/share/kak" + rm -Rf "$out/DELETE_ME" ''; meta = kakoune.meta // { priority = (kakoune.meta.priority or 0) - 1; };