From 7e08d4ac1d10e47e0ca4720c993cef4aaf9e4a0a Mon Sep 17 00:00:00 2001
From: Derek Stavis <dekestavis@gmail.com>
Date: Fri, 5 Feb 2016 00:35:43 -0200
Subject: [PATCH] init: rewrite init process

Now use pure globbing to generate 100% valid function and
completion paths, effectively splitting the init process in two
steps, one which paths are added, and other when initialization
is done (sourcing init).

Package initialization code is done in a new function called
`initialize`, which takes care of the dependencies, ensuring
proper `init.fish` call order and handling compatibility.

This initialization code introduces a new interface for
`init.fish` hook, which deprecates the previously used event
model. The new interface injects three variables into `init.fish`:
path, package and bundle. This variables can be used by the
package to autoload paths, use bundled files, etc.

Also supports key bindings by sourcing
$OMF_CONFIG/key_bindings.fish and also key_bindings.fish in
packages (plugins and themes) root directories. This is done
when fish_user_key_bindings is called.
---
 init.fish           | 79 +++++++++++++++++++--------------------------
 lib/initialize.fish | 22 +++++++++++++
 lib/require.fish    | 53 +++++++++++++-----------------
 3 files changed, 77 insertions(+), 77 deletions(-)
 create mode 100644 lib/initialize.fish

diff --git a/init.fish b/init.fish
index 82cfc65..026ac06 100644
--- a/init.fish
+++ b/init.fish
@@ -1,55 +1,42 @@
-# SYNOPSIS
-#   Initialize Oh My Fish.
-#
-# OVERVIEW
-#   + Source $OMF_CONFIG/before.init.fish
-#
-#   + Autoload Oh My Fish packages, themes and config path
-#   + For each <pkg> inside {$OMF_PATH,$OMF_CONFIG}
-#     + Autoload <pkg> directory
-#     + Source <pkg>.fish
-#     + Emit init_<pkg> event
-#
-#   + Autoload {$OMF_PATH,$OMF_CONFIG}/functions
-#   + Source $OMF_CONFIG/init.fish
-#
-# ENV
-#   OMF_PATH      ~/.local/share/omf by default.
-#   OMF_IGNORE    List of packages to ignore.
-#   OMF_CONFIG    ~/.config/omf by default.
-#   OMF_VERSION   Oh My Fish! version
-
 # Set OMF_CONFIG if not set.
 if not set -q OMF_CONFIG
   set -q XDG_CONFIG_HOME; or set -l XDG_CONFIG_HOME "$HOME/.config"
   set -gx OMF_CONFIG "$XDG_CONFIG_HOME/omf"
 end
-
 # Source custom before.init.fish file
 source $OMF_CONFIG/before.init.fish ^/dev/null
-
-# Save the head of function path and autoload core functions
-set -l user_function_path $fish_function_path[1]
-set fish_function_path[1] $OMF_PATH/lib
-
-# Autoload util functions
-autoload $OMF_PATH/lib $OMF_PATH/lib/git
-
-for path in {$OMF_PATH,$OMF_CONFIG}/pkg/*
-  set -l name (basename $path)
-
-  contains -- $name $OMF_IGNORE; and continue
-  require $name
-end
-
-# Autoload theme
-autoload {$OMF_PATH,$OMF_CONFIG}/themes/(cat $OMF_CONFIG/theme)
-
-# Autoload custom functions
-autoload $OMF_CONFIG/functions
-autoload $user_function_path
-
+# Read current theme
+read -l theme < $OMF_CONFIG/theme
+# Prepare Oh My Fish paths
+set -l omf_function_path $OMF_PATH/{lib/{,git}}
+set -l omf_package_function_path {$OMF_CONFIG,$OMF_PATH}/{themes*/$theme/{,functions},pkg/*/{,functions},functions*}
+set -l omf_package_complete_path {$OMF_CONFIG,$OMF_PATH}/{themes*/$theme/completions,pkg/*/completions}
+# Autoload functions
+set fish_function_path $fish_function_path[1] \
+                       $omf_package_function_path \
+                       $omf_function_path \
+                       $fish_function_path[2..-1]
+# Autoload completions
+set fish_complete_path $fish_complete_path[1] \
+                       $omf_package_complete_path \
+                       $fish_complete_path[2..-1]
+# Do package initialization
+initialize {$OMF_CONFIG,$OMF_PATH}/{pkg,theme}/*/init.fish
 # Source custom init.fish file
 source $OMF_CONFIG/init.fish ^/dev/null
-
-set -g OMF_VERSION "1.0.0"
+# Backup key bindings
+functions -q fish_user_key_bindings
+  and functions -c fish_user_key_bindings __original_fish_user_key_bindings
+# Override key bindings, calling original if existant
+function fish_user_key_bindings
+  # Read packages key bindings
+  for file in {$OMF_CONFIG,$OMF_PATH}/{pkg,theme}/*/key_bindings.fish
+    source $file
+  end
+  # Read custom key bindings file
+  source $OMF_CONFIG/key_bindings.fish ^/dev/null
+  # Call original key bindings if existant
+  functions -q __original_fish_user_key_bindings
+    and __original_fish_user_key_bindings
+end
+set -g OMF_VERSION "1.1.0-dev"
diff --git a/lib/initialize.fish b/lib/initialize.fish
new file mode 100644
index 0000000..0e7fa36
--- /dev/null
+++ b/lib/initialize.fish
@@ -0,0 +1,22 @@
+function initialize -d "Initialize a package"
+  for init in $argv
+    set -l IFS '/'
+    echo $init | read -la components
+
+    set package $components[-2]
+    set path (printf '/%s' $components[1..-2])
+    set bundle $path/bundle
+
+    if test -f $bundle
+      while read -l type dependency
+        test "$type" = package
+          and require "$dependency"
+      end < $bundle
+    end
+
+    source $init $path
+    emit init_$package $path
+
+    set -g omf_packages_loaded $omf_packages_loaded $package
+  end
+end
diff --git a/lib/require.fish b/lib/require.fish
index db7c959..21a99e6 100644
--- a/lib/require.fish
+++ b/lib/require.fish
@@ -1,41 +1,32 @@
-# SYNOPSIS
-#   require [name]
-#
-# OVERVIEW
-#   Require a plugin:
-#     - Autoload its functions and completions.
-#     - Require bundle dependencies.
-#     - Source its initialization file.
-#     - Emit its initialization event.
-#
-#   If the required plugin has already been loaded, does nothing.
+function require
+  set packages $argv
 
-function require -a name
   # Skip if plugin has already been loaded.
-  contains -- $OMF_PATH/pkg/$name $fish_function_path;
-    or contains -- $OMF_CONFIG/pkg/$name $fish_function_path;
-    and return 0
+  for package in $packages
+    if contains -- $package $omf_packages_loaded
+      set index (contains -i -- $package $packages)
+      set -e packages[$index]
+    end
+  end
 
-  for path in {$OMF_PATH,$OMF_CONFIG}/pkg/$name
-    test -d $path; or continue
+  set function_path {$OMF_PATH,$OMF_CONFIG}/pkg*/$packages{,/functions}
+  set completion_path {$OMF_PATH,$OMF_CONFIG}/pkg*/$packages/completions
 
-    if autoload $path $path/functions $path/completions
+  # Autoload functions
+  test "$function_path"
+    and set fish_function_path $fish_function_path[1] \
+                               $function_path \
+                               $fish_function_path[2..-1]
 
-      if test -f $path/bundle
-        for line in (cat $path/bundle)
-          test (echo $line | cut -d' ' -f1) = package;
-            and set dependency (basename (echo $line | cut -d' ' -f2));
-              and require $dependency
-        end
-      end
+  # Autoload completions
+  test "$complete_path"
+    and set fish_complete_path $fish_complete_path[1] \
+                               $complete_path \
+                               $fish_complete_path[2..-1]
 
-      source $path/init.fish ^/dev/null;
-        or source $path/$name.fish ^/dev/null;
-        and emit init_$name $path
-    end
-  end
+  initialize {$OMF_CONFIG,$OMF_PATH}/pkg*/$packages/init.fish
 
-  functions -e init  # Cleanup previously sourced function
+  set -g omf_packages_loaded $packages $omf_packages_loaded
 
   return 0
 end
-- 
GitLab