Merge pull request #114 from emilb/master
Added Maven completion file
diff --git a/.gitignore b/.gitignore
index 32e62de..b27cddd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,10 @@
*/enabled/*
.DS_Store
-custom/*.bash
+custom/*
!custom/example.bash
.rvmrc
aliases/custom.aliases.bash
lib/custom.bash
plugins/custom.plugins.bash
*.swp
+.*.un~
diff --git a/README.md b/README.md
index 0c9c303..105d5be 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Bash it
-**Bash it** is a mash up of my own bash commands and scripts, other bash stuff I have found.
+**Bash it** is a mash up of my own bash commands and scripts, other bash stuff I have found.
(And a shameless ripoff of [oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh). :)
@@ -13,18 +13,19 @@
3. Edit your `~/.bash_profile` file in order to customize bash-it.
**NOTE:**
-The install script will also prompt you asking if you use [Jekyll](https://github.com/mojombo/jekyll).
+The install script will also prompt you asking if you use [Jekyll](https://github.com/mojombo/jekyll).
This is to set up the `.jekyllconfig` file, which stores info necessary to use the Jekyll plugin.
## Help Screens
```
-bash-it (will show all the help commands)
-aliases-help
-rails-help
-git-help
-plugins-help
+bash-it show aliases # shows installed and available aliases
+bash-it show completions # shows installed and available completions
+bash-it show plugins # shows installed and available plugins
+bash-it help aliases # shows help for installed aliases
+bash-it help completions # shows help for installed completions
+bash-it help plugins # shows help for installed plugins
```
## Your Custom scripts, aliases, and functions
@@ -45,7 +46,7 @@
I think everyone has their own custom scripts accumulated over time. And so, following in the footsteps of oh-my-zsh, bash it is a framework for easily customizing your bash shell. Everyone's got a custom toolbox, so let's start making them even better, **as a community!**
-Send me a pull request and I'll merge it as long as it looks good. If you change an existing command, please give an explanation why. That will help a lot when I merge your changes in.
+Send me a pull request and I'll merge it as long as it looks good. If you change an existing command, please give an explanation why. That will help a lot when I merge your changes in.
Thanks, and happing bashing!
diff --git a/aliases/available/bundler.aliases.bash b/aliases/available/bundler.aliases.bash
index a7756be..fc20f4f 100644
--- a/aliases/available/bundler.aliases.bash
+++ b/aliases/available/bundler.aliases.bash
@@ -1,21 +1,9 @@
-#!/usr/bin/env bash
+cite 'about-alias'
+about-alias 'ruby bundler'
# Bundler Commands
-alias be="bundle exec"
-alias bi="bundle install"
-alias bl="bundle list"
-alias bu="bundle update"
-alias bp="bundle package"
-
-
-function bundler-help() {
- echo "Bundler Aliases Usage"
- echo
- echo " be = bundle exec"
- echo " bi = bundle install"
- echo " bl = bundle list"
- echo " bu = bundle update"
- echo " bp = bundle package"
- echo
-}
-
+alias be='bundle exec'
+alias bi='bundle install'
+alias bl='bundle list'
+alias bu='bundle update'
+alias bp='bundle package'
diff --git a/aliases/available/emacs.aliases.bash b/aliases/available/emacs.aliases.bash
index a133984..ffdb9f3 100644
--- a/aliases/available/emacs.aliases.bash
+++ b/aliases/available/emacs.aliases.bash
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+cite 'about-alias'
+about-alias 'emacs editor'
case $OSTYPE in
linux*)
@@ -6,6 +7,6 @@
alias e='emacsclient -n'
;;
darwin*)
- alias em="open -a emacs"
+ alias em='open -a emacs'
;;
esac
diff --git a/aliases/available/general.aliases.bash b/aliases/available/general.aliases.bash
index 660a8ca..3e87e2d 100644
--- a/aliases/available/general.aliases.bash
+++ b/aliases/available/general.aliases.bash
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+cite about-alias
+about-alias 'general aliases'
# List directory contents
alias sl=ls
@@ -27,20 +28,20 @@
alias edit="$EDITOR"
alias pager="$PAGER"
-alias q="exit"
+alias q='exit'
alias irc="$IRC_CLIENT"
-alias rb="ruby"
+alias rb='ruby'
# Pianobar can be found here: http://github.com/PromyLOPh/pianobar/
-alias piano="pianobar"
+alias piano='pianobar'
alias ..='cd ..' # Go up one directory
alias ...='cd ../..' # Go up two directories
alias ....='cd ../../..' # Go up two directories
-alias -- -="cd -" # Go back
+alias -- -='cd -' # Go back
# Shell History
alias h='history'
@@ -53,30 +54,4 @@
# Directory
alias md='mkdir -p'
-alias rd=rmdir
-
-function aliases-help() {
-echo "Generic Alias Usage"
-echo
-echo " sl = ls"
-echo " ls = ls -G"
-echo " la = ls -AF"
-echo " ll = ls -al"
-echo " l = ls -a"
-echo " c/k/cls = clear"
-echo " .. = cd .."
-echo " ... = cd ../.."
-echo " - = cd -"
-echo " h = history"
-echo " md = mkdir -p"
-echo " rd = rmdir"
-echo " editor = $EDITOR"
-echo " pager = $PAGER"
-echo " piano = pianobar"
-echo " q = exit"
-echo " irc = $IRC_CLIENT"
-echo " md = mkdir -p"
-echo " rd = rmdir"
-echo " rb = ruby"
-echo
-}
+alias rd='rmdir'
diff --git a/aliases/available/git.aliases.bash b/aliases/available/git.aliases.bash
index abfa996..bbac313 100644
--- a/aliases/available/git.aliases.bash
+++ b/aliases/available/git.aliases.bash
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+cite 'about-alias'
+about-alias 'common git abbreviations'
# Aliases
alias gcl='git clone'
@@ -38,36 +39,3 @@
alias gd='git diff'
;;
esac
-
-
-
-function git-help() {
- echo "Git Custom Aliases Usage"
- echo
- echo " gcl = git clone"
- echo " g = git"
- echo " get = git"
- echo " ga = git add"
- echo " gall = git add ."
- echo " gst/gs = git status"
- echo " gss = git status -s"
- echo " gl = git pull"
- echo " gup = git fetch && git rebase"
- echo " gp = git push"
- echo " gd = git diff | mate"
- echo " gdv = git diff -w \"$@\" | vim -R -"
- echo " gc = git commit -v"
- echo " gca = git commit -v -a"
- echo " gci = git commit --interactive"
- echo " gb = git branch"
- echo " gba = git branch -a"
- echo " gcount = git shortlog -sn"
- echo " gcp = git cherry-pick"
- echo " gco = git checkout"
- echo " gexport = git git archive --format zip --output"
- echo " gdel = git branch -D"
- echo " gpo = git push origin"
- echo " gmu = git fetch origin -v; git fetch upstream -v; git merge upstream/master"
- echo " gll = git log --graph --pretty=oneline --abbrev-commit"
- echo
-}
diff --git a/aliases/available/heroku.aliases.bash b/aliases/available/heroku.aliases.bash
index 7bc1dbe..a749d42 100644
--- a/aliases/available/heroku.aliases.bash
+++ b/aliases/available/heroku.aliases.bash
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+cite 'about-alias'
+about-alias 'heroku task abbreviations'
# heroku
alias h='heroku'
@@ -31,26 +32,3 @@
alias hca='heroku config:add'
alias hcr='heroku config:remove'
alias hcc='heroku config:clear'
-
-function heroku-help() {
- echo "Heroku Aliases Usage"
- echo
- echo " h = heroku"
- echo " hl = heroku list"
- echo " hi = heroku info"
- echo " ho = heroku open"
- echo " hd = heroku dynos"
- echo " hw = heroku workers"
- echo " hr = heroku rake"
- echo " hcon = heroku console"
- echo " hnew = heroku create"
- echo " hrestart = heroku restart"
- echo " hlog = heroku logs"
- echo " hon = heroku maintenance:on"
- echo " hoff = heroku maintenance:off"
- echo " hc = heroku config"
- echo " hca = heroku config:add"
- echo " hcr = heroku config:remove"
- echo " hcc = heroku config:clear"
- echo
-}
diff --git a/aliases/available/hg.aliases.bash b/aliases/available/hg.aliases.bash
index 245c529..eea819f 100644
--- a/aliases/available/hg.aliases.bash
+++ b/aliases/available/hg.aliases.bash
@@ -1,14 +1,6 @@
-#!/usr/bin/env bash
+cite 'about-alias'
+about-alias 'mercurial abbreviations'
alias hs='hg status'
alias hsum='hg summary'
alias hcm='hg commit -m'
-
-function hg-help() {
- echo "Mercurial Alias Help"
- echo
- echo " hs = hg status"
- echo " hsum = hg summary"
- echo " hcm = hg commit -m"
- echo
-}
diff --git a/aliases/available/homebrew.aliases.bash b/aliases/available/homebrew.aliases.bash
index 051081d..b8f1481 100644
--- a/aliases/available/homebrew.aliases.bash
+++ b/aliases/available/homebrew.aliases.bash
@@ -1,24 +1,13 @@
# Some aliases for Homebrew
-alias bup="brew update && brew upgrade"
-alias bout="brew outdated"
-alias bin="brew install"
-alias brm="brew uninstall"
-alias bls="brew list"
-alias bsr="brew search"
-alias binf="brew info"
-alias bdr="brew doctor"
+cite 'about-alias'
+about-alias 'homebrew abbreviations'
-function brew-help() {
- echo "Homebrew Alias Usage"
- echo
- echo "bup = brew update && brew upgrade"
- echo "bout = brew outdated"
- echo "bin = brew install"
- echo "brm = brew uninstall"
- echo "bls = brew list"
- echo "bsr = brew search"
- echo "binf = brew info"
- echo "bdr = brew doctor"
- echo
-}
+alias bup='brew update && brew upgrade'
+alias bout='brew outdated'
+alias bin='brew install'
+alias brm='brew uninstall'
+alias bls='brew list'
+alias bsr='brew search'
+alias binf='brew info'
+alias bdr='brew doctor'
diff --git a/aliases/available/maven.aliases.bash b/aliases/available/maven.aliases.bash
index 349f9d8..4cd89d2 100644
--- a/aliases/available/maven.aliases.bash
+++ b/aliases/available/maven.aliases.bash
@@ -1,22 +1,11 @@
-alias mci="mvn clean install"
-alias mi="mvn install"
-alias mrprep="mvn release:prepare"
-alias mrperf="mvn release:perform"
-alias mrrb="mvn release:rollback"
-alias mdep="mvn dependency:tree"
-alias mpom="mvn help:effective-pom"
-alias mcisk="mci -Dmaven.test.skip=true"
+cite 'about-alias'
+about-alias 'maven abbreviations'
-function maven-help() {
- echo "Maven Custom Aliases Usage"
- echo
- echo " mci = mvn clean install"
- echo " mi = mvn install"
- echo " mrprep = mvn release:prepare"
- echo " mrperf = mvn release:perform"
- echo " mrrb = mvn release:rollback"
- echo " mdep = mvn dependency:tree"
- echo " mpom = mvn help:effective-pom"
- echo " mcisk = mvn clean install -Dmaven.test.skip=true"
- echo
-}
+alias mci='mvn clean install'
+alias mi='mvn install'
+alias mrprep='mvn release:prepare'
+alias mrperf='mvn release:perform'
+alias mrrb='mvn release:rollback'
+alias mdep='mvn dependency:tree'
+alias mpom='mvn help:effective-pom'
+alias mcisk='mci -Dmaven.test.skip=true'
diff --git a/aliases/available/osx.aliases.bash b/aliases/available/osx.aliases.bash
index 008b67c..ffe3ca0 100644
--- a/aliases/available/osx.aliases.bash
+++ b/aliases/available/osx.aliases.bash
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+cite 'about-alias'
+about-alias 'osx-specific aliases'
# Desktop Programs
alias fireworks="open -a '/Applications/Adobe Fireworks CS3/Adobe Fireworks CS3.app'"
@@ -18,3 +19,6 @@
if [ -s /usr/bin/firefox ] ; then
unalias firefox
fi
+
+# Requires growlnotify, which can be found in the Growl DMG under "Extras"
+alias grnot='growlnotify -s -t Terminal -m "Done"'
diff --git a/aliases/available/rails.aliases.bash b/aliases/available/rails.aliases.bash
index 1d7b310..ae664bf 100644
--- a/aliases/available/rails.aliases.bash
+++ b/aliases/available/rails.aliases.bash
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+cite 'about-alias'
+about-alias 'rails abbreviations'
# Rails Commands
alias r='rails'
@@ -19,24 +20,3 @@
alias restart='touch tmp/restart.txt' # restart passenger
alias devlog='tail -f log/development.log'
alias taild='tail -f log/development.log' # tail dev log
-
-function rails-help() {
- echo "Rails Aliases Usage"
- echo
- echo " r = rails"
- echo " rg = rails generate"
- echo " rs/ss = rails server"
- echo " ts = thin server"
- echo " rc/sc = rails console"
- echo " rn = rails new"
- echo " rd = rails dbconsole"
- echo " rp = rails plugin"
- echo " ra = rails application"
- echo " rd = rails destroy"
- echo " restartapp = touch tmp/restart.txt"
- echo " restart = touch tmp/restart.txt"
- echo " devlog = tail -f log/development.log"
- echo " taild = tail -f log/development.log"
- echo
-}
-
diff --git a/aliases/available/textmate.aliases.bash b/aliases/available/textmate.aliases.bash
index 897c7d3..f0f69e4 100644
--- a/aliases/available/textmate.aliases.bash
+++ b/aliases/available/textmate.aliases.bash
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+cite 'about-alias'
+about-alias 'textmate abbreviations'
case $OSTYPE in
darwin*)
diff --git a/aliases/available/todo.txt-cli.aliases.bash b/aliases/available/todo.txt-cli.aliases.bash
index ce27716..5bf35d0 100644
--- a/aliases/available/todo.txt-cli.aliases.bash
+++ b/aliases/available/todo.txt-cli.aliases.bash
@@ -1,19 +1,8 @@
-#!/usr/bin/env bash
+cite 'about-alias'
+about-alias 'todo.txt-cli abbreviations'
alias tls="$TODO ls"
alias ta="$TODO a"
alias trm="$TODO rm"
alias tdo="$TODO do"
alias tpri="$TODO pri"
-
-todo-help() {
- echo
- echo "todo.txt-cli Custom Aliases Usage"
- echo
- echo " tls = $TODO ls"
- echo " ta = $TODO add"
- echo " trm = $TODO rm"
- echo " tdo = $TODO do"
- echo " tpri = $TODO pri"
- echo
-}
diff --git a/aliases/available/vim.aliases.bash b/aliases/available/vim.aliases.bash
index c156ffd..c14f32b 100644
--- a/aliases/available/vim.aliases.bash
+++ b/aliases/available/vim.aliases.bash
@@ -1,3 +1,4 @@
-#!/usr/bin/env bash
+cite 'about-alias'
+about-alias 'vim abbreviations'
alias v='mvim --remote-tab'
diff --git a/bash_it.sh b/bash_it.sh
old mode 100644
new mode 100755
index 8564c88..226213f
--- a/bash_it.sh
+++ b/bash_it.sh
@@ -21,6 +21,12 @@
unset $BASH_THEME;
fi
+# Load composure first, so we support function metadata
+source "${BASH_IT}/lib/composure.sh"
+
+# support 'plumbing' metadata
+cite _about _param _example _group _author _version
+
# Load colors first so they can be use in base theme
source "${BASH_IT}/themes/colors.theme.bash"
source "${BASH_IT}/themes/base.theme.bash"
@@ -69,21 +75,3 @@
then
. $HOME/.jekyllconfig
fi
-
-
-#
-# Custom Help
-
-function bash-it() {
- echo "Welcome to Bash It!"
- echo
- echo "Here is a list of commands you can use to get help screens for specific pieces of Bash it:"
- echo
- echo " rails-help This will list out all the aliases you can use with rails."
- echo " git-help This will list out all the aliases you can use with git."
- echo " todo-help This will list out all the aliases you can use with todo.txt-cli"
- echo " brew-help This will list out all the aliases you can use with Homebrew"
- echo " aliases-help Generic list of aliases."
- echo " plugins-help This will list out all the plugins and functions you can use with bash-it"
- echo
-}
diff --git a/completion/available/git.completion.bash b/completion/available/git.completion.bash
index 35dbf04..1496c6d 100644
--- a/completion/available/git.completion.bash
+++ b/completion/available/git.completion.bash
@@ -1,6 +1,6 @@
#!bash
#
-# bash completion support for core Git.
+# bash/zsh completion support for core Git.
#
# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
# Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/).
@@ -18,27 +18,48 @@
# To use these routines:
#
# 1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
-# 2) Added the following line to your .bashrc:
+# 2) Add the following line to your .bashrc/.zshrc:
# source ~/.git-completion.sh
#
-# 3) You may want to make sure the git executable is available
-# in your PATH before this script is sourced, as some caching
-# is performed while the script loads. If git isn't found
-# at source time then all lookups will be done on demand,
-# which may be slightly slower.
-#
-# 4) Consider changing your PS1 to also show the current branch:
-# PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
+# 3) Consider changing your PS1 to also show the current branch:
+# Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
+# ZSH: PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
#
# The argument to __git_ps1 will be displayed only if you
# are currently in a git repository. The %s token will be
# the name of the current branch.
#
-# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty
-# value, unstaged (*) and staged (+) changes will be shown next
-# to the branch name. You can configure this per-repository
-# with the bash.showDirtyState variable, which defaults to true
-# once GIT_PS1_SHOWDIRTYSTATE is enabled.
+# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty
+# value, unstaged (*) and staged (+) changes will be shown next
+# to the branch name. You can configure this per-repository
+# with the bash.showDirtyState variable, which defaults to true
+# once GIT_PS1_SHOWDIRTYSTATE is enabled.
+#
+# You can also see if currently something is stashed, by setting
+# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
+# then a '$' will be shown next to the branch name.
+#
+# If you would like to see if there're untracked files, then you can
+# set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're
+# untracked files, then a '%' will be shown next to the branch name.
+#
+# If you would like to see the difference between HEAD and its
+# upstream, set GIT_PS1_SHOWUPSTREAM="auto". A "<" indicates
+# you are behind, ">" indicates you are ahead, and "<>"
+# indicates you have diverged. You can further control
+# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated
+# list of values:
+# verbose show number of commits ahead/behind (+/-) upstream
+# legacy don't use the '--count' option available in recent
+# versions of git-rev-list
+# git always compare HEAD to @{upstream}
+# svn always compare HEAD to your SVN upstream
+# By default, __git_ps1 will compare HEAD to your SVN upstream
+# if it can find one, or @{upstream} otherwise. Once you have
+# set GIT_PS1_SHOWUPSTREAM, you can override it on a
+# per-repository basis by setting the bash.showUpstream config
+# variable.
+#
#
# To submit patches:
#
@@ -52,6 +73,10 @@
# git@vger.kernel.org
#
+if [[ -n ${ZSH_VERSION-} ]]; then
+ autoload -U +X bashcompinit && bashcompinit
+fi
+
case "$COMP_WORDBREAKS" in
*:*) : great ;;
*) COMP_WORDBREAKS="$COMP_WORDBREAKS:"
@@ -62,7 +87,7 @@
__gitdir ()
{
if [ -z "${1-}" ]; then
- if [ -n "$__git_dir" ]; then
+ if [ -n "${__git_dir-}" ]; then
echo "$__git_dir"
elif [ -d .git ]; then
echo .git
@@ -76,73 +101,219 @@
fi
}
+# stores the divergence from upstream in $p
+# used by GIT_PS1_SHOWUPSTREAM
+__git_ps1_show_upstream ()
+{
+ local key value
+ local svn_remote=() svn_url_pattern count n
+ local upstream=git legacy="" verbose=""
+
+ # get some config options from git-config
+ local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
+ while read -r key value; do
+ case "$key" in
+ bash.showupstream)
+ GIT_PS1_SHOWUPSTREAM="$value"
+ if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
+ p=""
+ return
+ fi
+ ;;
+ svn-remote.*.url)
+ svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value"
+ svn_url_pattern+="\\|$value"
+ upstream=svn+git # default upstream is SVN if available, else git
+ ;;
+ esac
+ done <<< "$output"
+
+ # parse configuration values
+ for option in ${GIT_PS1_SHOWUPSTREAM}; do
+ case "$option" in
+ git|svn) upstream="$option" ;;
+ verbose) verbose=1 ;;
+ legacy) legacy=1 ;;
+ esac
+ done
+
+ # Find our upstream
+ case "$upstream" in
+ git) upstream="@{upstream}" ;;
+ svn*)
+ # get the upstream from the "git-svn-id: ..." in a commit message
+ # (git-svn uses essentially the same procedure internally)
+ local svn_upstream=($(git log --first-parent -1 \
+ --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
+ if [[ 0 -ne ${#svn_upstream[@]} ]]; then
+ svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]}
+ svn_upstream=${svn_upstream%@*}
+ local n_stop="${#svn_remote[@]}"
+ for ((n=1; n <= n_stop; ++n)); do
+ svn_upstream=${svn_upstream#${svn_remote[$n]}}
+ done
+
+ if [[ -z "$svn_upstream" ]]; then
+ # default branch name for checkouts with no layout:
+ upstream=${GIT_SVN_ID:-git-svn}
+ else
+ upstream=${svn_upstream#/}
+ fi
+ elif [[ "svn+git" = "$upstream" ]]; then
+ upstream="@{upstream}"
+ fi
+ ;;
+ esac
+
+ # Find how many commits we are ahead/behind our upstream
+ if [[ -z "$legacy" ]]; then
+ count="$(git rev-list --count --left-right \
+ "$upstream"...HEAD 2>/dev/null)"
+ else
+ # produce equivalent output to --count for older versions of git
+ local commits
+ if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)"
+ then
+ local commit behind=0 ahead=0
+ for commit in $commits
+ do
+ case "$commit" in
+ "<"*) let ++behind
+ ;;
+ *) let ++ahead
+ ;;
+ esac
+ done
+ count="$behind $ahead"
+ else
+ count=""
+ fi
+ fi
+
+ # calculate the result
+ if [[ -z "$verbose" ]]; then
+ case "$count" in
+ "") # no upstream
+ p="" ;;
+ "0 0") # equal to upstream
+ p="=" ;;
+ "0 "*) # ahead of upstream
+ p=">" ;;
+ *" 0") # behind upstream
+ p="<" ;;
+ *) # diverged from upstream
+ p="<>" ;;
+ esac
+ else
+ case "$count" in
+ "") # no upstream
+ p="" ;;
+ "0 0") # equal to upstream
+ p=" u=" ;;
+ "0 "*) # ahead of upstream
+ p=" u+${count#0 }" ;;
+ *" 0") # behind upstream
+ p=" u-${count% 0}" ;;
+ *) # diverged from upstream
+ p=" u+${count#* }-${count% *}" ;;
+ esac
+ fi
+
+}
+
+
# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
# returns text to add to bash PS1 prompt (includes branch name)
__git_ps1 ()
{
- local g="$(git rev-parse --git-dir 2>/dev/null)"
+ local g="$(__gitdir)"
if [ -n "$g" ]; then
- local r
- local b
- if [ -d "$g/rebase-apply" ]
- then
- if test -f "$g/rebase-apply/rebasing"
- then
- r="|REBASE"
- elif test -f "$g/rebase-apply/applying"
- then
- r="|AM"
- else
- r="|AM/REBASE"
- fi
- b="$(git symbolic-ref HEAD 2>/dev/null)"
- elif [ -f "$g/rebase-merge/interactive" ]
- then
+ local r=""
+ local b=""
+ if [ -f "$g/rebase-merge/interactive" ]; then
r="|REBASE-i"
b="$(cat "$g/rebase-merge/head-name")"
- elif [ -d "$g/rebase-merge" ]
- then
+ elif [ -d "$g/rebase-merge" ]; then
r="|REBASE-m"
b="$(cat "$g/rebase-merge/head-name")"
- elif [ -f "$g/MERGE_HEAD" ]
- then
- r="|MERGING"
- b="$(git symbolic-ref HEAD 2>/dev/null)"
else
- if [ -f "$g/BISECT_LOG" ]
- then
+ if [ -d "$g/rebase-apply" ]; then
+ if [ -f "$g/rebase-apply/rebasing" ]; then
+ r="|REBASE"
+ elif [ -f "$g/rebase-apply/applying" ]; then
+ r="|AM"
+ else
+ r="|AM/REBASE"
+ fi
+ elif [ -f "$g/MERGE_HEAD" ]; then
+ r="|MERGING"
+ elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
+ r="|CHERRY-PICKING"
+ elif [ -f "$g/BISECT_LOG" ]; then
r="|BISECTING"
fi
- if ! b="$(git symbolic-ref HEAD 2>/dev/null)"
- then
- if ! b="$(git describe --exact-match HEAD 2>/dev/null)"
- then
- b="$(cut -c1-7 "$g/HEAD")..."
+
+ b="$(git symbolic-ref HEAD 2>/dev/null)" || {
+
+ b="$(
+ case "${GIT_PS1_DESCRIBE_STYLE-}" in
+ (contains)
+ git describe --contains HEAD ;;
+ (branch)
+ git describe --contains --all HEAD ;;
+ (describe)
+ git describe HEAD ;;
+ (* | default)
+ git describe --tags --exact-match HEAD ;;
+ esac 2>/dev/null)" ||
+
+ b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
+ b="unknown"
+ b="($b)"
+ }
+ fi
+
+ local w=""
+ local i=""
+ local s=""
+ local u=""
+ local c=""
+ local p=""
+
+ if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
+ if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
+ c="BARE:"
+ else
+ b="GIT_DIR!"
+ fi
+ elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
+ if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
+ if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then
+ git diff --no-ext-diff --quiet --exit-code || w="*"
+ if git rev-parse --quiet --verify HEAD >/dev/null; then
+ git diff-index --cached --quiet HEAD -- || i="+"
+ else
+ i="#"
+ fi
fi
fi
+ if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
+ git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
+ fi
+
+ if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
+ if [ -n "$(git ls-files --others --exclude-standard)" ]; then
+ u="%"
+ fi
+ fi
+
+ if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
+ __git_ps1_show_upstream
+ fi
fi
- local w
- local i
-
- if test -n "$GIT_PS1_SHOWDIRTYSTATE"; then
- if test "$(git config --bool bash.showDirtyState)" != "false"; then
- git diff --no-ext-diff --ignore-submodules \
- --quiet --exit-code || w="*"
- if git rev-parse --quiet --verify HEAD >/dev/null; then
- git diff-index --cached --quiet \
- --ignore-submodules HEAD -- || i="+"
- else
- i="#"
- fi
- fi
- fi
-
- if [ -n "${1-}" ]; then
- printf "$1" "${b##refs/heads/}$w$i$r"
- else
- printf " (%s)" "${b##refs/heads/}$w$i$r"
- fi
+ local f="$w$i$s$u"
+ printf "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p"
fi
}
@@ -159,15 +330,177 @@
done
}
-# __gitcomp accepts 1, 2, 3, or 4 arguments
-# generates completion reply with compgen
+# The following function is based on code from:
+#
+# bash_completion - programmable completion functions for bash 3.2+
+#
+# Copyright © 2006-2008, Ian Macdonald <ian@caliban.org>
+# © 2009-2010, Bash Completion Maintainers
+# <bash-completion-devel@lists.alioth.debian.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The latest version of this software can be obtained here:
+#
+# http://bash-completion.alioth.debian.org/
+#
+# RELEASE: 2.x
+
+# This function can be used to access a tokenized list of words
+# on the command line:
+#
+# __git_reassemble_comp_words_by_ref '=:'
+# if test "${words_[cword_-1]}" = -w
+# then
+# ...
+# fi
+#
+# The argument should be a collection of characters from the list of
+# word completion separators (COMP_WORDBREAKS) to treat as ordinary
+# characters.
+#
+# This is roughly equivalent to going back in time and setting
+# COMP_WORDBREAKS to exclude those characters. The intent is to
+# make option types like --date=<type> and <rev>:<path> easy to
+# recognize by treating each shell word as a single token.
+#
+# It is best not to set COMP_WORDBREAKS directly because the value is
+# shared with other completion scripts. By the time the completion
+# function gets called, COMP_WORDS has already been populated so local
+# changes to COMP_WORDBREAKS have no effect.
+#
+# Output: words_, cword_, cur_.
+
+__git_reassemble_comp_words_by_ref()
+{
+ local exclude i j first
+ # Which word separators to exclude?
+ exclude="${1//[^$COMP_WORDBREAKS]}"
+ cword_=$COMP_CWORD
+ if [ -z "$exclude" ]; then
+ words_=("${COMP_WORDS[@]}")
+ return
+ fi
+ # List of word completion separators has shrunk;
+ # re-assemble words to complete.
+ for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
+ # Append each nonempty word consisting of just
+ # word separator characters to the current word.
+ first=t
+ while
+ [ $i -gt 0 ] &&
+ [ -n "${COMP_WORDS[$i]}" ] &&
+ # word consists of excluded word separators
+ [ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
+ do
+ # Attach to the previous token,
+ # unless the previous token is the command name.
+ if [ $j -ge 2 ] && [ -n "$first" ]; then
+ ((j--))
+ fi
+ first=
+ words_[$j]=${words_[j]}${COMP_WORDS[i]}
+ if [ $i = $COMP_CWORD ]; then
+ cword_=$j
+ fi
+ if (($i < ${#COMP_WORDS[@]} - 1)); then
+ ((i++))
+ else
+ # Done.
+ return
+ fi
+ done
+ words_[$j]=${words_[j]}${COMP_WORDS[i]}
+ if [ $i = $COMP_CWORD ]; then
+ cword_=$j
+ fi
+ done
+}
+
+if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
+if [[ -z ${ZSH_VERSION:+set} ]]; then
+_get_comp_words_by_ref ()
+{
+ local exclude cur_ words_ cword_
+ if [ "$1" = "-n" ]; then
+ exclude=$2
+ shift 2
+ fi
+ __git_reassemble_comp_words_by_ref "$exclude"
+ cur_=${words_[cword_]}
+ while [ $# -gt 0 ]; do
+ case "$1" in
+ cur)
+ cur=$cur_
+ ;;
+ prev)
+ prev=${words_[$cword_-1]}
+ ;;
+ words)
+ words=("${words_[@]}")
+ ;;
+ cword)
+ cword=$cword_
+ ;;
+ esac
+ shift
+ done
+}
+else
+_get_comp_words_by_ref ()
+{
+ while [ $# -gt 0 ]; do
+ case "$1" in
+ cur)
+ cur=${COMP_WORDS[COMP_CWORD]}
+ ;;
+ prev)
+ prev=${COMP_WORDS[COMP_CWORD-1]}
+ ;;
+ words)
+ words=("${COMP_WORDS[@]}")
+ ;;
+ cword)
+ cword=$COMP_CWORD
+ ;;
+ -n)
+ # assume COMP_WORDBREAKS is already set sanely
+ shift
+ ;;
+ esac
+ shift
+ done
+}
+fi
+fi
+
+# Generates completion reply with compgen, appending a space to possible
+# completion words, if necessary.
+# It accepts 1 to 4 arguments:
+# 1: List of possible completion words.
+# 2: A prefix to be added to each possible completion word (optional).
+# 3: Generate possible completion matches for this word (optional).
+# 4: A suffix to be appended to each possible completion word (optional).
__gitcomp ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
+ local cur_="$cur"
+
if [ $# -gt 2 ]; then
- cur="$3"
+ cur_="$3"
fi
- case "$cur" in
+ case "$cur_" in
--*=)
COMPREPLY=()
;;
@@ -175,80 +508,118 @@
local IFS=$'\n'
COMPREPLY=($(compgen -P "${2-}" \
-W "$(__gitcomp_1 "${1-}" "${4-}")" \
- -- "$cur"))
+ -- "$cur_"))
;;
esac
}
-# __git_heads accepts 0 or 1 arguments (to pass to __gitdir)
+# Generates completion reply with compgen from newline-separated possible
+# completion words by appending a space to all of them.
+# It accepts 1 to 4 arguments:
+# 1: List of possible completion words, separated by a single newline.
+# 2: A prefix to be added to each possible completion word (optional).
+# 3: Generate possible completion matches for this word (optional).
+# 4: A suffix to be appended to each possible completion word instead of
+# the default space (optional). If specified but empty, nothing is
+# appended.
+__gitcomp_nl ()
+{
+ local s=$'\n' IFS=' '$'\t'$'\n'
+ local cur_="$cur" suffix=" "
+
+ if [ $# -gt 2 ]; then
+ cur_="$3"
+ if [ $# -gt 3 ]; then
+ suffix="$4"
+ fi
+ fi
+
+ IFS=$s
+ COMPREPLY=($(compgen -P "${2-}" -S "$suffix" -W "$1" -- "$cur_"))
+}
+
__git_heads ()
{
- local cmd i is_hash=y dir="$(__gitdir "${1-}")"
+ local dir="$(__gitdir)"
if [ -d "$dir" ]; then
git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
refs/heads
return
fi
- for i in $(git ls-remote "${1-}" 2>/dev/null); do
- case "$is_hash,$i" in
- y,*) is_hash=n ;;
- n,*^{}) is_hash=y ;;
- n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
- n,*) is_hash=y; echo "$i" ;;
- esac
- done
}
-# __git_tags accepts 0 or 1 arguments (to pass to __gitdir)
__git_tags ()
{
- local cmd i is_hash=y dir="$(__gitdir "${1-}")"
+ local dir="$(__gitdir)"
if [ -d "$dir" ]; then
git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
refs/tags
return
fi
- for i in $(git ls-remote "${1-}" 2>/dev/null); do
- case "$is_hash,$i" in
- y,*) is_hash=n ;;
- n,*^{}) is_hash=y ;;
- n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
- n,*) is_hash=y; echo "$i" ;;
- esac
- done
}
-# __git_refs accepts 0 or 1 arguments (to pass to __gitdir)
+# __git_refs accepts 0, 1 (to pass to __gitdir), or 2 arguments
+# presence of 2nd argument means use the guess heuristic employed
+# by checkout for tracking branches
__git_refs ()
{
- local i is_hash=y dir="$(__gitdir "${1-}")"
- local cur="${COMP_WORDS[COMP_CWORD]}" format refs
+ local i hash dir="$(__gitdir "${1-}")" track="${2-}"
+ local format refs
if [ -d "$dir" ]; then
case "$cur" in
refs|refs/*)
format="refname"
refs="${cur%/*}"
+ track=""
;;
*)
- if [ -e "$dir/HEAD" ]; then echo HEAD; fi
+ for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
+ if [ -e "$dir/$i" ]; then echo $i; fi
+ done
format="refname:short"
refs="refs/tags refs/heads refs/remotes"
;;
esac
git --git-dir="$dir" for-each-ref --format="%($format)" \
$refs
+ if [ -n "$track" ]; then
+ # employ the heuristic used by git checkout
+ # Try to find a remote branch that matches the completion word
+ # but only output if the branch name is unique
+ local ref entry
+ git --git-dir="$dir" for-each-ref --shell --format="ref=%(refname:short)" \
+ "refs/remotes/" | \
+ while read -r entry; do
+ eval "$entry"
+ ref="${ref#*/}"
+ if [[ "$ref" == "$cur"* ]]; then
+ echo "$ref"
+ fi
+ done | uniq -u
+ fi
return
fi
- for i in $(git ls-remote "$dir" 2>/dev/null); do
- case "$is_hash,$i" in
- y,*) is_hash=n ;;
- n,*^{}) is_hash=y ;;
- n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
- n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
- n,refs/remotes/*) is_hash=y; echo "${i#refs/remotes/}" ;;
- n,*) is_hash=y; echo "$i" ;;
- esac
- done
+ case "$cur" in
+ refs|refs/*)
+ git ls-remote "$dir" "$cur*" 2>/dev/null | \
+ while read -r hash i; do
+ case "$i" in
+ *^{}) ;;
+ *) echo "$i" ;;
+ esac
+ done
+ ;;
+ *)
+ git ls-remote "$dir" HEAD ORIG_HEAD 'refs/tags/*' 'refs/heads/*' 'refs/remotes/*' 2>/dev/null | \
+ while read -r hash i; do
+ case "$i" in
+ *^{}) ;;
+ refs/*) echo "${i#refs/*/}" ;;
+ *) echo "$i" ;;
+ esac
+ done
+ ;;
+ esac
}
# __git_refs2 requires 1 argument (to pass to __git_refs)
@@ -263,46 +634,30 @@
# __git_refs_remotes requires 1 argument (to pass to ls-remote)
__git_refs_remotes ()
{
- local cmd i is_hash=y
- for i in $(git ls-remote "$1" 2>/dev/null); do
- case "$is_hash,$i" in
- n,refs/heads/*)
- is_hash=y
- echo "$i:refs/remotes/$1/${i#refs/heads/}"
- ;;
- y,*) is_hash=n ;;
- n,*^{}) is_hash=y ;;
- n,refs/tags/*) is_hash=y;;
- n,*) is_hash=y; ;;
- esac
+ local i hash
+ git ls-remote "$1" 'refs/heads/*' 2>/dev/null | \
+ while read -r hash i; do
+ echo "$i:refs/remotes/$1/${i#refs/heads/}"
done
}
__git_remotes ()
{
local i ngoff IFS=$'\n' d="$(__gitdir)"
- shopt -q nullglob || ngoff=1
- shopt -s nullglob
+ __git_shopt -q nullglob || ngoff=1
+ __git_shopt -s nullglob
for i in "$d/remotes"/*; do
echo ${i#$d/remotes/}
done
- [ "$ngoff" ] && shopt -u nullglob
- for i in $(git --git-dir="$d" config --list); do
- case "$i" in
- remote.*.url=*)
- i="${i#remote.}"
- echo "${i/.url=*/}"
- ;;
- esac
+ [ "$ngoff" ] && __git_shopt -u nullglob
+ for i in $(git --git-dir="$d" config --get-regexp 'remote\..*\.url' 2>/dev/null); do
+ i="${i#remote.}"
+ echo "${i/.url*/}"
done
}
-__git_merge_strategies ()
+__git_list_merge_strategies ()
{
- if [ -n "$__git_merge_strategylist" ]; then
- echo "$__git_merge_strategylist"
- return
- fi
git merge -s help 2>&1 |
sed -n -e '/[Aa]vailable strategies are: /,/^$/{
s/\.$//
@@ -312,27 +667,39 @@
p
}'
}
-__git_merge_strategylist=
-__git_merge_strategylist=$(__git_merge_strategies 2>/dev/null)
-__git_complete_file ()
+__git_merge_strategies=
+# 'git merge -s help' (and thus detection of the merge strategy
+# list) fails, unfortunately, if run outside of any git working
+# tree. __git_merge_strategies is set to the empty string in
+# that case, and the detection will be repeated the next time it
+# is needed.
+__git_compute_merge_strategies ()
{
- local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}"
- case "$cur" in
+ : ${__git_merge_strategies:=$(__git_list_merge_strategies)}
+}
+
+__git_complete_revlist_file ()
+{
+ local pfx ls ref cur_="$cur"
+ case "$cur_" in
+ *..?*:*)
+ return
+ ;;
?*:*)
- ref="${cur%%:*}"
- cur="${cur#*:}"
- case "$cur" in
+ ref="${cur_%%:*}"
+ cur_="${cur_#*:}"
+ case "$cur_" in
?*/*)
- pfx="${cur%/*}"
- cur="${cur##*/}"
+ pfx="${cur_%/*}"
+ cur_="${cur_##*/}"
ls="$ref:$pfx"
pfx="$pfx/"
;;
*)
ls="$ref"
;;
- esac
+ esac
case "$COMP_WORDBREAKS" in
*:*) : great ;;
@@ -355,42 +722,127 @@
s,$,/,
}
s/^.* //')" \
- -- "$cur"))
+ -- "$cur_"))
+ ;;
+ *...*)
+ pfx="${cur_%...*}..."
+ cur_="${cur_#*...}"
+ __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
+ ;;
+ *..*)
+ pfx="${cur_%..*}.."
+ cur_="${cur_#*..}"
+ __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
;;
*)
- __gitcomp "$(__git_refs)"
+ __gitcomp_nl "$(__git_refs)"
;;
esac
}
+
+__git_complete_file ()
+{
+ __git_complete_revlist_file
+}
+
__git_complete_revlist ()
{
- local pfx cur="${COMP_WORDS[COMP_CWORD]}"
- case "$cur" in
- *...*)
- pfx="${cur%...*}..."
- cur="${cur#*...}"
- __gitcomp "$(__git_refs)" "$pfx" "$cur"
+ __git_complete_revlist_file
+}
+
+__git_complete_remote_or_refspec ()
+{
+ local cur_="$cur" cmd="${words[1]}"
+ local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0
+ while [ $c -lt $cword ]; do
+ i="${words[c]}"
+ case "$i" in
+ --mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;;
+ --all)
+ case "$cmd" in
+ push) no_complete_refspec=1 ;;
+ fetch)
+ COMPREPLY=()
+ return
+ ;;
+ *) ;;
+ esac
+ ;;
+ -*) ;;
+ *) remote="$i"; break ;;
+ esac
+ c=$((++c))
+ done
+ if [ -z "$remote" ]; then
+ __gitcomp_nl "$(__git_remotes)"
+ return
+ fi
+ if [ $no_complete_refspec = 1 ]; then
+ COMPREPLY=()
+ return
+ fi
+ [ "$remote" = "." ] && remote=
+ case "$cur_" in
+ *:*)
+ case "$COMP_WORDBREAKS" in
+ *:*) : great ;;
+ *) pfx="${cur_%%:*}:" ;;
+ esac
+ cur_="${cur_#*:}"
+ lhs=0
;;
- *..*)
- pfx="${cur%..*}.."
- cur="${cur#*..}"
- __gitcomp "$(__git_refs)" "$pfx" "$cur"
+ +*)
+ pfx="+"
+ cur_="${cur_#+}"
;;
- *)
- __gitcomp "$(__git_refs)"
+ esac
+ case "$cmd" in
+ fetch)
+ if [ $lhs = 1 ]; then
+ __gitcomp_nl "$(__git_refs2 "$remote")" "$pfx" "$cur_"
+ else
+ __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
+ fi
+ ;;
+ pull)
+ if [ $lhs = 1 ]; then
+ __gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_"
+ else
+ __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
+ fi
+ ;;
+ push)
+ if [ $lhs = 1 ]; then
+ __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
+ else
+ __gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_"
+ fi
;;
esac
}
-__git_all_commands ()
+__git_complete_strategy ()
{
- if [ -n "$__git_all_commandlist" ]; then
- echo "$__git_all_commandlist"
- return
- fi
+ __git_compute_merge_strategies
+ case "$prev" in
+ -s|--strategy)
+ __gitcomp "$__git_merge_strategies"
+ return 0
+ esac
+ case "$cur" in
+ --strategy=*)
+ __gitcomp "$__git_merge_strategies" "" "${cur##--strategy=}"
+ return 0
+ ;;
+ esac
+ return 1
+}
+
+__git_list_all_commands ()
+{
local i IFS=" "$'\n'
- for i in $(git help -a|egrep '^ ')
+ for i in $(git help -a|egrep '^ [a-zA-Z0-9]')
do
case $i in
*--*) : helper pattern;;
@@ -398,17 +850,18 @@
esac
done
}
-__git_all_commandlist=
-__git_all_commandlist="$(__git_all_commands 2>/dev/null)"
-__git_porcelain_commands ()
+__git_all_commands=
+__git_compute_all_commands ()
{
- if [ -n "$__git_porcelain_commandlist" ]; then
- echo "$__git_porcelain_commandlist"
- return
- fi
+ : ${__git_all_commands:=$(__git_list_all_commands)}
+}
+
+__git_list_porcelain_commands ()
+{
local i IFS=" "$'\n'
- for i in "help" $(__git_all_commands)
+ __git_compute_all_commands
+ for i in "help" $__git_all_commands
do
case $i in
*--*) : helper pattern;;
@@ -459,7 +912,7 @@
quiltimport) : import;;
read-tree) : plumbing;;
receive-pack) : plumbing;;
- reflog) : plumbing;;
+ remote-*) : transport;;
repo-config) : deprecated;;
rerere) : plumbing;;
rev-list) : plumbing;;
@@ -489,17 +942,35 @@
esac
done
}
-__git_porcelain_commandlist=
-__git_porcelain_commandlist="$(__git_porcelain_commands 2>/dev/null)"
+
+__git_porcelain_commands=
+__git_compute_porcelain_commands ()
+{
+ __git_compute_all_commands
+ : ${__git_porcelain_commands:=$(__git_list_porcelain_commands)}
+}
+
+__git_pretty_aliases ()
+{
+ local i IFS=$'\n'
+ for i in $(git --git-dir="$(__gitdir)" config --get-regexp "pretty\..*" 2>/dev/null); do
+ case "$i" in
+ pretty.*)
+ i="${i#pretty.}"
+ echo "${i/ */}"
+ ;;
+ esac
+ done
+}
__git_aliases ()
{
local i IFS=$'\n'
- for i in $(git --git-dir="$(__gitdir)" config --list); do
+ for i in $(git --git-dir="$(__gitdir)" config --get-regexp "alias\..*" 2>/dev/null); do
case "$i" in
alias.*)
i="${i#alias.}"
- echo "${i/=*/}"
+ echo "${i/ */}"
;;
esac
done
@@ -511,20 +982,28 @@
local word cmdline=$(git --git-dir="$(__gitdir)" \
config --get "alias.$1")
for word in $cmdline; do
- if [ "${word##-*}" ]; then
- echo $word
+ case "$word" in
+ \!gitk|gitk)
+ echo "gitk"
return
- fi
+ ;;
+ \!*) : shell command alias ;;
+ -*) : option ;;
+ *=*) : setting env ;;
+ git) : git itself ;;
+ *)
+ echo "$word"
+ return
+ esac
done
}
-# __git_find_subcommand requires 1 argument
-__git_find_subcommand ()
+# __git_find_on_cmdline requires 1 argument
+__git_find_on_cmdline ()
{
local word subcommand c=1
-
- while [ $c -lt $COMP_CWORD ]; do
- word="${COMP_WORDS[c]}"
+ while [ $c -lt $cword ]; do
+ word="${words[c]}"
for subcommand in $1; do
if [ "$subcommand" = "$word" ]; then
echo "$subcommand"
@@ -538,8 +1017,8 @@
__git_has_doubledash ()
{
local c=1
- while [ $c -lt $COMP_CWORD ]; do
- if [ "--" = "${COMP_WORDS[c]}" ]; then
+ while [ $c -lt $cword ]; do
+ if [ "--" = "${words[c]}" ]; then
return 0
fi
c=$((++c))
@@ -551,9 +1030,9 @@
_git_am ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
+ local dir="$(__gitdir)"
if [ -d "$dir"/rebase-apply ]; then
- __gitcomp "--skip --resolved --abort"
+ __gitcomp "--skip --continue --resolved --abort"
return
fi
case "$cur" in
@@ -563,8 +1042,10 @@
;;
--*)
__gitcomp "
- --signoff --utf8 --binary --3way --interactive
- --whitespace=
+ --3way --committer-date-is-author-date --ignore-date
+ --ignore-whitespace --ignore-space-change
+ --interactive --keep --no-utf8 --signoff --utf8
+ --whitespace= --scissors
"
return
esac
@@ -573,7 +1054,6 @@
_git_apply ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--whitespace=*)
__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
@@ -584,6 +1064,7 @@
--stat --numstat --summary --check --index
--cached --index-info --reverse --reject --unidiff-zero
--apply --no-add --exclude=
+ --ignore-whitespace --ignore-space-change
--whitespace= --inaccurate-eof --verbose
"
return
@@ -595,7 +1076,6 @@
{
__git_has_doubledash && return
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
@@ -609,14 +1089,13 @@
_git_archive ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--format=*)
__gitcomp "$(git archive --list)" "" "${cur##--format=}"
return
;;
--remote=*)
- __gitcomp "$(__git_remotes)" "" "${cur##--remote=}"
+ __gitcomp_nl "$(__git_remotes)" "" "${cur##--remote=}"
return
;;
--*)
@@ -635,15 +1114,19 @@
__git_has_doubledash && return
local subcommands="start bad good skip reset visualize replay log run"
- local subcommand="$(__git_find_subcommand "$subcommands")"
+ local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
- __gitcomp "$subcommands"
+ if [ -f "$(__gitdir)"/BISECT_START ]; then
+ __gitcomp "$subcommands"
+ else
+ __gitcomp "replay start"
+ fi
return
fi
case "$subcommand" in
- bad|good|reset|skip)
- __gitcomp "$(__git_refs)"
+ bad|good|reset|skip|start)
+ __gitcomp_nl "$(__git_refs)"
;;
*)
COMPREPLY=()
@@ -655,8 +1138,8 @@
{
local i c=1 only_local_ref="n" has_r="n"
- while [ $c -lt $COMP_CWORD ]; do
- i="${COMP_WORDS[c]}"
+ while [ $c -lt $cword ]; do
+ i="${words[c]}"
case "$i" in
-d|-m) only_local_ref="y" ;;
-r) has_r="y" ;;
@@ -664,18 +1147,19 @@
c=$((++c))
done
- case "${COMP_WORDS[COMP_CWORD]}" in
+ case "$cur" in
--*)
__gitcomp "
--color --no-color --verbose --abbrev= --no-abbrev
--track --no-track --contains --merged --no-merged
+ --set-upstream
"
;;
*)
if [ $only_local_ref = "y" -a $has_r = "n" ]; then
- __gitcomp "$(__git_heads)"
+ __gitcomp_nl "$(__git_heads)"
else
- __gitcomp "$(__git_refs)"
+ __gitcomp_nl "$(__git_refs)"
fi
;;
esac
@@ -683,8 +1167,8 @@
_git_bundle ()
{
- local cmd="${COMP_WORDS[2]}"
- case "$COMP_CWORD" in
+ local cmd="${words[2]}"
+ case "$cword" in
2)
__gitcomp "create list-heads verify unbundle"
;;
@@ -705,7 +1189,26 @@
{
__git_has_doubledash && return
- __gitcomp "$(__git_refs)"
+ case "$cur" in
+ --conflict=*)
+ __gitcomp "diff3 merge" "" "${cur##--conflict=}"
+ ;;
+ --*)
+ __gitcomp "
+ --quiet --ours --theirs --track --no-track --merge
+ --conflict= --orphan --patch
+ "
+ ;;
+ *)
+ # check if --track, --no-track, or --no-guess was specified
+ # if so, disable DWIM mode
+ local flags="--track --no-track --no-guess" track=1
+ if [ -n "$(__git_find_on_cmdline "$flags")" ]; then
+ track=''
+ fi
+ __gitcomp_nl "$(__git_refs '' $track)"
+ ;;
+ esac
}
_git_cherry ()
@@ -715,13 +1218,12 @@
_git_cherry_pick ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--edit --no-commit"
;;
*)
- __gitcomp "$(__git_refs)"
+ __gitcomp_nl "$(__git_refs)"
;;
esac
}
@@ -730,7 +1232,6 @@
{
__git_has_doubledash && return
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--dry-run --quiet"
@@ -742,7 +1243,6 @@
_git_clone ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
@@ -769,12 +1269,29 @@
{
__git_has_doubledash && return
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
+ --cleanup=*)
+ __gitcomp "default strip verbatim whitespace
+ " "" "${cur##--cleanup=}"
+ return
+ ;;
+ --reuse-message=*|--reedit-message=*|\
+ --fixup=*|--squash=*)
+ __gitcomp_nl "$(__git_refs)" "" "${cur#*=}"
+ return
+ ;;
+ --untracked-files=*)
+ __gitcomp "all no normal" "" "${cur##--untracked-files=}"
+ return
+ ;;
--*)
__gitcomp "
--all --author= --signoff --verify --no-verify
--edit --amend --include --only --interactive
+ --dry-run --reuse-message= --reedit-message=
+ --reset-author --file= --message= --template=
+ --cleanup= --untracked-files --untracked-files=
+ --verbose --quiet --fixup= --squash=
"
return
esac
@@ -783,7 +1300,6 @@
_git_describe ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
@@ -792,7 +1308,7 @@
"
return
esac
- __gitcomp "$(__git_refs)"
+ __gitcomp_nl "$(__git_refs)"
}
__git_diff_common_options="--stat --numstat --shortstat --summary
@@ -807,61 +1323,85 @@
--inter-hunk-context=
--patience
--raw
+ --dirstat --dirstat= --dirstat-by-file
+ --dirstat-by-file= --cumulative
"
_git_diff ()
{
__git_has_doubledash && return
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
- __gitcomp "--cached --pickaxe-all --pickaxe-regex
- --base --ours --theirs
+ __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
+ --base --ours --theirs --no-index
$__git_diff_common_options
"
return
;;
esac
+ __git_complete_revlist_file
+}
+
+__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff
+ tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3
+"
+
+_git_difftool ()
+{
+ __git_has_doubledash && return
+
+ case "$cur" in
+ --tool=*)
+ __gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}"
+ return
+ ;;
+ --*)
+ __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
+ --base --ours --theirs
+ --no-renames --diff-filter= --find-copies-harder
+ --relative --ignore-submodules
+ --tool="
+ return
+ ;;
+ esac
__git_complete_file
}
+__git_fetch_options="
+ --quiet --verbose --append --upload-pack --force --keep --depth=
+ --tags --no-tags --all --prune --dry-run
+"
+
_git_fetch ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
-
- if [ "$COMP_CWORD" = 2 ]; then
- __gitcomp "$(__git_remotes)"
- else
- case "$cur" in
- *:*)
- local pfx=""
- case "$COMP_WORDBREAKS" in
- *:*) : great ;;
- *) pfx="${cur%%:*}:" ;;
- esac
- __gitcomp "$(__git_refs)" "$pfx" "${cur#*:}"
- ;;
- *)
- __gitcomp "$(__git_refs2 "${COMP_WORDS[2]}")"
- ;;
- esac
- fi
+ case "$cur" in
+ --*)
+ __gitcomp "$__git_fetch_options"
+ return
+ ;;
+ esac
+ __git_complete_remote_or_refspec
}
_git_format_patch ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
+ --thread=*)
+ __gitcomp "
+ deep shallow
+ " "" "${cur##--thread=}"
+ return
+ ;;
--*)
__gitcomp "
- --stdout --attach --thread
+ --stdout --attach --no-attach --thread --thread=
--output-directory
--numbered --start-number
--numbered-files
--keep-subject
- --signoff
- --in-reply-to=
+ --signoff --signature --no-signature
+ --in-reply-to= --cc=
--full-index --binary
--not --all
--cover-letter
@@ -875,9 +1415,22 @@
__git_complete_revlist
}
+_git_fsck ()
+{
+ case "$cur" in
+ --*)
+ __gitcomp "
+ --tags --root --unreachable --cache --no-reflogs --full
+ --strict --verbose --lost-found
+ "
+ return
+ ;;
+ esac
+ COMPREPLY=()
+}
+
_git_gc ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--prune --aggressive"
@@ -887,49 +1440,68 @@
COMPREPLY=()
}
+_git_gitk ()
+{
+ _gitk
+}
+
+__git_match_ctag() {
+ awk "/^${1////\\/}/ { print \$1 }" "$2"
+}
+
_git_grep ()
{
__git_has_doubledash && return
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
--cached
--text --ignore-case --word-regexp --invert-match
- --full-name
+ --full-name --line-number
--extended-regexp --basic-regexp --fixed-strings
+ --perl-regexp
--files-with-matches --name-only
--files-without-match
+ --max-depth
--count
--and --or --not --all-match
"
return
;;
esac
- COMPREPLY=()
+
+ case "$cword,$prev" in
+ 2,*|*,-*)
+ if test -r tags; then
+ __gitcomp_nl "$(__git_match_ctag "$cur" tags)"
+ return
+ fi
+ ;;
+ esac
+
+ __gitcomp_nl "$(__git_refs)"
}
_git_help ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--all --info --man --web"
return
;;
esac
- __gitcomp "$(__git_all_commands)
+ __git_compute_all_commands
+ __gitcomp "$__git_all_commands $(__git_aliases)
attributes cli core-tutorial cvs-migration
diffcore gitk glossary hooks ignore modules
- repository-layout tutorial tutorial-2
+ namespaces repository-layout tutorial tutorial-2
workflows
"
}
_git_init ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--shared=*)
__gitcomp "
@@ -949,7 +1521,6 @@
{
__git_has_doubledash && return
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--cached --deleted --modified --others --ignored
@@ -967,7 +1538,7 @@
_git_ls_remote ()
{
- __gitcomp "$(__git_remotes)"
+ __gitcomp_nl "$(__git_remotes)"
}
_git_ls_tree ()
@@ -975,43 +1546,71 @@
__git_complete_file
}
+# Options that go well for log, shortlog and gitk
+__git_log_common_options="
+ --not --all
+ --branches --tags --remotes
+ --first-parent --merges --no-merges
+ --max-count=
+ --max-age= --since= --after=
+ --min-age= --until= --before=
+ --min-parents= --max-parents=
+ --no-min-parents --no-max-parents
+"
+# Options that go well for log and gitk (not shortlog)
+__git_log_gitk_options="
+ --dense --sparse --full-history
+ --simplify-merges --simplify-by-decoration
+ --left-right --notes --no-notes
+"
+# Options that go well for log and shortlog (not gitk)
+__git_log_shortlog_options="
+ --author= --committer= --grep=
+ --all-match
+"
+
__git_log_pretty_formats="oneline short medium full fuller email raw format:"
+__git_log_date_formats="relative iso8601 rfc2822 short local default raw"
_git_log ()
{
__git_has_doubledash && return
- local cur="${COMP_WORDS[COMP_CWORD]}"
+ local g="$(git rev-parse --git-dir 2>/dev/null)"
+ local merge=""
+ if [ -f "$g/MERGE_HEAD" ]; then
+ merge="--merge"
+ fi
case "$cur" in
- --pretty=*)
- __gitcomp "$__git_log_pretty_formats
- " "" "${cur##--pretty=}"
+ --pretty=*|--format=*)
+ __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
+ " "" "${cur#*=}"
return
;;
--date=*)
- __gitcomp "
- relative iso8601 rfc2822 short local default
- " "" "${cur##--date=}"
+ __gitcomp "$__git_log_date_formats" "" "${cur##--date=}"
+ return
+ ;;
+ --decorate=*)
+ __gitcomp "long short" "" "${cur##--decorate=}"
return
;;
--*)
__gitcomp "
- --max-count= --max-age= --since= --after=
- --min-age= --before= --until=
+ $__git_log_common_options
+ $__git_log_shortlog_options
+ $__git_log_gitk_options
--root --topo-order --date-order --reverse
- --no-merges --follow
+ --follow --full-diff
--abbrev-commit --abbrev=
--relative-date --date=
- --author= --committer= --grep=
- --all-match
- --pretty=
- --not --all
- --left-right --cherry-pick
+ --pretty= --format= --oneline
+ --cherry-pick
--graph
- --decorate
+ --decorate --decorate=
--walk-reflogs
- --parents --children --full-history
- --merge
+ --parents --children
+ $merge
$__git_diff_common_options
--pickaxe-all --pickaxe-regex
"
@@ -1021,37 +1620,28 @@
__git_complete_revlist
}
+__git_merge_options="
+ --no-commit --no-stat --log --no-log --squash --strategy
+ --commit --stat --no-squash --ff --no-ff --ff-only
+"
+
_git_merge ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
- case "${COMP_WORDS[COMP_CWORD-1]}" in
- -s|--strategy)
- __gitcomp "$(__git_merge_strategies)"
- return
- esac
+ __git_complete_strategy && return
+
case "$cur" in
- --strategy=*)
- __gitcomp "$(__git_merge_strategies)" "" "${cur##--strategy=}"
- return
- ;;
--*)
- __gitcomp "
- --no-commit --no-stat --log --no-log --squash --strategy
- "
+ __gitcomp "$__git_merge_options"
return
esac
- __gitcomp "$(__git_refs)"
+ __gitcomp_nl "$(__git_refs)"
}
_git_mergetool ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--tool=*)
- __gitcomp "
- kdiff3 tkdiff meld xxdiff emerge
- vimdiff gvimdiff ecmerge opendiff
- " "" "${cur##--tool=}"
+ __gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}"
return
;;
--*)
@@ -1064,12 +1654,11 @@
_git_merge_base ()
{
- __gitcomp "$(__git_refs)"
+ __gitcomp_nl "$(__git_refs)"
}
_git_mv ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--dry-run"
@@ -1084,80 +1673,164 @@
__gitcomp "--tags --all --stdin"
}
+_git_notes ()
+{
+ local subcommands='add append copy edit list prune remove show'
+ local subcommand="$(__git_find_on_cmdline "$subcommands")"
+
+ case "$subcommand,$cur" in
+ ,--*)
+ __gitcomp '--ref'
+ ;;
+ ,*)
+ case "${words[cword-1]}" in
+ --ref)
+ __gitcomp_nl "$(__git_refs)"
+ ;;
+ *)
+ __gitcomp "$subcommands --ref"
+ ;;
+ esac
+ ;;
+ add,--reuse-message=*|append,--reuse-message=*|\
+ add,--reedit-message=*|append,--reedit-message=*)
+ __gitcomp_nl "$(__git_refs)" "" "${cur#*=}"
+ ;;
+ add,--*|append,--*)
+ __gitcomp '--file= --message= --reedit-message=
+ --reuse-message='
+ ;;
+ copy,--*)
+ __gitcomp '--stdin'
+ ;;
+ prune,--*)
+ __gitcomp '--dry-run --verbose'
+ ;;
+ prune,*)
+ ;;
+ *)
+ case "${words[cword-1]}" in
+ -m|-F)
+ ;;
+ *)
+ __gitcomp_nl "$(__git_refs)"
+ ;;
+ esac
+ ;;
+ esac
+}
+
_git_pull ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
+ __git_complete_strategy && return
- if [ "$COMP_CWORD" = 2 ]; then
- __gitcomp "$(__git_remotes)"
- else
- __gitcomp "$(__git_refs "${COMP_WORDS[2]}")"
- fi
+ case "$cur" in
+ --*)
+ __gitcomp "
+ --rebase --no-rebase
+ $__git_merge_options
+ $__git_fetch_options
+ "
+ return
+ ;;
+ esac
+ __git_complete_remote_or_refspec
}
_git_push ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
-
- if [ "$COMP_CWORD" = 2 ]; then
- __gitcomp "$(__git_remotes)"
- else
- case "$cur" in
- *:*)
- local pfx=""
- case "$COMP_WORDBREAKS" in
- *:*) : great ;;
- *) pfx="${cur%%:*}:" ;;
- esac
-
- __gitcomp "$(__git_refs "${COMP_WORDS[2]}")" "$pfx" "${cur#*:}"
- ;;
- +*)
- __gitcomp "$(__git_refs)" + "${cur#+}"
- ;;
- *)
- __gitcomp "$(__git_refs)"
- ;;
- esac
- fi
+ case "$prev" in
+ --repo)
+ __gitcomp_nl "$(__git_remotes)"
+ return
+ esac
+ case "$cur" in
+ --repo=*)
+ __gitcomp_nl "$(__git_remotes)" "" "${cur##--repo=}"
+ return
+ ;;
+ --*)
+ __gitcomp "
+ --all --mirror --tags --dry-run --force --verbose
+ --receive-pack= --repo= --set-upstream
+ "
+ return
+ ;;
+ esac
+ __git_complete_remote_or_refspec
}
_git_rebase ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
+ local dir="$(__gitdir)"
if [ -d "$dir"/rebase-apply ] || [ -d "$dir"/rebase-merge ]; then
__gitcomp "--continue --skip --abort"
return
fi
- case "${COMP_WORDS[COMP_CWORD-1]}" in
- -s|--strategy)
- __gitcomp "$(__git_merge_strategies)"
- return
- esac
+ __git_complete_strategy && return
case "$cur" in
- --strategy=*)
- __gitcomp "$(__git_merge_strategies)" "" "${cur##--strategy=}"
+ --whitespace=*)
+ __gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
return
;;
--*)
- __gitcomp "--onto --merge --strategy --interactive"
+ __gitcomp "
+ --onto --merge --strategy --interactive
+ --preserve-merges --stat --no-stat
+ --committer-date-is-author-date --ignore-date
+ --ignore-whitespace --whitespace=
+ --autosquash
+ "
+
return
esac
- __gitcomp "$(__git_refs)"
+ __gitcomp_nl "$(__git_refs)"
}
+_git_reflog ()
+{
+ local subcommands="show delete expire"
+ local subcommand="$(__git_find_on_cmdline "$subcommands")"
+
+ if [ -z "$subcommand" ]; then
+ __gitcomp "$subcommands"
+ else
+ __gitcomp_nl "$(__git_refs)"
+ fi
+}
+
+__git_send_email_confirm_options="always never auto cc compose"
+__git_send_email_suppresscc_options="author self cc bodycc sob cccmd body all"
+
_git_send_email ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
+ --confirm=*)
+ __gitcomp "
+ $__git_send_email_confirm_options
+ " "" "${cur##--confirm=}"
+ return
+ ;;
+ --suppress-cc=*)
+ __gitcomp "
+ $__git_send_email_suppresscc_options
+ " "" "${cur##--suppress-cc=}"
+
+ return
+ ;;
+ --smtp-encryption=*)
+ __gitcomp "ssl tls" "" "${cur##--smtp-encryption=}"
+ return
+ ;;
--*)
- __gitcomp "--bcc --cc --cc-cmd --chain-reply-to --compose
- --dry-run --envelope-sender --from --identity
+ __gitcomp "--annotate --bcc --cc --cc-cmd --chain-reply-to
+ --compose --confirm= --dry-run --envelope-sender
+ --from --identity
--in-reply-to --no-chain-reply-to --no-signed-off-by-cc
--no-suppress-from --no-thread --quiet
--signed-off-by-cc --smtp-pass --smtp-server
- --smtp-server-port --smtp-ssl --smtp-user --subject
- --suppress-cc --suppress-from --thread --to
+ --smtp-server-port --smtp-encryption= --smtp-user
+ --subject --suppress-cc= --suppress-from --thread --to
--validate --no-validate"
return
;;
@@ -1165,41 +1838,84 @@
COMPREPLY=()
}
+_git_stage ()
+{
+ _git_add
+}
+
+__git_config_get_set_variables ()
+{
+ local prevword word config_file= c=$cword
+ while [ $c -gt 1 ]; do
+ word="${words[c]}"
+ case "$word" in
+ --global|--system|--file=*)
+ config_file="$word"
+ break
+ ;;
+ -f|--file)
+ config_file="$word $prevword"
+ break
+ ;;
+ esac
+ prevword=$word
+ c=$((--c))
+ done
+
+ git --git-dir="$(__gitdir)" config $config_file --list 2>/dev/null |
+ while read -r line
+ do
+ case "$line" in
+ *.*=*)
+ echo "${line/=*/}"
+ ;;
+ esac
+ done
+}
+
_git_config ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
- local prv="${COMP_WORDS[COMP_CWORD-1]}"
- case "$prv" in
+ case "$prev" in
branch.*.remote)
- __gitcomp "$(__git_remotes)"
+ __gitcomp_nl "$(__git_remotes)"
return
;;
branch.*.merge)
- __gitcomp "$(__git_refs)"
+ __gitcomp_nl "$(__git_refs)"
return
;;
remote.*.fetch)
- local remote="${prv#remote.}"
+ local remote="${prev#remote.}"
remote="${remote%.fetch}"
- __gitcomp "$(__git_refs_remotes "$remote")"
+ if [ -z "$cur" ]; then
+ COMPREPLY=("refs/heads/")
+ return
+ fi
+ __gitcomp_nl "$(__git_refs_remotes "$remote")"
return
;;
remote.*.push)
- local remote="${prv#remote.}"
+ local remote="${prev#remote.}"
remote="${remote%.push}"
- __gitcomp "$(git --git-dir="$(__gitdir)" \
+ __gitcomp_nl "$(git --git-dir="$(__gitdir)" \
for-each-ref --format='%(refname):%(refname)' \
refs/heads)"
return
;;
pull.twohead|pull.octopus)
- __gitcomp "$(__git_merge_strategies)"
+ __git_compute_merge_strategies
+ __gitcomp "$__git_merge_strategies"
return
;;
- color.branch|color.diff|color.status)
+ color.branch|color.diff|color.interactive|\
+ color.showbranch|color.status|color.ui)
__gitcomp "always never auto"
return
;;
+ color.pager)
+ __gitcomp "false true"
+ return
+ ;;
color.*.*)
__gitcomp "
normal black red green yellow blue magenta cyan white
@@ -1207,6 +1923,30 @@
"
return
;;
+ help.format)
+ __gitcomp "man info web html"
+ return
+ ;;
+ log.date)
+ __gitcomp "$__git_log_date_formats"
+ return
+ ;;
+ sendemail.aliasesfiletype)
+ __gitcomp "mutt mailrc pine elm gnus"
+ return
+ ;;
+ sendemail.confirm)
+ __gitcomp "$__git_send_email_confirm_options"
+ return
+ ;;
+ sendemail.suppresscc)
+ __gitcomp "$__git_send_email_suppresscc_options"
+ return
+ ;;
+ --get|--get-all|--unset|--unset-all)
+ __gitcomp_nl "$(__git_config_get_set_variables)"
+ return
+ ;;
*.*)
COMPREPLY=()
return
@@ -1224,56 +1964,113 @@
return
;;
branch.*.*)
- local pfx="${cur%.*}."
- cur="${cur##*.}"
- __gitcomp "remote merge mergeoptions" "$pfx" "$cur"
+ local pfx="${cur%.*}." cur_="${cur##*.}"
+ __gitcomp "remote merge mergeoptions rebase" "$pfx" "$cur_"
return
;;
branch.*)
- local pfx="${cur%.*}."
- cur="${cur#*.}"
- __gitcomp "$(__git_heads)" "$pfx" "$cur" "."
+ local pfx="${cur%.*}." cur_="${cur#*.}"
+ __gitcomp_nl "$(__git_heads)" "$pfx" "$cur_" "."
+ return
+ ;;
+ guitool.*.*)
+ local pfx="${cur%.*}." cur_="${cur##*.}"
+ __gitcomp "
+ argprompt cmd confirm needsfile noconsole norescan
+ prompt revprompt revunmerged title
+ " "$pfx" "$cur_"
+ return
+ ;;
+ difftool.*.*)
+ local pfx="${cur%.*}." cur_="${cur##*.}"
+ __gitcomp "cmd path" "$pfx" "$cur_"
+ return
+ ;;
+ man.*.*)
+ local pfx="${cur%.*}." cur_="${cur##*.}"
+ __gitcomp "cmd path" "$pfx" "$cur_"
+ return
+ ;;
+ mergetool.*.*)
+ local pfx="${cur%.*}." cur_="${cur##*.}"
+ __gitcomp "cmd path trustExitCode" "$pfx" "$cur_"
+ return
+ ;;
+ pager.*)
+ local pfx="${cur%.*}." cur_="${cur#*.}"
+ __git_compute_all_commands
+ __gitcomp_nl "$__git_all_commands" "$pfx" "$cur_"
return
;;
remote.*.*)
- local pfx="${cur%.*}."
- cur="${cur##*.}"
+ local pfx="${cur%.*}." cur_="${cur##*.}"
__gitcomp "
url proxy fetch push mirror skipDefaultUpdate
- receivepack uploadpack tagopt
- " "$pfx" "$cur"
+ receivepack uploadpack tagopt pushurl
+ " "$pfx" "$cur_"
return
;;
remote.*)
- local pfx="${cur%.*}."
- cur="${cur#*.}"
- __gitcomp "$(__git_remotes)" "$pfx" "$cur" "."
+ local pfx="${cur%.*}." cur_="${cur#*.}"
+ __gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "."
+ return
+ ;;
+ url.*.*)
+ local pfx="${cur%.*}." cur_="${cur##*.}"
+ __gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur_"
return
;;
esac
__gitcomp "
+ add.ignoreErrors
+ advice.commitBeforeMerge
+ advice.detachedHead
+ advice.implicitIdentity
+ advice.pushNonFastForward
+ advice.resolveConflict
+ advice.statusHints
+ alias.
+ am.keepcr
+ apply.ignorewhitespace
apply.whitespace
branch.autosetupmerge
branch.autosetuprebase
+ browser.
clean.requireForce
color.branch
color.branch.current
color.branch.local
color.branch.plain
color.branch.remote
+ color.decorate.HEAD
+ color.decorate.branch
+ color.decorate.remoteBranch
+ color.decorate.stash
+ color.decorate.tag
color.diff
color.diff.commit
color.diff.frag
+ color.diff.func
color.diff.meta
color.diff.new
color.diff.old
color.diff.plain
color.diff.whitespace
+ color.grep
+ color.grep.context
+ color.grep.filename
+ color.grep.function
+ color.grep.linenumber
+ color.grep.match
+ color.grep.selected
+ color.grep.separator
color.interactive
+ color.interactive.error
color.interactive.header
color.interactive.help
color.interactive.prompt
color.pager
+ color.showbranch
color.status
color.status.added
color.status.changed
@@ -1282,20 +2079,29 @@
color.status.untracked
color.status.updated
color.ui
+ commit.status
commit.template
+ core.abbrev
+ core.askpass
+ core.attributesfile
core.autocrlf
core.bare
+ core.bigFileThreshold
core.compression
+ core.createObject
core.deltaBaseCacheLimit
core.editor
+ core.eol
core.excludesfile
core.fileMode
core.fsyncobjectfiles
core.gitProxy
core.ignoreCygwinFSTricks
core.ignoreStat
+ core.ignorecase
core.logAllRefUpdates
core.loosecompression
+ core.notesRef
core.packedGitLimit
core.packedGitWindowSize
core.pager
@@ -1305,6 +2111,7 @@
core.repositoryFormatVersion
core.safecrlf
core.sharedRepository
+ core.sparseCheckout
core.symlinks
core.trustctime
core.warnAmbiguousRefs
@@ -1312,15 +2119,30 @@
core.worktree
diff.autorefreshindex
diff.external
+ diff.ignoreSubmodules
diff.mnemonicprefix
+ diff.noprefix
diff.renameLimit
- diff.renameLimit.
diff.renames
+ diff.suppressBlankEmpty
+ diff.tool
+ diff.wordRegex
+ difftool.
+ difftool.prompt
+ fetch.recurseSubmodules
fetch.unpackLimit
+ format.attach
+ format.cc
format.headers
format.numbered
format.pretty
+ format.signature
+ format.signoff
+ format.subjectprefix
format.suffix
+ format.thread
+ format.to
+ gc.
gc.aggressiveWindow
gc.auto
gc.autopacklimit
@@ -1331,6 +2153,7 @@
gc.rerereresolved
gc.rerereunresolved
gitcvs.allbinary
+ gitcvs.commitmsgannotation
gitcvs.dbTableNamePrefix
gitcvs.dbdriver
gitcvs.dbname
@@ -1339,6 +2162,7 @@
gitcvs.enabled
gitcvs.logfile
gitcvs.usecrlfattr
+ guitool.
gui.blamehistoryctx
gui.commitmsgwidth
gui.copyblamethreshold
@@ -1356,30 +2180,59 @@
http.lowSpeedLimit
http.lowSpeedTime
http.maxRequests
+ http.minSessions
http.noEPSV
+ http.postBuffer
http.proxy
http.sslCAInfo
http.sslCAPath
http.sslCert
+ http.sslCertPasswordProtected
http.sslKey
http.sslVerify
+ http.useragent
i18n.commitEncoding
i18n.logOutputEncoding
+ imap.authMethod
+ imap.folder
+ imap.host
+ imap.pass
+ imap.port
+ imap.preformattedHTML
+ imap.sslverify
+ imap.tunnel
+ imap.user
+ init.templatedir
instaweb.browser
instaweb.httpd
instaweb.local
instaweb.modulepath
instaweb.port
+ interactive.singlekey
log.date
+ log.decorate
log.showroot
+ mailmap.file
+ man.
man.viewer
+ merge.
merge.conflictstyle
merge.log
merge.renameLimit
+ merge.renormalize
merge.stat
merge.tool
merge.verbosity
+ mergetool.
mergetool.keepBackup
+ mergetool.keepTemporaries
+ mergetool.prompt
+ notes.displayRef
+ notes.rewrite.
+ notes.rewrite.amend
+ notes.rewrite.rebase
+ notes.rewriteMode
+ notes.rewriteRef
pack.compression
pack.deltaCacheLimit
pack.deltaCacheSize
@@ -1389,21 +2242,58 @@
pack.threads
pack.window
pack.windowMemory
+ pager.
+ pretty.
pull.octopus
pull.twohead
+ push.default
+ rebase.autosquash
+ rebase.stat
+ receive.autogc
receive.denyCurrentBranch
+ receive.denyDeleteCurrent
receive.denyDeletes
receive.denyNonFastForwards
receive.fsckObjects
receive.unpackLimit
+ receive.updateserverinfo
+ remotes.
repack.usedeltabaseoffset
rerere.autoupdate
rerere.enabled
+ sendemail.
+ sendemail.aliasesfile
+ sendemail.aliasfiletype
+ sendemail.bcc
+ sendemail.cc
+ sendemail.cccmd
+ sendemail.chainreplyto
+ sendemail.confirm
+ sendemail.envelopesender
+ sendemail.from
+ sendemail.identity
+ sendemail.multiedit
+ sendemail.signedoffbycc
+ sendemail.smtpdomain
+ sendemail.smtpencryption
+ sendemail.smtppass
+ sendemail.smtpserver
+ sendemail.smtpserveroption
+ sendemail.smtpserverport
+ sendemail.smtpuser
+ sendemail.suppresscc
+ sendemail.suppressfrom
+ sendemail.thread
+ sendemail.to
+ sendemail.validate
showbranch.default
status.relativePaths
status.showUntrackedFiles
+ status.submodulesummary
+ submodule.
tar.umask
transfer.unpackLimit
+ url.
user.email
user.name
user.signingkey
@@ -1414,8 +2304,8 @@
_git_remote ()
{
- local subcommands="add rename rm show prune update"
- local subcommand="$(__git_find_subcommand "$subcommands")"
+ local subcommands="add rename rm show prune update set-head"
+ local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
__gitcomp "$subcommands"
return
@@ -1423,17 +2313,13 @@
case "$subcommand" in
rename|rm|show|prune)
- __gitcomp "$(__git_remotes)"
+ __gitcomp_nl "$(__git_remotes)"
;;
update)
local i c='' IFS=$'\n'
- for i in $(git --git-dir="$(__gitdir)" config --list); do
- case "$i" in
- remotes.*)
- i="${i#remotes.}"
- c="$c ${i/=*/}"
- ;;
- esac
+ for i in $(git --git-dir="$(__gitdir)" config --get-regexp "remotes\..*" 2>/dev/null); do
+ i="${i#remotes.}"
+ c="$c ${i/ */}"
done
__gitcomp "$c"
;;
@@ -1443,37 +2329,39 @@
esac
}
+_git_replace ()
+{
+ __gitcomp_nl "$(__git_refs)"
+}
+
_git_reset ()
{
__git_has_doubledash && return
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
- __gitcomp "--merge --mixed --hard --soft"
+ __gitcomp "--merge --mixed --hard --soft --patch"
return
;;
esac
- __gitcomp "$(__git_refs)"
+ __gitcomp_nl "$(__git_refs)"
}
_git_revert ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--edit --mainline --no-edit --no-commit --signoff"
return
;;
esac
- __gitcomp "$(__git_refs)"
+ __gitcomp_nl "$(__git_refs)"
}
_git_rm ()
{
__git_has_doubledash && return
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "--cached --dry-run --ignore-unmatch --quiet"
@@ -1487,16 +2375,11 @@
{
__git_has_doubledash && return
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
- --max-count= --max-age= --since= --after=
- --min-age= --before= --until=
- --no-merges
- --author= --committer= --grep=
- --all-match
- --not --all
+ $__git_log_common_options
+ $__git_log_shortlog_options
--numbered --summary
"
return
@@ -1509,15 +2392,14 @@
{
__git_has_doubledash && return
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
- --pretty=*)
- __gitcomp "$__git_log_pretty_formats
- " "" "${cur##--pretty=}"
+ --pretty=*|--format=*)
+ __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
+ " "" "${cur#*=}"
return
;;
--*)
- __gitcomp "--pretty=
+ __gitcomp "--pretty= --format= --abbrev-commit --oneline
$__git_diff_common_options
"
return
@@ -1528,13 +2410,13 @@
_git_show_branch ()
{
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$cur" in
--*)
__gitcomp "
--all --remotes --topo-order --current --more=
--list --independent --merge-base --no-name
- --sha1-name --topics --reflog
+ --color --no-color
+ --sha1-name --sparse --topics --reflog
"
return
;;
@@ -1544,24 +2426,35 @@
_git_stash ()
{
+ local save_opts='--keep-index --no-keep-index --quiet --patch'
local subcommands='save list show apply clear drop pop create branch'
- local subcommand="$(__git_find_subcommand "$subcommands")"
+ local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
- __gitcomp "$subcommands"
+ case "$cur" in
+ --*)
+ __gitcomp "$save_opts"
+ ;;
+ *)
+ if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then
+ __gitcomp "$subcommands"
+ else
+ COMPREPLY=()
+ fi
+ ;;
+ esac
else
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$subcommand,$cur" in
save,--*)
- __gitcomp "--keep-index"
+ __gitcomp "$save_opts"
;;
- apply,--*)
- __gitcomp "--index"
+ apply,--*|pop,--*)
+ __gitcomp "--index --quiet"
;;
- show,--*|drop,--*|pop,--*|branch,--*)
+ show,--*|drop,--*|branch,--*)
COMPREPLY=()
;;
show,*|apply,*|drop,*|pop,*|branch,*)
- __gitcomp "$(git --git-dir="$(__gitdir)" stash list \
+ __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \
| sed -n -e 's/:.*//p')"
;;
*)
@@ -1576,8 +2469,7 @@
__git_has_doubledash && return
local subcommands="add status init update summary foreach sync"
- if [ -z "$(__git_find_subcommand "$subcommands")" ]; then
- local cur="${COMP_WORDS[COMP_CWORD]}"
+ if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
case "$cur" in
--*)
__gitcomp "--quiet --cached"
@@ -1595,9 +2487,10 @@
local subcommands="
init fetch clone rebase dcommit log find-rev
set-tree commit-diff info create-ignore propget
- proplist show-ignore show-externals
+ proplist show-ignore show-externals branch tag blame
+ migrate mkdirs reset gc
"
- local subcommand="$(__git_find_subcommand "$subcommands")"
+ local subcommand="$(__git_find_on_cmdline "$subcommands")"
if [ -z "$subcommand" ]; then
__gitcomp "$subcommands"
else
@@ -1606,19 +2499,20 @@
--follow-parent --authors-file= --repack=
--no-metadata --use-svm-props --use-svnsync-props
--log-window-size= --no-checkout --quiet
- --repack-flags --user-log-author --localtime $remote_opts
+ --repack-flags --use-log-author --localtime
+ --ignore-paths= $remote_opts
"
local init_opts="
--template= --shared= --trunk= --tags=
--branches= --stdlayout --minimize-url
--no-metadata --use-svm-props --use-svnsync-props
- --rewrite-root= $remote_opts
+ --rewrite-root= --prefix= --use-log-author
+ --add-author-from $remote_opts
"
local cmt_opts="
--edit --rmdir --find-copies-harder --copy-similarity=
"
- local cur="${COMP_WORDS[COMP_CWORD]}"
case "$subcommand,$cur" in
fetch,--*)
__gitcomp "--revision= --fetch-all $fc_opts"
@@ -1632,27 +2526,28 @@
dcommit,--*)
__gitcomp "
--merge --strategy= --verbose --dry-run
- --fetch-all --no-rebase $cmt_opts $fc_opts
+ --fetch-all --no-rebase --commit-url
+ --revision $cmt_opts $fc_opts
"
;;
set-tree,--*)
__gitcomp "--stdin $cmt_opts $fc_opts"
;;
create-ignore,--*|propget,--*|proplist,--*|show-ignore,--*|\
- show-externals,--*)
+ show-externals,--*|mkdirs,--*)
__gitcomp "--revision="
;;
log,--*)
__gitcomp "
--limit= --revision= --verbose --incremental
--oneline --show-commit --non-recursive
- --authors-file=
+ --authors-file= --color
"
;;
rebase,--*)
__gitcomp "
--merge --verbose --strategy= --local
- --fetch-all $fc_opts
+ --fetch-all --dry-run $fc_opts
"
;;
commit-diff,--*)
@@ -1661,6 +2556,24 @@
info,--*)
__gitcomp "--url"
;;
+ branch,--*)
+ __gitcomp "--dry-run --message --tag"
+ ;;
+ tag,--*)
+ __gitcomp "--dry-run --message"
+ ;;
+ blame,--*)
+ __gitcomp "--git-format"
+ ;;
+ migrate,--*)
+ __gitcomp "
+ --config-dir= --ignore-paths= --minimize
+ --no-auth-cache --username=
+ "
+ ;;
+ reset,--*)
+ __gitcomp "--revision= --parent"
+ ;;
*)
COMPREPLY=()
;;
@@ -1671,11 +2584,11 @@
_git_tag ()
{
local i c=1 f=0
- while [ $c -lt $COMP_CWORD ]; do
- i="${COMP_WORDS[c]}"
+ while [ $c -lt $cword ]; do
+ i="${words[c]}"
case "$i" in
-d|-v)
- __gitcomp "$(__git_tags)"
+ __gitcomp_nl "$(__git_tags)"
return
;;
-f)
@@ -1685,29 +2598,49 @@
c=$((++c))
done
- case "${COMP_WORDS[COMP_CWORD-1]}" in
+ case "$prev" in
-m|-F)
COMPREPLY=()
;;
-*|tag)
if [ $f = 1 ]; then
- __gitcomp "$(__git_tags)"
+ __gitcomp_nl "$(__git_tags)"
else
COMPREPLY=()
fi
;;
*)
- __gitcomp "$(__git_refs)"
+ __gitcomp_nl "$(__git_refs)"
;;
esac
}
+_git_whatchanged ()
+{
+ _git_log
+}
+
_git ()
{
local i c=1 command __git_dir
- while [ $c -lt $COMP_CWORD ]; do
- i="${COMP_WORDS[c]}"
+ if [[ -n ${ZSH_VERSION-} ]]; then
+ emulate -L bash
+ setopt KSH_TYPESET
+
+ # workaround zsh's bug that leaves 'words' as a special
+ # variable in versions < 4.3.12
+ typeset -h words
+
+ # workaround zsh's bug that quotes spaces in the COMPREPLY
+ # array if IFS doesn't contain spaces.
+ typeset -h IFS
+ fi
+
+ local cur words cword prev
+ _get_comp_words_by_ref -n =: cur words cword prev
+ while [ $c -lt $cword ]; do
+ i="${words[c]}"
case "$i" in
--git-dir=*) __git_dir="${i#--git-dir=}" ;;
--bare) __git_dir="." ;;
@@ -1719,7 +2652,7 @@
done
if [ -z "$command" ]; then
- case "${COMP_WORDS[COMP_CWORD]}" in
+ case "$cur" in
--*) __gitcomp "
--paginate
--no-pager
@@ -1727,84 +2660,60 @@
--bare
--version
--exec-path
+ --html-path
--work-tree=
+ --namespace=
--help
"
;;
- *) __gitcomp "$(__git_porcelain_commands) $(__git_aliases)" ;;
+ *) __git_compute_porcelain_commands
+ __gitcomp "$__git_porcelain_commands $(__git_aliases)" ;;
esac
return
fi
- local expansion=$(__git_aliased_command "$command")
- [ "$expansion" ] && command="$expansion"
+ local completion_func="_git_${command//-/_}"
+ declare -f $completion_func >/dev/null && $completion_func && return
- case "$command" in
- am) _git_am ;;
- add) _git_add ;;
- apply) _git_apply ;;
- archive) _git_archive ;;
- bisect) _git_bisect ;;
- bundle) _git_bundle ;;
- branch) _git_branch ;;
- checkout) _git_checkout ;;
- cherry) _git_cherry ;;
- cherry-pick) _git_cherry_pick ;;
- clean) _git_clean ;;
- clone) _git_clone ;;
- commit) _git_commit ;;
- config) _git_config ;;
- describe) _git_describe ;;
- diff) _git_diff ;;
- fetch) _git_fetch ;;
- format-patch) _git_format_patch ;;
- gc) _git_gc ;;
- grep) _git_grep ;;
- help) _git_help ;;
- init) _git_init ;;
- log) _git_log ;;
- ls-files) _git_ls_files ;;
- ls-remote) _git_ls_remote ;;
- ls-tree) _git_ls_tree ;;
- merge) _git_merge;;
- mergetool) _git_mergetool;;
- merge-base) _git_merge_base ;;
- mv) _git_mv ;;
- name-rev) _git_name_rev ;;
- pull) _git_pull ;;
- push) _git_push ;;
- rebase) _git_rebase ;;
- remote) _git_remote ;;
- reset) _git_reset ;;
- revert) _git_revert ;;
- rm) _git_rm ;;
- send-email) _git_send_email ;;
- shortlog) _git_shortlog ;;
- show) _git_show ;;
- show-branch) _git_show_branch ;;
- stash) _git_stash ;;
- stage) _git_add ;;
- submodule) _git_submodule ;;
- svn) _git_svn ;;
- tag) _git_tag ;;
- whatchanged) _git_log ;;
- *) COMPREPLY=() ;;
- esac
+ local expansion=$(__git_aliased_command "$command")
+ if [ -n "$expansion" ]; then
+ completion_func="_git_${expansion//-/_}"
+ declare -f $completion_func >/dev/null && $completion_func
+ fi
}
_gitk ()
{
+ if [[ -n ${ZSH_VERSION-} ]]; then
+ emulate -L bash
+ setopt KSH_TYPESET
+
+ # workaround zsh's bug that leaves 'words' as a special
+ # variable in versions < 4.3.12
+ typeset -h words
+
+ # workaround zsh's bug that quotes spaces in the COMPREPLY
+ # array if IFS doesn't contain spaces.
+ typeset -h IFS
+ fi
+
+ local cur words cword prev
+ _get_comp_words_by_ref -n =: cur words cword prev
+
__git_has_doubledash && return
- local cur="${COMP_WORDS[COMP_CWORD]}"
- local g="$(git rev-parse --git-dir 2>/dev/null)"
+ local g="$(__gitdir)"
local merge=""
- if [ -f $g/MERGE_HEAD ]; then
+ if [ -f "$g/MERGE_HEAD" ]; then
merge="--merge"
fi
case "$cur" in
--*)
- __gitcomp "--not --all $merge"
+ __gitcomp "
+ $__git_log_common_options
+ $__git_log_gitk_options
+ $merge
+ "
return
;;
esac
@@ -1815,3 +2724,42 @@
|| complete -o default -o nospace -F _git git
complete -o bashdefault -o default -o nospace -F _gitk gitk 2>/dev/null \
|| complete -o default -o nospace -F _gitk gitk
+
+# The following are necessary only for Cygwin, and only are needed
+# when the user has tab-completed the executable name and consequently
+# included the '.exe' suffix.
+#
+if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
+complete -o bashdefault -o default -o nospace -F _git git.exe 2>/dev/null \
+ || complete -o default -o nospace -F _git git.exe
+fi
+
+if [[ -n ${ZSH_VERSION-} ]]; then
+ __git_shopt () {
+ local option
+ if [ $# -ne 2 ]; then
+ echo "USAGE: $0 (-q|-s|-u) <option>" >&2
+ return 1
+ fi
+ case "$2" in
+ nullglob)
+ option="$2"
+ ;;
+ *)
+ echo "$0: invalid option: $2" >&2
+ return 1
+ esac
+ case "$1" in
+ -q) setopt | grep -q "$option" ;;
+ -u) unsetopt "$option" ;;
+ -s) setopt "$option" ;;
+ *)
+ echo "$0: invalid flag: $1" >&2
+ return 1
+ esac
+ }
+else
+ __git_shopt () {
+ shopt "$@"
+ }
+fi
diff --git a/completion/available/tmux.completion.bash b/completion/available/tmux.completion.bash
index c872ec5..a1b8f06 100644
--- a/completion/available/tmux.completion.bash
+++ b/completion/available/tmux.completion.bash
@@ -5,6 +5,90 @@
# Usage: Put "source bash_completion_tmux.sh" into your .bashrc
# Based upon the example at http://paste-it.appspot.com/Pj4mLycDE
+ _tmux_cmds=" \
+attach-session \
+bind-key \
+break-pane \
+capture-pane \
+choose-client \
+choose-session \
+choose-window \
+clear-history \
+clock-mode \
+command-prompt \
+confirm-before \
+copy-buffer \
+copy-mode \
+delete-buffer \
+detach-client \
+display-message \
+display-panes \
+down-pane \
+find-window \
+has-session \
+if-shell \
+join-pane \
+kill-pane \
+kill-server \
+kill-session \
+kill-window \
+last-window \
+link-window \
+list-buffers \
+list-clients \
+list-commands \
+list-keys \
+list-panes \
+list-sessions \
+list-windows \
+load-buffer \
+lock-client \
+lock-server \
+lock-session \
+move-window \
+new-session \
+new-window \
+next-layout \
+next-window \
+paste-buffer \
+pipe-pane \
+previous-layout \
+previous-window \
+refresh-client \
+rename-session \
+rename-window \
+resize-pane \
+respawn-window \
+rotate-window \
+run-shell \
+save-buffer \
+select-layout \
+select-pane \
+select-prompt \
+select-window \
+send-keys \
+send-prefix \
+server-info \
+set-buffer \
+set-environment \
+set-option \
+set-window-option \
+show-buffer \
+show-environment \
+show-messages \
+show-options \
+show-window-options \
+source-file \
+split-window \
+start-server \
+suspend-client \
+swap-pane \
+swap-window \
+switch-client \
+unbind-key \
+unlink-window \
+up-pane"
+
_tmux_expand ()
{
[ "$cur" != "${cur%\\}" ] && cur="$cur"'\';
@@ -34,12 +118,12 @@
function _tmux_complete_client() {
local IFS=$'\n'
local cur="${1}"
- COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "$(tmux -q list-clients | cut -f 1 -d ':')" -- "${cur}") )
+ COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "$(tmux -q list-clients 2>/dev/null | cut -f 1 -d ':')" -- "${cur}") )
}
function _tmux_complete_session() {
local IFS=$'\n'
local cur="${1}"
- COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "$(tmux -q list-sessions | cut -f 1 -d ':')" -- "${cur}") )
+ COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "$(tmux -q list-sessions 2>/dev/null | cut -f 1 -d ':')" -- "${cur}") )
}
function _tmux_complete_window() {
local IFS=$'\n'
@@ -47,10 +131,10 @@
local session_name="$(echo "${cur}" | sed 's/\\//g' | cut -d ':' -f 1)"
local sessions
- sessions="$(tmux -q list-sessions | sed -re 's/([^:]+:).*$/\1/')"
+ sessions="$(tmux -q list-sessions 2>/dev/null | sed -re 's/([^:]+:).*$/\1/')"
if [[ -n "${session_name}" ]]; then
sessions="${sessions}
-$(tmux -q list-windows -t "${session_name}" | sed -re 's/^([^:]+):.*$/'"${session_name}"':\1/')"
+$(tmux -q list-windows -t "${session_name}" 2>/dev/null | sed -re 's/^([^:]+):.*$/'"${session_name}"':\1/')"
fi
cur="$(echo "${cur}" | sed -e 's/:/\\\\:/')"
sessions="$(echo "${sessions}" | sed -e 's/:/\\\\:/')"
@@ -102,8 +186,7 @@
if [[ $COMP_CWORD -le $cmd_index ]]; then
# The user has not specified a command yet
- local all_commands="$(tmux -q list-commands | cut -f 1 -d ' ')"
- COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "${all_commands}" -- "${cur}") )
+ COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "${_tmux_cmds}" -- "${cur}") )
else
case ${cmd} in
attach-session|attach)
diff --git a/install.sh b/install.sh
index a80a749..0f1da39 100755
--- a/install.sh
+++ b/install.sh
@@ -31,23 +31,33 @@
function load_all() {
file_type=$1
[ ! -d "$BASH_IT/$file_type/enabled" ] && mkdir "$BASH_IT/${file_type}/enabled"
- ln -s $BASH_IT/${file_type}/available/* "${BASH_IT}/${file_type}/enabled"
+ for src in $BASH_IT/${file_type}/available/*; do
+ filename="$(basename ${src})"
+ [ ${filename:0:1} = "_" ] && continue
+ dest="${BASH_IT}/${file_type}/enabled/${filename}"
+ if [ ! -e "${dest}" ]; then
+ ln -s "${src}" "${dest}"
+ else
+ echo "File ${dest} exists, skipping"
+ fi
+ done
}
function load_some() {
file_type=$1
- for file in `ls $BASH_IT/${file_type}/available`
+ for path in `ls $BASH_IT/${file_type}/available/[^_]*`
do
if [ ! -d "$BASH_IT/$file_type/enabled" ]
then
mkdir "$BASH_IT/$file_type/enabled"
fi
+ file_name=$(basename "$path")
while true
do
- read -p "Would you like to enable the ${file%.*.*} $file_type? [Y/N] " RESP
+ read -p "Would you like to enable the ${file_name%%.*} $file_type? [Y/N] " RESP
case $RESP in
[yY])
- ln -s "$BASH_IT/$file_type/available/$file" "$BASH_IT/$file_type/enabled"
+ ln -s "$path" "$BASH_IT/$file_type/enabled"
break
;;
[nN])
diff --git a/lib/composure.sh b/lib/composure.sh
new file mode 100644
index 0000000..beaf13a
--- /dev/null
+++ b/lib/composure.sh
@@ -0,0 +1,438 @@
+# composure - by erichs
+# light-hearted functions for intuitive shell programming
+
+# install: source this script in your ~/.profile or ~/.${SHELL}rc script
+
+# latest source available at http://git.io/composure
+# known to work on bash, zsh, and ksh93
+
+# 'plumbing' functions
+
+composure_keywords ()
+{
+ echo "about author example group param version"
+}
+
+letterpress ()
+{
+ typeset rightcol="$1" leftcol="${2:- }"
+
+ if [ -z "$rightcol" ]; then
+ return
+ fi
+
+ printf "%-20s%s\n" "$leftcol" "$rightcol"
+}
+
+transcribe ()
+{
+ typeset func=$1
+ typeset file=$2
+ typeset operation="$3"
+
+ if git --version >/dev/null 2>&1; then
+ if [ -d ~/.composure ]; then
+ (
+ cd ~/.composure
+ if git rev-parse 2>/dev/null; then
+ if [ ! -f $file ]; then
+ printf "%s\n" "Oops! Couldn't find $file to version it for you..."
+ return
+ fi
+ cp $file ~/.composure/$func.inc
+ git add --all .
+ git commit -m "$operation $func"
+ fi
+ )
+ else
+ if [ "$USE_COMPOSURE_REPO" = "0" ]; then
+ return # if you say so...
+ fi
+ printf "%s\n" "I see you don't have a ~/.composure repo..."
+ typeset input
+ typeset valid=0
+ while [ $valid != 1 ]; do
+ printf "\n%s" 'would you like to create one? y/n: '
+ read input
+ case $input in
+ y|yes|Y|Yes|YES)
+ (
+ echo 'creating git repository for your functions...'
+ mkdir ~/.composure
+ cd ~/.composure
+ git init
+ echo "composure stores your function definitions here" > README.txt
+ git add README.txt
+ git commit -m 'initial commit'
+ )
+ # if at first you don't succeed...
+ transcribe "$func" "$file" "$operation"
+ valid=1
+ ;;
+ n|no|N|No|NO)
+ printf "%s\n" "ok. add 'export USE_COMPOSURE_REPO=0' to your startup script to disable this message."
+ valid=1
+ ;;
+ *)
+ printf "%s\n" "sorry, didn't get that..."
+ ;;
+ esac
+ done
+ fi
+ fi
+}
+
+transcribe ()
+{
+ typeset func=$1
+ typeset file=$2
+ typeset operation="$3"
+
+ if git --version >/dev/null 2>&1; then
+ if [ -d ~/.composure ]; then
+ (
+ cd ~/.composure
+ if git rev-parse 2>/dev/null; then
+ if [ ! -f $file ]; then
+ printf "%s\n" "Oops! Couldn't find $file to version it for you..."
+ return
+ fi
+ cp $file ~/.composure/$func.inc
+ git add --all .
+ git commit -m "$operation $func"
+ fi
+ )
+ else
+ if [ "$USE_COMPOSURE_REPO" = "0" ]; then
+ return # if you say so...
+ fi
+ printf "%s\n" "I see you don't have a ~/.composure repo..."
+ typeset input
+ typeset valid=0
+ while [ $valid != 1 ]; do
+ printf "\n%s" 'would you like to create one? y/n: '
+ read input
+ case $input in
+ y|yes|Y|Yes|YES)
+ (
+ echo 'creating git repository for your functions...'
+ mkdir ~/.composure
+ cd ~/.composure
+ git init
+ echo "composure stores your function definitions here" > README.txt
+ git add README.txt
+ git commit -m 'initial commit'
+ )
+ # if at first you don't succeed...
+ transcribe "$func" "$file" "$operation"
+ valid=1
+ ;;
+ n|no|N|No|NO)
+ printf "%s\n" "ok. add 'export USE_COMPOSURE_REPO=0' to your startup script to disable this message."
+ valid=1
+ ;;
+ *)
+ printf "%s\n" "sorry, didn't get that..."
+ ;;
+ esac
+ done
+ fi
+ fi
+}
+
+typeset_functions ()
+{
+ # unfortunately, there does not seem to be a easy, portable way to list just the
+ # names of the defined shell functions...
+
+ # first, determine our shell:
+ typeset shell
+ if [ -n "$SHELL" ]; then
+ shell=$(basename $SHELL) # we assume this is set correctly!
+ else
+ # we'll have to try harder
+ # here's a hack I modified from a StackOverflow post:
+ # we loop over the ps listing for the current process ($$), and print the last column (CMD)
+ # stripping any leading hyphens bash sometimes throws in there
+ typeset x ans
+ typeset this=$(for x in $(ps -p $$); do ans=$x; done; printf "%s\n" $ans | sed 's/^-*//')
+ typeset shell=$(basename $this) # e.g. /bin/bash => bash
+ fi
+ case "$shell" in
+ bash)
+ typeset -F | awk '{print $3}'
+ ;;
+ *)
+ # trim everything following '()' in ksh
+ typeset +f | sed 's/().*$//'
+ ;;
+ esac
+}
+
+
+# bootstrap metadata keywords for porcelain functions
+for f in $(composure_keywords)
+do
+ eval "$f() { :; }"
+done
+unset f
+
+
+# 'porcelain' functions
+
+cite ()
+{
+ about creates one or more meta keywords for use in your functions
+ param one or more keywords
+ example '$ cite url username'
+ example '$ url http://somewhere.com'
+ example '$ username alice'
+ group composure
+
+ # this is the storage half of the 'metadata' system:
+ # we create dynamic metadata keywords with function wrappers around
+ # the NOP command, ':'
+
+ # anything following a keyword will get parsed as a positional
+ # parameter, but stay resident in the ENV. As opposed to shell
+ # comments, '#', which do not get parsed and are not available
+ # at runtime.
+
+ # a BIG caveat--your metadata must be roughly parsable: do not use
+ # contractions, and consider single or double quoting if it contains
+ # non-alphanumeric characters
+
+ if [ -z "$1" ]; then
+ printf '%s\n' 'missing parameter(s)'
+ reference cite
+ return
+ fi
+
+ typeset keyword
+ for keyword in $*; do
+ eval "$keyword() { :; }"
+ done
+}
+
+draft ()
+{
+ about wraps command from history into a new function, default is last command
+ param 1: name to give function
+ param 2: optional history line number
+ example '$ ls'
+ example '$ draft list'
+ example '$ draft newfunc 1120 # wraps command at history line 1120 in newfunc()'
+ group composure
+
+ typeset func=$1
+ typeset num=$2
+ typeset cmd
+
+ if [ -z "$func" ]; then
+ printf '%s\n' 'missing parameter(s)'
+ reference draft
+ return
+ fi
+
+ # aliases bind tighter than function names, disallow them
+ if [ -n "$(type -a $func 2>/dev/null | grep 'is.*alias')" ]; then
+ printf '%s\n' "sorry, $(type -a $func). please choose another name."
+ return
+ fi
+
+ if [ -z "$num" ]; then
+ # parse last command from fc output
+ # some versions of 'fix command, fc' need corrective lenses...
+ typeset myopic=$(fc -ln -1 | grep draft)
+ typeset lines=1
+ if [ -n "$myopic" ]; then
+ lines=2
+ fi
+ cmd=$(fc -ln -$lines | head -1 | sed 's/^[[:blank:]]*//')
+ else
+ # parse command from history line number
+ cmd=$(eval "history | grep '^[[:blank:]]*$num' | head -1" | sed 's/^[[:blank:][:digit:]]*//')
+ fi
+ eval "$func() { $cmd; }"
+ typeset file=$(mktemp /tmp/draft.XXXX)
+ typeset -f $func > $file
+ transcribe $func $file draft
+ rm $file 2>/dev/null
+}
+
+glossary ()
+{
+ about displays help summary for all functions, or summary for a group of functions
+ param 1: optional, group name
+ example '$ glossary'
+ example '$ glossary misc'
+ group composure
+
+ typeset targetgroup=${1:-}
+
+ for func in $(typeset_functions); do
+ if [ -n "$targetgroup" ]; then
+ typeset group="$(typeset -f $func | metafor group)"
+ if [ "$group" != "$targetgroup" ]; then
+ continue # skip non-matching groups, if specified
+ fi
+ fi
+ typeset about="$(typeset -f $func | metafor about)"
+ letterpress "$about" $func
+ done
+}
+
+metafor ()
+{
+ about prints function metadata associated with keyword
+ param 1: meta keyword
+ example '$ typeset -f glossary | metafor example'
+ group composure
+
+ typeset keyword=$1
+
+ if [ -z "$keyword" ]; then
+ printf '%s\n' 'missing parameter(s)'
+ reference metafor
+ return
+ fi
+
+ # this sed-fu is the retrieval half of the 'metadata' system:
+ # 'grep' for the metadata keyword, and then parse/filter the matching line
+
+ # grep keyword # strip trailing '|"|; # ignore thru keyword and leading '|"
+ sed -n "/$keyword / s/['\";]*$//;s/^[ ]*$keyword ['\"]*\([^([].*\)*$/\1/p"
+}
+
+reference ()
+{
+ about displays apidoc help for a specific function
+ param 1: function name
+ example '$ reference revise'
+ group composure
+
+ typeset func=$1
+ if [ -z "$func" ]; then
+ printf '%s\n' 'missing parameter(s)'
+ reference reference
+ return
+ fi
+
+ typeset line
+
+ typeset about="$(typeset -f $func | metafor about)"
+ letterpress "$about" $func
+
+ typeset author="$(typeset -f $func | metafor author)"
+ if [ -n "$author" ]; then
+ letterpress "$author" 'author:'
+ fi
+
+ typeset version="$(typeset -f $func | metafor version)"
+ if [ -n "$version" ]; then
+ letterpress "$version" 'version:'
+ fi
+
+ if [ -n "$(typeset -f $func | metafor param)" ]; then
+ printf "parameters:\n"
+ typeset -f $func | metafor param | while read line
+ do
+ letterpress "$line"
+ done
+ fi
+
+ if [ -n "$(typeset -f $func | metafor example)" ]; then
+ printf "examples:\n"
+ typeset -f $func | metafor example | while read line
+ do
+ letterpress "$line"
+ done
+ fi
+}
+
+revise ()
+{
+ about loads function into editor for revision
+ param 1: name of function
+ example '$ revise myfunction'
+ group composure
+
+ typeset func=$1
+ typeset temp=$(mktemp /tmp/revise.XXXX)
+
+ if [ -z "$func" ]; then
+ printf '%s\n' 'missing parameter(s)'
+ reference revise
+ return
+ fi
+
+ # populate tempfile...
+ if [ -f ~/.composure/$func.inc ]; then
+ # ...with contents of latest git revision...
+ cat ~/.composure/$func.inc >> $temp
+ else
+ # ...or from ENV if not previously versioned
+ typeset -f $func >> $temp
+ fi
+
+ if [ -z "$EDITOR" ]
+ then
+ typeset EDITOR=vi
+ fi
+
+ $EDITOR $temp
+ . $temp # source edited file
+
+ transcribe $func $temp revise
+ rm $temp
+}
+
+write ()
+{
+ about writes one or more composed function definitions to stdout
+ param one or more function names
+ example '$ write finddown foo'
+ example '$ write finddown'
+ group composure
+
+ if [ -z "$1" ]; then
+ printf '%s\n' 'missing parameter(s)'
+ reference write
+ return
+ fi
+
+# bootstrap metadata
+cat <<END
+for f in $(composure_keywords)
+do
+ eval "\$f() { :; }"
+done
+unset f
+END
+
+ # include cite() to enable custom keywords
+ typeset -f cite $*
+}
+
+: <<EOF
+License: The MIT License
+
+Copyright © 2012 Erich Smith
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be included in all copies
+or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+EOF
diff --git a/lib/helpers.bash b/lib/helpers.bash
index ec6587e..e1787fe 100644
--- a/lib/helpers.bash
+++ b/lib/helpers.bash
@@ -1,11 +1,11 @@
# Helper function loading various enable-able files
function _load_bash_it_files() {
- file_type="$1"
- if [ ! -d "${BASH_IT}/${file_type}/enabled" ]
+ subdirectory="$1"
+ if [ ! -d "${BASH_IT}/${subdirectory}/enabled" ]
then
continue
fi
- FILES="${BASH_IT}/${file_type}/enabled/*.bash"
+ FILES="${BASH_IT}/${subdirectory}/enabled/*.bash"
for config_file in $FILES
do
if [ -e "${config_file}" ]; then
@@ -28,3 +28,326 @@
function reload_plugins() {
_load_bash_it_files "plugins"
}
+
+bash-it ()
+{
+ about 'bash-it help and maintenance'
+ param '1: verb [one of: help | show | enable | disable ]'
+ param '2: component type [one of: alias(es) | completion(s) | plugin(s) ]'
+ param '3: specific component [optional]'
+ example '$ bash-it show plugins'
+ example '$ bash-it help aliases'
+ example '$ bash-it enable plugin git'
+ example '$ bash-it disable alias hg'
+ typeset verb=${1:-}
+ shift
+ typeset component=${1:-}
+ shift
+ typeset func
+ case $verb in
+ show)
+ func=_bash-it-$component;;
+ enable)
+ func=_enable-$component;;
+ disable)
+ func=_disable-$component;;
+ help)
+ func=_help-$component;;
+ *)
+ reference bash-it
+ return;;
+ esac
+
+ # pluralize component if necessary
+ if ! _is_function $func; then
+ if _is_function ${func}s; then
+ func=${func}s
+ else
+ if _is_function ${func}es; then
+ func=${func}es
+ else
+ echo "oops! $component is not a valid option!"
+ reference bash-it
+ return
+ fi
+ fi
+ fi
+ $func $*
+}
+
+_is_function ()
+{
+ _about 'sets $? to true if parameter is the name of a function'
+ _param '1: name of alleged function'
+ _group 'lib'
+ [ -n "$(type -a $1 2>/dev/null | grep 'is a function')" ]
+}
+
+_bash-it-aliases ()
+{
+ _about 'summarizes available bash_it aliases'
+ _group 'lib'
+
+ _bash-it-describe "aliases" "an" "alias" "Alias"
+}
+
+_bash-it-completions ()
+{
+ _about 'summarizes available bash_it completions'
+ _group 'lib'
+
+ _bash-it-describe "completion" "a" "completion" "Completion"
+}
+
+_bash-it-plugins ()
+{
+ _about 'summarizes available bash_it plugins'
+ _group 'lib'
+
+ _bash-it-describe "plugins" "a" "plugin" "Plugin"
+}
+
+_bash-it-describe ()
+{
+ _about 'summarizes available bash_it components'
+ _param '1: subdirectory'
+ _param '2: preposition'
+ _param '3: file_type'
+ _param '4: column_header'
+ _example '$ _bash-it-describe "plugins" "a" "plugin" "Plugin"'
+
+ subdirectory="$1"
+ preposition="$2"
+ file_type="$3"
+ column_header="$4"
+
+ typeset f
+ typeset enabled
+ printf "%-20s%-10s%s\n" "$column_header" 'Enabled?' 'Description'
+ for f in $BASH_IT/$subdirectory/available/*.bash
+ do
+ if [ -e $BASH_IT/$subdirectory/enabled/$(basename $f) ]; then
+ enabled='x'
+ else
+ enabled=' '
+ fi
+ printf "%-20s%-10s%s\n" "$(basename $f | cut -d'.' -f1)" " [$enabled]" "$(cat $f | metafor about-$file_type)"
+ done
+ printf '\n%s\n' "to enable $preposition $file_type, do:"
+ printf '%s\n' "$ bash-it enable $file_type <$file_type name> -or- $ bash-it enable $file_type all"
+ printf '\n%s\n' "to disable $preposition $file_type, do:"
+ printf '%s\n' "$ bash-it disable $file_type <$file_type name> -or- $ bash-it disable $file_type all"
+}
+
+_disable-plugin ()
+{
+ _about 'disables bash_it plugin'
+ _param '1: plugin name'
+ _example '$ disable-plugin rvm'
+ _group 'lib'
+
+ _disable-thing "plugins" "plugin" $1
+}
+
+_disable-alias ()
+{
+ _about 'disables bash_it alias'
+ _param '1: alias name'
+ _example '$ disable-alias git'
+ _group 'lib'
+
+ _disable-thing "aliases" "alias" $1
+}
+
+_disable-completion ()
+{
+ _about 'disables bash_it completion'
+ _param '1: completion name'
+ _example '$ disable-completion git'
+ _group 'lib'
+
+ _disable-thing "completion" "completion" $1
+}
+
+_disable-thing ()
+{
+ _about 'disables a bash_it component'
+ _param '1: subdirectory'
+ _param '2: file_type'
+ _param '3: file_entity'
+ _example '$ _disable-thing "plugins" "plugin" "ssh"'
+
+ subdirectory="$1"
+ file_type="$2"
+ file_entity="$3"
+
+ if [ -z "$file_entity" ]; then
+ reference "disable-$file_type"
+ return
+ fi
+
+ if [ "$file_entity" = "all" ]; then
+ typeset f $file_type
+ for f in $BASH_IT/$subdirectory/available/*.bash
+ do
+ plugin=$(basename $f)
+ if [ -e $BASH_IT/$subdirectory/enabled/$plugin ]; then
+ rm $BASH_IT/$subdirectory/enabled/$(basename $plugin)
+ fi
+ done
+ else
+ typeset plugin=$(command ls $BASH_IT/$subdirectory/enabled/$file_entity.*bash 2>/dev/null | head -1)
+ if [ -z "$plugin" ]; then
+ printf '%s\n' "sorry, that does not appear to be an enabled $file_type."
+ return
+ fi
+ rm $BASH_IT/$subdirectory/enabled/$(basename $plugin)
+ fi
+
+ printf '%s\n' "$file_entity disabled."
+}
+
+_enable-plugin ()
+{
+ _about 'enables bash_it plugin'
+ _param '1: plugin name'
+ _example '$ enable-plugin rvm'
+ _group 'lib'
+
+ _enable-thing "plugins" "plugin" $1
+}
+
+_enable-alias ()
+{
+ _about 'enables bash_it alias'
+ _param '1: alias name'
+ _example '$ enable-alias git'
+ _group 'lib'
+
+ _enable-thing "aliases" "alias" $1
+}
+
+_enable-completion ()
+{
+ _about 'enables bash_it completion'
+ _param '1: completion name'
+ _example '$ enable-completion git'
+ _group 'lib'
+
+ _enable-thing "completion" "completion" $1
+}
+
+_enable-thing ()
+{
+ cite _about _param _example
+ _about 'enables a bash_it component'
+ _param '1: subdirectory'
+ _param '2: file_type'
+ _param '3: file_entity'
+ _example '$ _enable-thing "plugins" "plugin" "ssh"'
+
+ subdirectory="$1"
+ file_type="$2"
+ file_entity="$3"
+
+ if [ -z "$file_entity" ]; then
+ reference "enable-$file_type"
+ return
+ fi
+
+ if [ "$file_entity" = "all" ]; then
+ typeset f $file_type
+ for f in $BASH_IT/$subdirectory/available/*.bash
+ do
+ plugin=$(basename $f)
+ if [ ! -h $BASH_IT/$subdirectory/enabled/$plugin ]; then
+ ln -s $BASH_IT/$subdirectory/available/$plugin $BASH_IT/$subdirectory/enabled/$plugin
+ fi
+ done
+ else
+ typeset plugin=$(command ls $BASH_IT/$subdirectory/available/$file_entity.*bash 2>/dev/null | head -1)
+ if [ -z "$plugin" ]; then
+ printf '%s\n' "sorry, that does not appear to be an available $file_type."
+ return
+ fi
+
+ plugin=$(basename $plugin)
+ if [ -e $BASH_IT/$subdirectory/enabled/$plugin ]; then
+ printf '%s\n' "$file_entity is already enabled."
+ return
+ fi
+
+ ln -s $BASH_IT/$subdirectory/available/$plugin $BASH_IT/$subdirectory/enabled/$plugin
+ fi
+
+ printf '%s\n' "$file_entity enabled."
+}
+
+_help-aliases()
+{
+ _about 'shows help for all aliases, or a specific alias group'
+ _param '1: optional alias group'
+ _example '$ alias-help'
+ _example '$ alias-help git'
+
+ if [ -n "$1" ]; then
+ cat $BASH_IT/aliases/available/$1.aliases.bash | metafor alias | sed "s/$/'/"
+ else
+ typeset f
+ for f in $BASH_IT/aliases/enabled/*
+ do
+ typeset file=$(basename $f)
+ printf '\n\n%s:\n' "${file%%.*}"
+ # metafor() strips trailing quotes, restore them with sed..
+ cat $f | metafor alias | sed "s/$/'/"
+ done
+ fi
+}
+
+_help-plugins()
+{
+ _about 'summarize all functions defined by enabled bash-it plugins'
+ _group 'lib'
+
+ # display a brief progress message...
+ printf '%s' 'please wait, building help...'
+ typeset grouplist=$(mktemp /tmp/grouplist.XXXX)
+ typeset func
+ for func in $(typeset_functions)
+ do
+ typeset group="$(typeset -f $func | metafor group)"
+ if [ -z "$group" ]; then
+ group='misc'
+ fi
+ typeset about="$(typeset -f $func | metafor about)"
+ letterpress "$about" $func >> $grouplist.$group
+ echo $grouplist.$group >> $grouplist
+ done
+ # clear progress message
+ printf '\r%s\n' ' '
+ typeset group
+ typeset gfile
+ for gfile in $(cat $grouplist | sort | uniq)
+ do
+ printf '%s\n' "${gfile##*.}:"
+ cat $gfile
+ printf '\n'
+ rm $gfile 2> /dev/null
+ done | less
+ rm $grouplist 2> /dev/null
+}
+
+all_groups ()
+{
+ about 'displays all unique metadata groups'
+ group 'lib'
+
+ typeset func
+ typeset file=$(mktemp /tmp/composure.XXXX)
+ for func in $(typeset_functions)
+ do
+ typeset -f $func | metafor group >> $file
+ done
+ cat $file | sort | uniq
+ rm $file
+}
diff --git a/plugins/available/_xterm.plugin.bash b/plugins/available/_xterm.plugin.bash
new file mode 100644
index 0000000..b3810e7
--- /dev/null
+++ b/plugins/available/_xterm.plugin.bash
@@ -0,0 +1,28 @@
+# This plugin is known to cause issues on OS X with the evaluation of
+# colors. Please read [issue 108] for more information.
+#
+# You can manually turn this on by symlinking it into your
+# plugins/enabled/ directory.
+#
+# [issue 108]: https://github.com/revans/bash-it/issues/108
+
+cite about-plugin
+about-plugin 'automatically set your xterm title with host and location info'
+
+set_xterm_title () {
+ local title="$1"
+ echo -ne "\e]0;$title\007"
+}
+
+
+precmd () {
+ set_xterm_title "${USER}@${HOSTNAME} `dirs -0` $PROMPTCHAR"
+}
+
+preexec () {
+ set_xterm_title "$1 {`dirs -0`} (${USER}@${HOSTNAME})"
+}
+
+case "$TERM" in
+ xterm*|rxvt*) preexec_install;;
+esac
diff --git a/plugins/available/base.plugin.bash b/plugins/available/base.plugin.bash
index 3edd8ad..e07401b 100644
--- a/plugins/available/base.plugin.bash
+++ b/plugins/available/base.plugin.bash
@@ -1,85 +1,140 @@
-#!/usr/bin/env bash
+cite about-plugin
+about-plugin 'miscellaneous tools'
-# For generic functions.
-
-function ips {
- ifconfig | grep "inet " | awk '{ print $2 }'
+ips ()
+{
+ about 'display all ip addresses for this host'
+ group 'base'
+ ifconfig | grep "inet " | awk '{ print $2 }'
}
-function down4me() {
- curl -s "http://www.downforeveryoneorjustme.com/$1" | sed '/just you/!d;s/<[^>]*>//g'
+down4me ()
+{
+ about 'checks whether a website is down for you, or everybody'
+ param '1: website url'
+ example '$ down4me http://www.google.com'
+ group 'base'
+ curl -s "http://www.downforeveryoneorjustme.com/$1" | sed '/just you/!d;s/<[^>]*>//g'
}
-function myip {
- res=$(curl -s checkip.dyndns.org | grep -Eo '[0-9\.]+')
- echo -e "Your public IP is: ${echo_bold_green} $res ${echo_normal}"
-}
-
-pass() {
- which gshuf &> /dev/null
- if [ $? -eq 1 ]
- then
- echo "Error: shuf isn't installed!"
- return 1
- fi
-
- pass=$(shuf -n4 /usr/share/dict/words | tr '\n' ' ')
- echo "With spaces (easier to memorize): $pass"
- echo "Without (use this as the pass): $(echo $pass | tr -d ' ')"
-}
-
-# Function for previewing markdown files in the browser
-
-function pmdown() {
- if command -v markdown &>/dev/null
- then
- markdown $1 | browser
- else
- echo "You don't have a markdown command installed!"
- fi
-}
-
-# Make a directory and immediately 'cd' into it
-
-function mkcd() {
- mkdir -p "$*"
- cd "$*"
-}
-
-# Search through directory contents with grep
-
-function lsgrep(){
- ls | grep "$*"
-}
-
-# View man documentation in Preview
-pman () {
- man -t "${1}" | open -f -a $PREVIEW
+myip ()
+{
+ about 'displays your ip address, as seen by the Internet'
+ group 'base'
+ res=$(curl -s checkip.dyndns.org | grep -Eo '[0-9\.]+')
+ echo -e "Your public IP is: ${echo_bold_green} $res ${echo_normal}"
}
-pcurl() {
- curl "${1}" | open -f -a $PREVIEW
+pickfrom ()
+{
+ about 'picks random line from file'
+ param '1: filename'
+ example '$ pickfrom /usr/share/dict/words'
+ group 'base'
+ local file=$1
+ [ -z "$file" ] && reference $FUNCNAME && return
+ length=$(cat $file | wc -l)
+ n=$(expr $RANDOM \* $length \/ 32768 + 1)
+ head -n $n $file | tail -1
}
-pri() {
- ri -T "${1}" | open -f -a $PREVIEW
+pass ()
+{
+ about 'generates random password from dictionary words'
+ param 'optional integer length'
+ param 'if unset, defaults to 4'
+ example '$ pass'
+ example '$ pass 6'
+ group 'base'
+ local i pass length=${1:-4}
+ pass=$(echo $(for i in $(eval echo "{1..$length}"); do pickfrom /usr/share/dict/words; done))
+ echo "With spaces (easier to memorize): $pass"
+ echo "Without (use this as the pass): $(echo $pass | tr -d ' ')"
}
-quiet() {
+pmdown ()
+{
+ about 'preview markdown file in a browser'
+ param '1: markdown file'
+ example '$ pmdown README.md'
+ group 'base'
+ if command -v markdown &>/dev/null
+ then
+ markdown $1 | browser
+ else
+ echo "You don't have a markdown command installed!"
+ fi
+}
+
+mkcd ()
+{
+ about 'make a directory and cd into it'
+ param 'path to create'
+ example '$ mkcd foo'
+ example '$ mkcd /tmp/img/photos/large'
+ group 'base'
+ mkdir -p "$*"
+ cd "$*"
+}
+
+lsgrep ()
+{
+ about 'search through directory contents with grep'
+ group 'base'
+ ls | grep "$*"
+}
+
+
+pman ()
+{
+ about 'view man documentation in Preview'
+ param '1: man page to view'
+ example '$ pman bash'
+ group 'base'
+ man -t "${1}" | open -f -a $PREVIEW
+}
+
+
+pcurl ()
+{
+ about 'download file and Preview it'
+ param '1: download URL'
+ example '$ pcurl http://www.irs.gov/pub/irs-pdf/fw4.pdf'
+ group 'base'
+ curl "${1}" | open -f -a $PREVIEW
+}
+
+pri ()
+{
+ about 'display information about Ruby classes, modules, or methods, in Preview'
+ param '1: Ruby method, module, or class'
+ example '$ pri Array'
+ group 'base'
+ ri -T "${1}" | open -f -a $PREVIEW
+}
+
+quiet ()
+{
+ about 'what *does* this do?'
+ group 'base'
$* &> /dev/null &
}
-banish-cookies() {
+banish-cookies ()
+{
+ about 'redirect .adobe and .macromedia files to /dev/null'
+ group 'base'
rm -r ~/.macromedia ~/.adobe
ln -s /dev/null ~/.adobe
ln -s /dev/null ~/.macromedia
}
-# disk usage per directory
-# in Mac OS X and Linux
usage ()
{
+ about 'disk usage per directory, in Mac OS X and Linux'
+ param '1: directory name'
+ group 'base'
if [ $(uname) = "Darwin" ]; then
if [ -n $1 ]; then
du -hd $1
@@ -96,42 +151,37 @@
fi
}
-# One thing todo
-function t() {
- if [[ "$*" == "" ]] ; then
- cat ~/.t
- else
- echo "$*" > ~/.t
- fi
-}
+if [ ! -e $BASH_IT/plugins/enabled/todo.plugin.bash ]; then
+# if user has installed todo plugin, skip this...
+ t ()
+ {
+ about 'one thing todo'
+ param 'if not set, display todo item'
+ param '1: todo text'
+ if [[ "$*" == "" ]] ; then
+ cat ~/.t
+ else
+ echo "$*" > ~/.t
+ fi
+ }
+fi
-# Checks for existence of a command
-command_exists () {
+command_exists ()
+{
+ about 'checks for existence of a command'
+ param '1: command to check'
+ example '$ command_exists ls && echo exists'
+ group 'base'
type "$1" &> /dev/null ;
}
-# List all plugins and functions defined by bash-it
-function plugins-help() {
-
- echo "bash-it Plugins Help-Message"
- echo
-
- set | grep "()" \
- | sed -e "/^_/d" | grep -v "BASH_ARGC=()" \
- | sed -e "/^\s/d" | grep -v "BASH_LINENO=()" \
- | grep -v "BASH_ARGV=()" \
- | grep -v "BASH_SOURCE=()" \
- | grep -v "DIRSTACK=()" \
- | grep -v "GROUPS=()" \
- | grep -v "BASH_CMDS=()" \
- | grep -v "BASH_ALIASES=()" \
- | grep -v "COMPREPLY=()" | sed -e "s/()//"
-}
-
-# back up file with timestamp
# useful for administrators and configs
-buf () {
- filename=$1
- filetime=$(date +%Y%m%d_%H%M%S)
+buf ()
+{
+ about 'back up file with timestamp'
+ param 'filename'
+ group 'base'
+ local filename=$1
+ local filetime=$(date +%Y%m%d_%H%M%S)
cp ${filename} ${filename}_${filetime}
}
diff --git a/plugins/available/battery.plugin.bash b/plugins/available/battery.plugin.bash
index 4b9d4b9..002d42f 100644
--- a/plugins/available/battery.plugin.bash
+++ b/plugins/available/battery.plugin.bash
@@ -1,11 +1,15 @@
-#!/usr/bin/env bash
+cite about-plugin
+about-plugin 'display info about your battery charge level'
battery_percentage(){
+ about 'displays battery charge as a percentage of full (100%)'
+ group 'battery'
+
if command_exists acpi;
then
local ACPI_OUTPUT=$(acpi -b)
case $ACPI_OUTPUT in
- *" Unknown"*)
+ *" Unknown"*)
local PERC_OUTPUT=$(echo $ACPI_OUTPUT | head -c 22 | tail -c 2)
case $PERC_OUTPUT in
*%)
@@ -16,7 +20,7 @@
;;
esac
;;
- *" Discharging"*)
+ *" Discharging"*)
local PERC_OUTPUT=$(echo $ACPI_OUTPUT | head -c 26 | tail -c 2)
case $PERC_OUTPUT in
*%)
@@ -27,7 +31,7 @@
;;
esac
;;
- *" Charging"*)
+ *" Charging"*)
local PERC_OUTPUT=$(echo $ACPI_OUTPUT | head -c 23 | tail -c 2)
case $PERC_OUTPUT in
*%)
@@ -38,7 +42,7 @@
;;
esac
;;
- *" Full"*)
+ *" Full"*)
echo '99'
;;
*)
@@ -52,7 +56,7 @@
#local IOREG_OUTPUT_10_5=$(ioreg -l | grep -i capacity | grep -v Legacy| tr '\n' ' | ' | awk '{printf("%.2f%%", $14/$7 * 100)}')
local IOREG_OUTPUT=$(ioreg -n AppleSmartBattery -r | awk '$1~/Capacity/{c[$1]=$3} END{OFMT="%.2f%%"; max=c["\"MaxCapacity\""]; print (max>0? 100*c["\"CurrentCapacity\""]/max: "?")}')
case $IOREG_OUTPUT in
- 100*)
+ 100*)
echo '99'
;;
*)
@@ -65,6 +69,9 @@
}
battery_charge(){
+ about 'graphical display of your battery charge'
+ group 'battery'
+
# Full char
local F_C='▸'
# Depleted char
diff --git a/plugins/available/browser.plugin.bash b/plugins/available/browser.plugin.bash
index fdfba4f..f7d820a 100644
--- a/plugins/available/browser.plugin.bash
+++ b/plugins/available/browser.plugin.bash
@@ -1,42 +1,34 @@
# based on https://gist.github.com/318247
-# Usage: browser
-# pipe html to a browser
-# e.g.
-# $ echo "<h1>hi mom!</h1>" | browser
-# $ ron -5 man/rip.5.ron | browser
+cite about-plugin
+about-plugin 'render commandline output in your browser'
function browser() {
+ about 'pipe html to a browser'
+ example '$ echo "<h1>hi mom!</h1>" | browser'
+ example '$ ron -5 man/rip.5.ron | browser'
+ group 'browser'
+
if [ -t 0 ]; then
if [ -n "$1" ]; then
open $1
else
- cat <<usage
-Usage: browser
-pipe html to a browser
-
-$ echo '<h1>hi mom!</h1>' | browser
-$ ron -5 man/rip.5.ron | browser
-usage
-
- fi
+ reference browser
+ fi
else
f="/tmp/browser.$RANDOM.html"
cat /dev/stdin > $f
- open $f
+ open $f
fi
}
-# pipe hot spicy interwebs into textmate and cleanup!
-#
-# Usage: wmate
-# wget into a pipe into TextMate and force Tidy (you can undo in textmate)
-# e.g.
-# $ wmate google.com
-
function wmate() {
+ about 'pipe hot spicy interwebs into textmate and cleanup!'
+ example '$ wmate google.com'
+ group 'browser'
+
if [ -t 0 ]; then
if [ -n "$1" ]; then
wget -qO- $1 | /usr/bin/mate
@@ -64,34 +56,21 @@
EOT`
else
- cat <<usage
-Usage: wmate google.com
-wget into a pipe into TextMate and force Tidy (you can undo in textmate)
-
-$ wmate google.com
-usage
-
+ reference wmate
fi
fi
}
-#
-# Usage: raw google.com
-# wget into a temp file and pump it into your browser
-#
-# e.g.
-# $ raw google.com
function raw() {
+ about 'write wget into a temp file and pump it into your browser'
+ example '$ raw google.com'
+ group 'browser'
+
if [ -t 0 ]; then
if [ -n "$1" ]; then
wget -qO- $1 | browser
else
- cat <<usage
-Usage: raw google.com
-wget into a temp file and pump it into your browser
-
-$ raw google.com
-usage
- fi
+ reference raw
+ fi
fi
}
diff --git a/plugins/available/dirs.plugins.bash b/plugins/available/dirs.plugin.bash
old mode 100755
new mode 100644
similarity index 85%
rename from plugins/available/dirs.plugins.bash
rename to plugins/available/dirs.plugin.bash
index e03ccf5..bb1fb02
--- a/plugins/available/dirs.plugins.bash
+++ b/plugins/available/dirs.plugin.bash
@@ -1,5 +1,3 @@
-#!/usr/bin/env bash
-
# Directory stack navigation:
#
# Add to stack with: pu /path/to/directory
@@ -7,6 +5,9 @@
# Show stack with: d
# Jump to location by number.
+cite about-plugin
+about-plugin 'directory stack navigation'
+
# Show directory stack
alias d="dirs -v -l"
@@ -31,6 +32,9 @@
alias po="popd"
function dirs-help() {
+ about 'directory navigation alias usage'
+ group 'dirs'
+
echo "Directory Navigation Alias Usage"
echo
echo "Use the power of directory stacking to move"
@@ -64,10 +68,18 @@
alias L='cat ~/.dirs'
G () { # goes to distination dir otherwise , stay in the dir
+ about 'goes to destination dir'
+ param '1: directory'
+ example '$ G ..'
+ group 'dirs'
+
cd ${1:-$(pwd)} ;
}
S () { # SAVE a BOOKMARK
+ about 'save a bookmark'
+ group 'dirs'
+
sed "/$@/d" ~/.dirs > ~/.dirs1;
\mv ~/.dirs1 ~/.dirs;
echo "$@"=\"`pwd`\" >> ~/.dirs;
@@ -75,6 +87,9 @@
}
R () { # remove a BOOKMARK
+ about 'remove a bookmark'
+ group 'dirs'
+
sed "/$@/d" ~/.dirs > ~/.dirs1;
\mv ~/.dirs1 ~/.dirs;
}
diff --git a/plugins/available/extract.plugin.bash b/plugins/available/extract.plugin.bash
index 1c3e9b1..bb52045 100644
--- a/plugins/available/extract.plugin.bash
+++ b/plugins/available/extract.plugin.bash
@@ -1,3 +1,5 @@
+cite about-plugin
+about-plugin 'one command to extract them all...'
extract () {
if [ $# -ne 1 ]
then
diff --git a/plugins/available/fasd.plugin.bash b/plugins/available/fasd.plugin.bash
new file mode 100755
index 0000000..ee810e2
--- /dev/null
+++ b/plugins/available/fasd.plugin.bash
@@ -0,0 +1,598 @@
+#!/usr/bin/env sh
+
+# Fasd (this file) can be sourced or executed by any POSIX compatible shell.
+
+# Fasd is originally written based on code from z (https://github.com/rupa/z)
+# by rupa deadwyler under the WTFPL license. Most if not all of the code has
+# been rewritten.
+
+# Copyright (C) 2011, 2012 by Wei Dai. All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+fasd() {
+
+ case "$1" in
+ --init)
+ shift
+ while [ "$1" ]; do
+ case $1 in
+ env)
+ { # source rc files if present
+ [ -s "/etc/fasdrc" ] && . "/etc/fasdrc"
+ [ -s "$HOME/.fasdrc" ] && . "$HOME/.fasdrc"
+
+ # set default options
+ [ -z "$_FASD_DATA" ] && _FASD_DATA="$HOME/.fasd"
+ [ -z "$_FASD_BLACKLIST" ] && _FASD_BLACKLIST="--help"
+ [ -z "$_FASD_SHIFT" ] && _FASD_SHIFT="sudo busybox"
+ [ -z "$_FASD_IGNORE" ] && _FASD_IGNORE="fasd cd ls echo"
+ [ -z "$_FASD_SINK" ] && _FASD_SINK=/dev/null
+ [ -z "$_FASD_TRACK_PWD" ] && _FASD_TRACK_PWD=1
+ [ -z "$_FASD_MAX" ] && _FASD_MAX=2000
+ [ -z "$_FASD_BACKENDS" ] && _FASD_BACKENDS=native
+
+ if [ -z "$_FASD_AWK" ]; then
+ # awk preferences
+ local awk; for awk in mawk gawk original-awk nawk awk; do
+ $awk "" && _FASD_AWK=$awk && break
+ done
+ fi
+ } >> "${_FASD_SINK:-/dev/null}" 2>&1
+ ;;
+
+ auto) cat <<EOS
+{ if compctl; then # zsh
+ eval "\$(fasd --init posix-alias zsh-hook zsh-ccomp zsh-ccomp-install \
+ zsh-wcomp zsh-wcomp-install)"
+ elif complete; then # bash
+ eval "\$(fasd --init posix-alias bash-hook bash-ccomp bash-ccomp-install)"
+ else # posix shell
+ eval "\$(fasd --init posix-alias posix-hook)"
+ fi
+} >> "$_FASD_SINK" 2>&1
+
+EOS
+ ;;
+
+ posix-alias) cat <<EOS
+alias a='fasd -a'
+alias s='fasd -si'
+alias sd='fasd -sid'
+alias sf='fasd -sif'
+alias d='fasd -d'
+alias f='fasd -f'
+# function to execute built-in cd
+fasd_cd() { [ \$# -gt 1 ] && cd "\$(fasd -e echo "\$@")" || fasd "\$@"; }
+alias z='fasd_cd -d'
+
+EOS
+ ;;
+
+ zsh-hook) cat <<EOS
+# add zsh hook
+_fasd_preexec() {
+ { eval "fasd --proc \$(fasd --sanitize \$3)"; } >> "$_FASD_SINK" 2>&1
+}
+autoload -U add-zsh-hook
+add-zsh-hook preexec _fasd_preexec
+
+EOS
+ ;;
+
+ bash-hook) cat <<EOS
+# add bash hook
+echo \$PROMPT_COMMAND | grep -v -q "fasd --proc" && \
+ PROMPT_COMMAND='eval "fasd --proc \$(fasd --sanitize \$(history 1 | \
+ sed -e "s/^[ ]*[0-9]*[ ]*//"))" >> "$_FASD_SINK" 2>&1;'"\$PROMPT_COMMAND"
+
+EOS
+ ;;
+
+ posix-hook) cat <<EOS
+_fasd_ps1_func() {
+ { eval "fasd --proc \$(fasd --sanitize \
+ \$(fc -nl -0 | sed -n '\$s/\s*\(.*\)/\1/p'))"; } >> "$_FASD_SINK" 2>&1
+}
+echo "\$PS1" | grep -v -q "_fasd_ps1_func" && \
+export PS1="\\\$(_fasd_ps1_func)\$PS1"
+
+EOS
+ ;;
+
+ zsh-ccomp) cat <<EOS
+# zsh command mode completion
+_fasd_zsh_cmd_complete() {
+ local compl
+ read -c compl
+ compstate[insert]=menu # no expand
+ reply=(\${(f)"\$(fasd --complete "\$compl")"})
+}
+
+EOS
+ ;;
+
+ zsh-wcomp) cat <<EOS
+# zsh word mode completion
+_fasd_zsh_word_complete() {
+ [ "\$2" ] && local _fasd_cur="\$2"
+ [ -z "\$_fasd_cur" ] && local _fasd_cur="\${words[CURRENT]}"
+ local fnd="\${_fasd_cur//,/ }"
+ local typ=\${1:-e}
+ fasd --query \$typ \$fnd | sort -nr | sed 's/^[0-9.]*[ ]*//' | \
+ while read line; do
+ compadd -U -V fasd "\$line"
+ done
+ compstate[insert]=menu # no expand
+}
+_fasd_zsh_word_complete_f() { _fasd_zsh_word_complete f ; }
+_fasd_zsh_word_complete_d() { _fasd_zsh_word_complete d ; }
+_fasd_zsh_word_complete_trigger() {
+ local _fasd_cur="\${words[CURRENT]}"
+ eval \$(fasd --word-complete-trigger _fasd_zsh_word_complete \$_fasd_cur)
+}
+# define zle widgets
+zle -C fasd-complete 'menu-select' _fasd_zsh_word_complete
+zle -C fasd-complete-f 'menu-select' _fasd_zsh_word_complete_f
+zle -C fasd-complete-d 'menu-select' _fasd_zsh_word_complete_d
+
+EOS
+ ;;
+
+ zsh-ccomp-install) cat <<EOS
+# enbale command mode completion
+compctl -U -K _fasd_zsh_cmd_complete -V fasd -x 'C[-1,-*e],s[-]n[1,e]' -c - \
+ 'c[-1,-A][-1,-D]' -f -- fasd fasd_cd
+
+EOS
+ ;;
+
+ zsh-wcomp-install) cat <<EOS
+# enable word mode completion
+zstyle ':completion:*' completer _complete _ignored \
+ _fasd_zsh_word_complete_trigger
+
+EOS
+ ;;
+
+ bash-ccomp) cat <<EOS
+# bash command mode completion
+_fasd_bash_cmd_complete() {
+ # complete command after "-e"
+ local cur=\${COMP_WORDS[COMP_CWORD]}
+ [[ \${COMP_WORDS[COMP_CWORD-1]} == -*e ]] && \
+ COMPREPLY=( \$(compgen -A command \$cur) ) && return
+ # complete using default readline complete after "-A" or "-D"
+ case \${COMP_WORDS[COMP_CWORD-1]} in
+ -A|-D) COMPREPLY=( \$(compgen -o default \$cur) ) && return
+ esac
+ # get completion results using expanded aliases
+ local RESULT=\$( fasd -q --complete "\$(alias -p \$COMP_WORDS \
+ 2>> "$_FASD_SINK" | sed -n "\\\$s/^.*'\(.*\)'/\1/p") \${COMP_LINE#* }" )
+ IFS=\$'\n' COMPREPLY=( \$RESULT )
+}
+_fasd_bash_hook_cmd_complete() {
+ for cmd in \$*; do
+ complete -F _fasd_bash_cmd_complete \$cmd
+ done
+}
+
+EOS
+ ;;
+
+ bash-wcomp) cat <<EOS
+# bash word mode completion
+_fasd_bash_word_complete() {
+ [ "\$2" ] && local _fasd_cur="\$2"
+ [ "\$_fasd_cur" ] || local _fasd_cur="\${COMP_WORDS[COMP_CWORD]}"
+ local typ=\${1:-e}
+ local fnd="\${_fasd_cur//,/ }"
+ local RESULT=\$(fasd -q --query \$typ \$fnd | sed 's/^[0-9.]*[ ]*//')
+ IFS=\$'\n' COMPREPLY=( \$RESULT )
+} >> "$_FASD_SINK" 2>&1
+_fasd_bash_word_complete_trigger() {
+ [ "\$_fasd_cur" ] || local _fasd_cur="\${COMP_WORDS[COMP_CWORD]}"
+ eval "\$(fasd --word-complete-trigger _fasd_bash_word_complete \$_fasd_cur)"
+} >> "$_FASD_SINK" 2>&1
+_fasd_bash_word_complete_wrap() {
+ local _fasd_cur="\${COMP_WORDS[COMP_CWORD]}"
+ _fasd_bash_word_complete_trigger
+ local z=\${COMP_WORDS[0]}
+ # try original comp func
+ [ "\$COMPREPLY" ] || eval "\$( echo "\$_FASD_BASH_COMPLETE_P" | \
+ sed -n "/ \$z\$/"'s/.*-F \(.*\) .*/\1/p' )"
+ # fall back on original complete options
+ local cmd="\$(echo "\$_FASD_BASH_COMPLETE_P" | \
+ sed -n "/ \$z\$/"'s/complete/compgen/') \$_fasd_cur"
+ [ "\$COMPREPLY" ] || COMPREPLY=( \$(eval \$cmd) )
+} >> "$_FASD_SINK" 2>&1
+
+EOS
+ ;;
+
+ bash-ccomp-install) cat <<EOS
+# enable bash command mode completion
+_fasd_bash_hook_cmd_complete fasd a s d f sd sf z
+
+EOS
+ ;;
+
+ bash-wcomp-install) cat <<EOS
+_FASD_BASH_COMPLETE_P="\$(complete -p)"
+for cmd in \$(complete -p | awk '{print \$NF}' | tr '\n' ' '); do
+ complete -o default -o bashdefault -F _fasd_bash_word_complete_wrap \$cmd
+done
+# enable word mode completion as default completion
+complete -o default -o bashdefault -D -F _fasd_bash_word_complete_trigger \
+ >> "$_FASD_SINK" 2>&1
+
+EOS
+ ;;
+ esac; shift
+ done
+ ;;
+
+ --init-alias)
+ fasd --init posix-alias
+ ;;
+
+ --init-zsh)
+ fasd --init zsh-hook zsh-ccomp zsh-ccomp-install zsh-wcomp zsh-wcomp-install
+ ;;
+
+ --init-bash)
+ fasd --init bash-hook bash-ccomp bash-ccomp-install
+ ;;
+
+ --init-posix)
+ fasd --init posix-hook
+ ;;
+
+ # if "$_fasd_cur" is a query, then eval all the arguments
+ --word-complete-trigger)
+ shift; [ "$2" ] && local _fasd_cur="$2" || return
+ case "$_fasd_cur" in
+ ,*) echo "$1" e "$_fasd_cur";;
+ f,*) echo "$1" f "${_fasd_cur#?}";;
+ d,*) echo "$1" d "${_fasd_cur#?}";;
+ *,,) echo "$1" e "$_fasd_cur";;
+ *,,f) echo "$1" f "${_fasd_cur%?}";;
+ *,,d) echo "$1" d "${_fasd_cur%?}";;
+ esac
+ ;;
+
+ --sanitize)
+ shift; echo "$@" | \
+ sed 's/\([^\]\)$([^ ]*\([^)]*\)))*/\1\2/g;s/\([^\]\)[|&;<>$`]\{1,\}/\1 /g'
+ ;;
+
+ --proc) shift # process commands
+ # stop if we don't own ~/.fasd (we're another user but our ENV is still set)
+ [ -f "$_FASD_DATA" -a ! -O "$_FASD_DATA" ] && return
+
+ # make zsh do word splitting for the for loop to work
+ [ "$ZSH_VERSION" ] && emulate sh && setopt localoptions
+
+ # blacklists
+ local each; for each in $_FASD_BLACKLIST; do
+ case " $* " in *\ $each\ *) return;; esac
+ done
+
+ # shifts
+ while true; do
+ case " $_FASD_SHIFT " in
+ *\ $1\ *) shift;;
+ *) break
+ esac
+ done
+
+ # ignores
+ case " $_FASD_IGNORE " in
+ *\ $1\ *) return
+ esac
+
+ shift; fasd --add "$@" # add all arguments except command
+ ;;
+
+ --add|-A) shift # add entries
+ # find all valid path arguments, convert them to simplest absolute form
+ local paths="$(while [ "$1" ]; do
+ [ -e "$1" ] && echo "$1"; shift
+ done | sed '/^[^/]/s@^@'"$PWD"'/@
+ s@/\.\.$@/\.\./@;s@/\(\./\)\{1,\}@/@g;: 0;s@[^/][^/]*//*\.\./@/@;t 0
+ s@^/*\.\./@/@;s@//*@/@g;s@/\.\{0,1\}$@@;s@^$@/@' | tr '\n' '|')"
+
+ # add current pwd if the option is set
+ [ "$_FASD_TRACK_PWD" = "1" -a "$PWD" != "$HOME" ] && paths="$paths|$PWD"
+
+ [ -z "${paths##\|}" ] && return # stop if we have nothing to add
+
+ # maintain the file
+ local tempfile
+ tempfile="$(mktemp "$_FASD_DATA".XXXXXX)" || return
+ $_FASD_AWK -v list="$paths" -v now="$(date +%s)" -v max="$_FASD_MAX" -F"|" '
+ BEGIN {
+ split(list, files, "|")
+ for(i in files) {
+ path = files[i]
+ if(path == "") continue
+ paths[path] = path # array for checking
+ rank[path] = 1
+ time[path] = now
+ }
+ }
+ $2 >= 1 {
+ if($1 in paths) {
+ rank[$1] = $2 + 1
+ time[$1] = now
+ } else {
+ rank[$1] = $2
+ time[$1] = $3
+ }
+ count += $2
+ }
+ END {
+ if(count > max)
+ for(i in rank) print i "|" 0.9*rank[i] "|" time[i] # aging
+ else
+ for(i in rank) print i "|" rank[i] "|" time[i]
+ }' "$_FASD_DATA" 2>> "$_FASD_SINK" >| "$tempfile"
+ if [ $? -ne 0 -a -f "$_FASD_DATA" ]; then
+ env rm -f "$tempfile"
+ else
+ env mv -f "$tempfile" "$_FASD_DATA"
+ fi
+ ;;
+
+ --delete|-D) shift # delete entries
+ # turn valid arguments into entry-deleting sed commands
+ local sed_cmd="$(while [ "$1" ]; do echo "$1"; shift; done | \
+ sed '/^[^/]/s@^@'"$PWD"'/@;s@/\.\.$@/\.\./@;s@/\(\./\)\{1,\}@/@g
+ : 0;s@[^/][^/]*//*\.\./@/@;t 0;s@^/*\.\./@/@;s@//*@/@g;s@/\.\{0,1\}$@@
+ s@^$@/@;s@\([.[/*^$]\)@\\\1@g;s@^\(.*\)$@/^\1|/d@')"
+
+ # maintain the file
+ local tempfile
+ tempfile="$(mktemp "$_FASD_DATA".XXXXXX)" || return
+
+ sed -e "$sed_cmd" "$_FASD_DATA" 2>> "$_FASD_SINK" >| "$tempfile"
+
+ if [ $? -ne 0 -a -f "$_FASD_DATA" ]; then
+ env rm -f "$tempfile"
+ else
+ env mv -f "$tempfile" "$_FASD_DATA"
+ fi
+ ;;
+
+ --query) shift # query the db, --query [$typ ["$fnd" [$mode [$quote]]]]
+ [ -f "$_FASD_DATA" ] || return # no db yet
+ [ "$1" ] && local typ="$1"
+ [ "$2" ] && local fnd="$2"
+ [ "$3" ] && local mode="$3"
+ [ "$4" ] && local quote="$4"
+ [ "$quote" ] && local qts='"\""' || local qts=
+
+ # make zsh do word spliting for the for loop to work
+ [ "$ZSH_VERSION" ] && emulate sh && setopt localoptions
+
+ # cat all backends
+ local each _fasd_data; for each in $_FASD_BACKENDS; do
+ _fasd_data="$_fasd_data
+$(fasd --backend $each)"
+ done
+ [ "$_fasd_data" ] || _fasd_data="$(cat "$_FASD_DATA")"
+
+ # set mode specific code for calculating the prior
+ case $mode in
+ rank) local prior='times[i]';;
+ recent) local prior='sqrt(100000/(1+t-la[i]))';;
+ *) local prior='times[i] * frecent(la[i])';;
+ esac
+
+ # query the database
+ echo "$_fasd_data" | while read line; do
+ [ -${typ:-e} "${line%%\|*}" ] && echo "$line"
+ done | $_FASD_AWK -v t="$(date +%s)" -v q="$fnd" -F"|" '
+ function frecent(time) {
+ dx = t-time
+ if( dx < 3600 ) return 6
+ if( dx < 86400 ) return 4
+ if( dx < 604800 ) return 2
+ return 1
+ }
+ function likelihood(pattern, path) {
+ m = gsub("/+", "/", path)
+ r = 1
+ for(i in pattern) {
+ tmp = path
+ gsub(".*" pattern[i], "", tmp)
+ n = gsub("/+", "/", tmp)
+ if(n == m)
+ return 0
+ else if(n == 0)
+ r *= 20 # F
+ else
+ r *= 1 - (n / m)
+ }
+ return r
+ }
+ BEGIN {
+ split(q, pattern, " ")
+ for(i in pattern) pattern_lower[i] = tolower(pattern[i]) # nocase
+ }
+ {
+ if(!wcase[$1]) {
+ times[$1] = $2
+ la[$1] = $3
+ wcase[$1] = likelihood(pattern, $1)
+ if(!cx) nocase[$1] = likelihood(pattern_lower, tolower($1))
+ } else {
+ times[$1] += $2
+ if($3 > la[$1]) la[$1] = $3
+ }
+ cx = cx || wcase[$1]
+ ncx = ncx || nocase[$1]
+ }
+ END {
+ if(cx) {
+ for(i in wcase) {
+ if(wcase[i])
+ printf "%-10s %s\n", '"$prior"' * wcase[i], '"$qts"' i '"$qts"'
+ }
+ } else if(ncx) {
+ for(i in nocase) {
+ if(nocase[i])
+ printf "%-10s %s\n", '"$prior"' * nocase[i], '"$qts"' i '"$qts"'
+ }
+ }
+ }' - 2>> "$_FASD_SINK"
+ ;;
+
+ --backend)
+ case $2 in
+ native) cat "$_FASD_DATA";;
+ viminfo)
+ local t="$(date +%s)"
+ < "$HOME/.viminfo" sed -n '/^>/{s@~@'"$HOME"'@;p}' | \
+ while IFS=" " read line; do
+ t=$((t-60)); echo "${line#??}|1|$t"
+ done
+ ;;
+ recently-used)
+ tr -d '\n' < "$HOME/.local/share/recently-used.xbel" | \
+ sed 's@file:/@\n@g;s@count="@\n@g' | sed '1d;s/".*$//' | \
+ tr '\n' '|' | sed 's@|/@\n@g' | $_FASD_AWK -F'|' '{
+ sum = 0
+ for( i=2; i<=NF; i++ ) sum += $i
+ print $1 "|" sum
+ }'
+ ;;
+ *) eval "$2";;
+ esac
+ ;;
+
+ *) # parsing logic and processing
+ local fnd last _FASD_BACKENDS="$_FASD_BACKENDS" _fasd_data
+ while [ "$1" ]; do case "$1" in
+ --complete) [ "$2" = "--" ] && shift; set -- $(echo $2); local lst=1 r=r;;
+ --query|--add|--delete|-A|-D) fasd "$@"; return $?;;
+ --version) echo "0.5.4"; return 0;;
+ --) while [ "$2" ]; do shift; fnd="$fnd$1 "; last="$1"; done;;
+ -*) local o="${1#-}"; while [ "$o" ]; do case "$o" in
+ s*) local show=1;;
+ l*) local lst=1;;
+ i*) local interactive=1 show=1;;
+ r*) local mode=rank;;
+ t*) local mode=recent;;
+ e*) o="${o#?}"; if [ "$o" ]; then # there are characters after "-e"
+ local exec="$o" # anything after "-e"
+ else # use the next argument
+ local exec="${2:?"-e: Argument needed "}"
+ shift
+ fi; break;;
+ b*) o="${o#?}"; if [ "$o" ]; then
+ _FASD_BACKENDS="$o"
+ else
+ _FASD_BACKENDS="${2:?"-b: Argument needed"}"
+ shift
+ fi; break;;
+ B*) o="${o#?}"; if [ "$o" ]; then
+ _FASD_BACKENDS="$_FASD_BACKENDS $o"
+ else
+ _FASD_BACKENDS="$_FASD_BACKENDS ${2:?"-B: Argument needed"}"
+ shift
+ fi; break;;
+ a*) local typ=e;;
+ d*) local typ=d;;
+ f*) local typ=f;;
+ q*) local quote=1;;
+ h*) echo "fasd [options] [query ...]
+[f|a|s|d|z] [opions] [query ...]
+ options:
+ -s show list of files with their ranks
+ -l list paths only
+ -i interactive mode
+ -e <cmd> set command to execute on the result file
+ -b <name> only use <name> backend
+ -b <name> add additional backend <name>
+ -a match files and directories
+ -d match directories only
+ -f match files only
+ -r match by rank only
+ -t match by recent access only
+ -h show a brief help message
+
+fasd [-A|-D] [paths ...]
+ -A add paths
+ -D delete paths" >&2; return;;
+ esac; o="${o#?}"; done;;
+ *) fnd="$fnd $1"; last="$1";;
+ esac; shift; done
+
+ # if we hit enter on a completion just execute
+ case "$last" in
+ # completions will always start with /
+ /*) [ -z "$show$lst" -a -${typ:-e} "$last" -a "$exec" ] \
+ && eval $exec "\"$last\"" && return;;
+ esac
+
+ local result
+ result="$(fasd --query 2>> "$_FASD_SINK")" # query the database
+ [ $? -gt 0 ] && return
+ if [ "$interactive" ] || [ "$exec" -a -z "$fnd$lst$show" -a -t 1 ]; then
+ result="$(echo "$result" | sort -nr)"
+ echo "$result" | sed = | sed 'N;s/\n/ /' | sort -nr >&2; printf "> " >&2
+ local i; read i; [ 0 -lt "${i:-0}" ] 2>> "$_FASD_SINK" || return 1
+ result="$(echo "$result" | sed -n "${i:-1}"'s/^[0-9.]*[ ]*//p')"
+ if [ "$result" ]; then
+ fasd --add "$result"; eval ${exec:-echo} "\"$result\""
+ fi
+ elif [ "$lst" ]; then
+ echo "$result" | sort -n${r} | sed 's/^[0-9.]*[ ]*//'
+ elif [ "$show" ]; then
+ echo "$result" | sort -n
+ elif [ "$fnd" -a "$exec" ]; then # exec
+ result="$(echo "$result" | sort -n | sed -n '$s/^[0-9.]*[ ]*//p')"
+ fasd --add "$result"; eval $exec "\"$result\""
+ elif [ "$fnd" -a ! -t 1 ]; then # echo if output is not terminal
+ result="$(echo "$result" | sort -n | sed -n '$s/^[0-9.]*[ ]*//p')"
+ fasd --add "$result"; echo "$result"
+ else # no args, show
+ echo "$result" | sort -n
+ fi
+
+ esac
+}
+
+fasd --init env
+
+case $- in
+ *i*) cite about-plugin
+ about-plugin 'navigate "frecently" used files and directories'
+ eval "$(fasd --init auto)"
+ ;;
+ *) # assume being executed as an executable
+ if [ -x "$_FASD_SHELL" -a -z "$_FASD_SET" ]; then
+ _FASD_SET=1 exec $_FASD_SHELL "$0" "$@"
+ else
+ fasd "$@"
+ fi
+esac
+
diff --git a/plugins/available/git.plugins.bash b/plugins/available/git.plugin.bash
similarity index 83%
rename from plugins/available/git.plugins.bash
rename to plugins/available/git.plugin.bash
index 41b031f..0b77111 100644
--- a/plugins/available/git.plugins.bash
+++ b/plugins/available/git.plugin.bash
@@ -1,26 +1,42 @@
-#!/usr/bin/env bash
+cite about-plugin
+about-plugin 'git helper functions'
function git_remote {
+ about 'adds remote $GIT_HOSTING:$1 to current repo'
+ group 'git'
+
echo "Running: git remote add origin ${GIT_HOSTING}:$1.git"
git remote add origin $GIT_HOSTING:$1.git
}
function git_first_push {
+ about 'push into origin refs/heads/master'
+ group 'git'
+
echo "Running: git push origin master:refs/heads/master"
git push origin master:refs/heads/master
}
function git_remove_missing_files() {
+ about "git rm's missing files"
+ group 'git'
+
git ls-files -d -z | xargs -0 git update-index --remove
}
# Adds files to git's exclude file (same as .gitignore)
function local-ignore() {
+ about 'adds file or path to git exclude file'
+ param '1: file or path fragment to ignore'
+ group 'git'
echo "$1" >> .git/info/exclude
}
# get a quick overview for your git repo
function git_info() {
+ about 'overview for your git repo'
+ group 'git'
+
if [ -n "$(git symbolic-ref HEAD 2> /dev/null)" ]; then
# print informations
echo "git repo overview"
@@ -29,7 +45,7 @@
# print all remotes and thier details
for remote in $(git remote show); do
- echo $remote:
+ echo $remote:
git remote show $remote
echo
done
@@ -43,10 +59,10 @@
fi
# print at least 5 last log entries
- echo
+ echo
echo "log:"
git log -5 --oneline
- echo
+ echo
else
echo "you're currently not in a git repository"
@@ -55,6 +71,9 @@
}
function git_stats {
+ about 'display stats per author'
+ group 'git'
+
# awesome work from https://github.com/esc/git-stats
# including some modifications
diff --git a/plugins/available/hg.plugin.bash b/plugins/available/hg.plugin.bash
new file mode 100644
index 0000000..020b920
--- /dev/null
+++ b/plugins/available/hg.plugin.bash
@@ -0,0 +1,25 @@
+cite about-plugin
+about-plugin 'hg helper functions'
+
+hg_dirty() {
+ about 'displays dirty status of hg repository'
+ group 'hg'
+
+ hg status --no-color 2> /dev/null \
+ | awk '$1 == "?" { print "?" } $1 != "?" { print "!" }' \
+ | sort | uniq | head -c1
+}
+
+hg_in_repo() {
+ about 'determine if pwd is an hg repo'
+ group 'hg'
+
+ [[ `hg branch 2> /dev/null` ]] && echo 'on '
+}
+
+hg_branch() {
+ about 'display current hg branch'
+ group 'hg'
+
+ hg branch 2> /dev/null
+}
diff --git a/plugins/available/hg.plugins.bash b/plugins/available/hg.plugins.bash
deleted file mode 100644
index 33c81d3..0000000
--- a/plugins/available/hg.plugins.bash
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env bash
-hg_dirty() {
- hg status --no-color 2> /dev/null \
- | awk '$1 == "?" { print "?" } $1 != "?" { print "!" }' \
- | sort | uniq | head -c1
-}
-
-hg_in_repo() {
- [[ `hg branch 2> /dev/null` ]] && echo 'on '
-}
-
-hg_branch() {
- hg branch 2> /dev/null
-}
diff --git a/plugins/available/java.plugin.bash b/plugins/available/java.plugin.bash
new file mode 100644
index 0000000..98e4624
--- /dev/null
+++ b/plugins/available/java.plugin.bash
@@ -0,0 +1,11 @@
+cite about-plugin
+about-plugin 'Java and JAR helper functions'
+
+function jar_manifest {
+ about "extracts the specified JAR file's MANIFEST file and prints it to stdout"
+ group 'java'
+ param '1: JAR file to extract the MANIFEST from'
+ example 'jar_manifest lib/foo.jar'
+
+ unzip -c $1 META-INF/MANIFEST.MF
+}
diff --git a/plugins/available/javascript.plugins.bash b/plugins/available/javascript.plugin.bash
similarity index 67%
rename from plugins/available/javascript.plugins.bash
rename to plugins/available/javascript.plugin.bash
index 76a7e13..e8037b9 100644
--- a/plugins/available/javascript.plugins.bash
+++ b/plugins/available/javascript.plugin.bash
@@ -1,16 +1,22 @@
-#!/usr/bin/env bash
-#
-# The install directory is hard-coded. TOOD: allow the directory to be specified on the command line.
-#
+# The install directory is hard-coded. TODO: allow the directory to be specified on the command line.
+
+cite about-plugin
+about-plugin 'download jquery files into current project'
[[ -z "$JQUERY_VERSION_NUMBER" ]] && JQUERY_VERSION_NUMBER="1.6.1"
[[ -z "$JQUERY_UI_VERSION_NUMBER" ]] && JQUERY_UI_VERSION_NUMBER="1.8.13"
function rails_jquery {
+ about 'download rails.js into public/javascripts'
+ group 'javascript'
+
curl -o public/javascripts/rails.js http://github.com/rails/jquery-ujs/raw/master/src/rails.js
}
function jquery_install {
+ about 'download jquery.js into public/javascripts'
+ group 'javascript'
+
if [ -z "$1" ]
then
version=$JQUERY_VERSION_NUMBER
@@ -21,6 +27,9 @@
}
function jquery_ui_install {
+ about 'download jquery_us.js into public/javascripts'
+ group 'javascript'
+
if [ -z "$1" ]
then
version=$JQUERY_UI_VERSION_NUMBER
diff --git a/plugins/available/jekyll.plugins.bash b/plugins/available/jekyll.plugin.bash
similarity index 92%
rename from plugins/available/jekyll.plugins.bash
rename to plugins/available/jekyll.plugin.bash
index 74e3cb1..6254a87 100644
--- a/plugins/available/jekyll.plugins.bash
+++ b/plugins/available/jekyll.plugin.bash
@@ -1,6 +1,11 @@
-#!/usr/bin/env bash
+cite about-plugin
+about-plugin 'manage your jekyll site'
editpost() {
+ about 'edit a post'
+ param '1: site directory'
+ group 'jekyll'
+
unset SITE
if [ -z "$1" ]
then
@@ -35,11 +40,11 @@
DATE=`echo $POST | grep -oE "[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}"`
TITLE=`cat $POST | grep -oE "title: (.+)"`
TITLE=`echo $TITLE | sed 's/title: //'`
- echo "$COUNTER) $DATE $TITLE" >> "$TMPFILE"
+ echo "$COUNTER) $DATE $TITLE" >> "$TMPFILE"
POSTS[$COUNTER]=$POST
COUNTER=`expr $COUNTER + 1`
done
- less $TMPFILE
+ less $TMPFILE
read -p "Number of post to edit: " POST_TO_EDIT
if [ -z "$JEKYLL_EDITOR" ]
then
@@ -50,6 +55,10 @@
}
newpost() {
+ about 'create a new post'
+ param '1: site directory'
+ group 'jekyll'
+
unset SITE
if [ -z "$1" ]
then
@@ -93,7 +102,7 @@
then
select OPTION in $OPTIONS
do
- if [[ $OPTION = "Text" ]]
+ if [[ $OPTION = "Text" ]]
then
POST_TYPE="Text"
break
@@ -257,6 +266,10 @@
}
function testsite() {
+ about 'launches local jekyll server'
+ param '1: site directory'
+ group 'jekyll'
+
unset SITE
if [ -z "$1" ]
then
@@ -285,6 +298,10 @@
}
function buildsite() {
+ about 'builds site'
+ param '1: site directory'
+ group 'jekyll'
+
unset SITE
if [ -z "$1" ]
then
@@ -314,6 +331,10 @@
}
function deploysite() {
+ about 'rsyncs site to remote host'
+ param '1: site directory'
+ group 'jekyll'
+
unset SITE
if [ -z "$1" ]
then
diff --git a/plugins/available/latex.plugin.bash b/plugins/available/latex.plugin.bash
index c2ce9dd..eefec59 100644
--- a/plugins/available/latex.plugin.bash
+++ b/plugins/available/latex.plugin.bash
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+cite about-plugin
+about-plugin 'use mactex'
# add mactex to the path if its present
MACTEX_PATH=/usr/local/texlive/2009/bin/universal-darwin
diff --git a/plugins/available/nginx.plugins.bash b/plugins/available/nginx.plugin.bash
similarity index 81%
rename from plugins/available/nginx.plugins.bash
rename to plugins/available/nginx.plugin.bash
index 6dd86dd..660b503 100644
--- a/plugins/available/nginx.plugins.bash
+++ b/plugins/available/nginx.plugin.bash
@@ -1,6 +1,10 @@
-#!/usr/bin/env bash
+cite about-plugin
+about-plugin 'manage your nginx service'
function nginx_reload() {
+ about 'reload your nginx config'
+ group 'nginx'
+
FILE="${NGINX_PATH}/logs/nginx.pid"
if [ -e $FILE ]; then
echo "Reloading NGINX..."
@@ -13,6 +17,9 @@
}
function nginx_stop() {
+ about 'stop nginx'
+ group 'nginx'
+
FILE="${NGINX_PATH}/logs/nginx.pid"
if [ -e $FILE ]; then
echo "Stopping NGINX..."
@@ -25,6 +32,9 @@
}
function nginx_start() {
+ about 'start nginx'
+ group 'nginx'
+
FILE="${NGINX_PATH}/sbin/nginx"
if [ -e $FILE ]; then
echo "Starting NGINX..."
@@ -35,6 +45,9 @@
}
function nginx_restart() {
+ about 'restart nginx'
+ group 'nginx'
+
FILE="${NGINX_PATH}/logs/nginx.pid"
if [ -e $FILE ]; then
echo "Stopping NGINX..."
diff --git a/plugins/available/nvm.plugin.bash b/plugins/available/nvm.plugin.bash
index 3f489dd..2e607d6 100644
--- a/plugins/available/nvm.plugin.bash
+++ b/plugins/available/nvm.plugin.bash
@@ -5,6 +5,9 @@
# Implemented by Tim Caswell <tim@creationix.com>
# with much bash help from Matthew Ranney
+cite about-plugin
+about-plugin 'node version manager, as a bash function'
+
export NVM_DIR=$HOME/.nvm
if [ ! -d "$NVM_DIR" ]; then
@@ -75,6 +78,10 @@
nvm()
{
+ about 'Node Version Manager'
+ param '1: command, see nvm help'
+ group 'nvm'
+
if [ $# -lt 1 ]; then
nvm help
return
diff --git a/plugins/available/osx.plugin.bash b/plugins/available/osx.plugin.bash
index 7d3d077..fde9c83 100644
--- a/plugins/available/osx.plugin.bash
+++ b/plugins/available/osx.plugin.bash
@@ -1,6 +1,10 @@
-#!/usr/bin/env bash
+cite about-plugin
+about-plugin 'osx-specific functions'
function tab() {
+ about 'opens a new terminal tab'
+ group 'osx'
+
osascript 2>/dev/null <<EOF
tell application "System Events"
tell process "Terminal" to keystroke "t" using command down
@@ -15,6 +19,10 @@
# this one switches your os x dock between 2d and 3d
# thanks to savier.zwetschge.org
function dock-switch() {
+ about 'switch dock between 2d and 3d'
+ param '1: "2d" or "3d"'
+ example '$ dock-switch 2d'
+ group 'osx'
if [ $(uname) = "Darwin" ]; then
@@ -39,6 +47,10 @@
# Download a file and open it in Preview
function prevcurl() {
+ about 'download a file and open it in Preview'
+ param '1: url'
+ group 'osx'
+
if [ ! $(uname) = "Darwin" ]
then
echo "This function only works with Mac OS X"
diff --git a/plugins/available/python.plugin.bash b/plugins/available/python.plugin.bash
index 6c87f8a..c705d5b 100644
--- a/plugins/available/python.plugin.bash
+++ b/plugins/available/python.plugin.bash
@@ -1,4 +1,5 @@
-#!/usr/bin/env bash
+cite about-plugin
+about-plugin 'alias "http" to SimpleHTTPServer'
if [ $(uname) = "Linux" ]
then
diff --git a/plugins/available/rbenv.plugin.bash b/plugins/available/rbenv.plugin.bash
index bd3f78e..70fe62c 100644
--- a/plugins/available/rbenv.plugin.bash
+++ b/plugins/available/rbenv.plugin.bash
@@ -1,8 +1,10 @@
-#!/usr/bin/env bash
-
# Load rbebv, if you are using it
+
+cite about-plugin
+about-plugin 'load rbenv, if you are using it'
+
export PATH="$HOME/.rbenv/bin:$PATH"
-eval "$(rbenv init -)"
+[[ `which rbenv` ]] && eval "$(rbenv init -)"
# Load the auto-completion script if rbenv was loaded.
-source ~/.rbenv/completions/rbenv.bash
+[[ -e ~/.rbenv/completions/rbenv.bash ]] && source ~/.rbenv/completions/rbenv.bash
diff --git a/plugins/available/ruby.plugin.bash b/plugins/available/ruby.plugin.bash
index 9ae61a4..f36bb15 100644
--- a/plugins/available/ruby.plugin.bash
+++ b/plugins/available/ruby.plugin.bash
@@ -1,4 +1,10 @@
-#!/usr/bin/env bash
+cite about-plugin
+about-plugin 'adds "remove_gem" function'
+
function remove_gem {
+ about 'removes installed gem'
+ param '1: installed gem name'
+ group 'ruby'
+
gem list | grep $1 | awk '{ print $1; }' | xargs sudo gem uninstall
}
diff --git a/plugins/available/rvm.plugin.bash b/plugins/available/rvm.plugin.bash
index e0d18ba..6acad07 100644
--- a/plugins/available/rvm.plugin.bash
+++ b/plugins/available/rvm.plugin.bash
@@ -1,6 +1,8 @@
-#!/usr/bin/env bash
-
# Load RVM, if you are using it
+
+cite about-plugin
+about-plugin 'load rvm, if you are using it'
+
[[ -s $HOME/.rvm/scripts/rvm ]] && source $HOME/.rvm/scripts/rvm
# Check to make sure that RVM is actually loaded before adding
diff --git a/plugins/available/ssh.plugin.bash b/plugins/available/ssh.plugin.bash
new file mode 100644
index 0000000..4e17206
--- /dev/null
+++ b/plugins/available/ssh.plugin.bash
@@ -0,0 +1,19 @@
+cite about-plugin
+about-plugin 'ssh helper functions'
+
+function add_ssh() {
+ about 'add entry to ssh config'
+ param '1: host'
+ param '2: hostname'
+ param '3: user'
+ group 'ssh'
+
+ echo -en "\n\nHost $1\n HostName $2\n User $3\n ServerAliveInterval 30\n ServerAliveCountMax 120" >> ~/.ssh/config
+}
+
+function sshlist() {
+ about 'list hosts defined in ssh config'
+ group 'ssh'
+
+ awk '$1 ~ /Host$/ { print $2 }' ~/.ssh/config
+}
diff --git a/plugins/available/ssh.plugins.bash b/plugins/available/ssh.plugins.bash
deleted file mode 100644
index 39718fb..0000000
--- a/plugins/available/ssh.plugins.bash
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env bash
-
-function add_ssh() {
- echo -en "\n\nHost $1\n HostName $2\n User $3\n ServerAliveInterval 30\n ServerAliveCountMax 120" >> ~/.ssh/config
-}
-
-function sshlist() {
- awk '$1 ~ /Host$/ { print $2 }' ~/.ssh/config
-}
diff --git a/plugins/available/subversion.plugin.bash b/plugins/available/subversion.plugin.bash
index a7fe941..bdb3edf 100644
--- a/plugins/available/subversion.plugin.bash
+++ b/plugins/available/subversion.plugin.bash
@@ -1,8 +1,21 @@
-#!/usr/bin/env bash
+cite about-plugin
+about-plugin 'svn helper functions'
+
rm_svn(){
+ about 'remove ".svn" files from directory'
+ param '1: directory to search for files'
+ group 'svn'
+
+ if [ -z "$1" ]; then
+ reference rm_svn
+ return
+ fi
find $1 -name .svn -print0 | xargs -0 rm -rf
}
svn_add(){
- svn status | grep '^\?' | sed -e 's/? *//' | sed -e 's/ /\ /g' | xargs svn add
+ about 'add to svn repo'
+ group 'svn'
+
+ svn status | grep '^\?' | sed -e 's/? *//' | sed -e 's/ /\ /g' | xargs svn add
}
diff --git a/plugins/available/tmux.plugin.bash b/plugins/available/tmux.plugin.bash
index ff35336..f7ee337 100644
--- a/plugins/available/tmux.plugin.bash
+++ b/plugins/available/tmux.plugin.bash
@@ -1,2 +1,6 @@
# make sure that tmux is launched in 256 color mode
+
+cite about-plugin
+about-plugin 'make sure that tmux is launched in 256 color mode'
+
alias tmux="TERM=xterm-256color tmux"
diff --git a/plugins/available/tmuxinator.plugin.bash b/plugins/available/tmuxinator.plugin.bash
index cf5500d..a011435 100644
--- a/plugins/available/tmuxinator.plugin.bash
+++ b/plugins/available/tmuxinator.plugin.bash
@@ -1,3 +1,4 @@
-#!/usr/bin/env bash
+cite about-plugin
+about-plugin 'sources tmuxinator script if available'
[[ -s $HOME/.tmuxinator/scripts/tmuxinator ]] && . $HOME/.tmuxinator/scripts/tmuxinator
diff --git a/plugins/available/todo.plugin.bash b/plugins/available/todo.plugin.bash
new file mode 100755
index 0000000..28559de
--- /dev/null
+++ b/plugins/available/todo.plugin.bash
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# you may override any of the exported variables below in your .bash_profile
+
+if [ -z "$TODO_DIR" ]; then
+ export TODO_DIR=$BASH_IT/custom # store todo items in user's custom dir, ignored by git
+fi
+if [ -z "$TODOTXT_DEFAULT_ACTION" ]; then
+ export TODOTXT_DEFAULT_ACTION=ls # typing 't' by itself will list current todos
+fi
+if [ -z "$TODO_SRC_DIR" ]; then
+ export TODO_SRC_DIR=$BASH_IT/plugins/available/todo
+fi
+
+# respect ENV var set in .bash_profile, default is 't'
+alias $TODO='$TODO_SRC_DIR/todo.sh -d $TODO_SRC_DIR/todo.cfg'
+
+export PATH=$PATH:$TODO_SRC_DIR
+source $TODO_SRC_DIR/todo_completion # bash completion for todo.sh
+complete -F _todo $TODO # enable completion for 't' alias
diff --git a/plugins/available/todo/todo.cfg b/plugins/available/todo/todo.cfg
new file mode 100644
index 0000000..d79bf77
--- /dev/null
+++ b/plugins/available/todo/todo.cfg
@@ -0,0 +1,75 @@
+# === EDIT FILE LOCATIONS BELOW ===
+
+# Your todo/done/report.txt locations
+export TODO_FILE="$TODO_DIR/todo.txt"
+export DONE_FILE="$TODO_DIR/done.txt"
+export REPORT_FILE="$TODO_DIR/report.txt"
+
+# You can customize your actions directory location
+#export TODO_ACTIONS_DIR="$HOME/.todo.actions.d"
+
+# == EDIT FILE LOCATIONS ABOVE ===
+
+# === COLOR MAP ===
+
+## Text coloring and formatting is done by inserting ANSI escape codes.
+## If you have re-mapped your color codes, or use the todo.txt
+## output in another output system (like Conky), you may need to
+## over-ride by uncommenting and editing these defaults.
+## If you change any of these here, you also need to uncomment
+## the defaults in the COLORS section below. Otherwise, todo.txt
+## will still use the defaults!
+
+# export BLACK='\\033[0;30m'
+# export RED='\\033[0;31m'
+# export GREEN='\\033[0;32m'
+# export BROWN='\\033[0;33m'
+# export BLUE='\\033[0;34m'
+# export PURPLE='\\033[0;35m'
+# export CYAN='\\033[0;36m'
+# export LIGHT_GREY='\\033[0;37m'
+# export DARK_GREY='\\033[1;30m'
+# export LIGHT_RED='\\033[1;31m'
+# export LIGHT_GREEN='\\033[1;32m'
+# export YELLOW='\\033[1;33m'
+# export LIGHT_BLUE='\\033[1;34m'
+# export LIGHT_PURPLE='\\033[1;35m'
+# export LIGHT_CYAN='\\033[1;36m'
+# export WHITE='\\033[1;37m'
+# export DEFAULT='\\033[0m'
+
+# === COLORS ===
+
+## Uncomment and edit to override these defaults.
+## Reference the constants from the color map above,
+## or use $NONE to disable highlighting.
+#
+# Priorities can be any upper-case letter.
+# A,B,C are highlighted; you can add coloring for more.
+#
+# export PRI_A=$YELLOW # color for A priority
+# export PRI_B=$GREEN # color for B priority
+# export PRI_C=$LIGHT_BLUE # color for C priority
+# export PRI_D=... # define your own
+# export PRI_X=$WHITE # color unless explicitly defined
+
+# There is highlighting for tasks that have been done,
+# but haven't been archived yet.
+#
+# export COLOR_DONE=$LIGHT_GREY
+
+# === BEHAVIOR ===
+
+## customize list output
+#
+# TODOTXT_SORT_COMMAND will filter after line numbers are
+# inserted, but before colorization, and before hiding of
+# priority, context, and project.
+#
+# export TODOTXT_SORT_COMMAND='env LC_COLLATE=C sort -f -k2'
+
+# TODOTXT_FINAL_FILTER will filter list output after colorization,
+# priority hiding, context hiding, and project hiding. That is,
+# just before the list output is displayed.
+#
+# export TODOTXT_FINAL_FILTER='cat'
diff --git a/plugins/available/todo/todo.sh b/plugins/available/todo/todo.sh
new file mode 100755
index 0000000..59f88a9
--- /dev/null
+++ b/plugins/available/todo/todo.sh
@@ -0,0 +1,1321 @@
+#! /bin/bash
+
+# === HEAVY LIFTING ===
+shopt -s extglob extquote
+
+# NOTE: Todo.sh requires the .todo/config configuration file to run.
+# Place the .todo/config file in your home directory or use the -d option for a custom location.
+
+[ -f VERSION-FILE ] && . VERSION-FILE || VERSION="2.9"
+version() {
+ cat <<-EndVersion
+ TODO.TXT Command Line Interface v$VERSION
+
+ First release: 5/11/2006
+ Original conception by: Gina Trapani (http://ginatrapani.org)
+ Contributors: http://github.com/ginatrapani/todo.txt-cli/network
+ License: GPL, http://www.gnu.org/copyleft/gpl.html
+ More information and mailing list at http://todotxt.com
+ Code repository: http://github.com/ginatrapani/todo.txt-cli/tree/master
+ EndVersion
+ exit 1
+}
+
+# Set script name and full path early.
+TODO_SH=$(basename "$0")
+TODO_FULL_SH="$0"
+export TODO_SH TODO_FULL_SH
+
+oneline_usage="$TODO_SH [-fhpantvV] [-d todo_config] action [task_number] [task_description]"
+
+usage()
+{
+ cat <<-EndUsage
+ Usage: $oneline_usage
+ Try '$TODO_SH -h' for more information.
+ EndUsage
+ exit 1
+}
+
+shorthelp()
+{
+ cat <<-EndHelp
+ Usage: $oneline_usage
+
+ Actions:
+ add|a "THING I NEED TO DO +project @context"
+ addm "THINGS I NEED TO DO
+ MORE THINGS I NEED TO DO"
+ addto DEST "TEXT TO ADD"
+ append|app ITEM# "TEXT TO APPEND"
+ archive
+ command [ACTIONS]
+ deduplicate
+ del|rm ITEM# [TERM]
+ depri|dp ITEM#[, ITEM#, ITEM#, ...]
+ do ITEM#[, ITEM#, ITEM#, ...]
+ help
+ list|ls [TERM...]
+ listall|lsa [TERM...]
+ listaddons
+ listcon|lsc
+ listfile|lf [SRC [TERM...]]
+ listpri|lsp [PRIORITIES] [TERM...]
+ listproj|lsprj [TERM...]
+ move|mv ITEM# DEST [SRC]
+ prepend|prep ITEM# "TEXT TO PREPEND"
+ pri|p ITEM# PRIORITY
+ replace ITEM# "UPDATED TODO"
+ report
+ shorthelp
+
+ Actions can be added and overridden using scripts in the actions
+ directory.
+ EndHelp
+
+ # Only list the one-line usage from the add-on actions. This assumes that
+ # add-ons use the same usage indentation structure as todo.sh.
+ addonHelp | grep -e '^ Add-on Actions:' -e '^ [[:alpha:]]'
+
+ cat <<-EndHelpFooter
+
+ See "help" for more details.
+ EndHelpFooter
+ exit 0
+}
+
+help()
+{
+ cat <<-EndOptionsHelp
+ Usage: $oneline_usage
+
+ Options:
+ -@
+ Hide context names in list output. Use twice to show context
+ names (default).
+ -+
+ Hide project names in list output. Use twice to show project
+ names (default).
+ -c
+ Color mode
+ -d CONFIG_FILE
+ Use a configuration file other than the default ~/.todo/config
+ -f
+ Forces actions without confirmation or interactive input
+ -h
+ Display a short help message; same as action "shorthelp"
+ -p
+ Plain mode turns off colors
+ -P
+ Hide priority labels in list output. Use twice to show
+ priority labels (default).
+ -a
+ Don't auto-archive tasks automatically on completion
+ -A
+ Auto-archive tasks automatically on completion
+ -n
+ Don't preserve line numbers; automatically remove blank lines
+ on task deletion
+ -N
+ Preserve line numbers
+ -t
+ Prepend the current date to a task automatically
+ when it's added.
+ -T
+ Do not prepend the current date to a task automatically
+ when it's added.
+ -v
+ Verbose mode turns on confirmation messages
+ -vv
+ Extra verbose mode prints some debugging information and
+ additional help text
+ -V
+ Displays version, license and credits
+ -x
+ Disables TODOTXT_FINAL_FILTER
+
+
+ EndOptionsHelp
+
+ [ $TODOTXT_VERBOSE -gt 1 ] && cat <<-'EndVerboseHelp'
+ Environment variables:
+ TODOTXT_AUTO_ARCHIVE is same as option -a (0)/-A (1)
+ TODOTXT_CFG_FILE=CONFIG_FILE is same as option -d CONFIG_FILE
+ TODOTXT_FORCE=1 is same as option -f
+ TODOTXT_PRESERVE_LINE_NUMBERS is same as option -n (0)/-N (1)
+ TODOTXT_PLAIN is same as option -p (1)/-c (0)
+ TODOTXT_DATE_ON_ADD is same as option -t (1)/-T (0)
+ TODOTXT_VERBOSE=1 is same as option -v
+ TODOTXT_DISABLE_FILTER=1 is same as option -x
+ TODOTXT_DEFAULT_ACTION="" run this when called with no arguments
+ TODOTXT_SORT_COMMAND="sort ..." customize list output
+ TODOTXT_FINAL_FILTER="sed ..." customize list after color, P@+ hiding
+ TODOTXT_SOURCEVAR=\$DONE_FILE use another source for listcon, listproj
+
+
+ EndVerboseHelp
+ cat <<-EndActionsHelp
+ Built-in Actions:
+ add "THING I NEED TO DO +project @context"
+ a "THING I NEED TO DO +project @context"
+ Adds THING I NEED TO DO to your todo.txt file on its own line.
+ Project and context notation optional.
+ Quotes optional.
+
+ addm "FIRST THING I NEED TO DO +project1 @context
+ SECOND THING I NEED TO DO +project2 @context"
+ Adds FIRST THING I NEED TO DO to your todo.txt on its own line and
+ Adds SECOND THING I NEED TO DO to you todo.txt on its own line.
+ Project and context notation optional.
+
+ addto DEST "TEXT TO ADD"
+ Adds a line of text to any file located in the todo.txt directory.
+ For example, addto inbox.txt "decide about vacation"
+
+ append ITEM# "TEXT TO APPEND"
+ app ITEM# "TEXT TO APPEND"
+ Adds TEXT TO APPEND to the end of the task on line ITEM#.
+ Quotes optional.
+
+ archive
+ Moves all done tasks from todo.txt to done.txt and removes blank lines.
+
+ command [ACTIONS]
+ Runs the remaining arguments using only todo.sh builtins.
+ Will not call any .todo.actions.d scripts.
+
+ deduplicate
+ Removes duplicate lines from todo.txt.
+
+ del ITEM# [TERM]
+ rm ITEM# [TERM]
+ Deletes the task on line ITEM# in todo.txt.
+ If TERM specified, deletes only TERM from the task.
+
+ depri ITEM#[, ITEM#, ITEM#, ...]
+ dp ITEM#[, ITEM#, ITEM#, ...]
+ Deprioritizes (removes the priority) from the task(s)
+ on line ITEM# in todo.txt.
+
+ do ITEM#[, ITEM#, ITEM#, ...]
+ Marks task(s) on line ITEM# as done in todo.txt.
+
+ help
+ Display this help message.
+
+ list [TERM...]
+ ls [TERM...]
+ Displays all tasks that contain TERM(s) sorted by priority with line
+ numbers. Each task must match all TERM(s) (logical AND); to display
+ tasks that contain any TERM (logical OR), use
+ "TERM1\|TERM2\|..." (with quotes), or TERM1\\\|TERM2 (unquoted).
+ Hides all tasks that contain TERM(s) preceded by a
+ minus sign (i.e. -TERM). If no TERM specified, lists entire todo.txt.
+
+ listall [TERM...]
+ lsa [TERM...]
+ Displays all the lines in todo.txt AND done.txt that contain TERM(s)
+ sorted by priority with line numbers. Hides all tasks that
+ contain TERM(s) preceded by a minus sign (i.e. -TERM). If no
+ TERM specified, lists entire todo.txt AND done.txt
+ concatenated and sorted.
+
+ listaddons
+ Lists all added and overridden actions in the actions directory.
+
+ listcon
+ lsc
+ Lists all the task contexts that start with the @ sign in todo.txt.
+
+ listfile [SRC [TERM...]]
+ lf [SRC [TERM...]]
+ Displays all the lines in SRC file located in the todo.txt directory,
+ sorted by priority with line numbers. If TERM specified, lists
+ all lines that contain TERM(s) in SRC file. Hides all tasks that
+ contain TERM(s) preceded by a minus sign (i.e. -TERM).
+ Without any arguments, the names of all text files in the todo.txt
+ directory are listed.
+
+ listpri [PRIORITIES] [TERM...]
+ lsp [PRIORITIES] [TERM...]
+ Displays all tasks prioritized PRIORITIES.
+ PRIORITIES can be a single one (A) or a range (A-C).
+ If no PRIORITIES specified, lists all prioritized tasks.
+ If TERM specified, lists only prioritized tasks that contain TERM(s).
+ Hides all tasks that contain TERM(s) preceded by a minus sign
+ (i.e. -TERM).
+
+ listproj
+ lsprj
+ Lists all the projects (terms that start with a + sign) in
+ todo.txt.
+
+ move ITEM# DEST [SRC]
+ mv ITEM# DEST [SRC]
+ Moves a line from source text file (SRC) to destination text file (DEST).
+ Both source and destination file must be located in the directory defined
+ in the configuration directory. When SRC is not defined
+ it's by default todo.txt.
+
+ prepend ITEM# "TEXT TO PREPEND"
+ prep ITEM# "TEXT TO PREPEND"
+ Adds TEXT TO PREPEND to the beginning of the task on line ITEM#.
+ Quotes optional.
+
+ pri ITEM# PRIORITY
+ p ITEM# PRIORITY
+ Adds PRIORITY to task on line ITEM#. If the task is already
+ prioritized, replaces current priority with new PRIORITY.
+ PRIORITY must be a letter between A and Z.
+
+ replace ITEM# "UPDATED TODO"
+ Replaces task on line ITEM# with UPDATED TODO.
+
+ report
+ Adds the number of open tasks and done tasks to report.txt.
+
+ shorthelp
+ List the one-line usage of all built-in and add-on actions.
+
+ EndActionsHelp
+
+ addonHelp
+ exit 1
+}
+
+addonHelp()
+{
+ if [ -d "$TODO_ACTIONS_DIR" ]; then
+ didPrintAddonActionsHeader=
+ for action in "$TODO_ACTIONS_DIR"/*
+ do
+ if [ -f "$action" -a -x "$action" ]; then
+ if [ ! "$didPrintAddonActionsHeader" ]; then
+ cat <<-EndAddonActionsHeader
+ Add-on Actions:
+ EndAddonActionsHeader
+ didPrintAddonActionsHeader=1
+ fi
+ "$action" usage
+ fi
+ done
+ fi
+}
+
+die()
+{
+ echo "$*"
+ exit 1
+}
+
+cleaninput()
+{
+ # Parameters: When $1 = "for sed", performs additional escaping for use
+ # in sed substitution with "|" separators.
+ # Precondition: $input contains text to be cleaned.
+ # Postcondition: Modifies $input.
+
+ # Replace CR and LF with space; tasks always comprise a single line.
+ input=${input//$'\r'/ }
+ input=${input//$'\n'/ }
+
+ if [ "$1" = "for sed" ]; then
+ # This action uses sed with "|" as the substitution separator, and & as
+ # the matched string; these must be escaped.
+ # Backslashes must be escaped, too, and before the other stuff.
+ input=${input//\\/\\\\}
+ input=${input//|/\\|}
+ input=${input//&/\\&}
+ fi
+}
+
+getPrefix()
+{
+ # Parameters: $1: todo file; empty means $TODO_FILE.
+ # Returns: Uppercase FILE prefix to be used in place of "TODO:" where
+ # a different todo file can be specified.
+ local base=$(basename "${1:-$TODO_FILE}")
+ echo "${base%%.[^.]*}" | tr 'a-z' 'A-Z'
+}
+
+getTodo()
+{
+ # Parameters: $1: task number
+ # $2: Optional todo file
+ # Precondition: $errmsg contains usage message.
+ # Postcondition: $todo contains task text.
+
+ local item=$1
+ [ -z "$item" ] && die "$errmsg"
+ [ "${item//[0-9]/}" ] && die "$errmsg"
+
+ todo=$(sed "$item!d" "${2:-$TODO_FILE}")
+ [ -z "$todo" ] && die "$(getPrefix "$2"): No task $item."
+}
+getNewtodo()
+{
+ # Parameters: $1: task number
+ # $2: Optional todo file
+ # Precondition: None.
+ # Postcondition: $newtodo contains task text.
+
+ local item=$1
+ [ -z "$item" ] && die 'Programming error: $item should exist.'
+ [ "${item//[0-9]/}" ] && die 'Programming error: $item should be numeric.'
+
+ newtodo=$(sed "$item!d" "${2:-$TODO_FILE}")
+ [ -z "$newtodo" ] && die "$(getPrefix "$2"): No updated task $item."
+}
+
+replaceOrPrepend()
+{
+ action=$1; shift
+ case "$action" in
+ replace)
+ backref=
+ querytext="Replacement: "
+ ;;
+ prepend)
+ backref=' &'
+ querytext="Prepend: "
+ ;;
+ esac
+ shift; item=$1; shift
+ getTodo "$item"
+
+ if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then
+ echo -n "$querytext"
+ read input
+ else
+ input=$*
+ fi
+ cleaninput "for sed"
+
+ # Retrieve existing priority and prepended date
+ priority=$(sed -e "$item!d" -e $item's/^\((.) \)\{0,1\}\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} \)\{0,1\}.*/\1/' "$TODO_FILE")
+ prepdate=$(sed -e "$item!d" -e $item's/^\((.) \)\{0,1\}\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} \)\{0,1\}.*/\2/' "$TODO_FILE")
+
+ if [ "$prepdate" -a "$action" = "replace" ] && [ "$(echo "$input"|sed -e 's/^\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\}\)\{0,1\}.*/\1/')" ]; then
+ # If the replaced text starts with a date, it will replace the existing
+ # date, too.
+ prepdate=
+ fi
+
+ # Temporarily remove any existing priority and prepended date, perform the
+ # change (replace/prepend) and re-insert the existing priority and prepended
+ # date again.
+ sed -i.bak -e "$item s/^${priority}${prepdate}//" -e "$item s|^.*|${priority}${prepdate}${input}${backref}|" "$TODO_FILE"
+ if [ $TODOTXT_VERBOSE -gt 0 ]; then
+ getNewtodo "$item"
+ case "$action" in
+ replace)
+ echo "$item $todo"
+ echo "TODO: Replaced task with:"
+ echo "$item $newtodo"
+ ;;
+ prepend)
+ echo "$item $newtodo"
+ ;;
+ esac
+ fi
+}
+
+#Preserving environment variables so they don't get clobbered by the config file
+OVR_TODOTXT_AUTO_ARCHIVE="$TODOTXT_AUTO_ARCHIVE"
+OVR_TODOTXT_FORCE="$TODOTXT_FORCE"
+OVR_TODOTXT_PRESERVE_LINE_NUMBERS="$TODOTXT_PRESERVE_LINE_NUMBERS"
+OVR_TODOTXT_PLAIN="$TODOTXT_PLAIN"
+OVR_TODOTXT_DATE_ON_ADD="$TODOTXT_DATE_ON_ADD"
+OVR_TODOTXT_DISABLE_FILTER="$TODOTXT_DISABLE_FILTER"
+OVR_TODOTXT_VERBOSE="$TODOTXT_VERBOSE"
+OVR_TODOTXT_DEFAULT_ACTION="$TODOTXT_DEFAULT_ACTION"
+OVR_TODOTXT_SORT_COMMAND="$TODOTXT_SORT_COMMAND"
+OVR_TODOTXT_FINAL_FILTER="$TODOTXT_FINAL_FILTER"
+
+# == PROCESS OPTIONS ==
+while getopts ":fhpcnNaAtTvVx+@Pd:" Option
+do
+ case $Option in
+ '@' )
+ ## HIDE_CONTEXT_NAMES starts at zero (false); increment it to one
+ ## (true) the first time this flag is seen. Each time the flag
+ ## is seen after that, increment it again so that an even
+ ## number shows context names and an odd number hides context
+ ## names.
+ : $(( HIDE_CONTEXT_NAMES++ ))
+ if [ $(( $HIDE_CONTEXT_NAMES % 2 )) -eq 0 ]
+ then
+ ## Zero or even value -- show context names
+ unset HIDE_CONTEXTS_SUBSTITUTION
+ else
+ ## One or odd value -- hide context names
+ export HIDE_CONTEXTS_SUBSTITUTION='[[:space:]]@[[:graph:]]\{1,\}'
+ fi
+ ;;
+ '+' )
+ ## HIDE_PROJECT_NAMES starts at zero (false); increment it to one
+ ## (true) the first time this flag is seen. Each time the flag
+ ## is seen after that, increment it again so that an even
+ ## number shows project names and an odd number hides project
+ ## names.
+ : $(( HIDE_PROJECT_NAMES++ ))
+ if [ $(( $HIDE_PROJECT_NAMES % 2 )) -eq 0 ]
+ then
+ ## Zero or even value -- show project names
+ unset HIDE_PROJECTS_SUBSTITUTION
+ else
+ ## One or odd value -- hide project names
+ export HIDE_PROJECTS_SUBSTITUTION='[[:space:]][+][[:graph:]]\{1,\}'
+ fi
+ ;;
+ a )
+ OVR_TODOTXT_AUTO_ARCHIVE=0
+ ;;
+ A )
+ OVR_TODOTXT_AUTO_ARCHIVE=1
+ ;;
+ c )
+ OVR_TODOTXT_PLAIN=0
+ ;;
+ d )
+ TODOTXT_CFG_FILE=$OPTARG
+ ;;
+ f )
+ OVR_TODOTXT_FORCE=1
+ ;;
+ h )
+ # Short-circuit option parsing and forward to the action.
+ # Cannot just invoke shorthelp() because we need the configuration
+ # processed to locate the add-on actions directory.
+ set -- '-h' 'shorthelp'
+ ;;
+ n )
+ OVR_TODOTXT_PRESERVE_LINE_NUMBERS=0
+ ;;
+ N )
+ OVR_TODOTXT_PRESERVE_LINE_NUMBERS=1
+ ;;
+ p )
+ OVR_TODOTXT_PLAIN=1
+ ;;
+ P )
+ ## HIDE_PRIORITY_LABELS starts at zero (false); increment it to one
+ ## (true) the first time this flag is seen. Each time the flag
+ ## is seen after that, increment it again so that an even
+ ## number shows priority labels and an odd number hides priority
+ ## labels.
+ : $(( HIDE_PRIORITY_LABELS++ ))
+ if [ $(( $HIDE_PRIORITY_LABELS % 2 )) -eq 0 ]
+ then
+ ## Zero or even value -- show priority labels
+ unset HIDE_PRIORITY_SUBSTITUTION
+ else
+ ## One or odd value -- hide priority labels
+ export HIDE_PRIORITY_SUBSTITUTION="([A-Z])[[:space:]]"
+ fi
+ ;;
+ t )
+ OVR_TODOTXT_DATE_ON_ADD=1
+ ;;
+ T )
+ OVR_TODOTXT_DATE_ON_ADD=0
+ ;;
+ v )
+ : $(( TODOTXT_VERBOSE++ ))
+ ;;
+ V )
+ version
+ ;;
+ x )
+ OVR_TODOTXT_DISABLE_FILTER=1
+ ;;
+ esac
+done
+shift $(($OPTIND - 1))
+
+# defaults if not yet defined
+TODOTXT_VERBOSE=${TODOTXT_VERBOSE:-1}
+TODOTXT_PLAIN=${TODOTXT_PLAIN:-0}
+TODOTXT_CFG_FILE=${TODOTXT_CFG_FILE:-$HOME/.todo/config}
+TODOTXT_FORCE=${TODOTXT_FORCE:-0}
+TODOTXT_PRESERVE_LINE_NUMBERS=${TODOTXT_PRESERVE_LINE_NUMBERS:-1}
+TODOTXT_AUTO_ARCHIVE=${TODOTXT_AUTO_ARCHIVE:-1}
+TODOTXT_DATE_ON_ADD=${TODOTXT_DATE_ON_ADD:-0}
+TODOTXT_DEFAULT_ACTION=${TODOTXT_DEFAULT_ACTION:-}
+TODOTXT_SORT_COMMAND=${TODOTXT_SORT_COMMAND:-env LC_COLLATE=C sort -f -k2}
+TODOTXT_DISABLE_FILTER=${TODOTXT_DISABLE_FILTER:-}
+TODOTXT_FINAL_FILTER=${TODOTXT_FINAL_FILTER:-cat}
+
+# Export all TODOTXT_* variables
+export ${!TODOTXT_@}
+
+# Default color map
+export NONE=''
+export BLACK='\\033[0;30m'
+export RED='\\033[0;31m'
+export GREEN='\\033[0;32m'
+export BROWN='\\033[0;33m'
+export BLUE='\\033[0;34m'
+export PURPLE='\\033[0;35m'
+export CYAN='\\033[0;36m'
+export LIGHT_GREY='\\033[0;37m'
+export DARK_GREY='\\033[1;30m'
+export LIGHT_RED='\\033[1;31m'
+export LIGHT_GREEN='\\033[1;32m'
+export YELLOW='\\033[1;33m'
+export LIGHT_BLUE='\\033[1;34m'
+export LIGHT_PURPLE='\\033[1;35m'
+export LIGHT_CYAN='\\033[1;36m'
+export WHITE='\\033[1;37m'
+export DEFAULT='\\033[0m'
+
+# Default priority->color map.
+export PRI_A=$YELLOW # color for A priority
+export PRI_B=$GREEN # color for B priority
+export PRI_C=$LIGHT_BLUE # color for C priority
+export PRI_X=$WHITE # color unless explicitly defined
+
+# Default highlight colors.
+export COLOR_DONE=$LIGHT_GREY # color for done (but not yet archived) tasks
+
+# Default sentence delimiters for todo.sh append.
+# If the text to be appended to the task begins with one of these characters, no
+# whitespace is inserted in between. This makes appending to an enumeration
+# (todo.sh add 42 ", foo") syntactically correct.
+export SENTENCE_DELIMITERS=',.:;'
+
+[ -e "$TODOTXT_CFG_FILE" ] || {
+ CFG_FILE_ALT="$HOME/todo.cfg"
+
+ if [ -e "$CFG_FILE_ALT" ]
+ then
+ TODOTXT_CFG_FILE="$CFG_FILE_ALT"
+ fi
+}
+
+[ -e "$TODOTXT_CFG_FILE" ] || {
+ CFG_FILE_ALT="$HOME/.todo.cfg"
+
+ if [ -e "$CFG_FILE_ALT" ]
+ then
+ TODOTXT_CFG_FILE="$CFG_FILE_ALT"
+ fi
+}
+
+[ -e "$TODOTXT_CFG_FILE" ] || {
+ CFG_FILE_ALT=$(dirname "$0")"/todo.cfg"
+
+ if [ -e "$CFG_FILE_ALT" ]
+ then
+ TODOTXT_CFG_FILE="$CFG_FILE_ALT"
+ fi
+}
+
+
+if [ -z "$TODO_ACTIONS_DIR" -o ! -d "$TODO_ACTIONS_DIR" ]
+then
+ TODO_ACTIONS_DIR="$HOME/.todo/actions"
+ export TODO_ACTIONS_DIR
+fi
+
+[ -d "$TODO_ACTIONS_DIR" ] || {
+ TODO_ACTIONS_DIR_ALT="$HOME/.todo.actions.d"
+
+ if [ -d "$TODO_ACTIONS_DIR_ALT" ]
+ then
+ TODO_ACTIONS_DIR="$TODO_ACTIONS_DIR_ALT"
+ fi
+}
+
+# === SANITY CHECKS (thanks Karl!) ===
+[ -r "$TODOTXT_CFG_FILE" ] || die "Fatal Error: Cannot read configuration file $TODOTXT_CFG_FILE"
+
+. "$TODOTXT_CFG_FILE"
+
+# === APPLY OVERRIDES
+if [ -n "$OVR_TODOTXT_AUTO_ARCHIVE" ] ; then
+ TODOTXT_AUTO_ARCHIVE="$OVR_TODOTXT_AUTO_ARCHIVE"
+fi
+if [ -n "$OVR_TODOTXT_FORCE" ] ; then
+ TODOTXT_FORCE="$OVR_TODOTXT_FORCE"
+fi
+if [ -n "$OVR_TODOTXT_PRESERVE_LINE_NUMBERS" ] ; then
+ TODOTXT_PRESERVE_LINE_NUMBERS="$OVR_TODOTXT_PRESERVE_LINE_NUMBERS"
+fi
+if [ -n "$OVR_TODOTXT_PLAIN" ] ; then
+ TODOTXT_PLAIN="$OVR_TODOTXT_PLAIN"
+fi
+if [ -n "$OVR_TODOTXT_DATE_ON_ADD" ] ; then
+ TODOTXT_DATE_ON_ADD="$OVR_TODOTXT_DATE_ON_ADD"
+fi
+if [ -n "$OVR_TODOTXT_DISABLE_FILTER" ] ; then
+ TODOTXT_DISABLE_FILTER="$OVR_TODOTXT_DISABLE_FILTER"
+fi
+if [ -n "$OVR_TODOTXT_VERBOSE" ] ; then
+ TODOTXT_VERBOSE="$OVR_TODOTXT_VERBOSE"
+fi
+if [ -n "$OVR_TODOTXT_DEFAULT_ACTION" ] ; then
+ TODOTXT_DEFAULT_ACTION="$OVR_TODOTXT_DEFAULT_ACTION"
+fi
+if [ -n "$OVR_TODOTXT_SORT_COMMAND" ] ; then
+ TODOTXT_SORT_COMMAND="$OVR_TODOTXT_SORT_COMMAND"
+fi
+if [ -n "$OVR_TODOTXT_FINAL_FILTER" ] ; then
+ TODOTXT_FINAL_FILTER="$OVR_TODOTXT_FINAL_FILTER"
+fi
+
+ACTION=${1:-$TODOTXT_DEFAULT_ACTION}
+
+[ -z "$ACTION" ] && usage
+[ -d "$TODO_DIR" ] || die "Fatal Error: $TODO_DIR is not a directory"
+( cd "$TODO_DIR" ) || die "Fatal Error: Unable to cd to $TODO_DIR"
+
+[ -f "$TODO_FILE" ] || cp /dev/null "$TODO_FILE"
+[ -f "$DONE_FILE" ] || cp /dev/null "$DONE_FILE"
+[ -f "$REPORT_FILE" ] || cp /dev/null "$REPORT_FILE"
+
+if [ $TODOTXT_PLAIN = 1 ]; then
+ for clr in ${!PRI_@}; do
+ export $clr=$NONE
+ done
+ PRI_X=$NONE
+ DEFAULT=$NONE
+ COLOR_DONE=$NONE
+fi
+
+_addto() {
+ file="$1"
+ input="$2"
+ cleaninput
+
+ if [[ $TODOTXT_DATE_ON_ADD = 1 ]]; then
+ now=$(date '+%Y-%m-%d')
+ input=$(echo "$input" | sed -e 's/^\(([A-Z]) \)\{0,1\}/\1'"$now /")
+ fi
+ echo "$input" >> "$file"
+ if [ $TODOTXT_VERBOSE -gt 0 ]; then
+ TASKNUM=$(sed -n '$ =' "$file")
+ echo "$TASKNUM $input"
+ echo "$(getPrefix "$file"): $TASKNUM added."
+ fi
+}
+
+shellquote()
+{
+ typeset -r qq=\'; printf %s\\n "'${1//\'/${qq}\\${qq}${qq}}'";
+}
+
+filtercommand()
+{
+ filter=${1:-}
+ shift
+ post_filter=${1:-}
+ shift
+
+ for search_term
+ do
+ ## See if the first character of $search_term is a dash
+ if [ "${search_term:0:1}" != '-' ]
+ then
+ ## First character isn't a dash: hide lines that don't match
+ ## this $search_term
+ filter="${filter:-}${filter:+ | }grep -i $(shellquote "$search_term")"
+ else
+ ## First character is a dash: hide lines that match this
+ ## $search_term
+ #
+ ## Remove the first character (-) before adding to our filter command
+ filter="${filter:-}${filter:+ | }grep -v -i $(shellquote "${search_term:1}")"
+ fi
+ done
+
+ [ -n "$post_filter" ] && {
+ filter="${filter:-}${filter:+ | }${post_filter:-}"
+ }
+
+ printf %s "$filter"
+}
+
+_list() {
+ local FILE="$1"
+ ## If the file starts with a "/" use absolute path. Otherwise,
+ ## try to find it in either $TODO_DIR or using a relative path
+ if [ "${1:0:1}" == / ]; then
+ ## Absolute path
+ src="$FILE"
+ elif [ -f "$TODO_DIR/$FILE" ]; then
+ ## Path relative to todo.sh directory
+ src="$TODO_DIR/$FILE"
+ elif [ -f "$FILE" ]; then
+ ## Path relative to current working directory
+ src="$FILE"
+ elif [ -f "$TODO_DIR/${FILE}.txt" ]; then
+ ## Path relative to todo.sh directory, missing file extension
+ src="$TODO_DIR/${FILE}.txt"
+ else
+ die "TODO: File $FILE does not exist."
+ fi
+
+ ## Get our search arguments, if any
+ shift ## was file name, new $1 is first search term
+
+ _format "$src" '' "$@"
+
+ if [ $TODOTXT_VERBOSE -gt 0 ]; then
+ echo "--"
+ echo "$(getPrefix "$src"): ${NUMTASKS:-0} of ${TOTALTASKS:-0} tasks shown"
+ fi
+}
+getPadding()
+{
+ ## We need one level of padding for each power of 10 $LINES uses.
+ LINES=$(sed -n '$ =' "${1:-$TODO_FILE}")
+ printf %s ${#LINES}
+}
+_format()
+{
+ # Parameters: $1: todo input file; when empty formats stdin
+ # $2: ITEM# number width; if empty auto-detects from $1 / $TODO_FILE.
+ # Precondition: None
+ # Postcondition: $NUMTASKS and $TOTALTASKS contain statistics (unless $TODOTXT_VERBOSE=0).
+
+ FILE=$1
+ shift
+
+ ## Figure out how much padding we need to use, unless this was passed to us.
+ PADDING=${1:-$(getPadding "$FILE")}
+ shift
+
+ ## Number the file, then run the filter command,
+ ## then sort and mangle output some more
+ if [[ $TODOTXT_DISABLE_FILTER = 1 ]]; then
+ TODOTXT_FINAL_FILTER="cat"
+ fi
+ items=$(
+ if [ "$FILE" ]; then
+ sed = "$FILE"
+ else
+ sed =
+ fi \
+ | sed -e '''
+ N
+ s/^/ /
+ s/ *\([ 0-9]\{'"$PADDING"',\}\)\n/\1 /
+ /^[ 0-9]\{1,\} *$/d
+ '''
+ )
+
+ ## Build and apply the filter.
+ filter_command=$(filtercommand "${pre_filter_command:-}" "${post_filter_command:-}" "$@")
+ if [ "${filter_command}" ]; then
+ filtered_items=$(echo -n "$items" | eval "${filter_command}")
+ else
+ filtered_items=$items
+ fi
+ filtered_items=$(
+ echo -n "$filtered_items" \
+ | sed '''
+ s/^ /00000/;
+ s/^ /0000/;
+ s/^ /000/;
+ s/^ /00/;
+ s/^ /0/;
+ ''' \
+ | eval ${TODOTXT_SORT_COMMAND} \
+ | awk '''
+ function highlight(colorVar, color) {
+ color = ENVIRON[colorVar]
+ gsub(/\\+033/, "\033", color)
+ return color
+ }
+ {
+ if (match($0, /^[0-9]+ x /)) {
+ print highlight("COLOR_DONE") $0 highlight("DEFAULT")
+ } else if (match($0, /^[0-9]+ \([A-Z]\) /)) {
+ clr = highlight("PRI_" substr($0, RSTART + RLENGTH - 3, 1))
+ print \
+ (clr ? clr : highlight("PRI_X")) \
+ (ENVIRON["HIDE_PRIORITY_SUBSTITUTION"] == "" ? $0 : substr($0, 1, RLENGTH - 4) substr($0, RSTART + RLENGTH)) \
+ highlight("DEFAULT")
+ } else { print }
+ }
+ ''' \
+ | sed '''
+ s/'"${HIDE_PROJECTS_SUBSTITUTION:-^}"'//g
+ s/'"${HIDE_CONTEXTS_SUBSTITUTION:-^}"'//g
+ s/'"${HIDE_CUSTOM_SUBSTITUTION:-^}"'//g
+ ''' \
+ | eval ${TODOTXT_FINAL_FILTER} \
+ )
+ [ "$filtered_items" ] && echo "$filtered_items"
+
+ if [ $TODOTXT_VERBOSE -gt 0 ]; then
+ NUMTASKS=$( echo -n "$filtered_items" | sed -n '$ =' )
+ TOTALTASKS=$( echo -n "$items" | sed -n '$ =' )
+ fi
+ if [ $TODOTXT_VERBOSE -gt 1 ]; then
+ echo "TODO DEBUG: Filter Command was: ${filter_command:-cat}"
+ fi
+}
+
+export -f cleaninput getPrefix getTodo getNewtodo shellquote filtercommand _list getPadding _format die
+
+# == HANDLE ACTION ==
+action=$( printf "%s\n" "$ACTION" | tr 'A-Z' 'a-z' )
+
+## If the first argument is "command", run the rest of the arguments
+## using todo.sh builtins.
+## Else, run a actions script with the name of the command if it exists
+## or fallback to using a builtin
+if [ "$action" == command ]
+then
+ ## Get rid of "command" from arguments list
+ shift
+ ## Reset action to new first argument
+ action=$( printf "%s\n" "$1" | tr 'A-Z' 'a-z' )
+elif [ -d "$TODO_ACTIONS_DIR" -a -x "$TODO_ACTIONS_DIR/$action" ]
+then
+ "$TODO_ACTIONS_DIR/$action" "$@"
+ exit $?
+fi
+
+## Only run if $action isn't found in .todo.actions.d
+case $action in
+"add" | "a")
+ if [[ -z "$2" && $TODOTXT_FORCE = 0 ]]; then
+ echo -n "Add: "
+ read input
+ else
+ [ -z "$2" ] && die "usage: $TODO_SH add \"TODO ITEM\""
+ shift
+ input=$*
+ fi
+ _addto "$TODO_FILE" "$input"
+ ;;
+
+"addm")
+ if [[ -z "$2" && $TODOTXT_FORCE = 0 ]]; then
+ echo -n "Add: "
+ read input
+ else
+ [ -z "$2" ] && die "usage: $TODO_SH addm \"TODO ITEM\""
+ shift
+ input=$*
+ fi
+
+ # Set Internal Field Seperator as newline so we can
+ # loop across multiple lines
+ SAVEIFS=$IFS
+ IFS=$'\n'
+
+ # Treat each line seperately
+ for line in $input ; do
+ _addto "$TODO_FILE" "$line"
+ done
+ IFS=$SAVEIFS
+ ;;
+
+"addto" )
+ [ -z "$2" ] && die "usage: $TODO_SH addto DEST \"TODO ITEM\""
+ dest="$TODO_DIR/$2"
+ [ -z "$3" ] && die "usage: $TODO_SH addto DEST \"TODO ITEM\""
+ shift
+ shift
+ input=$*
+
+ if [ -f "$dest" ]; then
+ _addto "$dest" "$input"
+ else
+ die "TODO: Destination file $dest does not exist."
+ fi
+ ;;
+
+"append" | "app" )
+ errmsg="usage: $TODO_SH append ITEM# \"TEXT TO APPEND\""
+ shift; item=$1; shift
+ getTodo "$item"
+
+ if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then
+ echo -n "Append: "
+ read input
+ else
+ input=$*
+ fi
+ case "$input" in
+ [$SENTENCE_DELIMITERS]*) appendspace=;;
+ *) appendspace=" ";;
+ esac
+ cleaninput "for sed"
+
+ if sed -i.bak $item" s|^.*|&${appendspace}${input}|" "$TODO_FILE"; then
+ if [ $TODOTXT_VERBOSE -gt 0 ]; then
+ getNewtodo "$item"
+ echo "$item $newtodo"
+ fi
+ else
+ die "TODO: Error appending task $item."
+ fi
+ ;;
+
+"archive" )
+ # defragment blank lines
+ sed -i.bak -e '/./!d' "$TODO_FILE"
+ [ $TODOTXT_VERBOSE -gt 0 ] && grep "^x " "$TODO_FILE"
+ grep "^x " "$TODO_FILE" >> "$DONE_FILE"
+ sed -i.bak '/^x /d' "$TODO_FILE"
+ if [ $TODOTXT_VERBOSE -gt 0 ]; then
+ echo "TODO: $TODO_FILE archived."
+ fi
+ ;;
+
+"del" | "rm" )
+ # replace deleted line with a blank line when TODOTXT_PRESERVE_LINE_NUMBERS is 1
+ errmsg="usage: $TODO_SH del ITEM# [TERM]"
+ item=$2
+ getTodo "$item"
+
+ if [ -z "$3" ]; then
+ if [ $TODOTXT_FORCE = 0 ]; then
+ echo "Delete '$todo'? (y/n)"
+ read ANSWER
+ else
+ ANSWER="y"
+ fi
+ if [ "$ANSWER" = "y" ]; then
+ if [ $TODOTXT_PRESERVE_LINE_NUMBERS = 0 ]; then
+ # delete line (changes line numbers)
+ sed -i.bak -e $item"s/^.*//" -e '/./!d' "$TODO_FILE"
+ else
+ # leave blank line behind (preserves line numbers)
+ sed -i.bak -e $item"s/^.*//" "$TODO_FILE"
+ fi
+ if [ $TODOTXT_VERBOSE -gt 0 ]; then
+ echo "$item $todo"
+ echo "TODO: $item deleted."
+ fi
+ else
+ echo "TODO: No tasks were deleted."
+ fi
+ else
+ sed -i.bak \
+ -e $item"s/^\((.) \)\{0,1\} *$3 */\1/g" \
+ -e $item"s/ *$3 *\$//g" \
+ -e $item"s/ *$3 */ /g" \
+ -e $item"s/ *$3 */ /g" \
+ -e $item"s/$3//g" \
+ "$TODO_FILE"
+ getNewtodo "$item"
+ if [ "$todo" = "$newtodo" ]; then
+ [ $TODOTXT_VERBOSE -gt 0 ] && echo "$item $todo"
+ die "TODO: '$3' not found; no removal done."
+ fi
+ if [ $TODOTXT_VERBOSE -gt 0 ]; then
+ echo "$item $todo"
+ echo "TODO: Removed '$3' from task."
+ echo "$item $newtodo"
+ fi
+ fi
+ ;;
+
+"depri" | "dp" )
+ errmsg="usage: $TODO_SH depri ITEM#[, ITEM#, ITEM#, ...]"
+ shift;
+ [ $# -eq 0 ] && die "$errmsg"
+
+ # Split multiple depri's, if comma separated change to whitespace separated
+ # Loop the 'depri' function for each item
+ for item in ${*//,/ }; do
+ getTodo "$item"
+
+ if [[ "$todo" = \(?\)\ * ]]; then
+ sed -i.bak -e $item"s/^(.) //" "$TODO_FILE"
+ if [ $TODOTXT_VERBOSE -gt 0 ]; then
+ getNewtodo "$item"
+ echo "$item $newtodo"
+ echo "TODO: $item deprioritized."
+ fi
+ else
+ echo "TODO: $item is not prioritized."
+ fi
+ done
+ ;;
+
+"do" )
+ errmsg="usage: $TODO_SH do ITEM#[, ITEM#, ITEM#, ...]"
+ # shift so we get arguments to the do request
+ shift;
+ [ "$#" -eq 0 ] && die "$errmsg"
+
+ # Split multiple do's, if comma separated change to whitespace separated
+ # Loop the 'do' function for each item
+ for item in ${*//,/ }; do
+ getTodo "$item"
+
+ # Check if this item has already been done
+ if [ "${todo:0:2}" != "x " ]; then
+ now=$(date '+%Y-%m-%d')
+ # remove priority once item is done
+ sed -i.bak $item"s/^(.) //" "$TODO_FILE"
+ sed -i.bak $item"s|^|x $now |" "$TODO_FILE"
+ if [ $TODOTXT_VERBOSE -gt 0 ]; then
+ getNewtodo "$item"
+ echo "$item $newtodo"
+ echo "TODO: $item marked as done."
+ fi
+ else
+ echo "TODO: $item is already marked done."
+ fi
+ done
+
+ if [ $TODOTXT_AUTO_ARCHIVE = 1 ]; then
+ # Recursively invoke the script to allow overriding of the archive
+ # action.
+ "$TODO_FULL_SH" archive
+ fi
+ ;;
+
+"help" )
+ if [ -t 1 ] ; then # STDOUT is a TTY
+ if which "${PAGER:-less}" >/dev/null 2>&1; then
+ # we have a working PAGER (or less as a default)
+ help | "${PAGER:-less}" && exit 0
+ fi
+ fi
+ help # just in case something failed above, we go ahead and just spew to STDOUT
+ ;;
+
+"shorthelp" )
+ if [ -t 1 ] ; then # STDOUT is a TTY
+ if which "${PAGER:-less}" >/dev/null 2>&1; then
+ # we have a working PAGER (or less as a default)
+ shorthelp | "${PAGER:-less}" && exit 0
+ fi
+ fi
+ shorthelp # just in case something failed above, we go ahead and just spew to STDOUT
+ ;;
+
+"list" | "ls" )
+ shift ## Was ls; new $1 is first search term
+ _list "$TODO_FILE" "$@"
+ ;;
+
+"listall" | "lsa" )
+ shift ## Was lsa; new $1 is first search term
+
+ TOTAL=$( sed -n '$ =' "$TODO_FILE" )
+ PADDING=${#TOTAL}
+
+ post_filter_command="awk -v TOTAL=$TOTAL -v PADDING=$PADDING '{ \$1 = sprintf(\"%\" PADDING \"d\", (\$1 > TOTAL ? 0 : \$1)); print }' "
+ cat "$TODO_FILE" "$DONE_FILE" | TODOTXT_VERBOSE=0 _format '' "$PADDING" "$@"
+
+ if [ $TODOTXT_VERBOSE -gt 0 ]; then
+ TDONE=$( sed -n '$ =' "$DONE_FILE" )
+ TASKNUM=$(TODOTXT_PLAIN=1 TODOTXT_VERBOSE=0 _format "$TODO_FILE" 1 "$@" | sed -n '$ =')
+ DONENUM=$(TODOTXT_PLAIN=1 TODOTXT_VERBOSE=0 _format "$DONE_FILE" 1 "$@" | sed -n '$ =')
+ echo "--"
+ echo "$(getPrefix "$TODO_FILE"): ${TASKNUM:-0} of ${TOTAL:-0} tasks shown"
+ echo "$(getPrefix "$DONE_FILE"): ${DONENUM:-0} of ${TDONE:-0} tasks shown"
+ echo "total $((TASKNUM + DONENUM)) of $((TOTAL + TDONE)) tasks shown"
+ fi
+ ;;
+
+"listfile" | "lf" )
+ shift ## Was listfile, next $1 is file name
+ if [ $# -eq 0 ]; then
+ [ $TODOTXT_VERBOSE -gt 0 ] && echo "Files in the todo.txt directory:"
+ cd "$TODO_DIR" && ls -1 *.txt
+ else
+ FILE="$1"
+ shift ## Was filename; next $1 is first search term
+
+ _list "$FILE" "$@"
+ fi
+ ;;
+
+"listcon" | "lsc" )
+ FILE=$TODO_FILE
+ [ "$TODOTXT_SOURCEVAR" ] && eval "FILE=$TODOTXT_SOURCEVAR"
+ grep -ho '[^ ]*@[^ ]\+' "${FILE[@]}" | grep '^@' | sort -u
+ ;;
+
+"listproj" | "lsprj" )
+ FILE=$TODO_FILE
+ [ "$TODOTXT_SOURCEVAR" ] && eval "FILE=$TODOTXT_SOURCEVAR"
+ shift
+ eval "$(filtercommand 'cat "${FILE[@]}"' '' "$@")" | grep -o '[^ ]*+[^ ]\+' | grep '^+' | sort -u
+ ;;
+
+"listpri" | "lsp" )
+ shift ## was "listpri", new $1 is priority to list or first TERM
+
+ pri=$(printf "%s\n" "$1" | tr 'a-z' 'A-Z' | grep -e '^[A-Z]$' -e '^[A-Z]-[A-Z]$') && shift || pri="A-Z"
+ post_filter_command="grep '^ *[0-9]\+ ([${pri}]) '"
+ _list "$TODO_FILE" "$@"
+ ;;
+
+"move" | "mv" )
+ # replace moved line with a blank line when TODOTXT_PRESERVE_LINE_NUMBERS is 1
+ errmsg="usage: $TODO_SH mv ITEM# DEST [SRC]"
+ item=$2
+ dest="$TODO_DIR/$3"
+ src="$TODO_DIR/$4"
+
+ [ -z "$4" ] && src="$TODO_FILE"
+ [ -z "$dest" ] && die "$errmsg"
+
+ [ -f "$src" ] || die "TODO: Source file $src does not exist."
+ [ -f "$dest" ] || die "TODO: Destination file $dest does not exist."
+
+ getTodo "$item" "$src"
+ [ -z "$todo" ] && die "$item: No such item in $src."
+ if [ $TODOTXT_FORCE = 0 ]; then
+ echo "Move '$todo' from $src to $dest? (y/n)"
+ read ANSWER
+ else
+ ANSWER="y"
+ fi
+ if [ "$ANSWER" = "y" ]; then
+ if [ $TODOTXT_PRESERVE_LINE_NUMBERS = 0 ]; then
+ # delete line (changes line numbers)
+ sed -i.bak -e $item"s/^.*//" -e '/./!d' "$src"
+ else
+ # leave blank line behind (preserves line numbers)
+ sed -i.bak -e $item"s/^.*//" "$src"
+ fi
+ echo "$todo" >> "$dest"
+
+ if [ $TODOTXT_VERBOSE -gt 0 ]; then
+ echo "$item $todo"
+ echo "TODO: $item moved from '$src' to '$dest'."
+ fi
+ else
+ echo "TODO: No tasks moved."
+ fi
+ ;;
+
+"prepend" | "prep" )
+ errmsg="usage: $TODO_SH prepend ITEM# \"TEXT TO PREPEND\""
+ replaceOrPrepend 'prepend' "$@"
+ ;;
+
+"pri" | "p" )
+ item=$2
+ newpri=$( printf "%s\n" "$3" | tr 'a-z' 'A-Z' )
+
+ errmsg="usage: $TODO_SH pri ITEM# PRIORITY
+note: PRIORITY must be anywhere from A to Z."
+
+ [ "$#" -ne 3 ] && die "$errmsg"
+ [[ "$newpri" = @([A-Z]) ]] || die "$errmsg"
+ getTodo "$item"
+
+ oldpri=
+ if [[ "$todo" = \(?\)\ * ]]; then
+ oldpri=${todo:1:1}
+ fi
+
+ if [ "$oldpri" != "$newpri" ]; then
+ sed -i.bak -e $item"s/^(.) //" -e $item"s/^/($newpri) /" "$TODO_FILE"
+ fi
+ if [ $TODOTXT_VERBOSE -gt 0 ]; then
+ getNewtodo "$item"
+ echo "$item $newtodo"
+ if [ "$oldpri" != "$newpri" ]; then
+ if [ "$oldpri" ]; then
+ echo "TODO: $item re-prioritized from ($oldpri) to ($newpri)."
+ else
+ echo "TODO: $item prioritized ($newpri)."
+ fi
+ fi
+ fi
+ if [ "$oldpri" = "$newpri" ]; then
+ echo "TODO: $item already prioritized ($newpri)."
+ fi
+ ;;
+
+"replace" )
+ errmsg="usage: $TODO_SH replace ITEM# \"UPDATED ITEM\""
+ replaceOrPrepend 'replace' "$@"
+ ;;
+
+"report" )
+ # archive first
+ # Recursively invoke the script to allow overriding of the archive
+ # action.
+ "$TODO_FULL_SH" archive
+
+ TOTAL=$( sed -n '$ =' "$TODO_FILE" )
+ TDONE=$( sed -n '$ =' "$DONE_FILE" )
+ NEWDATA="${TOTAL:-0} ${TDONE:-0}"
+ LASTREPORT=$(sed -ne '$p' "$REPORT_FILE")
+ LASTDATA=${LASTREPORT#* } # Strip timestamp.
+ if [ "$LASTDATA" = "$NEWDATA" ]; then
+ echo "$LASTREPORT"
+ [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: Report file is up-to-date."
+ else
+ NEWREPORT="$(date +%Y-%m-%dT%T) ${NEWDATA}"
+ echo "${NEWREPORT}" >> "$REPORT_FILE"
+ echo "${NEWREPORT}"
+ [ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: Report file updated."
+ fi
+ ;;
+
+"deduplicate" )
+ if [ $TODOTXT_PRESERVE_LINE_NUMBERS = 0 ]; then
+ deduplicateSedCommand='d'
+ else
+ deduplicateSedCommand='s/^.*//; p'
+ fi
+
+ # To determine the difference when deduplicated lines are preserved, only
+ # non-empty lines must be counted.
+ originalTaskNum=$( sed -e '/./!d' "$TODO_FILE" | sed -n '$ =' )
+
+ # Look for duplicate lines and discard the second occurrence.
+ # We start with an empty hold space on the first line. For each line:
+ # G - appends newline + hold space to the pattern space
+ # s/\n/&&/; - double up the first new line so we catch adjacent dups
+ # /^\([^\n]*\n\).*\n\1/b dedup
+ # If the first line of the hold space shows up again later as an
+ # entire line, it's a duplicate. Jump to the "dedup" label, where
+ # either of the following is executed, depending on whether empty
+ # lines should be preserved:
+ # d - Delete the current pattern space, quit this line and
+ # move on to the next, or:
+ # s/^.*//; p - Clear the task text, print this line and move on to
+ # the next.
+ # s/\n//; - else (no duplicate), drop the doubled newline
+ # h; - replace the hold space with the expanded pattern space
+ # P; - print up to the first newline (that is, the input line)
+ # b - end processing of the current line
+ sed -i.bak -n \
+ -e 'G; s/\n/&&/; /^\([^\n]*\n\).*\n\1/b dedup' \
+ -e 's/\n//; h; P; b' \
+ -e ':dedup' \
+ -e "$deduplicateSedCommand" \
+ "$TODO_FILE"
+
+ newTaskNum=$( sed -e '/./!d' "$TODO_FILE" | sed -n '$ =' )
+ deduplicateNum=$(( originalTaskNum - newTaskNum ))
+ if [ $deduplicateNum -eq 0 ]; then
+ echo "TODO: No duplicate tasks found"
+ else
+ echo "TODO: $deduplicateNum duplicate task(s) removed"
+ fi
+ ;;
+
+"listaddons" )
+ if [ -d "$TODO_ACTIONS_DIR" ]; then
+ cd "$TODO_ACTIONS_DIR" || exit $?
+ for action in *
+ do
+ if [ -f "$action" -a -x "$action" ]; then
+ echo "$action"
+ fi
+ done
+ fi
+ ;;
+
+* )
+ usage;;
+esac
diff --git a/plugins/available/todo/todo_completion b/plugins/available/todo/todo_completion
new file mode 100644
index 0000000..3f9d308
--- /dev/null
+++ b/plugins/available/todo/todo_completion
@@ -0,0 +1,107 @@
+#!/bin/bash source-this-script
+[ "$BASH_VERSION" ] || return
+
+_todo()
+{
+ local cur prev opts
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+
+ local -r OPTS="-@ -@@ -+ -++ -d -f -h -p -P -PP -a -n -t -v -vv -V -x"
+ local -r COMMANDS="\
+ add a addto addm append app archive command del \
+ rm depri dp do help list ls listaddons listall lsa listcon \
+ lsc listfile lf listpri lsp listproj lsprj move \
+ mv prepend prep pri p replace report shorthelp"
+
+ local _todo_sh=${_todo_sh:-todo.sh}
+ local completions
+ if [ $COMP_CWORD -eq 1 ]; then
+ completions="$COMMANDS $(eval TODOTXT_VERBOSE=0 $_todo_sh command listaddons) $OPTS"
+ elif [[ $COMP_CWORD -gt 2 && ( \
+ "${COMP_WORDS[COMP_CWORD-2]}" =~ ^(move|mv)$ || \
+ "${COMP_WORDS[COMP_CWORD-3]}" =~ ^(move|mv)$ ) ]]; then
+ # "move ITEM# DEST [SRC]" has file arguments on positions 2 and 3.
+ completions=$(eval TODOTXT_VERBOSE=0 $_todo_sh command listfile)
+ else
+ case "$prev" in
+ command)
+ completions=$COMMANDS;;
+ addto|listfile|lf)
+ completions=$(eval TODOTXT_VERBOSE=0 $_todo_sh command listfile);;
+ -*) completions="$COMMANDS $(eval TODOTXT_VERBOSE=0 $_todo_sh command listaddons) $OPTS";;
+ *) case "$cur" in
+ +*) completions=$(eval TODOTXT_VERBOSE=0 $_todo_sh command listproj)
+ COMPREPLY=( $( compgen -W "$completions" -- $cur ))
+ [ ${#COMPREPLY[@]} -gt 0 ] && return 0
+ # Fall back to projects extracted from done tasks.
+ completions=$(eval 'TODOTXT_VERBOSE=0 TODOTXT_SOURCEVAR=\$DONE_FILE' $_todo_sh command listproj)
+ ;;
+ @*) completions=$(eval TODOTXT_VERBOSE=0 $_todo_sh command listcon)
+ COMPREPLY=( $( compgen -W "$completions" -- $cur ))
+ [ ${#COMPREPLY[@]} -gt 0 ] && return 0
+ # Fall back to contexts extracted from done tasks.
+ completions=$(eval 'TODOTXT_VERBOSE=0 TODOTXT_SOURCEVAR=\$DONE_FILE' $_todo_sh command listcon)
+ ;;
+ *) if [[ "$cur" =~ ^[0-9]+$ ]]; then
+ # Remove the (padded) task number; we prepend the
+ # user-provided $cur instead.
+ # Remove the timestamp prepended by the -t option,
+ # and the done date (for done tasks); there's no
+ # todo.txt option for that yet.
+ # But keep priority and "x"; they're short and may
+ # provide useful context.
+ # Remove any trailing whitespace; the Bash
+ # completion inserts a trailing space itself.
+ # Finally, limit the output to a single line just as
+ # a safety check of the ls action output.
+ local todo=$( \
+ eval TODOTXT_VERBOSE=0 $_todo_sh '-@ -+ -p -x command ls "^ *${cur} "' | \
+ sed -e 's/^ *[0-9]\{1,\} //' -e 's/\((.) \)[0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} /\1/' \
+ -e 's/\([xX] \)\([0-9]\{2,4\}-[0-9]\{2\}-[0-9]\{2\} \)\{1,2\}/\1/' \
+ -e 's/[[:space:]]*$//' \
+ -e '1q' \
+ )
+ # Append task text as a shell comment. This
+ # completion can be a safety check before a
+ # destructive todo.txt operation.
+ [ "$todo" ] && COMPREPLY[0]="$cur # $todo"
+ return 0
+ else
+ return 0
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+
+ COMPREPLY=( $( compgen -W "$completions" -- $cur ))
+ return 0
+}
+complete -F _todo todo.sh
+
+# If you define an alias (e.g. "t") to todo.sh, you need to explicitly enable
+# completion for it, too:
+#complete -F _todo t
+
+# If you have renamed the todo.sh executable, or if it is not accessible through
+# PATH, you need to add and use a wrapper completion function, like this:
+#_todoElsewhere()
+#{
+# local _todo_sh='/path/to/todo2.sh'
+# _todo "$@"
+#}
+#complete -F _todoElsewhere /path/to/todo2.sh
+
+# If you use aliases to use different configuration(s), you need to add and use
+# a wrapper completion function for each configuration if you want to complete
+# fron the actual configured task locations:
+#alias todo2='todo.sh -d "$HOME/todo2.cfg"'
+#_todo2()
+#{
+# local _todo_sh='todo.sh -d "$HOME/todo2.cfg"'
+# _todo "$@"
+#}
+#complete -F _todo2 todo2
diff --git a/plugins/available/vagrant.plugins.bash b/plugins/available/vagrant.plugin.bash
similarity index 94%
rename from plugins/available/vagrant.plugins.bash
rename to plugins/available/vagrant.plugin.bash
index 3131744..aa223e7 100644
--- a/plugins/available/vagrant.plugins.bash
+++ b/plugins/available/vagrant.plugin.bash
@@ -1,4 +1,6 @@
-#!/usr/bin/env bash
+cite about-plugin
+about-plugin 'set up vagrant autocompletion'
+
_vagrant()
{
cur="${COMP_WORDS[COMP_CWORD]}"
diff --git a/plugins/available/virtualenv.plugin.bash b/plugins/available/virtualenv.plugin.bash
index ba27c76..302e19d 100644
--- a/plugins/available/virtualenv.plugin.bash
+++ b/plugins/available/virtualenv.plugin.bash
@@ -1,19 +1,30 @@
-#!/usr/bin/env bash
-
# make sure virtualenvwrapper is enabled if available
+
+cite about-plugin
+about-plugin 'virtualenvwrapper helper functions'
+
[[ `which virtualenvwrapper.sh` ]] && . virtualenvwrapper.sh
-# create a new virtualenv for this directory
+
function mkvenv {
+ about 'create a new virtualenv for this directory'
+ group 'virtualenv'
+
cwd=`basename \`pwd\``
mkvirtualenv --no-site-packages --distribute $cwd
}
-# create a new virtualenv for the branch you're currently in
+
function mkvbranch {
+ about 'create a new virtualenv for the current branch'
+ group 'virtualenv'
+
mkvirtualenv --no-site-packages --distribute "$(basename `pwd`)@$(git_prompt_info)"
}
function wovbranch {
+ about 'sets workon branch'
+ group 'virtualenv'
+
workon "$(basename `pwd`)@$(git_prompt_info)"
}
diff --git a/plugins/available/xterm.plugins.bash b/plugins/available/xterm.plugins.bash
deleted file mode 100644
index 3e4ac9e..0000000
--- a/plugins/available/xterm.plugins.bash
+++ /dev/null
@@ -1,17 +0,0 @@
-set_xterm_title () {
- local title="$1"
- echo -ne "\e]0;$title\007"
-}
-
-
-precmd () {
- set_xterm_title "${USER}@${HOSTNAME} `dirs -0` $PROMPTCHAR"
-}
-
-preexec () {
- set_xterm_title "$1 {`dirs -0`} (${USER}@${HOSTNAME})"
-}
-
-case "$TERM" in
- xterm*|rxvt*) preexec_install;;
-esac
diff --git a/plugins/available/z.bash b/plugins/available/z.plugin.bash
similarity index 91%
rename from plugins/available/z.bash
rename to plugins/available/z.plugin.bash
index ef3e3d9..6653575 100644
--- a/plugins/available/z.bash
+++ b/plugins/available/z.plugin.bash
@@ -1,7 +1,7 @@
-#!/usr/bin/env bash
+cite about-plugin
+about-plugin 'maintains a jump-list of the directories you actually use'
+about-plugin ' z is DEPRECATED, use fasd instead'
-# maintains a jump-list of the directories you actually use
-#
# INSTALL:
# * put something like this in your .bashrc:
# . /path/to/z.sh
@@ -15,6 +15,11 @@
# * z -t foo # goes to most recently accessed dir matching foo
# * z -l foo # list all dirs matching foo (by frecency)
+if [ -e $BASH_IT/plugins/enabled/fasd.plugin.bash ]; then
+ printf '%s\n' 'sorry, the z plugin is incompatible with the fasd plugin. you may use either, but not both.'
+ return
+fi
+
z() {
local datafile="$HOME/.z"
if [ "$1" = "--add" ]; then
diff --git a/plugins/available/z_autoenv.plugins.bash b/plugins/available/z_autoenv.plugin.bash
similarity index 87%
rename from plugins/available/z_autoenv.plugins.bash
rename to plugins/available/z_autoenv.plugin.bash
index 04efa85..dd1aec1 100644
--- a/plugins/available/z_autoenv.plugins.bash
+++ b/plugins/available/z_autoenv.plugin.bash
@@ -1,4 +1,6 @@
-#!/usr/bin/env bash
+cite about-plugin
+about-plugin 'source into environment when cding to directories'
+
if [[ -n "${ZSH_VERSION}" ]]
then __array_offset=0
else __array_offset=1
diff --git a/themes/base.theme.bash b/themes/base.theme.bash
index fe112ec..f096fda 100644
--- a/themes/base.theme.bash
+++ b/themes/base.theme.bash
@@ -31,7 +31,7 @@
RBFU_THEME_PROMPT_SUFFIX='|'
function scm {
- if [[ -d .git ]]; then SCM=$SCM_GIT
+ if [[ -f .git/HEAD ]]; then SCM=$SCM_GIT
elif [[ -n "$(git symbolic-ref HEAD 2> /dev/null)" ]]; then SCM=$SCM_GIT
elif [[ -d .hg ]]; then SCM=$SCM_HG
elif [[ -n "$(hg root 2> /dev/null)" ]]; then SCM=$SCM_HG
@@ -121,7 +121,7 @@
function rbenv_version_prompt {
if which rbenv &> /dev/null; then
- rbenv=$(rbenv global) || return
+ rbenv=$(rbenv version-name) || return
echo -e "$RBENV_THEME_PROMPT_PREFIX$rbenv$RBENV_THEME_PROMPT_SUFFIX"
fi
}
diff --git a/themes/candy/candy.theme.bash b/themes/candy/candy.theme.bash
index e568964..77f8ff4 100644
--- a/themes/candy/candy.theme.bash
+++ b/themes/candy/candy.theme.bash
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
function prompt_command() {
- PS1="${green}\u@\h ${blue}\T ${reset_color}${white}\w${reset_color}$(scm_prompt_info)\]${blue} →${bold_blue} ${reset_color} ";
+ PS1="${green}\u@\h ${blue}\T ${reset_color}${white}\w${reset_color}$(scm_prompt_info)${blue} →${bold_blue} ${reset_color} ";
}
PROMPT_COMMAND=prompt_command;
diff --git a/themes/doubletime/doubletime.theme.bash b/themes/doubletime/doubletime.theme.bash
index 6756976..87ced7e 100644
--- a/themes/doubletime/doubletime.theme.bash
+++ b/themes/doubletime/doubletime.theme.bash
@@ -59,14 +59,15 @@
PROMPT_COMMAND=prompt_setter
git_prompt_status() {
-
- if [ -n "$(git status | grep 'Changes not staged' 2> /dev/null)" ]; then
+ local git_status_output
+ git_status_output=$(git status 2> /dev/null )
+ if [ -n "$(echo $git_status_output | grep 'Changes not staged')" ]; then
git_status="${bold_red}$(scm_prompt_info) ✗"
- elif [ -n "$(git status | grep 'Changes to be committed' 2> /dev/null)" ]; then
+ elif [ -n "$(echo $git_status_output | grep 'Changes to be committed')" ]; then
git_status="${bold_yellow}$(scm_prompt_info) ^"
- elif [ -n "$(git status | grep 'Untracked files' 2> /dev/null)" ]; then
+ elif [ -n "$(echo $git_status_output | grep 'Untracked files')" ]; then
git_status="${bold_cyan}$(scm_prompt_info) +"
- elif [ -n "$(git status | grep 'nothing to commit' 2> /dev/null)" ]; then
+ elif [ -n "$(echo $git_status_output | grep 'nothing to commit')" ]; then
git_status="${bold_green}$(scm_prompt_info) ${green}✓"
else
git_status="$(scm_prompt_info)"
@@ -74,18 +75,3 @@
echo "[$git_status${normal}]"
}
-
-# git_prompt_color() {
-#
-# if [ -n "$(git status | grep 'Changes not staged' 2> /dev/null)" ]; then
-# git_status='${bold_red} ✗'
-# elif [ -n "$(git status | grep 'Changes to be committed' 2> /dev/null)" ]; then
-# git_status='${bold_yellow} ^'
-# elif [ -n "$(git status | grep 'Untracked files' 2> /dev/null)" ]; then
-# git_status='${bold_cyan} +'
-# else
-# git_status='${bold_green} ✓'
-# fi
-# echo $git_status
-#
-# }