mirror of
https://github.com/keanuplayz/dotfiles.git
synced 2024-08-15 02:33:12 +00:00
[zsh] reinvent the wheel yet again by creating a plugin manager
This commit is contained in:
parent
d7d3fb6b08
commit
ff92a1ab7a
3 changed files with 541 additions and 31 deletions
|
@ -1,31 +1,54 @@
|
||||||
#!/usr/bin/env zsh
|
#!/usr/bin/env zsh
|
||||||
|
|
||||||
configure_oh_my_zsh() {
|
# https://github.com/zdharma/zplugin/blob/master/doc/mod-install.sh
|
||||||
# disable automatic updates because OMZ is managed by zgen
|
# https://github.com/zdharma/zplugin/blob/master/zmodules/Src/Makefile.in
|
||||||
DISABLE_AUTO_UPDATE="true"
|
# https://github.com/zsh-users/zsh/blob/master/Etc/zsh-development-guide
|
||||||
|
|
||||||
|
source "$ZSH_DOTFILES/zplg.zsh"
|
||||||
|
|
||||||
|
plugin completions 'zsh-users/zsh-completions'
|
||||||
|
|
||||||
|
# Oh-My-Zsh {{{
|
||||||
|
|
||||||
|
# initialize the completion system
|
||||||
|
autoload -Uz compinit && compinit -C
|
||||||
|
|
||||||
|
ZSH_CACHE_DIR="$ZSH_DOTFILES/cache"
|
||||||
|
|
||||||
|
# disable automatic updates because OMZ is managed by my plugin manager
|
||||||
|
DISABLE_AUTO_UPDATE=true
|
||||||
|
|
||||||
# use hyphen-insensitive completion (makes `_` and `-` interchangeable)
|
# use hyphen-insensitive completion (makes `_` and `-` interchangeable)
|
||||||
HYPHEN_INSENSITIVE="true"
|
HYPHEN_INSENSITIVE=true
|
||||||
|
|
||||||
# enable command auto-correction
|
# enable command auto-correction
|
||||||
ENABLE_CORRECTION="true"
|
ENABLE_CORRECTION=true
|
||||||
|
|
||||||
# display red dots while waiting for completion
|
# display red dots while waiting for completion
|
||||||
COMPLETION_WAITING_DOTS="true"
|
COMPLETION_WAITING_DOTS=true
|
||||||
|
|
||||||
# disable marking untracked files under VCS as dirty (this makes repository
|
# disable marking untracked files under VCS as dirty (this makes repository
|
||||||
# status check for large repositories faster)
|
# status check for large repositories much faster)
|
||||||
DISABLE_UNTRACKED_FILES_DIRTY="true"
|
DISABLE_UNTRACKED_FILES_DIRTY=true
|
||||||
|
|
||||||
# command execution time stamp shown in the history
|
# command execution time stamp shown in the history
|
||||||
HIST_STAMPS="mm/dd/yyyy"
|
HIST_STAMPS=dd.mm.yyyy
|
||||||
}
|
|
||||||
|
|
||||||
configure_syntax_highlighting() {
|
omz_plugins=(git extract fasd)
|
||||||
FAST_WORK_DIR="$ZSH_DOTFILES/cache"
|
|
||||||
}
|
plugin oh-my-zsh 'robbyrussell/oh-my-zsh' \
|
||||||
|
load='lib/*.zsh' load='plugins/'${^omz_plugins}'/*.plugin.zsh' \
|
||||||
|
ignore='lib/(compfix|diagnostics).zsh' \
|
||||||
|
before_load='ZSH="$plugin_dir"' \
|
||||||
|
after_load='plugin-cfg-path fpath prepend completions functions' \
|
||||||
|
after_load='plugin-cfg-path fpath prepend plugins/'${^omz_plugins}
|
||||||
|
|
||||||
|
unset omz_plugins
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
# spaceship prompt {{{
|
||||||
|
|
||||||
configure_prompt() {
|
|
||||||
SPACESHIP_PROMPT_ADD_NEWLINE=false
|
SPACESHIP_PROMPT_ADD_NEWLINE=false
|
||||||
|
|
||||||
SPACESHIP_PROMPT_ORDER=(
|
SPACESHIP_PROMPT_ORDER=(
|
||||||
|
@ -56,27 +79,23 @@ configure_prompt() {
|
||||||
SPACESHIP_DIR_TRUNC_REPO=false
|
SPACESHIP_DIR_TRUNC_REPO=false
|
||||||
|
|
||||||
SPACESHIP_EXIT_CODE_SHOW=true
|
SPACESHIP_EXIT_CODE_SHOW=true
|
||||||
}
|
|
||||||
|
|
||||||
configure_oh_my_zsh
|
plugin spaceship-prompt 'denysdovhan/spaceship-prompt'
|
||||||
configure_syntax_highlighting
|
|
||||||
configure_prompt
|
|
||||||
|
|
||||||
source "$ZSH_DOTFILES/zgen/zgen.zsh"
|
# }}}
|
||||||
|
|
||||||
if ! zgen saved; then
|
plugin fzf 'junegunn/fzf' build='./install --bin' \
|
||||||
zgen oh-my-zsh
|
after_load='plugin-cfg-path path prepend bin' \
|
||||||
|
after_load='plugin-cfg-path manpath prepend man'
|
||||||
|
|
||||||
zgen oh-my-zsh plugins/git
|
plugin alias-tips 'djui/alias-tips'
|
||||||
zgen oh-my-zsh plugins/extract
|
|
||||||
zgen oh-my-zsh plugins/fasd
|
|
||||||
is_linux && zgen oh-my-zsh plugins/command-not-found
|
|
||||||
|
|
||||||
zgen load zdharma/fast-syntax-highlighting
|
plugin ssh 'zpm-zsh/ssh'
|
||||||
|
|
||||||
zgen load denysdovhan/spaceship-prompt spaceship
|
plugin base16-shell 'chriskempson/base16-shell' \
|
||||||
|
after_load='export BASE16_SHELL="$plugin_dir"'
|
||||||
|
|
||||||
zgen load chriskempson/base16-shell
|
autoload -Uz compinit && compinit -C
|
||||||
|
|
||||||
zgen save
|
FAST_WORK_DIR="$ZSH_CACHE_DIR"
|
||||||
fi
|
plugin fast-syntax-highlighting 'zdharma/fast-syntax-highlighting'
|
||||||
|
|
492
zsh/zplg.zsh
Normal file
492
zsh/zplg.zsh
Normal file
|
@ -0,0 +1,492 @@
|
||||||
|
# This... is my DIY plugin manager for Zsh. "Why did I reinvent the wheel yet
|
||||||
|
# again and created my own plugin manager?" you might ask. Well, some of them
|
||||||
|
# are too slow (antigen, zplug), some are too complicated (antigen-hs, zplugin)
|
||||||
|
# and some are too simple (zgen, antibody). So, I decided to go into into my
|
||||||
|
# cave for a couple of weeks and now, I proudly present to you MY ZSH PLUGIN
|
||||||
|
# MANAGER (ZPLG for short). It is very fast even without caching (that's why it
|
||||||
|
# isn't implemented), has the most essential features and is not bloated. The
|
||||||
|
# code is rather complex at the first glance because of two reasons:
|
||||||
|
#
|
||||||
|
# 1. The syntax of the shell language, to put it simply, utter trash designed
|
||||||
|
# 40 (!!!) years ago.
|
||||||
|
# 2. The shell language, especially when it comes to Zsh, is rather slow, so I
|
||||||
|
# had to use as less abstractions as possible.
|
||||||
|
#
|
||||||
|
# But, read my comments and they'll guide you through this jungle of shell
|
||||||
|
# script mess.
|
||||||
|
|
||||||
|
# Also:
|
||||||
|
#
|
||||||
|
# 1. This script is compatitable with SH_WORD_SPLIT (if you for whatever reason
|
||||||
|
# want to enable this), so I use "@" everywhere. This expansion modifier
|
||||||
|
# means "put all elements of the array in separate quotes".
|
||||||
|
# 2. I often use the following snippet to exit functions on errors:
|
||||||
|
# eval "$some_user_command_that_might_fail" || return "$?"
|
||||||
|
# I do this instead of `setopt localoptions errexit` because some plugins
|
||||||
|
# may not be compatitable with ERREXIT.
|
||||||
|
|
||||||
|
|
||||||
|
_ZPLG_SCRIPT_PATH="${(%):-%N}"
|
||||||
|
|
||||||
|
|
||||||
|
# $ZPLG_HOME is a directory where all your plugins are downloaded, it also
|
||||||
|
# might contain in the future some kind of state/lock/database files. It is
|
||||||
|
# recommended to change it before `source`-ing this script for compatitability
|
||||||
|
# with future versions.
|
||||||
|
if [[ -z "$ZPLG_HOME" ]]; then
|
||||||
|
ZPLG_HOME="${XDG_DATA_HOME:-$HOME/.local/share}/zplg"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Directory in which plugins are stored. It is separate from $ZPLG_HOME for
|
||||||
|
# compatitability with future versions.
|
||||||
|
_ZPLG_PLUGINS_DIR="$ZPLG_HOME/plugins"
|
||||||
|
|
||||||
|
# basic logging {{{
|
||||||
|
|
||||||
|
_ZPLG_ANSI_BOLD="$(tput bold)"
|
||||||
|
_ZPLG_ANSI_RED="$(tput setaf 1)"
|
||||||
|
_ZPLG_ANSI_GREEN="$(tput setaf 2)"
|
||||||
|
_ZPLG_ANSI_BLUE="$(tput setaf 4)"
|
||||||
|
_ZPLG_ANSI_RESET="$(tput sgr0)"
|
||||||
|
|
||||||
|
_zplg_log() {
|
||||||
|
print >&2 "${_ZPLG_ANSI_BLUE}${_ZPLG_ANSI_BOLD}[zplg]${_ZPLG_ANSI_RESET} $@"
|
||||||
|
}
|
||||||
|
|
||||||
|
_zplg_debug() {
|
||||||
|
if [[ -n "$ZPLG_DEBUG" ]]; then
|
||||||
|
_zplg_log "${_ZPLG_ANSI_GREEN}debug:${_ZPLG_ANSI_RESET} $@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_zplg_error() {
|
||||||
|
# try to find the place outside of the script that caused this error
|
||||||
|
local external_caller
|
||||||
|
local i; for (( i=1; i<=${#funcfiletrace}; i++ )); do
|
||||||
|
# $funcfiletrace contains file paths and line numbers
|
||||||
|
if [[ "${funcfiletrace[$i]}" != "$_ZPLG_SCRIPT_PATH"* ]]; then
|
||||||
|
# $functrace contains "ugly" call sites, the line numbers are
|
||||||
|
# relative to the beginning of a function/file here. I use it here
|
||||||
|
# only for consistency with the shell, TODO might change this in the
|
||||||
|
# future.
|
||||||
|
_zplg_log "${_ZPLG_ANSI_RED}error:${_ZPLG_ANSI_RESET} ${functrace[$i]}: $@"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# if for whatever reason we couldn't find the caller, simply print the
|
||||||
|
# error without it
|
||||||
|
_zplg_log "${_ZPLG_ANSI_RED}error:${_ZPLG_ANSI_RESET} $@"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
# These variables contain essential information about the currently loaded
|
||||||
|
# plugins. When I say "essential" I mean "required for upgrading,
|
||||||
|
# reinstallating and uninstalling plugins", so options for configuring loading
|
||||||
|
# behavior are not stored here.
|
||||||
|
#
|
||||||
|
# $ZPLG_LOADED_PLUGINS is an array of plugin IDs, other variables are
|
||||||
|
# associative arrays that have IDs as their keys. It is implemented this way
|
||||||
|
# because you can't put associative arrays (or any other alternative to
|
||||||
|
# "objects") into another associative array.
|
||||||
|
typeset -a ZPLG_LOADED_PLUGINS
|
||||||
|
typeset -A ZPLG_LOADED_PLUGIN_URLS ZPLG_LOADED_PLUGIN_SOURCES ZPLG_LOADED_PLUGIN_BUILD_CMDS
|
||||||
|
|
||||||
|
# Takes name of a variable with an array (array is passed by variable name
|
||||||
|
# because this reduces boilerplate) and runs every command in it, exits
|
||||||
|
# immediately with an error code if any command fails. This snippet was
|
||||||
|
# extracted in a function because it's often used to run plugin loading hooks
|
||||||
|
# (before_load/after_load) or build commands.
|
||||||
|
_zplg_run_commands() {
|
||||||
|
local var_name="$1"
|
||||||
|
# (P) modifier lets you access the variable dynamically by its name stored in
|
||||||
|
# another variable
|
||||||
|
local cmd; for cmd in "${(@P)var_name}"; do
|
||||||
|
eval "$cmd" || return "$?"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Expands a glob pattern with the NULL_GLOB flag from the first argument and
|
||||||
|
# puts all matched filenames into a variable from the second argument because
|
||||||
|
# shell functions can't return arrays. This function is needed to simplify
|
||||||
|
# handling of user-provided glob expressions because I can use LOCAL_OPTIONS
|
||||||
|
# inside a function which reverts NULL_GLOB to its previous value as soon as
|
||||||
|
# the function returns.
|
||||||
|
_zplg_expand_pattern() {
|
||||||
|
setopt localoptions nullglob
|
||||||
|
local pattern="$1" out_var_name="$2"
|
||||||
|
# ${~var_name} turns on globbing for this expansion, note lack of quotes: as
|
||||||
|
# it turns out glob expansions are automatically quoted by design, and when
|
||||||
|
# you explicitly write "${~pattern}" it is basically the same as "$pattern"
|
||||||
|
eval "$out_var_name=(\${~pattern})"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Wrapper around `source` for simpler profiling and debugging. You can override
|
||||||
|
# this function to change plugin loading strategy
|
||||||
|
_zplg_load() {
|
||||||
|
local script_path="$1"
|
||||||
|
source "$script_path"
|
||||||
|
}
|
||||||
|
|
||||||
|
# plugin sources {{{
|
||||||
|
# See documentation of the `plugin` function for description.
|
||||||
|
|
||||||
|
_zplg_source_url_download() {
|
||||||
|
local plugin_url="$1" plugin_dir="$2"
|
||||||
|
wget --timestamping --directory-prefix "$plugin_dir" -- "$plugin_url"
|
||||||
|
}
|
||||||
|
|
||||||
|
_zplg_source_url_upgrade() {
|
||||||
|
_zplg_source_url_download "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
_zplg_source_git_download() {
|
||||||
|
local plugin_url="$1" plugin_dir="$2"
|
||||||
|
git clone --depth=1 --recurse-submodules -- "$plugin_url" "$plugin_dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
_zplg_source_git_upgrade() {
|
||||||
|
local plugin_url="$1" plugin_dir="$2"
|
||||||
|
( cd "$plugin_dir" && git pull && git submodule update --init --recursive )
|
||||||
|
}
|
||||||
|
|
||||||
|
_zplg_source_github_download() {
|
||||||
|
local plugin_url="$1" plugin_dir="$2"
|
||||||
|
_zplg_source_git_download "https://github.com/$plugin_url.git" "$plugin_dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
_zplg_source_github_upgrade() {
|
||||||
|
local plugin_url="$1" plugin_dir="$2"
|
||||||
|
_zplg_source_git_upgrade "https://github.com/$plugin_url.git" "$plugin_dir"
|
||||||
|
}
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
# The main part of my plugin manager. This function does two things: it
|
||||||
|
# downloads a plugin if necessary and loads it into the shell. Usage is very
|
||||||
|
# simple:
|
||||||
|
#
|
||||||
|
# plugin <id> <url> option_a=value_a option_b=value_b ...
|
||||||
|
#
|
||||||
|
# <id>
|
||||||
|
# identifier of the plugin, alphanumeric, may contain underscores,
|
||||||
|
# hyphens and periods, mustn't start with a period.
|
||||||
|
#
|
||||||
|
# <url>
|
||||||
|
# I guess this is self-descreptive.
|
||||||
|
#
|
||||||
|
# Some options can be repeated (marked with a plus). Available options:
|
||||||
|
#
|
||||||
|
# from
|
||||||
|
# Sets plugin source. Sources are where the plugin will be downloaded from.
|
||||||
|
# Currently supported sources are:
|
||||||
|
# * git - clones a repository
|
||||||
|
# * github - clones a repository from GitHub
|
||||||
|
# * url - simply downloads a file
|
||||||
|
# Custom sources can easily be defined. Just create two functions:
|
||||||
|
# `_zplg_source_${name}_download` and `_zplg_source_${name}_upgrade`. Both
|
||||||
|
# functions take two arguments: plugin URL and plugin directory. Download
|
||||||
|
# function must, well, download a plugin from the given URL into the given
|
||||||
|
# directory, ugrade one, obviously, upgrades plugin inside of the given
|
||||||
|
# directory. Please note that neither of these functions is executed INSIDE
|
||||||
|
# of the plugin directory.
|
||||||
|
#
|
||||||
|
# build (+)
|
||||||
|
# Command which builds/compiles the plugin, executed INSIDE of $plugin_dir
|
||||||
|
# (i.e. cd $plugin_dir) once after downloading. Plugin directory can be
|
||||||
|
# accessed through the $plugin_dir variable.
|
||||||
|
#
|
||||||
|
# before_load (+) and after_load (+)
|
||||||
|
# Execute commands before and after loading of the plugin, useful when you
|
||||||
|
# need to read plugin directory which is available through the $plugin_dir
|
||||||
|
# variable.
|
||||||
|
#
|
||||||
|
# load (+) and ignore (+)
|
||||||
|
# Globs which tell what files should be sourced (load) or ignored (ignore).
|
||||||
|
# If glob expands to nothing (NULL_GLOB), nothing is loaded.
|
||||||
|
#
|
||||||
|
# Neat trick when using options: if you want to assign values using an array,
|
||||||
|
# write it like this: option=${^array}. That way `option=` is prepended to
|
||||||
|
# each value of `array`.
|
||||||
|
#
|
||||||
|
# For examples see my dotfiles: https://github.com/dmitmel/dotfiles/blob/master/zsh/plugins.zsh
|
||||||
|
# You may ask me why did I choose to merge loading and downloading behavior
|
||||||
|
# into one function. Well, first of all plugin manager itself becomes much
|
||||||
|
# simpler. Second: it allows you to load plugins from any part of zshrc (which
|
||||||
|
# is useful for me because my dotfiles are used by my friends, and they too
|
||||||
|
# want customization) and even in an active shell.
|
||||||
|
#
|
||||||
|
# Oh, and I had to optimize this function, so it is very long because I merged
|
||||||
|
# everything into one code block. I hope (this is also a message for my future
|
||||||
|
# self) that you'll be able to read this code, I tried to comment everything.
|
||||||
|
plugin() {
|
||||||
|
|
||||||
|
# parse basic arguments {{{
|
||||||
|
|
||||||
|
if (( $# < 2 )); then
|
||||||
|
_zplg_error "usage: $0 <id> <url> [option...]"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local plugin_id="$1"
|
||||||
|
local plugin_url="$2"
|
||||||
|
if [[ ! "$plugin_id" =~ '^[a-zA-Z0-9_\-][a-zA-Z0-9._\-]*$' ]]; then
|
||||||
|
_zplg_error "invalid plugin ID"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [[ -z "$plugin_url" ]]; then
|
||||||
|
_zplg_error "invalid plugin URL"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Don't even try to continue if the plugin has already been loaded. This is
|
||||||
|
# not or problem. Plugin manager loads plugins and shouldn't bother
|
||||||
|
# unloading them.
|
||||||
|
if _zplg_is_plugin_loaded "$plugin_id"; then
|
||||||
|
_zplg_error "plugin $plugin_id has already been loaded"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
# parse options {{{
|
||||||
|
|
||||||
|
local plugin_from="github"
|
||||||
|
local -a plugin_build plugin_before_load plugin_after_load plugin_load plugin_ignore
|
||||||
|
|
||||||
|
local option key value; shift 2; for option in "$@"; do
|
||||||
|
# globs are faster than regular expressions
|
||||||
|
if [[ "$option" != *?=?* ]]; then
|
||||||
|
_zplg_error "options must have the following format: <key>=<value>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# split 'option' at the first occurence of '='
|
||||||
|
key="${option%%=*}" value="${option#*=}"
|
||||||
|
case "$key" in
|
||||||
|
from)
|
||||||
|
eval "plugin_$key=\"\$value\"" ;;
|
||||||
|
build|before_load|after_load|load|ignore)
|
||||||
|
eval "plugin_$key+=(\"\$value\")" ;;
|
||||||
|
*)
|
||||||
|
_zplg_error "unknown option: $key"
|
||||||
|
return 1 ;;
|
||||||
|
esac
|
||||||
|
done; unset option key value
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
if (( ${#plugin_load} == 0 )); then
|
||||||
|
# default loading patterns:
|
||||||
|
# - *.plugin.zsh for most plugins and Oh-My-Zsh ones
|
||||||
|
# - *.zsh-theme for most themes and Oh-My-Zsh ones
|
||||||
|
# - init.zsh for Prezto plugins
|
||||||
|
# ([1]) means "expand only to the first match"
|
||||||
|
plugin_load=("(*.plugin.zsh|*.zsh-theme|init.zsh)([1])")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# download plugin {{{
|
||||||
|
|
||||||
|
local plugin_dir="$_ZPLG_PLUGINS_DIR/$plugin_id"
|
||||||
|
# simple check whether the plugin directory exists is enough for me
|
||||||
|
if [[ ! -d "$plugin_dir" ]]; then
|
||||||
|
_zplg_log "downloading $plugin_id"
|
||||||
|
_zplg_source_"$plugin_from"_download "$plugin_url" "$plugin_dir" || return "$?"
|
||||||
|
|
||||||
|
if (( ${#plugin_build} > 0 )); then
|
||||||
|
_zplg_log "building $plugin_id"
|
||||||
|
( cd "$plugin_dir" && _zplg_run_commands plugin_build ) || return "$?"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
# load plugin {{{
|
||||||
|
|
||||||
|
_zplg_run_commands plugin_before_load || return "$?"
|
||||||
|
|
||||||
|
local load_pattern ignore_pattern script_path; local -a script_paths
|
||||||
|
for load_pattern in "${plugin_load[@]}"; do
|
||||||
|
_zplg_expand_pattern "$plugin_dir/$load_pattern" script_paths
|
||||||
|
for script_path in "${script_paths[@]}"; do
|
||||||
|
for ignore_pattern in "${plugin_ignore[@]}"; do
|
||||||
|
if [[ "$script_path" == "$plugin_dir/"${~ignore_pattern} ]]; then
|
||||||
|
# continue outer loop
|
||||||
|
continue 2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
_zplg_debug "sourcing $script_path"
|
||||||
|
_zplg_load "$script_path" || return "$?"
|
||||||
|
done
|
||||||
|
done; unset load_pattern ignore_pattern script_path
|
||||||
|
|
||||||
|
_zplg_run_commands plugin_after_load || return "$?"
|
||||||
|
|
||||||
|
# plugin has finally been loaded, we can add it to $ZPLG_LOADED_PLUGINS
|
||||||
|
ZPLG_LOADED_PLUGINS+=("$plugin_id")
|
||||||
|
ZPLG_LOADED_PLUGIN_URLS[$plugin_id]="$plugin_url"
|
||||||
|
ZPLG_LOADED_PLUGIN_SOURCES[$plugin_id]="$plugin_from"
|
||||||
|
|
||||||
|
# HORRIBLE HACK: because you can't store arrays as values in associative
|
||||||
|
# arrays, I simply quote every element with the (@q) modifier, then join
|
||||||
|
# quoted ones into a string and put this "encoded" string into the
|
||||||
|
# associative array. Terrible idea? Maybe. Does it work? YES!!!
|
||||||
|
if (( ${#plugin_build} > 0 )); then
|
||||||
|
# extra ${...} is needed to turn array into a string by joining it with
|
||||||
|
# spaces
|
||||||
|
ZPLG_LOADED_PLUGIN_BUILD_CMDS[$plugin_id]="${${(@q)plugin_build}}"
|
||||||
|
unset plugin_build_quoted
|
||||||
|
fi
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# helper functions for plugin configuration {{{
|
||||||
|
|
||||||
|
# Simplifies modification of path variables (path/fpath/manpath etc) in
|
||||||
|
# after_load and before_load hooks.
|
||||||
|
plugin-cfg-path() {
|
||||||
|
if (( $# < 2 )); then
|
||||||
|
_zplg_error "usage: $0 <var_name> prepend|append <value...>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$plugin_dir" ]]; then
|
||||||
|
_zplg_error "this function is intended to be used in after_load or before_load hooks"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local var_name="$1" operator="$2"; shift 2; local values=("$@")
|
||||||
|
|
||||||
|
if [[ "$var_name" != *path || "${(Pt)var_name}" != array* ]]; then
|
||||||
|
_zplg_error "unknown path variable $var_name"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$operator" in
|
||||||
|
prepend) eval "$var_name=(\"\$plugin_dir/\"\${^values} \${$var_name[@]})" ;;
|
||||||
|
append) eval "$var_name=(\${$var_name[@]} \"\$plugin_dir/\"\${^values})" ;;
|
||||||
|
*) _zplg_error "unknown $0 operator $operator"
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
# Exits with success code 0 if the plugin is loaded, otherwise exits with error
|
||||||
|
# code 1. To be used in `if` statements.
|
||||||
|
_zplg_is_plugin_loaded() {
|
||||||
|
local plugin_id="$1"
|
||||||
|
# (ie) are subscript flags:
|
||||||
|
# - i returns index of the value (reverse subscripting) in the square
|
||||||
|
# brackets (subscript)
|
||||||
|
# - e disables patterns matching, so plain string matching is used instead
|
||||||
|
# unlike normal programming languages, if the value is not found an index
|
||||||
|
# greater than the length of the array is returned
|
||||||
|
(( ${ZPLG_LOADED_PLUGINS[(ie)$plugin_id]} <= ${#ZPLG_LOADED_PLUGINS} ))
|
||||||
|
}
|
||||||
|
|
||||||
|
# Here are some useful commands for managing plugins. I chose to make them
|
||||||
|
# functions because:
|
||||||
|
# 1. automatic completion
|
||||||
|
# 2. automatic correction
|
||||||
|
|
||||||
|
# Prints IDs of all loaded plugins.
|
||||||
|
plugin-list() {
|
||||||
|
# (F) modifier joins an array with newlines
|
||||||
|
print "${(F)ZPLG_LOADED_PLUGINS}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Upgrades all plugins if no arguments are given, otherwise upgrades plugins by
|
||||||
|
# their IDs.
|
||||||
|
plugin-upgrade() {
|
||||||
|
local plugin_ids_var
|
||||||
|
if (( $# > 0 )); then
|
||||||
|
plugin_ids_var="@"
|
||||||
|
else
|
||||||
|
plugin_ids_var="ZPLG_LOADED_PLUGINS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local plugin_id plugin_url plugin_from plugin_dir; local -a plugin_build
|
||||||
|
# for description of the (P) modifier see _zplg_run_commands
|
||||||
|
for plugin_id in "${(@P)plugin_ids_var}"; do
|
||||||
|
if ! _zplg_is_plugin_loaded "$plugin_id"; then
|
||||||
|
_zplg_error "unknown plugin $plugin_id"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
plugin_url="${ZPLG_LOADED_PLUGIN_URLS[$plugin_id]}"
|
||||||
|
plugin_from="${ZPLG_LOADED_PLUGIN_SOURCES[$plugin_id]}"
|
||||||
|
plugin_dir="$_ZPLG_PLUGINS_DIR/$plugin_id"
|
||||||
|
|
||||||
|
_zplg_log "upgrading $plugin_id"
|
||||||
|
_zplg_source_"$plugin_from"_upgrade "$plugin_url" "$plugin_dir" || return "$?"
|
||||||
|
|
||||||
|
if (( ${+ZPLG_LOADED_PLUGIN_BUILD_CMDS[$plugin_id]} )); then
|
||||||
|
# TERRIBLE HACK continued: this monstrosity is used to "decode" build
|
||||||
|
# commands. See ending of the `plugin` function for "encoding" procedure.
|
||||||
|
# First, I get encoded string. Then with the (z) modifier I split it into
|
||||||
|
# array taking into account quoting. Then with the (Q) modifier I unquote
|
||||||
|
# every value.
|
||||||
|
plugin_build=("${(@Q)${(z)${ZPLG_LOADED_PLUGIN_BUILD_CMDS[$plugin_id]}}}")
|
||||||
|
_zplg_log "building $plugin_id"
|
||||||
|
( cd "$plugin_dir" && _zplg_run_commands plugin_build ) || return "$?"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Reinstall plugins by IDs.
|
||||||
|
plugin-reinstall() {
|
||||||
|
if (( $# == 0 )); then
|
||||||
|
_zplg_error "usage: $0 <plugin...>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local plugin_id plugin_url plugin_from plugin_dir; local -a plugin_build
|
||||||
|
for plugin_id in "$@"; do
|
||||||
|
if ! _zplg_is_plugin_loaded "$plugin_id"; then
|
||||||
|
_zplg_error "unknown plugin $plugin_id"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
plugin_url="${ZPLG_LOADED_PLUGIN_URLS[$plugin_id]}"
|
||||||
|
plugin_from="${ZPLG_LOADED_PLUGIN_SOURCES[$plugin_id]}"
|
||||||
|
plugin_dir="$_ZPLG_PLUGINS_DIR/$plugin_id"
|
||||||
|
|
||||||
|
_zplg_log "removing $plugin_id"
|
||||||
|
rm -rf "$plugin_dir"
|
||||||
|
|
||||||
|
_zplg_log "downloading $plugin_id"
|
||||||
|
_zplg_source_"$plugin_from"_download "$plugin_url" "$plugin_dir" || return "$?"
|
||||||
|
|
||||||
|
if (( ${+ZPLG_LOADED_PLUGIN_BUILD_CMDS[$plugin_id]} )); then
|
||||||
|
# for description of this terrible hack see the ending of the
|
||||||
|
# `plugin-upgrade` function
|
||||||
|
plugin_build=("${(@Q)${(z)${ZPLG_LOADED_PLUGIN_BUILD_CMDS[$plugin_id]}}}")
|
||||||
|
_zplg_log "building $plugin_id"
|
||||||
|
( cd "$plugin_dir" && _zplg_run_commands plugin_build ) || return "$?"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clears directories of plugins by their IDs.
|
||||||
|
plugin-purge() {
|
||||||
|
if (( $# == 0 )); then
|
||||||
|
_zplg_error "usage: $0 <plugin...>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for plugin_id in "$@"; do
|
||||||
|
if ! _zplg_is_plugin_loaded "$plugin_id"; then
|
||||||
|
_zplg_error "unknown plugin $plugin_id"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local plugin_dir="$_ZPLG_PLUGINS_DIR/$plugin_id"
|
||||||
|
|
||||||
|
_zplg_log "removing $plugin_id"
|
||||||
|
rm -rf "$plugin_dir"
|
||||||
|
done
|
||||||
|
}
|
|
@ -9,7 +9,6 @@ done
|
||||||
|
|
||||||
command_exists rbenv && eval "$(rbenv init -)"
|
command_exists rbenv && eval "$(rbenv init -)"
|
||||||
|
|
||||||
export BASE16_SHELL="$HOME/.zgen/chriskempson/base16-shell-master"
|
|
||||||
BASE16_SHELL_profile_helper="$BASE16_SHELL/profile_helper.sh"
|
BASE16_SHELL_profile_helper="$BASE16_SHELL/profile_helper.sh"
|
||||||
[[ -n "$PS1" && -r "$BASE16_SHELL_profile_helper" ]] && eval "$("$BASE16_SHELL_profile_helper")"
|
[[ -n "$PS1" && -r "$BASE16_SHELL_profile_helper" ]] && eval "$("$BASE16_SHELL_profile_helper")"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue