Commit a164ebdd authored by Derek Willian Stavis's avatar Derek Willian Stavis

init: rewrite init process (#260)

* 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).

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.

* omf: migrate to new init hook

* omf/templates: migrate to new init and uninstall hooks

* docs: document new init and uninstall hooks interface

* README: update new hook interface spec
parent 17de8c4b
......@@ -62,7 +62,7 @@ Apply a theme. To list available themes, type `omf theme`. You can also [preview
Remove a theme or package.
> Packages subscribed to `uninstall_<pkg>` events are notified before the package is removed, so custom cleanup of resources can be done. See [Uninstall](/docs/en-US/Packages.md#uninstall) for more information.
> Packages can use uninstall hooks, so custom cleanup of resources can be done when uninstalling it. See [Uninstall](/docs/en-US/Packages.md#uninstall) for more information.
#### `omf reload`
......@@ -125,7 +125,7 @@ Every time a package/theme is installed or removed, the `bundle` file is updated
## Creating Packages
Oh My Fish uses an advanced and well defined plugin architecture to ease plugin development, including init/uninstall events and function autoloading. [See the documentation](docs/en-US/Packages.md) for more details.
Oh My Fish uses an advanced and well defined plugin architecture to ease plugin development, including init/uninstall hooks, function and completion autoloading. [See the packages documentation](docs/en-US/Packages.md) for more details.
[fishshell]: http://fishshell.com
......
......@@ -53,24 +53,27 @@ Packages were designed to take advantages of fish events. There are currently tw
## Initialization
If you want to be [notified](http://fishshell.com/docs/current/commands.html#emit) when your package loads, declare the following function in your `hello_world.fish`:
If you want code to be executed when the package loads, you can add code to `init.fish` file at package's root directory:
```fish
function init -a path --on-event init_hello_world
echo "hello_world initialized"
end
echo "hello_world initialized"
```
Use this event to modify the environment, load resources, autoload functions, etc. If your package does not export any functions, you can still use this event to add functionality to your package.
Inside this hook runs you can access three package-related variables:
* `$package`: Package name
* `$path`: Package installation path
* `$dependencies` : Package dependencies
Use this hook to modify the environment, load resources, autoload functions, etc. If your package does not export any function, you can still use this event to add functionality to your package, or dynamically create functions.
## Uninstall
Oh My Fish emits `uninstall_<pkg>` events before a package is removed via `omf remove <pkg>`. Subscribers can use the event to clean up custom resources, etc.
Oh My Fish also features `uninstall.fish` hook, which is called before a package is removed via `omf remove <pkg>`. Packages can use this hook to clean up custom resources, etc.
```fish
function uninstall --on-event uninstall_hello_world
end
```
Inside this hook you can access one package-related variable:
* `$path`: Package installation path
# Make it public
......
......@@ -54,24 +54,26 @@ end
## 初始化
如果你想在插件被加载时收到[通知](http://fishshell.com/docs/current/commands.html#emit),你可以在 `hello_world.fish` 添加下面的代码:
如果要执行的代码包时加载,可以为`init.fish`文件在包的根目录下添加代码:
```fish
function init -a path --on-event init_hello_world
echo "hello_world initialized"
end
echo "hello_world initialized"
```
该事件可以用于修改环境变量、加载资源和自动加载函数等。如果你的插件没有输出任何的函数,你仍然可以使用该事件加载其他的函数。
这里面挂机运行,您可以访问包相关的变量:
* `$package`:包名称
* `$path`:软件包的安装路径
* `$dependencies`:软件包依赖
使用这个钩子来修改环境,资源负载,自动加载的功能,等等。如果你的包不出口任何功能,您仍可以使用此事件将功能添加到您的包,还是动态创建功能。
## 卸载
Oh My Fish 通过 `omf remove <pkg>` 移除已安装的插件前会发送 `uninstall_<pkg>` 事件。订阅者可以使用该事件清理自定义的资源等操作
哦,我的鱼还设有`uninstall.fish`挂钩,通过 `omf remove <pkg>`被删除软件包之前被调用。包可以使用这个钩子清理自定义的资源,等等
```fish
function uninstall --on-event uninstall_hello_world
end
```
本书中,你可以访问一个包相关的变量:
* `$path`:软件包的安装路径
# 发布插件
......
......@@ -56,8 +56,7 @@ Oh My Fish 自带的辅助命令工具 `omf` 可以帮助你快速获取安装
移除主题或插件。
> 插件如果注册(subscribed)过 `uninstall_<pkg>` 事件将会在插件移除前触发,因此你可以自定义自身清理和扫尾的工作以保证插件干净移除。
详见[卸载部分](Packages.md#uninstall)获取更多信息。
> 包可以使用卸载挂钩,所以资源的自定义清理可以做到卸载时。有关更多信息,请参见 [卸载](Packages.md#uninstall) 。
#### `omf new pkg | theme` _`<name>`_
......
# 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
test -f $OMF_CONFIG/before.init.fish
and source $OMF_CONFIG/before.init.fish ^/dev/null
emit perf:timer:start "Oh My Fish initialisation"
# Read current theme
read -l theme < $OMF_CONFIG/theme
# Prepare Oh My Fish paths
set -l core_function_path $OMF_PATH/lib{,/git}
set -l theme_function_path {$OMF_CONFIG,$OMF_PATH}/themes*/$theme{,/functions}
# Autoload core library
set fish_function_path $fish_function_path[1] \
$core_function_path \
$theme_function_path \
$fish_function_path[2..-1]
# Require all packages
emit perf:timer:start "Oh My Fish init installed packages"
require --path {$OMF_PATH,$OMF_CONFIG}/pkg/*
emit perf:timer:finish "Oh My Fish init installed packages"
# 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 existent
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 existent
functions -q __original_fish_user_key_bindings
and __original_fish_user_key_bindings
end
# Autoload theme
autoload {$OMF_PATH,$OMF_CONFIG}/themes/(cat $OMF_CONFIG/theme)
# Autoload custom functions
autoload $OMF_CONFIG/functions
autoload $user_function_path
# Source custom init.fish file
source $OMF_CONFIG/init.fish ^/dev/null
set -g OMF_VERSION "2"
emit perf:timer:start "Oh My Fish init user config path"
require --no-bundle --path $OMF_CONFIG
emit perf:timer:finish "Oh My Fish init user config path"
set -g OMF_VERSION "1.1.0-dev"
emit perf:timer:finish "Oh My Fish initialisation"
# 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 -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 path in {$OMF_PATH,$OMF_CONFIG}/pkg/$name
test -d $path; or continue
if autoload $path $path/functions $path/completions
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
function require
set packages $argv
source $path/init.fish ^/dev/null;
or source $path/$name.fish ^/dev/null;
and emit init_$name $path
end
if test -z "$packages"
echo 'usage: require <name>...'
echo ' require --path <path>...'
echo ' require --no-bundle --path <path>...'
return 1
end
# If bundle should be
if set index (contains -i -- --no-bundle $packages)
set -e packages[$index]
set ignore_bundle
end
functions -e init # Cleanup previously sourced function
# Requiring absolute paths
if set index (contains -i -- --path $packages)
set -e packages[$index]
set package_path $packages
# Requiring specific packages from default paths
else
set package_path {$OMF_PATH,$OMF_CONFIG}/pkg*/$packages
# Exit with error if no package paths were generated
test -z "$package_path"
and return 1
end
set function_path $package_path/functions*
set completion_path $package_path/completions*
set init_path $package_path/init.fish*
# Autoload functions
test -n "$function_path"
and set fish_function_path $fish_function_path[1] \
$function_path \
$fish_function_path[2..-1]
# Autoload completions
test -n "$complete_path"
and set fish_complete_path $fish_complete_path[1] \
$complete_path \
$fish_complete_path[2..-1]
for init in $init_path
emit perf:timer:start $init
set -l IFS '/'
echo $init | read -la components
set path (printf '/%s' $components[1..-2])
contains $path $omf_init_path
and continue
set package $components[-2]
if not set -q ignore_bundle
set bundle $path/bundle
set dependencies
if test -f $bundle
set -l IFS ' '
while read -l type dependency
test "$type" != package
and continue
require "$dependency"
set dependencies $dependencies $dependency
end < $bundle
end
end
source $init $path
emit init_$package $path
set -g omf_init_path $omf_init_path $path
emit perf:timer:finish $init
end
return 0
end
function init -a path --on-event init_omf
set -g OMF_MISSING_ARG 1
set -g OMF_UNKNOWN_OPT 2
set -g OMF_INVALID_ARG 3
set -g OMF_UNKNOWN_ERR 4
set -g OMF_MISSING_ARG 1
set -g OMF_UNKNOWN_OPT 2
set -g OMF_INVALID_ARG 3
set -g OMF_UNKNOWN_ERR 4
function omf::em
set_color $fish_color_match ^/dev/null; or set_color cyan
end
function omf::dim
set_color $fish_color_autosuggestion ^/dev/null; or set_color 555
end
function omf::em
set_color $fish_color_match ^/dev/null; or set_color cyan
end
function omf::err
set_color $fish_color_error ^/dev/null; or set_color red --bold
end
function omf::dim
set_color $fish_color_autosuggestion ^/dev/null; or set_color 555
end
function omf::under
set_color --underline
end
function omf::err
set_color $fish_color_error ^/dev/null; or set_color red --bold
end
function omf::off
set_color normal
end
function omf::under
set_color --underline
end
autoload $path/functions/{compat,core,packages,themes,bundle,util,repo,cli,search}
function omf::off
set_color normal
end
autoload $path/functions/{compat,core,packages,themes,bundle,util,repo,cli}
# See → fishshell.com/docs/current/commands.html#complete
# Always provide completions for command line utilities.
#
# Check Fish documentation about completions:
# http://fishshell.com/docs/current/commands.html#complete
#
# If your package doesn't provide any command line utility,
# feel free to remove completions directory from the project.
\ No newline at end of file
# SYNOPSIS
# {{NAME}} [options]
#
# USAGE
# Options
#
function {{NAME}} -d "My package"
# Package entry-point
end
function init -a path --on-event init_{{NAME}}
end
# {{NAME}} initialization hook
#
# You can use the following variables in this file:
# * $package package name
# * $path package path
# * $dependencies package dependencies
function uninstall --on-event uninstall_{{NAME}}
end
# {{NAME}} uninstall hook
#
# You can use this file to do custom cleanup when the package is uninstalled.
# You can use the variable $path to access the package path.
# Set global color styles, for example:
#
# function {{NAME}}_error
# set_color -o red
# end
#
# function {{NAME}}_normal
# set_color normal
#
function fish_greeting
# Customize fish greeting message
end
function fish_prompt
set -l code $status
prompt_pwd
# Customize fish prompt
end
function fish_right_prompt
set -l code $status
# Customize the right prompt
end
function fish_title
# Customize the title bar of the terminal window.
# Customize terminal window title
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment