diff --git a/.ackrc b/.ackrc new file mode 100644 index 00000000..876f1317 --- /dev/null +++ b/.ackrc @@ -0,0 +1 @@ +--ignore-dir=enabled/ diff --git a/.editorconfig b/.editorconfig new file mode 100755 index 00000000..4dc96bd5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# EditorConfig is awesome: http://EditorConfig.org + +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index dc868103..b748d384 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.atom-build.json */enabled/* .DS_Store custom/* @@ -9,3 +10,5 @@ lib/custom.bash plugins/custom.plugins.bash *.swp .*.un~ +bats +.idea diff --git a/.travis.yml b/.travis.yml index a1745beb..34c38fe7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,3 @@ sudo: false -install: git clone --depth 1 https://github.com/sstephenson/bats.git -script: PATH="./bats/bin:$PATH" test/run +script: test/run language: c diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..b9bd7d91 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,34 @@ +# Contribution Guidelines + +When contributing a new feature, a bug fix, a new theme, or any other change to Bash-it, please consider the following guidelines. Most of this is common sense, but please try to stick to the conventions listed here. + +## Issues + +* When opening a new issue in the issue tracker, please include information about which _Operating System_ you're using, and which version of _Bash_. +* In many cases, it also makes sense to show which Bash-it plugins you are using. This information can be obtained using `bash-it show plugins`. +* If the issue happens while loading Bash-it, please also include your `~/.bash_profile` or `~/.bashrc` file, as well as the install location of Bash-it (default should be `~/.bash_it`). +* When reporting a bug or requesting a new feature, consider providing a Pull Request that fixes the issue or can be used as a starting point for the new feature. Don't be afraid, most things aren't that complex... + +## Pull Requests + +* Fork the Bash-it repo, create a new feature branch from _master_ and apply your changes there. Create a _Pull Request_ from your feature branch against Bash-it's _master_ branch. +* Limit each Pull Request to one feature. Don't bundle multiple features/changes (e.g. a new _Theme_ and a fix to an existing plugin) into a single Pull Request - create one PR for the theme, and a separate PR for the fix. +* For complex changes, try to _squash_ your changes into a single commit. Don't create a PR consisting of 20 commits that show your work in progress. Before you create the PR, _squash_ your changes into a single commit. + +## Code Style + +* Try to stick to the existing code style. Please don't reformat or change the syntax of existing code simply because you don't like that style. +* Indentation is using spaces, not tabs. Most of the code is indented with 2 spaces, some with 4 spaces. Please try to stick to 2 spaces. If you're using an editor that supports [EditorConfig](http://EditorConfig.org), the editor should automatically use the settings defined in Bash-it's [.editorconfig file](.editorconfig). +* When creating new functions, please use a dash ("-") to separate the words of the function's name, e.g. `my-new-function`. Don't use underscores, e.g. `my_new_function`. +* Internal functions that aren't to be used by the end user should start with an underscore, e.g. `_my-new-internal-function`. +* Use the provided meta functions to document your code, e.g. `about-plugin`, `about`, `group`, `param`, `example`. This will make it easier for other people to use your new functionality. Take a look at the existing code for an example (e.g. [the base plugin](plugins/available/base.plugin.bash)). +* When adding files, please use the existing file naming conventions, e.g. plugin files need to end in `.plugin.bash`. This is important for the installation functionality. + +## Features + +* When adding new completions or plugins, please don't simply copy existing tools into the Bash-it codebase, try to load/integrate the tools instead. An example is using `nvm`: Instead of copying the existing `nvm` script into Bash-it, the `nvm.plugin.bash` file tries to load an existing installation of `nvm`. This means an additional step for the user (installing `nvm` from its own repo, or through a package manager), but it will also ensure that `nvm` can be upgraded in an easy way. + +## Themes + +* When adding a new theme, please include a screenshot and a short description about what makes this theme unique in the Pull Request. +* Ideally, each theme's folder should contain a `README.md` file describing the theme and its configuration options. diff --git a/README.md b/README.md index ab63b9bb..36779e83 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,46 @@ -# Bash it +# Bash-it [![Build Status](https://travis-ci.org/Bash-it/bash-it.svg?branch=master)](https://travis-ci.org/Bash-it/bash-it) [![Join the chat at https://gitter.im/Bash-it/bash-it](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Bash-it/bash-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -**Bash it** is a collection of community bash commands and scripts. (And a shameless ripoff of [oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh). :) +**Bash-it** is a collection of community Bash commands and scripts. (And a shameless ripoff of [oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh) :smiley:) Includes autocompletion, themes, aliases, custom functions, a few stolen pieces from Steve Losh, and more. -Bash it provides a solid framework for using, developing and maintaining shell scripts and custom commands for your daily work. If you're using the _Bourne Again Shell_ (Bash) on a regular basis and have been looking for an easy way on how to keep all of these nice little scripts and aliases under control, then Bash it is for you! Stop polluting your `~/bin` directory and your `.bashrc` file, fork/clone Bash it and start hacking away. +Bash-it provides a solid framework for using, developing and maintaining shell scripts and custom commands for your daily work. If you're using the _Bourne Again Shell_ (Bash) on a regular basis and have been looking for an easy way on how to keep all of these nice little scripts and aliases under control, then Bash-it is for you! Stop polluting your `~/bin` directory and your `.bashrc` file, fork/clone Bash-it and start hacking away. ## Install -1. Check a clone of this repo: `git clone --depth=1 https://github.com/Bash-it/bash-it.git ~/.bash_it` -2. Run `~/.bash_it/install.sh` (it automatically backs up your `~/.bash_profile` or `~/.bashrc`, depends on your OS) -3. Edit your modified config (`~/.bash_profile` or `~/.bashrc`) 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). -This is to set up the `.jekyllconfig` file, which stores info necessary to use the Jekyll plugin. +1. Check out a clone of this repo to a location of your choice, such as: `git clone --depth=1 https://github.com/Bash-it/bash-it.git ~/.bash_it` +2. Run `~/.bash_it/install.sh` (it automatically backs up your `~/.bash_profile` or `~/.bashrc`, depending on your OS) +3. Edit your modified config (`~/.bash_profile` or `~/.bashrc`) file in order to customize Bash-it. +4. Check out available aliases, completions and plugins and enable the ones you want to use (see the next section for more details). **INSTALL OPTIONS:** The install script can take the following options: -* `--all`: Enable all aliases, plugins and completions. -* `--none`: Don't enable any aliases, plugins or completions. +* `--interactive`: Asks the user which aliases, completions and plugins to enable. -If none of these parameters is provided, the install script will ask the user. +When run without the `--interactive` switch, Bash-it only enables a sane default set of functionality to keep your shell clean and to avoid issues with missing dependencies. Feel free to enable the tools you want to use after the installation. + +**NOTE**: Keep in mind how Bash load its configuration files, `.bash_profile` for login shells (and in Mac OS X in terminal emulators like [Termminal.app](http://www.apple.com/osx/apps/) or [iTerm2](https://www.iterm2.com/)) and `.bashrc` for interactive shells (default mode in most of the GNU/Linux terminal emulators), to ensure that Bash-it is loaded correctly. A good "practice" is sourcing `.bashrc` into `.bash_profile` to keep things working in all the scenarios, to achieve this, you can add this snippet in your `.bash_profile`: + +``` +if [ -f ~/.bashrc ]; then + . ~/.bashrc +fi +``` + +Refer to the official [Bash documention](https://www.gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files) to get more info. + +## Update + +To update Bash-it, simply run: + +``` +bash-it update +``` + +that's all. ## Help Screens @@ -37,7 +53,67 @@ bash-it help completions # shows help for installed completions bash-it help plugins # shows help for installed plugins ``` -## Your Custom scripts, aliases, and functions +## Search + +If you need to quickly find out which of the plugins, aliases or completions +are available for a specific framework, programming language, or an environment, you can _search_ for +multiple terms related to the commands you use frequently. Search will +find and print out modules with the name or description matching the terms +provided. + +#### Syntax + +```bash + bash-it search term1 [[-]term2] [[-]term3].... +``` + +As an example, a ruby developer might want to enable everything +related to the commands such as `ruby`, `rake`, `gem`, `bundler` and `rails`. +Search command helps you find related modules, so that you can decide which +of them you'd like to use: + +```bash +❯ bash-it search ruby rake gem bundle irb rails + aliases: bundler rails + plugins: chruby chruby-auto ruby + completions: bundler gem rake +``` + +Currently enabled modules will be shown in green. + +#### Search with Negations + +You can prefix a search term with a "-" to exclude it from the results. In the above +example, if we wanted to hide `chruby` and `chruby-auto`, we could change the command as +follows: + +```bash +❯ bash-it search ruby rake gem bundle irb rails -chruby + aliases: bundler rails + plugins: ruby + completions: bundler gem rake +``` + +#### Using Search to Enable or Disable Components + +By adding a `--enable` or `--disable` to the search command, you can automatically +enable all modules that come up as a result of a search query. This could be quite +handy if you like to enable a bunch of components related to the same topic. + +#### Disabling ASCII Color + +To remove non-printing non-ASCII characters responsible for the coloring of the +search output, you can set environment variable `NO_COLOR`. Enabled components will +then be shown with a checkmark: + +```bash +❯ NO_COLOR=1 bash-it search ruby rake gem bundle irb rails -chruby + aliases => ✓bundler ✓rails + plugins => ✓ruby + completions => bundler gem rake +``` + +## Your Custom scripts, aliases, themes, and functions For custom scripts, and aliases, just create the following files (they'll be ignored by the git repo): @@ -45,38 +121,47 @@ For custom scripts, and aliases, just create the following files (they'll be ign * `completion/custom.completion.bash` * `lib/custom.bash` * `plugins/custom.plugins.bash` +* `custom/themes//.theme.bash` Anything in the custom directory will be ignored, with the exception of `custom/example.bash`. ## Themes -There are a few bash it themes. If you've created your own custom prompts, I'd love it if you shared with everyone else! Just submit a Pull Request to me (revans). +There are a few Bash-it themes. If you've created your own custom prompts, I'd love it if you shared with everyone else! Just submit a Pull Request. -You can see the theme screenshots [here](https://github.com/revans/bash-it/wiki/Themes) +You can see the theme screenshots [here](https://github.com/Bash-it/bash-it/wiki/Themes). -Alternatively, you can preview the themes in your own shell using `BASH_PREVIEW=true reload` +Alternatively, you can preview the themes in your own shell using `BASH_PREVIEW=true reload`. + +**NOTE**: Bash-it and some themes use UTF-8 characters, so to avoid extrange behaviors in your terminal, set your locale to `LC_ALL=en_US.UTF-8` or the equivalent to your language if isn't American English. ## Uninstalling -To uninstall Bash it, run the `uninstall.sh` script found in the `$BASH_IT` directory: +To uninstall Bash-it, run the `uninstall.sh` script found in the `$BASH_IT` directory: ``` cd $BASH_IT ./uninstall.sh ``` -This will restore your previous Bash profile. After the uninstall script finishes, remove the Bash it directory from your machine (`rm -rf $BASH_IT`) and start a new shell. +This will restore your previous Bash profile. After the uninstall script finishes, remove the Bash-it directory from your machine (`rm -rf $BASH_IT`) and start a new shell. + +## Contributing + +Please take a look at the [Contribution Guidelines](CONTRIBUTING.md) before reporting a bug or providing a new feature. ## Misc ### Bash Profile Aliases -Bash it creates a `reload` alias that makes it convenient to reload -your bash profile when you make changes. + +Bash-it creates a `reload` alias that makes it convenient to reload +your Bash profile when you make changes. ### Prompt Version Control Check -Bash it provides prompt themes the ability to check and display version control information for the current directory. The information is retrieved for each directory and can slow down the navigation of projects with a large number of files and folders. Turn version control checking off to prevent slow directory navigation within large projects. -Bash it provides a flag (`SCM_CHECK`) within the `~/.bash_profile` file that turns off/on version control information checking and display within all themes. Version control checking is on by default unless explicitly turned off. +Bash-it provides prompt themes the ability to check and display version control information for the current directory. The information is retrieved for each directory and can slow down the navigation of projects with a large number of files and folders. Turn version control checking off to prevent slow directory navigation within large projects. + +Bash-it provides a flag (`SCM_CHECK`) within the `~/.bash_profile` file that turns off/on version control information checking and display within all themes. Version control checking is on by default unless explicitly turned off. Set `SCM_CHECK` to 'false' to **turn off** version control checks for all themes: @@ -87,12 +172,17 @@ Set `SCM_CHECK` to 'true' (the default value) to **turn on** version control che * `export SCM_CHECK=true` **NOTE:** -It is possible for themes to ignore the `SCM_CHECK` flag and query specific version control information directly. For example, themes that use functions like `git_prompt_vars` skip the `SCM_CHECK` flag to retrieve and display git prompt information. If you turned version control checking off and you still see version control information within your prompt, then functions like `git_prompt_vars` are most likely the reason why. +It is possible for themes to ignore the `SCM_CHECK` flag and query specific version control information directly. For example, themes that use functions like `git_prompt_vars` skip the `SCM_CHECK` flag to retrieve and display git prompt information. If you turned version control checking off and you still see version control information within your prompt, then functions like `git_prompt_vars` are most likely the reason why. -### Git repository info in the prompt -Bash it can show some information about Git repositories in the shell prompt: the current branch, tag or commit you are at, how many commits the local branch is ahead or behind from the remote branch, and if you have changes stashed. +### Git prompt -Additionally, you can view the status of your working copy and get the count of staged, unstaged and untracked files. This feature is controlled through the flag `SCM_GIT_SHOW_DETAILS` as follows: +Bash-it has some nice features related to Git, continue reading to know more about these features. + +#### Repository info in the prompt + +Bash-it can show some information about Git repositories in the shell prompt: the current branch, tag or commit you are at, how many commits the local branch is ahead or behind from the remote branch, and if you have changes stashed. + +Additionally, you can view the status of your working copy and get the count of *staged*, *unstaged* and *untracked* files. This feature is controlled through the flag `SCM_GIT_SHOW_DETAILS` as follows: Set `SCM_GIT_SHOW_DETAILS` to 'true' (the default value) to **show** the working copy details in your prompt: @@ -102,21 +192,89 @@ Set `SCM_GIT_SHOW_DETAILS` to 'false' to **don't show** it: * `export SCM_GIT_SHOW_DETAILS=false` -#### pass function renamed to passgen +#### Remotes and remote branches -The Bash it `pass` function has been renamed to `passgen` in order to avoid a naming conflict with the [pass password manager]. In order to minimize the impact on users of the legacy Bash it `pass` function, Bash it will create the alias `pass` that calls the new `passgen` function if the `pass` password manager command is not found on the `PATH` (default behavior). +In some git workflows you must work with various remotes, for this reason, Bash-it can provide some useful information about your remotes and your remote branches, for example, the remote on you are working, or if your local branch is tracking a remote branch. + +You can control this feature with the flag `SCM_GIT_SHOW_REMOTE_INFO` as follows: + +Set `SCM_GIT_SHOW_REMOTE_INFO` to 'auto' (the default value) to activate it only when more than one remote is configured in the current repo: + +* `export SCM_GIT_SHOW_REMOTE_INFO=auto` + +Set `SCM_GIT_SHOW_REMOTE_INFO` to 'true' to always activate the feature: + +* `export SCM_GIT_SHOW_REMOTE_INFO=true` + +Set `SCM_GIT_SHOW_REMOTE_INFO` to 'false' to **disable the feature**: + +* `export SCM_GIT_SHOW_REMOTE_INFO=false` + +#### Untracked files + +By default, `git status` command shows information about *untracked* files, this behavior can be controlled through command line flags or git configuration files, for big repositories, ignoring *untracked* files can make git faster. Bash-it uses `git status` to gather the repo information it shows in the prompt, so in some circumstances, can be useful to instruct Bash-it to ignore these files. You can control this behavior with the flag `SCM_GIT_IGNORE_UNTRACKED`: + +Set `SCM_GIT_IGNORE_UNTRACKED` to 'false' (the default value) to get information about *untracked* files: + +* `export SCM_GIT_IGNORE_UNTRACKED=false` + +Set `SCM_GIT_IGNORE_UNTRACKED` to 'true' to **ignore** *untracked* files: + +* `export SCM_GIT_IGNORE_UNTRACKED=true` + +also, with this flag to false, Bash-it will not show the repository as dirty when the repo have *untracked* files, and will not display the count of *untracked* files. + +**NOTE:** If you set in git configuration file the option to ignore *untracked* files, this flag has no effect, and Bash-it will ignore *untracked* files always. + +#### Git user + +In some environments it is useful to know the value of the current git user, which is used to mark all new commits. For example, any organization that uses the practice of pair programming will typically author each commit with a [combined names of the two authors](https://github.com/pivotal/git_scripts). When another pair uses the same pairing station, the authors are changed at the beginning of the session. + +To get up and running with this technique, run `gem install pivotal_git_scripts`, and then edit your `~/.pairs` file, according to the specification on the [gem's homepage](https://github.com/pivotal/git_scripts) After that you should be able to run `git pair kg as` to set the author to, eg. "Konstantin Gredeskoul and Alex Saxby", assuming they've been added to the `~/.pairs` file. Please see gem's documentation for more information. + +To enable the display of the current pair in the prompt, you must set `SCM_GIT_SHOW_CURRENT_USER` to `true`. Once set, the `SCM_CURRENT_USER` variable will be automatically populated with the initials of the git author(s). It will also be included in the default git prompt. Even if you do not have `git pair` installed, as long as your `user.name` is set, your initials will be computed from your name, and shown in the prompt. + +You can control the prefix and the suffix of this component using the two variables: + +* `export SCM_THEME_CURRENT_USER_PREFFIX=' ☺︎ '` + +And + +* `export SCM_THEME_CURRENT_USER_SUFFIX=' '`` + +#### Ignore repo status + +When working in repos with a large code base Bash-it can slow down your prompt when checking the repo status, to avoid it, there is an option you can set via Git config to disable checking repo status in Bash-it. + +To disable checking the status in the current repo: + +``` +$ git config --add bash-it.hide-status 1 +``` + +But if you would like to disable it globally, and stop checking the status for all of your repos: + +``` +$ git config --global --add bash-it.hide-status 1 +``` + +setting this flag globally has the same effect that `SCM_CHECK=true` but only for Git repos. + +### Pass function renamed to passgen + +The Bash-it `pass` function has been renamed to `passgen` in order to avoid a naming conflict with the [pass password manager]. In order to minimize the impact on users of the legacy Bash-it `pass` function, Bash-it will create the alias `pass` that calls the new `passgen` function if the `pass` password manager command is not found on the `PATH` (default behavior). This behavior can be overridden with the `BASH_IT_LEGACY_PASS` flag as follows: -Set `BASH_IT_LEGACY_PASS` to 'true' to force Bash it to always **create** the `pass` alias to `passgen`: +Set `BASH_IT_LEGACY_PASS` to 'true' to force Bash-it to always **create** the `pass` alias to `passgen`: * `export BASH_IT_LEGACY_PASS=true` -Unset `BASH_IT_LEGACY_PASS` to have Bash it **return to default behavior**: +Unset `BASH_IT_LEGACY_PASS` to have Bash-it **return to default behavior**: * `unset BASH_IT_LEGACY_PASS` -#### Proxy Support +### Proxy Support If you are working in a corporate environment where you have to go through a proxy server for internet access, then you know how painful it is to configure the OS proxy variables in the shell, especially if you are switching between environments, e.g. office (with proxy) and home (without proxy). @@ -127,13 +285,13 @@ The Bash shell (and many shell tools) use the following variables to define the * `ALL_PROXY` (and `all_proxy`): Used by some tools for the same purpose as above * `NO_PROXY` (and `no_proxy`): Comma-separated list of hostnames that don't have to go through the proxy -Bash it's `proxy` plugin allows to enable and disable these variables with a simple command. To start using the `proxy` plugin, run the following: +Bash-it's `proxy` plugin allows to enable and disable these variables with a simple command. To start using the `proxy` plugin, run the following: ```bash bash-it enable plugin proxy ``` -Bash it also provides support for enabling/disabling proxy settings for various shell tools. The following backends are currently supported (in addition to the shell's environment variables): Git, SVN, npm, ssh. The `proxy` plugin changes the configuration files of these tools to enable or disable the proxy settings. +Bash-it also provides support for enabling/disabling proxy settings for various shell tools. The following backends are currently supported (in addition to the shell's environment variables): Git, SVN, npm, ssh. The `proxy` plugin changes the configuration files of these tools to enable or disable the proxy settings. Bash-it uses the following variables to set the shell's proxy settings when you call `enable-proxy`. These variables are best defined in a custom script in Bash-it's custom script folder (`$BASH_IT/custom`), e.g. `$BASH_IT/custom/proxy.env.bash` @@ -149,10 +307,12 @@ There are many more proxy commands, e.g. for changing the local Git project's pr ## Help out -We 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!** +We 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 us a pull request and we'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 we merge your changes in. +Please take a look at the [Contribution Guidelines](CONTRIBUTING.md) before reporting a bug or providing a new feature. + Thanks, and happing bashing! @@ -160,5 +320,5 @@ Thanks, and happing bashing! * [List of contributors][contribute] -[contribute]: https://github.com/revans/bash-it/contributors +[contribute]: https://github.com/Bash-it/bash-it/contributors [pass password manager]: http://www.passwordstore.org/ diff --git a/aliases/available/ag.aliases.bash b/aliases/available/ag.aliases.bash new file mode 100644 index 00000000..e3157f94 --- /dev/null +++ b/aliases/available/ag.aliases.bash @@ -0,0 +1,12 @@ +cite 'about-alias' +about-alias 'the silver searcher (ag) aliases' + +## Summary for args to less: +# less(1) +# -M (-M or --LONG-PROMPT) Prompt very verbosely +# -I (-I or --IGNORE-CASE) Searches with '/' ignore case +# -R (-R or --RAW-CONTROL-CHARS) For handling ANSI colors +# -F (-F or --quit-if-one-screen) Auto exit if <1 screen +# -X (-X or --no-init) Disable termcap init & deinit + +alias ag='ag --smart-case --pager="less -MIRFX"' diff --git a/aliases/available/apt.aliases.bash b/aliases/available/apt.aliases.bash new file mode 100644 index 00000000..2f444931 --- /dev/null +++ b/aliases/available/apt.aliases.bash @@ -0,0 +1,28 @@ +#!/bin/bash +# +# -binaryanomaly + +cite 'about-alias' +about-alias 'Apt and dpkg aliases for Ubuntu and Debian distros.' + +# set apt aliases +function _set_pkg_aliases() +{ + if [ -x $(which apt) ]; then + alias apts='apt-cache search' + alias aptshow='apt-cache show' + alias aptinst='sudo apt-get install -V' + alias aptupd='sudo apt-get update' + alias aptupg='sudo apt-get dist-upgrade -V && sudo apt-get autoremove' + alias aptupgd='sudo apt-get update && sudo apt-get dist-upgrade -V && sudo apt-get autoremove' + alias aptrm='sudo apt-get remove' + alias aptpurge='sudo apt-get remove --purge' + + alias chkup='/usr/lib/update-notifier/apt-check -p --human-readable' + alias chkboot='cat /var/run/reboot-required' + + alias pkgfiles='dpkg --listfiles' + fi +} + +_set_pkg_aliases diff --git a/aliases/available/atom.aliases.bash b/aliases/available/atom.aliases.bash index f067697d..8d70cffa 100644 --- a/aliases/available/atom.aliases.bash +++ b/aliases/available/atom.aliases.bash @@ -4,3 +4,4 @@ about-alias 'Atom.io editor abbreviations' alias a='atom' alias ah='atom .' alias apmup='apm update --no-confirm' +alias apmi='apm install' diff --git a/aliases/available/curl.aliases.bash b/aliases/available/curl.aliases.bash new file mode 100644 index 00000000..4618dae1 --- /dev/null +++ b/aliases/available/curl.aliases.bash @@ -0,0 +1,23 @@ +#!/bin/bash + +cite 'about-alias' +about-alias 'Curl aliases for convenience.' + +# set apt aliases +function _set_pkg_aliases() +{ + if [ -x $(which curl) ]; then + # follow redirects + alias cl='curl -L' + # follow redirects, download as original name + alias clo='curl -L -O' + # follow redirects, download as original name, continue + alias cloc='curl -L -C - -O' + # follow redirects, download as original name, continue, retry 5 times + alias clocr='curl -L -C - -O --retry 5' + # follow redirects, fetch banner + alias clb='curl -L -I' + fi +} + +_set_pkg_aliases diff --git a/aliases/available/docker-compose.aliases.bash b/aliases/available/docker-compose.aliases.bash new file mode 100644 index 00000000..99b1db19 --- /dev/null +++ b/aliases/available/docker-compose.aliases.bash @@ -0,0 +1,5 @@ +cite 'about-alias' +about-alias 'docker-compose abbreviations' + +alias dco="docker-compose" +alias dcofresh="docker-compose stop ; docker-compose rm -f ; docker-compose up -d ; docker-compose logs" diff --git a/aliases/available/emacs.aliases.bash b/aliases/available/emacs.aliases.bash index 597ae2dd..f8e1259b 100644 --- a/aliases/available/emacs.aliases.bash +++ b/aliases/available/emacs.aliases.bash @@ -4,11 +4,11 @@ about-alias 'emacs editor' case $OSTYPE in linux*) alias em='emacs' - alias et='emacs -nw' + alias en='emacs -nw' alias e='emacsclient -n' alias et='emacsclient -t' alias ed='emacs --daemon' - alias E='SUDO_EDITOR="emacsclient" sudo -e' + alias E='SUDO_EDITOR=emacsclient sudo -e' ;; darwin*) alias em='open -a emacs' diff --git a/aliases/available/general.aliases.bash b/aliases/available/general.aliases.bash index bc884050..99939386 100644 --- a/aliases/available/general.aliases.bash +++ b/aliases/available/general.aliases.bash @@ -32,7 +32,10 @@ alias q='exit' alias irc="$IRC_CLIENT" +# Language aliases alias rb='ruby' +alias py='python' +alias ipy='ipython' # Pianobar can be found here: http://github.com/PromyLOPh/pianobar/ @@ -53,8 +56,8 @@ then fi # Directory -alias md='mkdir -p' -alias rd='rmdir' +alias md='mkdir -p' +alias rd='rmdir' # Display whatever file is regular file or folder catt() { diff --git a/aliases/available/git.aliases.bash b/aliases/available/git.aliases.bash index 819f1450..d80c0927 100644 --- a/aliases/available/git.aliases.bash +++ b/aliases/available/git.aliases.bash @@ -4,7 +4,11 @@ about-alias 'common git abbreviations' # Aliases alias gcl='git clone' alias ga='git add' -alias gall='git add .' +alias gall='git add -A' +alias gf='git fetch --all --prune' +alias gft='git fetch --all --prune --tags' +alias gfv='git fetch --all --prune --verbose' +alias gftv='git fetch --all --prune --tags --verbose' alias gus='git reset HEAD' alias gm="git merge" alias g='git' @@ -19,6 +23,8 @@ alias gpp='git pull && git push' alias gup='git fetch && git rebase' alias gp='git push' alias gpo='git push origin' +alias gpu='git push --set-upstream' +alias gpom='git push origin master' alias gdv='git diff -w "$@" | vim -R -' alias gc='git commit -v' alias gca='git commit -v -a' @@ -26,14 +32,17 @@ alias gcm='git commit -v -m' alias gci='git commit --interactive' alias gb='git branch' alias gba='git branch -a' +alias gbt='git branch --track' alias gcount='git shortlog -sn' alias gcp='git cherry-pick' alias gco='git checkout' +alias gcb='git checkout -b' +alias gct='git checkout --track' alias gexport='git archive --format zip --output' alias gdel='git branch -D' alias gmu='git fetch origin -v; git fetch upstream -v; git merge upstream/master' alias gll='git log --graph --pretty=oneline --abbrev-commit' -alias gg="git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%Creset' --abbrev-commit --date=relative" +alias gg="git log --graph --pretty=format:'%C(bold)%h%Creset%C(magenta)%d%Creset %s %C(yellow)<%an> %C(cyan)(%cr)%Creset' --abbrev-commit --date=relative" alias ggs="gg --stat" alias gsl="git shortlog -sn" alias gw="git whatchanged" @@ -46,6 +55,7 @@ alias gtl="git tag -l" alias gnew="git log HEAD@{1}..HEAD@{0}" # Add uncommitted and unstaged changes to the last commit alias gcaa="git commit -a --amend -C HEAD" +alias ggui="git gui" case $OSTYPE in darwin*) diff --git a/aliases/available/homebrew-cask.aliases.bash b/aliases/available/homebrew-cask.aliases.bash index 37114bb1..f4c4836b 100644 --- a/aliases/available/homebrew-cask.aliases.bash +++ b/aliases/available/homebrew-cask.aliases.bash @@ -3,13 +3,13 @@ cite 'about-alias' about-alias 'homebrew-cask abbreviations' -alias bcup='brew-cask update' -alias bcin='brew-cask install' -alias bcrm='brew-cask uninstall' -alias bczp='brew-cask zap' -alias bccl='brew-cask cleanup' -alias bcsr='brew-cask search' -alias bcls='brew-cask list' -alias bcinf='brew-cask info' -alias bcdr='brew-cask doctor' -alias bced='brew-cask edit' +alias bcup='brew cask update' +alias bcin='brew cask install' +alias bcrm='brew cask uninstall' +alias bczp='brew cask zap' +alias bccl='brew cask cleanup' +alias bcsr='brew cask search' +alias bcls='brew cask list' +alias bcinf='brew cask info' +alias bcdr='brew cask doctor' +alias bced='brew cask edit' diff --git a/aliases/available/npm.aliases.bash b/aliases/available/npm.aliases.bash new file mode 100644 index 00000000..b01241e7 --- /dev/null +++ b/aliases/available/npm.aliases.bash @@ -0,0 +1,22 @@ +cite 'about-alias' +about-alias 'common npm abbreviations' + +# Aliases +alias ni='npm install' +alias nis='npm install --save' +alias nid='npm install --save-dev' +alias nit='npm install-test' +alias nits='npm install-test --save' +alias nitd='npm install-test --save-dev' +alias nu='npm uninstall' +alias nus='npm uninstall --save' +alias nud='npm uninstall --save-dev' +alias np='npm publish' +alias nup='npm unpublish' +alias nlk='npm link' +alias nod='npm outdated' +alias nrb='npm rebuild' +alias nud='npm update' +alias nr='npm run' +alias nls='npm list' +alias nlsg='npm list --global' diff --git a/aliases/available/osx.aliases.bash b/aliases/available/osx.aliases.bash index 5bc8a1e2..3d09605e 100644 --- a/aliases/available/osx.aliases.bash +++ b/aliases/available/osx.aliases.bash @@ -18,6 +18,7 @@ alias textedit='open -a TextEdit' alias hex='open -a "Hex Fiend"' alias skype='open -a Skype' alias mou='open -a Mou' +alias subl='open -a Sublime\ Text --args' if [ -s /usr/bin/firefox ] ; then unalias firefox @@ -51,4 +52,4 @@ alias unmute="osascript -e 'set volume output muted false'" # Pin to the tail of long commands for an audible alert after long processes ## curl http://downloads.com/hugefile.zip; lmk -alias lmk="say 'Process complete.'" \ No newline at end of file +alias lmk="say 'Process complete.'" diff --git a/bash_it.sh b/bash_it.sh index 21445034..9d877dd2 100755 --- a/bash_it.sh +++ b/bash_it.sh @@ -38,11 +38,14 @@ cite _about _param _example _group _author _version source "${BASH_IT}/themes/colors.theme.bash" source "${BASH_IT}/themes/base.theme.bash" -# library +# libraries, but skip appearance (themes) for now LIB="${BASH_IT}/lib/*.bash" +APPEARANCE_LIB="${BASH_IT}/lib/appearance.bash" for config_file in $LIB do - source $config_file + if [ $config_file != $APPEARANCE_LIB ]; then + source $config_file + fi done # Load enabled aliases, completion, plugins @@ -51,6 +54,9 @@ do _load_bash_it_files $file_type done +# appearance (themes) now, after all dependencies +source $APPEARANCE_LIB + # Load custom aliases, completion, plugins for file_type in "aliases" "completion" "plugins" do diff --git a/completion/available/awscli.completion.bash b/completion/available/awscli.completion.bash new file mode 100644 index 00000000..530bdd27 --- /dev/null +++ b/completion/available/awscli.completion.bash @@ -0,0 +1 @@ +[[ -x "$(which aws_completer)" ]] && complete -C "$(which aws_completer)" aws diff --git a/completion/available/bash-it.completion.bash b/completion/available/bash-it.completion.bash index 68d067c8..f4326a0a 100644 --- a/completion/available/bash-it.completion.bash +++ b/completion/available/bash-it.completion.bash @@ -51,27 +51,47 @@ _bash-it-comp() COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" - - opts="help show enable disable" - - case "${prev}" in + chose_opt="${COMP_WORDS[1]}" + file_type="${COMP_WORDS[2]}" + opts="help show enable disable update search" + case "${chose_opt}" in show) local show_args="plugins aliases completions" COMPREPLY=( $(compgen -W "${show_args}" -- ${cur}) ) return 0 ;; help) - local help_args="plugins aliases completions" + local help_args="plugins aliases completions update" COMPREPLY=( $(compgen -W "${help_args}" -- ${cur}) ) return 0 ;; - enable) - _bash-it-comp-enable-disable - return 0 - ;; - disable) - _bash-it-comp-enable-disable - return 0 + update | search) + return 0 + ;; + enable | disable) + if [ x"${chose_opt}" == x"enable" ];then + suffix="available-not-enabled" + else + suffix="enabled" + fi + case "${file_type}" in + alias) + _bash-it-comp-list-${suffix} aliases + return 0 + ;; + plugin) + _bash-it-comp-list-${suffix} plugins + return 0 + ;; + completion) + _bash-it-comp-list-${suffix} completion + return 0 + ;; + *) + _bash-it-comp-enable-disable + return 0 + ;; + esac ;; aliases) prevprev="${COMP_WORDS[COMP_CWORD-2]}" @@ -83,48 +103,6 @@ _bash-it-comp() ;; esac ;; - alias) - prevprev="${COMP_WORDS[COMP_CWORD-2]}" - - case "${prevprev}" in - enable) - _bash-it-comp-list-available-not-enabled aliases - return 0 - ;; - disable) - _bash-it-comp-list-enabled aliases - return 0 - ;; - esac - ;; - plugin) - prevprev="${COMP_WORDS[COMP_CWORD-2]}" - - case "${prevprev}" in - enable) - _bash-it-comp-list-available-not-enabled plugins - return 0 - ;; - disable) - _bash-it-comp-list-enabled plugins - return 0 - ;; - esac - ;; - completion) - prevprev="${COMP_WORDS[COMP_CWORD-2]}" - - case "${prevprev}" in - enable) - _bash-it-comp-list-available-not-enabled completion - return 0 - ;; - disable) - _bash-it-comp-list-enabled completion - return 0 - ;; - esac - ;; esac COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) diff --git a/completion/available/bundler.completion.bash b/completion/available/bundler.completion.bash new file mode 100644 index 00000000..274a4a36 --- /dev/null +++ b/completion/available/bundler.completion.bash @@ -0,0 +1,55 @@ +#! bash +# bash completion for the `bundle` command. +# +# Copyright (c) 2011-2013 Daniel Luz . +# Distributed under the MIT license. +# http://mernen.com/projects/completion-ruby +# +# To use, source this file on bash: +# . completion-bundle + +__bundle() { + local cur=$2 + local prev=$3 + local bundle_command + __bundle_get_command + COMPREPLY=() + + local options + if [[ $cur = -* ]]; then + options="--no-color --verbose" + if [[ -z $bundle_command ]]; then + options="$options --version --help" + fi + else + if [[ -z $bundle_command || $bundle_command = help ]]; then + options="help install update package exec config check list show + console open viz init gem" + fi + fi + COMPREPLY=($(compgen -W "$options" -- "$cur")) +} + +__bundle_get_command() { + local i + for ((i=1; i < $COMP_CWORD; ++i)); do + local arg=${COMP_WORDS[$i]} + + case $arg in + [^-]*) + bundle_command=$arg + return;; + --version) + # command-killer + bundle_command=- + return;; + --help) + bundle_command=help + return;; + esac + done +} + + +complete -F __bundle -o bashdefault -o default bundle +# vim: ai ft=sh sw=4 sts=2 et diff --git a/completion/available/capistrano.completion.bash b/completion/available/capistrano.completion.bash old mode 100644 new mode 100755 index a48bd4d6..d5fda06f --- a/completion/available/capistrano.completion.bash +++ b/completion/available/capistrano.completion.bash @@ -7,7 +7,14 @@ _capcomplete() { if [ -f Capfile ]; then recent=`ls -t .cap_tasks~ Capfile **/*.cap 2> /dev/null | head -n 1` if [[ $recent != '.cap_tasks~' ]]; then - cap --tool --tasks | cut -d " " -f 2 > .cap_tasks~ + cap --version | grep 'Capistrano v2.' > /dev/null + if [ $? -eq 0 ]; then + # Capistrano 2.x + cap --tool --verbose --tasks | cut -d " " -f 2 > .cap_tasks~ + else + # Capistrano 3.x + cap --all --tasks | cut -d " " -f 2 > .cap_tasks~ + fi fi COMPREPLY=($(compgen -W "`cat .cap_tasks~`" -- ${COMP_WORDS[COMP_CWORD]})) return 0 diff --git a/completion/available/docker.completion.bash b/completion/available/docker.completion.bash new file mode 100644 index 00000000..0e9d4b79 --- /dev/null +++ b/completion/available/docker.completion.bash @@ -0,0 +1,2038 @@ +#!/bin/bash +# +# bash completion file for core docker commands +# +# This script provides completion of: +# - commands and their options +# - container ids and names +# - image repos and tags +# - filepaths +# +# To enable the completions either: +# - place this file in /etc/bash_completion.d +# or +# - copy this file to e.g. ~/.docker-completion.sh and add the line +# below to your .bashrc after bash completion features are loaded +# . ~/.docker-completion.sh +# +# Configuration: +# +# For several commands, the amount of completions can be configured by +# setting environment variables. +# +# DOCKER_COMPLETION_SHOW_NETWORK_IDS +# "no" - Show names only (default) +# "yes" - Show names and ids +# +# You can tailor completion for the "events", "history", "inspect", "run", +# "rmi" and "save" commands by settings the following environment +# variables: +# +# DOCKER_COMPLETION_SHOW_IMAGE_IDS +# "none" - Show names only (default) +# "non-intermediate" - Show names and ids, but omit intermediate image IDs +# "all" - Show names and ids, including intermediate image IDs +# +# DOCKER_COMPLETION_SHOW_TAGS +# "yes" - include tags in completion options (default) +# "no" - don't include tags in completion options + +# +# Note: +# Currently, the completions will not work if the docker daemon is not +# bound to the default communication port/socket +# If the docker daemon is using a unix socket for communication your user +# must have access to the socket for the completions to function correctly +# +# Note for developers: +# Please arrange options sorted alphabetically by long name with the short +# options immediately following their corresponding long form. +# This order should be applied to lists, alternatives and code blocks. + +__docker_previous_extglob_setting=$(shopt -p extglob) +shopt -s extglob + +__docker_q() { + docker ${host:+-H "$host"} ${config:+--config "$config"} 2>/dev/null "$@" +} + +__docker_complete_containers_all() { + local IFS=$'\n' + local containers=( $(__docker_q ps -aq --no-trunc) ) + if [ "$1" ]; then + containers=( $(__docker_q inspect --format "{{if $1}}{{.Id}}{{end}}" "${containers[@]}") ) + fi + local names=( $(__docker_q inspect --format '{{.Name}}' "${containers[@]}") ) + names=( "${names[@]#/}" ) # trim off the leading "/" from the container names + unset IFS + COMPREPLY=( $(compgen -W "${names[*]} ${containers[*]}" -- "$cur") ) +} + +__docker_complete_containers_running() { + __docker_complete_containers_all '.State.Running' +} + +__docker_complete_containers_stopped() { + __docker_complete_containers_all 'not .State.Running' +} + +__docker_complete_containers_pauseable() { + __docker_complete_containers_all 'and .State.Running (not .State.Paused)' +} + +__docker_complete_containers_unpauseable() { + __docker_complete_containers_all '.State.Paused' +} + +__docker_complete_container_names() { + local containers=( $(__docker_q ps -aq --no-trunc) ) + local names=( $(__docker_q inspect --format '{{.Name}}' "${containers[@]}") ) + names=( "${names[@]#/}" ) # trim off the leading "/" from the container names + COMPREPLY=( $(compgen -W "${names[*]}" -- "$cur") ) +} + +__docker_complete_container_ids() { + local containers=( $(__docker_q ps -aq) ) + COMPREPLY=( $(compgen -W "${containers[*]}" -- "$cur") ) +} + +__docker_complete_images() { + local images_args="" + + case "$DOCKER_COMPLETION_SHOW_IMAGE_IDS" in + all) + images_args="--no-trunc -a" + ;; + non-intermediate) + images_args="--no-trunc" + ;; + esac + + local repo_print_command + if [ "${DOCKER_COMPLETION_SHOW_TAGS:-yes}" = "yes" ]; then + repo_print_command='print $1; print $1":"$2' + else + repo_print_command='print $1' + fi + + local awk_script + case "$DOCKER_COMPLETION_SHOW_IMAGE_IDS" in + all|non-intermediate) + awk_script='NR>1 { print $3; if ($1 != "") { '"$repo_print_command"' } }' + ;; + none|*) + awk_script='NR>1 && $1 != "" { '"$repo_print_command"' }' + ;; + esac + + local images=$(__docker_q images $images_args | awk "$awk_script") + COMPREPLY=( $(compgen -W "$images" -- "$cur") ) + __ltrim_colon_completions "$cur" +} + +__docker_complete_image_repos() { + local repos="$(__docker_q images | awk 'NR>1 && $1 != "" { print $1 }')" + COMPREPLY=( $(compgen -W "$repos" -- "$cur") ) +} + +__docker_complete_image_repos_and_tags() { + local reposAndTags="$(__docker_q images | awk 'NR>1 && $1 != "" { print $1; print $1":"$2 }')" + COMPREPLY=( $(compgen -W "$reposAndTags" -- "$cur") ) + __ltrim_colon_completions "$cur" +} + +__docker_complete_containers_and_images() { + __docker_complete_containers_all + local containers=( "${COMPREPLY[@]}" ) + __docker_complete_images + COMPREPLY+=( "${containers[@]}" ) +} + +__docker_networks() { + # By default, only network names are completed. + # Set DOCKER_COMPLETION_SHOW_NETWORK_IDS=yes to also complete network IDs. + local fields='$2' + [ "${DOCKER_COMPLETION_SHOW_NETWORK_IDS}" = yes ] && fields='$1,$2' + __docker_q network ls --no-trunc | awk "NR>1 {print $fields}" +} + +__docker_complete_networks() { + COMPREPLY=( $(compgen -W "$(__docker_networks)" -- "$cur") ) +} + +__docker_complete_network_ids() { + COMPREPLY=( $(compgen -W "$(__docker_q network ls -q --no-trunc)" -- "$cur") ) +} + +__docker_complete_network_names() { + COMPREPLY=( $(compgen -W "$(__docker_q network ls | awk 'NR>1 {print $2}')" -- "$cur") ) +} + +__docker_complete_containers_in_network() { + local containers=$(__docker_q network inspect -f '{{range $i, $c := .Containers}}{{$i}} {{$c.Name}} {{end}}' "$1") + COMPREPLY=( $(compgen -W "$containers" -- "$cur") ) +} + +__docker_complete_volumes() { + COMPREPLY=( $(compgen -W "$(__docker_q volume ls -q)" -- "$cur") ) +} + +__docker_plugins() { + __docker_q info | sed -n "/^Plugins/,/^[^ ]/s/ $1: //p" +} + +__docker_complete_plugins() { + COMPREPLY=( $(compgen -W "$(__docker_plugins $1)" -- "$cur") ) +} + +# Finds the position of the first word that is neither option nor an option's argument. +# If there are options that require arguments, you should pass a glob describing those +# options, e.g. "--option1|-o|--option2" +# Use this function to restrict completions to exact positions after the argument list. +__docker_pos_first_nonflag() { + local argument_flags=$1 + + local counter=$((${subcommand_pos:-${command_pos}} + 1)) + while [ $counter -le $cword ]; do + if [ -n "$argument_flags" ] && eval "case '${words[$counter]}' in $argument_flags) true ;; *) false ;; esac"; then + (( counter++ )) + # eat "=" in case of --option=arg syntax + [ "${words[$counter]}" = "=" ] && (( counter++ )) + else + case "${words[$counter]}" in + -*) + ;; + *) + break + ;; + esac + fi + + # Bash splits words at "=", retaining "=" as a word, examples: + # "--debug=false" => 3 words, "--log-opt syslog-facility=daemon" => 4 words + while [ "${words[$counter + 1]}" = "=" ] ; do + counter=$(( counter + 2)) + done + + (( counter++ )) + done + + echo $counter +} + +# Returns the value of the first option matching option_glob. +# Valid values for option_glob are option names like '--log-level' and +# globs like '--log-level|-l' +# Only positions between the command and the current word are considered. +__docker_value_of_option() { + local option_extglob=$(__docker_to_extglob "$1") + + local counter=$((command_pos + 1)) + while [ $counter -lt $cword ]; do + case ${words[$counter]} in + $option_extglob ) + echo ${words[$counter + 1]} + break + ;; + esac + (( counter++ )) + done +} + +# Transforms a multiline list of strings into a single line string +# with the words separated by "|". +# This is used to prepare arguments to __docker_pos_first_nonflag(). +__docker_to_alternatives() { + local parts=( $1 ) + local IFS='|' + echo "${parts[*]}" +} + +# Transforms a multiline list of options into an extglob pattern +# suitable for use in case statements. +__docker_to_extglob() { + local extglob=$( __docker_to_alternatives "$1" ) + echo "@($extglob)" +} + +# Subcommand processing. +# Locates the first occurrence of any of the subcommands contained in the +# first argument. In case of a match, calls the corresponding completion +# function and returns 0. +# If no match is found, 1 is returned. The calling function can then +# continue processing its completion. +# +# TODO if the preceding command has options that accept arguments and an +# argument is equal ot one of the subcommands, this is falsely detected as +# a match. +__docker_subcommands() { + local subcommands="$1" + + local counter=$(($command_pos + 1)) + while [ $counter -lt $cword ]; do + case "${words[$counter]}" in + $(__docker_to_extglob "$subcommands") ) + subcommand_pos=$counter + local subcommand=${words[$counter]} + local completions_func=_docker_${command}_${subcommand} + declare -F $completions_func >/dev/null && $completions_func + return 0 + ;; + esac + (( counter++ )) + done + return 1 +} + +# suppress trailing whitespace +__docker_nospace() { + # compopt is not available in ancient bash versions + type compopt &>/dev/null && compopt -o nospace +} + +__docker_complete_resolved_hostname() { + command -v host >/dev/null 2>&1 || return + COMPREPLY=( $(host 2>/dev/null "${cur%:}" | awk '/has address/ {print $4}') ) +} + +__docker_complete_capabilities() { + # The list of capabilities is defined in types.go, ALL was added manually. + COMPREPLY=( $( compgen -W " + ALL + AUDIT_CONTROL + AUDIT_WRITE + AUDIT_READ + BLOCK_SUSPEND + CHOWN + DAC_OVERRIDE + DAC_READ_SEARCH + FOWNER + FSETID + IPC_LOCK + IPC_OWNER + KILL + LEASE + LINUX_IMMUTABLE + MAC_ADMIN + MAC_OVERRIDE + MKNOD + NET_ADMIN + NET_BIND_SERVICE + NET_BROADCAST + NET_RAW + SETFCAP + SETGID + SETPCAP + SETUID + SYS_ADMIN + SYS_BOOT + SYS_CHROOT + SYSLOG + SYS_MODULE + SYS_NICE + SYS_PACCT + SYS_PTRACE + SYS_RAWIO + SYS_RESOURCE + SYS_TIME + SYS_TTY_CONFIG + WAKE_ALARM + " -- "$cur" ) ) +} + +__docker_complete_isolation() { + COMPREPLY=( $( compgen -W "default hyperv process" -- "$cur" ) ) +} + +__docker_complete_log_drivers() { + COMPREPLY=( $( compgen -W " + awslogs + fluentd + gelf + journald + json-file + none + splunk + syslog + " -- "$cur" ) ) +} + +__docker_complete_log_options() { + # see docs/reference/logging/index.md + local awslogs_options="awslogs-region awslogs-group awslogs-stream" + local fluentd_options="env fluentd-address labels tag" + local gelf_options="env gelf-address labels tag" + local journald_options="env labels" + local json_file_options="env labels max-file max-size" + local syslog_options="syslog-address syslog-facility tag" + local splunk_options="env labels splunk-caname splunk-capath splunk-index splunk-insecureskipverify splunk-source splunk-sourcetype splunk-token splunk-url tag" + + local all_options="$fluentd_options $gelf_options $journald_options $json_file_options $syslog_options $splunk_options" + + case $(__docker_value_of_option --log-driver) in + '') + COMPREPLY=( $( compgen -W "$all_options" -S = -- "$cur" ) ) + ;; + awslogs) + COMPREPLY=( $( compgen -W "$awslogs_options" -S = -- "$cur" ) ) + ;; + fluentd) + COMPREPLY=( $( compgen -W "$fluentd_options" -S = -- "$cur" ) ) + ;; + gelf) + COMPREPLY=( $( compgen -W "$gelf_options" -S = -- "$cur" ) ) + ;; + journald) + COMPREPLY=( $( compgen -W "$journald_options" -S = -- "$cur" ) ) + ;; + json-file) + COMPREPLY=( $( compgen -W "$json_file_options" -S = -- "$cur" ) ) + ;; + syslog) + COMPREPLY=( $( compgen -W "$syslog_options" -S = -- "$cur" ) ) + ;; + splunk) + COMPREPLY=( $( compgen -W "$splunk_options" -S = -- "$cur" ) ) + ;; + *) + return + ;; + esac + + __docker_nospace +} + +__docker_complete_log_driver_options() { + # "=" gets parsed to a word and assigned to either $cur or $prev depending on whether + # it is the last character or not. So we search for "xxx=" in the the last two words. + case "${words[$cword-2]}$prev=" in + *gelf-address=*) + COMPREPLY=( $( compgen -W "udp" -S "://" -- "${cur#=}" ) ) + __docker_nospace + return + ;; + *syslog-address=*) + COMPREPLY=( $( compgen -W "tcp udp unix" -S "://" -- "${cur#=}" ) ) + __docker_nospace + return + ;; + *syslog-facility=*) + COMPREPLY=( $( compgen -W " + auth + authpriv + cron + daemon + ftp + kern + local0 + local1 + local2 + local3 + local4 + local5 + local6 + local7 + lpr + mail + news + syslog + user + uucp + " -- "${cur#=}" ) ) + return + ;; + *splunk-url=*) + COMPREPLY=( $( compgen -W "http:// https://" -- "${cur#=}" ) ) + compopt -o nospace + __ltrim_colon_completions "${cur}" + return + ;; + *splunk-insecureskipverify=*) + COMPREPLY=( $( compgen -W "true false" -- "${cur#=}" ) ) + compopt -o nospace + return + ;; + esac + return 1 +} + +__docker_complete_log_levels() { + COMPREPLY=( $( compgen -W "debug info warn error fatal" -- "$cur" ) ) +} + +# a selection of the available signals that is most likely of interest in the +# context of docker containers. +__docker_complete_signals() { + local signals=( + SIGCONT + SIGHUP + SIGINT + SIGKILL + SIGQUIT + SIGSTOP + SIGTERM + SIGUSR1 + SIGUSR2 + ) + COMPREPLY=( $( compgen -W "${signals[*]} ${signals[*]#SIG}" -- "$( echo $cur | tr '[:lower:]' '[:upper:]')" ) ) +} + +# global options that may appear after the docker command +_docker_docker() { + local boolean_options=" + $global_boolean_options + --help + --version -v + " + + case "$prev" in + --config) + _filedir -d + return + ;; + --log-level|-l) + __docker_complete_log_levels + return + ;; + $(__docker_to_extglob "$global_options_with_args") ) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$boolean_options $global_options_with_args" -- "$cur" ) ) + ;; + *) + local counter=$( __docker_pos_first_nonflag $(__docker_to_extglob "$global_options_with_args") ) + if [ $cword -eq $counter ]; then + COMPREPLY=( $( compgen -W "${commands[*]} help" -- "$cur" ) ) + fi + ;; + esac +} + +_docker_attach() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help --no-stdin --sig-proxy" -- "$cur" ) ) + ;; + *) + local counter="$(__docker_pos_first_nonflag)" + if [ $cword -eq $counter ]; then + __docker_complete_containers_running + fi + ;; + esac +} + +_docker_build() { + local options_with_args=" + --build-arg + --cgroup-parent + --cpuset-cpus + --cpuset-mems + --cpu-shares + --cpu-period + --cpu-quota + --file -f + --isolation + --memory -m + --memory-swap + --tag -t + --ulimit + " + + local boolean_options=" + --disable-content-trust=false + --force-rm + --help + --no-cache + --pull + --quiet -q + --rm + " + + local all_options="$options_with_args $boolean_options" + + case "$prev" in + --build-arg) + COMPREPLY=( $( compgen -e -- "$cur" ) ) + __docker_nospace + return + ;; + --file|-f) + _filedir + return + ;; + --isolation) + __docker_complete_isolation + return + ;; + --tag|-t) + __docker_complete_image_repos_and_tags + return + ;; + $(__docker_to_extglob "$options_with_args") ) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$all_options" -- "$cur" ) ) + ;; + *) + local counter=$( __docker_pos_first_nonflag $( __docker_to_alternatives "$options_with_args" ) ) + if [ $cword -eq $counter ]; then + _filedir -d + fi + ;; + esac +} + +_docker_commit() { + case "$prev" in + --author|-a|--change|-c|--message|-m) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--author -a --change -c --help --message -m --pause -p" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag '--author|-a|--change|-c|--message|-m') + + if [ $cword -eq $counter ]; then + __docker_complete_containers_all + return + fi + (( counter++ )) + + if [ $cword -eq $counter ]; then + __docker_complete_image_repos_and_tags + return + fi + ;; + esac +} + +_docker_cp() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + case "$cur" in + *:) + return + ;; + *) + # combined container and filename completion + _filedir + local files=( ${COMPREPLY[@]} ) + + __docker_complete_containers_all + COMPREPLY=( $( compgen -W "${COMPREPLY[*]}" -S ':' ) ) + local containers=( ${COMPREPLY[@]} ) + + COMPREPLY=( $( compgen -W "${files[*]} ${containers[*]}" -- "$cur" ) ) + if [[ "$COMPREPLY" == *: ]]; then + __docker_nospace + fi + return + ;; + esac + fi + (( counter++ )) + + if [ $cword -eq $counter ]; then + if [ -e "$prev" ]; then + __docker_complete_containers_all + COMPREPLY=( $( compgen -W "${COMPREPLY[*]}" -S ':' ) ) + __docker_nospace + else + _filedir + fi + return + fi + ;; + esac +} + +_docker_create() { + _docker_run +} + +_docker_daemon() { + local boolean_options=" + $global_boolean_options + --disable-legacy-registry + --help + --icc=false + --ip-forward=false + --ip-masq=false + --iptables=false + --ipv6 + --selinux-enabled + --userland-proxy=false + " + local options_with_args=" + $global_options_with_args + --api-cors-header + --authz-plugin + --bip + --bridge -b + --cgroup-parent + --cluster-advertise + --cluster-store + --cluster-store-opt + --default-gateway + --default-gateway-v6 + --default-ulimit + --dns + --dns-search + --dns-opt + --exec-opt + --exec-root + --fixed-cidr + --fixed-cidr-v6 + --graph -g + --group -G + --insecure-registry + --ip + --label + --log-driver + --log-opt + --mtu + --pidfile -p + --registry-mirror + --storage-driver -s + --storage-opt + " + + case "$prev" in + --authz-plugin) + __docker_complete_plugins Authorization + return + ;; + --cluster-store) + COMPREPLY=( $( compgen -W "consul etcd zk" -S "://" -- "$cur" ) ) + __docker_nospace + return + ;; + --cluster-store-opt) + COMPREPLY=( $( compgen -W "kv.cacertfile kv.certfile kv.keyfile" -S = -- "$cur" ) ) + __docker_nospace + return + ;; + --exec-root|--graph|-g) + _filedir -d + return + ;; + --log-driver) + __docker_complete_log_drivers + return + ;; + --pidfile|-p|--tlscacert|--tlscert|--tlskey) + _filedir + return + ;; + --storage-driver|-s) + COMPREPLY=( $( compgen -W "aufs btrfs devicemapper overlay vfs zfs" -- "$(echo $cur | tr '[:upper:]' '[:lower:]')" ) ) + return + ;; + --storage-opt) + local devicemapper_options=" + dm.basesize + dm.blkdiscard + dm.blocksize + dm.fs + dm.loopdatasize + dm.loopmetadatasize + dm.mkfsarg + dm.mountopt + dm.override_udev_sync_check + dm.thinpooldev + dm.use_deferred_deletion + dm.use_deferred_removal + " + local zfs_options="zfs.fsname" + + case $(__docker_value_of_option '--storage-driver|-s') in + '') + COMPREPLY=( $( compgen -W "$devicemapper_options $zfs_options" -S = -- "$cur" ) ) + ;; + devicemapper) + COMPREPLY=( $( compgen -W "$devicemapper_options" -S = -- "$cur" ) ) + ;; + zfs) + COMPREPLY=( $( compgen -W "$zfs_options" -S = -- "$cur" ) ) + ;; + *) + return + ;; + esac + __docker_nospace + return + ;; + --log-level|-l) + __docker_complete_log_levels + return + ;; + --log-opt) + __docker_complete_log_options + return + ;; + $(__docker_to_extglob "$options_with_args") ) + return + ;; + esac + + __docker_complete_log_driver_options && return + + case "${words[$cword-2]}$prev=" in + # completions for --storage-opt + *dm.@(blkdiscard|override_udev_sync_check|use_deferred_@(removal|deletion))=*) + COMPREPLY=( $( compgen -W "false true" -- "${cur#=}" ) ) + return + ;; + *dm.fs=*) + COMPREPLY=( $( compgen -W "ext4 xfs" -- "${cur#=}" ) ) + return + ;; + *dm.thinpooldev=*) + _filedir + return + ;; + # completions for --cluster-store-opt + *kv.*file=*) + _filedir + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) ) + ;; + esac +} + +_docker_diff() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + __docker_complete_containers_all + fi + ;; + esac +} + +_docker_events() { + case "$prev" in + --filter|-f) + COMPREPLY=( $( compgen -S = -W "container event image" -- "$cur" ) ) + __docker_nospace + return + ;; + --since|--until) + return + ;; + esac + + case "${words[$cword-2]}$prev=" in + *container=*) + cur="${cur#=}" + __docker_complete_containers_all + return + ;; + *event=*) + COMPREPLY=( $( compgen -W " + attach + commit + copy + create + delete + destroy + die + exec_create + exec_start + export + import + kill + oom + pause + pull + push + rename + resize + restart + start + stop + tag + top + unpause + untag + " -- "${cur#=}" ) ) + return + ;; + *image=*) + cur="${cur#=}" + __docker_complete_images + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--filter -f --help --since --until" -- "$cur" ) ) + ;; + esac +} + +_docker_exec() { + case "$prev" in + --user|-u) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--detach -d --help --interactive -i --privileged -t --tty -u --user" -- "$cur" ) ) + ;; + *) + __docker_complete_containers_running + ;; + esac +} + +_docker_export() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + __docker_complete_containers_all + fi + ;; + esac +} + +_docker_help() { + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + COMPREPLY=( $( compgen -W "${commands[*]}" -- "$cur" ) ) + fi +} + +_docker_history() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help --no-trunc --quiet -q" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + __docker_complete_images + fi + ;; + esac +} + +_docker_images() { + case "$prev" in + --filter|-f) + COMPREPLY=( $( compgen -W "dangling=true label=" -- "$cur" ) ) + if [ "$COMPREPLY" = "label=" ]; then + __docker_nospace + fi + return + ;; + --format) + return + ;; + esac + + case "${words[$cword-2]}$prev=" in + *dangling=*) + COMPREPLY=( $( compgen -W "true false" -- "${cur#=}" ) ) + return + ;; + *label=*) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--all -a --digests --filter -f --format --help --no-trunc --quiet -q" -- "$cur" ) ) + ;; + =) + return + ;; + *) + __docker_complete_image_repos + ;; + esac +} + +_docker_import() { + case "$prev" in + --change|-c|--message|-m) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--change -c --help --message -m" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag '--change|-c|--message|-m') + if [ $cword -eq $counter ]; then + return + fi + (( counter++ )) + + if [ $cword -eq $counter ]; then + __docker_complete_image_repos_and_tags + return + fi + ;; + esac +} + +_docker_info() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + esac +} + +_docker_inspect() { + case "$prev" in + --format|-f) + return + ;; + --type) + COMPREPLY=( $( compgen -W "image container" -- "$cur" ) ) + return + ;; + + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--format -f --help --size -s --type" -- "$cur" ) ) + ;; + *) + case $(__docker_value_of_option --type) in + '') + __docker_complete_containers_and_images + ;; + container) + __docker_complete_containers_all + ;; + image) + __docker_complete_images + ;; + esac + esac +} + +_docker_kill() { + case "$prev" in + --signal|-s) + __docker_complete_signals + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help --signal -s" -- "$cur" ) ) + ;; + *) + __docker_complete_containers_running + ;; + esac +} + +_docker_load() { + case "$prev" in + --input|-i) + _filedir + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help --input -i" -- "$cur" ) ) + ;; + esac +} + +_docker_login() { + case "$prev" in + --email|-e|--password|-p|--username|-u) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--email -e --help --password -p --username -u" -- "$cur" ) ) + ;; + esac +} + +_docker_logout() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + esac +} + +_docker_logs() { + case "$prev" in + --since|--tail) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--follow -f --help --since --tail --timestamps -t" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag '--tail') + if [ $cword -eq $counter ]; then + __docker_complete_containers_all + fi + ;; + esac +} + +_docker_network_connect() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + __docker_complete_networks + elif [ $cword -eq $(($counter + 1)) ]; then + __docker_complete_containers_running + fi + ;; + esac +} + +_docker_network_create() { + case "$prev" in + --aux-address|--gateway|--ip-range|--opt|-o|--subnet) + return + ;; + --ipam-driver) + COMPREPLY=( $( compgen -W "default" -- "$cur" ) ) + return + ;; + --driver|-d) + local plugins=" $(__docker_plugins Network) " + # remove drivers that allow one instance only + plugins=${plugins/ host / } + plugins=${plugins/ null / } + COMPREPLY=( $(compgen -W "$plugins" -- "$cur") ) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--aux-address --driver -d --gateway --help --ip-range --ipam-driver --opt -o --subnet" -- "$cur" ) ) + ;; + esac +} + +_docker_network_disconnect() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + __docker_complete_networks + elif [ $cword -eq $(($counter + 1)) ]; then + __docker_complete_containers_in_network "$prev" + fi + ;; + esac +} + +_docker_network_inspect() { + case "$prev" in + --format|-f) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--format -f --help" -- "$cur" ) ) + ;; + *) + __docker_complete_networks + esac +} + +_docker_network_ls() { + case "$prev" in + --filter|-f) + COMPREPLY=( $( compgen -S = -W "id name type" -- "$cur" ) ) + __docker_nospace + return + ;; + esac + + case "${words[$cword-2]}$prev=" in + *id=*) + cur="${cur#=}" + __docker_complete_network_ids + return + ;; + *name=*) + cur="${cur#=}" + __docker_complete_network_names + return + ;; + *type=*) + COMPREPLY=( $( compgen -W "builtin custom" -- "${cur#=}" ) ) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--filter -f --help --no-trunc --quiet -q" -- "$cur" ) ) + ;; + esac +} + +_docker_network_rm() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + __docker_complete_networks + esac +} + +_docker_network() { + local subcommands=" + connect + create + disconnect + inspect + ls + rm + " + __docker_subcommands "$subcommands" && return + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) + ;; + esac +} + +_docker_pause() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + __docker_complete_containers_pauseable + fi + ;; + esac +} + +_docker_port() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + __docker_complete_containers_all + fi + ;; + esac +} + +_docker_ps() { + case "$prev" in + --before|--since) + __docker_complete_containers_all + ;; + --filter|-f) + COMPREPLY=( $( compgen -S = -W "ancestor exited id label name status" -- "$cur" ) ) + __docker_nospace + return + ;; + --format|-n) + return + ;; + esac + + case "${words[$cword-2]}$prev=" in + *ancestor=*) + cur="${cur#=}" + __docker_complete_images + return + ;; + *id=*) + cur="${cur#=}" + __docker_complete_container_ids + return + ;; + *name=*) + cur="${cur#=}" + __docker_complete_container_names + return + ;; + *status=*) + COMPREPLY=( $( compgen -W "exited paused restarting running" -- "${cur#=}" ) ) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--all -a --before --filter -f --format --help --latest -l -n --no-trunc --quiet -q --size -s --since" -- "$cur" ) ) + ;; + esac +} + +_docker_pull() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--all-tags -a --help" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + for arg in "${COMP_WORDS[@]}"; do + case "$arg" in + --all-tags|-a) + __docker_complete_image_repos + return + ;; + esac + done + __docker_complete_image_repos_and_tags + fi + ;; + esac +} + +_docker_push() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + __docker_complete_image_repos_and_tags + fi + ;; + esac +} + +_docker_rename() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + __docker_complete_containers_all + fi + ;; + esac +} + +_docker_restart() { + case "$prev" in + --time|-t) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help --time -t" -- "$cur" ) ) + ;; + *) + __docker_complete_containers_all + ;; + esac +} + +_docker_rm() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--force -f --help --link -l --volumes -v" -- "$cur" ) ) + ;; + *) + for arg in "${COMP_WORDS[@]}"; do + case "$arg" in + --force|-f) + __docker_complete_containers_all + return + ;; + esac + done + __docker_complete_containers_stopped + ;; + esac +} + +_docker_rmi() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--force -f --help --no-prune" -- "$cur" ) ) + ;; + *) + __docker_complete_images + ;; + esac +} + +_docker_run() { + local options_with_args=" + --add-host + --attach -a + --blkio-weight + --blkio-weight-device + --cap-add + --cap-drop + --cgroup-parent + --cidfile + --cpu-period + --cpu-quota + --cpuset-cpus + --cpuset-mems + --cpu-shares + --device + --device-read-bps + --device-read-iops + --device-write-bps + --device-write-iops + --dns + --dns-opt + --dns-search + --entrypoint + --env -e + --env-file + --expose + --group-add + --hostname -h + --ipc + --isolation + --kernel-memory + --label-file + --label -l + --link + --log-driver + --log-opt + --mac-address + --memory -m + --memory-swap + --memory-swappiness + --memory-reservation + --name + --net + --oom-score-adj + --pid + --publish -p + --restart + --security-opt + --stop-signal + --tmpfs + --ulimit + --user -u + --uts + --volume-driver + --volumes-from + --volume -v + --workdir -w + " + + local boolean_options=" + --disable-content-trust=false + --help + --interactive -i + --oom-kill-disable + --privileged + --publish-all -P + --read-only + --tty -t + " + + local all_options="$options_with_args $boolean_options" + + [ "$command" = "run" ] && all_options="$all_options + --detach -d + --rm + --sig-proxy=false + " + + case "$prev" in + --add-host) + case "$cur" in + *:) + __docker_complete_resolved_hostname + return + ;; + esac + ;; + --attach|-a) + COMPREPLY=( $( compgen -W 'stdin stdout stderr' -- "$cur" ) ) + return + ;; + --cap-add|--cap-drop) + __docker_complete_capabilities + return + ;; + --cidfile|--env-file|--label-file) + _filedir + return + ;; + --device|--tmpfs|--volume|-v) + case "$cur" in + *:*) + # TODO somehow do _filedir for stuff inside the image, if it's already specified (which is also somewhat difficult to determine) + ;; + '') + COMPREPLY=( $( compgen -W '/' -- "$cur" ) ) + __docker_nospace + ;; + /*) + _filedir + __docker_nospace + ;; + esac + return + ;; + --env|-e) + COMPREPLY=( $( compgen -e -- "$cur" ) ) + __docker_nospace + return + ;; + --ipc) + case "$cur" in + *:*) + cur="${cur#*:}" + __docker_complete_containers_running + ;; + *) + COMPREPLY=( $( compgen -W 'host container:' -- "$cur" ) ) + if [ "$COMPREPLY" = "container:" ]; then + __docker_nospace + fi + ;; + esac + return + ;; + --isolation) + __docker_complete_isolation + return + ;; + --link) + case "$cur" in + *:*) + ;; + *) + __docker_complete_containers_running + COMPREPLY=( $( compgen -W "${COMPREPLY[*]}" -S ':' ) ) + __docker_nospace + ;; + esac + return + ;; + --log-driver) + __docker_complete_log_drivers + return + ;; + --log-opt) + __docker_complete_log_options + return + ;; + --net) + case "$cur" in + container:*) + local cur=${cur#*:} + __docker_complete_containers_all + ;; + *) + COMPREPLY=( $( compgen -W "$(__docker_plugins Network) $(__docker_networks) container:" -- "$cur") ) + if [ "${COMPREPLY[*]}" = "container:" ] ; then + __docker_nospace + fi + ;; + esac + return + ;; + --restart) + case "$cur" in + on-failure:*) + ;; + *) + COMPREPLY=( $( compgen -W "always no on-failure on-failure: unless-stopped" -- "$cur") ) + ;; + esac + return + ;; + --security-opt) + case "$cur" in + label:*:*) + ;; + label:*) + local cur=${cur##*:} + COMPREPLY=( $( compgen -W "user: role: type: level: disable" -- "$cur") ) + if [ "${COMPREPLY[*]}" != "disable" ] ; then + __docker_nospace + fi + ;; + *) + COMPREPLY=( $( compgen -W "label apparmor seccomp" -S ":" -- "$cur") ) + __docker_nospace + ;; + esac + return + ;; + --volume-driver) + __docker_complete_plugins Volume + return + ;; + --volumes-from) + __docker_complete_containers_all + return + ;; + $(__docker_to_extglob "$options_with_args") ) + return + ;; + esac + + __docker_complete_log_driver_options && return + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$all_options" -- "$cur" ) ) + ;; + *) + local counter=$( __docker_pos_first_nonflag $( __docker_to_alternatives "$options_with_args" ) ) + if [ $cword -eq $counter ]; then + __docker_complete_images + fi + ;; + esac +} + +_docker_save() { + case "$prev" in + --output|-o) + _filedir + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help --output -o" -- "$cur" ) ) + ;; + *) + __docker_complete_images + ;; + esac +} + +_docker_search() { + case "$prev" in + --stars|-s) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--automated --help --no-trunc --stars -s" -- "$cur" ) ) + ;; + esac +} + +_docker_start() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--attach -a --help --interactive -i" -- "$cur" ) ) + ;; + *) + __docker_complete_containers_stopped + ;; + esac +} + +_docker_stats() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--all -a --help --no-stream" -- "$cur" ) ) + ;; + *) + __docker_complete_containers_running + ;; + esac +} + +_docker_stop() { + case "$prev" in + --time|-t) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help --time -t" -- "$cur" ) ) + ;; + *) + __docker_complete_containers_running + ;; + esac +} + +_docker_tag() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--force -f --help" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag) + + if [ $cword -eq $counter ]; then + __docker_complete_image_repos_and_tags + return + fi + (( counter++ )) + + if [ $cword -eq $counter ]; then + __docker_complete_image_repos_and_tags + return + fi + ;; + esac +} + +_docker_unpause() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + __docker_complete_containers_unpauseable + fi + ;; + esac +} + +_docker_update() { + local options_with_args=" + --blkio-weight + --cpu-period + --cpu-quota + --cpuset-cpus + --cpuset-mems + --cpu-shares + --kernel-memory + --memory -m + --memory-reservation + --memory-swap + " + + local boolean_options=" + --help + " + + local all_options="$options_with_args $boolean_options" + + case "$prev" in + $(__docker_to_extglob "$options_with_args") ) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$all_options" -- "$cur" ) ) + ;; + *) + __docker_complete_containers_all + ;; + esac +} + +_docker_top() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + __docker_complete_containers_running + fi + ;; + esac +} + +_docker_version() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + esac +} + +_docker_volume_create() { + case "$prev" in + --driver|-d) + __docker_complete_plugins Volume + return + ;; + --name|--opt|-o) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--driver -d --help --name --opt -o" -- "$cur" ) ) + ;; + esac +} + +_docker_volume_inspect() { + case "$prev" in + --format|-f) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--format -f --help" -- "$cur" ) ) + ;; + *) + __docker_complete_volumes + ;; + esac +} + +_docker_volume_ls() { + case "$prev" in + --filter|-f) + COMPREPLY=( $( compgen -W "dangling=true" -- "$cur" ) ) + return + ;; + esac + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--filter -f --help --quiet -q" -- "$cur" ) ) + ;; + esac +} + +_docker_volume_rm() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + __docker_complete_volumes + ;; + esac +} + +_docker_volume() { + local subcommands=" + create + inspect + ls + rm + " + __docker_subcommands "$subcommands" && return + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) + ;; + esac +} + +_docker_wait() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + ;; + *) + __docker_complete_containers_all + ;; + esac +} + +_docker() { + local previous_extglob_setting=$(shopt -p extglob) + shopt -s extglob + + local commands=( + attach + build + commit + cp + create + daemon + diff + events + exec + export + history + images + import + info + inspect + kill + load + login + logout + logs + network + pause + port + ps + pull + push + rename + restart + rm + rmi + run + save + search + start + stats + stop + tag + top + unpause + update + version + volume + wait + ) + + # These options are valid as global options for all client commands + # and valid as command options for `docker daemon` + local global_boolean_options=" + --debug -D + --tls + --tlsverify + " + local global_options_with_args=" + --config + --host -H + --log-level -l + --tlscacert + --tlscert + --tlskey + " + + local host config + + COMPREPLY=() + local cur prev words cword + _get_comp_words_by_ref -n : cur prev words cword + + local command='docker' command_pos=0 subcommand_pos + local counter=1 + while [ $counter -lt $cword ]; do + case "${words[$counter]}" in + # save host so that completion can use custom daemon + --host|-H) + (( counter++ )) + host="${words[$counter]}" + ;; + # save config so that completion can use custom configuration directories + --config) + (( counter++ )) + config="${words[$counter]}" + ;; + $(__docker_to_extglob "$global_options_with_args") ) + (( counter++ )) + ;; + -*) + ;; + =) + (( counter++ )) + ;; + *) + command="${words[$counter]}" + command_pos=$counter + break + ;; + esac + (( counter++ )) + done + + local completions_func=_docker_${command} + declare -F $completions_func >/dev/null && $completions_func + + eval "$previous_extglob_setting" + return 0 +} + +eval "$__docker_previous_extglob_setting" +unset __docker_previous_extglob_setting + +complete -F _docker docker diff --git a/completion/available/git.completion.bash b/completion/available/git.completion.bash index 5944c824..e3918c87 100644 --- a/completion/available/git.completion.bash +++ b/completion/available/git.completion.bash @@ -10,6 +10,7 @@ # *) local and remote tag names # *) .git/remotes file names # *) git 'subcommands' +# *) git email aliases for git-send-email # *) tree paths within 'ref:path/to/file' expressions # *) file paths within current working directory and index # *) common --long-options @@ -663,10 +664,11 @@ __git_list_porcelain_commands () check-mailmap) : plumbing;; check-ref-format) : plumbing;; checkout-index) : plumbing;; + column) : internal helper;; commit-tree) : plumbing;; count-objects) : infrequent;; - credential-cache) : credentials helper;; - credential-store) : credentials helper;; + credential) : credentials;; + credential-*) : credentials helper;; cvsexportcommit) : export;; cvsimport) : import;; cvsserver) : daemon;; @@ -735,35 +737,28 @@ __git_list_porcelain_commands () __git_porcelain_commands= __git_compute_porcelain_commands () { - __git_compute_all_commands test -n "$__git_porcelain_commands" || __git_porcelain_commands=$(__git_list_porcelain_commands) } +# Lists all set config variables starting with the given section prefix, +# with the prefix removed. +__git_get_config_variables () +{ + local section="$1" i IFS=$'\n' + for i in $(git --git-dir="$(__gitdir)" config --name-only --get-regexp "^$section\..*" 2>/dev/null); do + echo "${i#$section.}" + done +} + __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_get_config_variables "pretty" } __git_aliases () { - local i IFS=$'\n' - for i in $(git --git-dir="$(__gitdir)" config --get-regexp "alias\..*" 2>/dev/null); do - case "$i" in - alias.*) - i="${i#alias.}" - echo "${i/ */}" - ;; - esac - done + __git_get_config_variables "alias" } # __git_aliased_command requires 1 argument @@ -1114,7 +1109,7 @@ _git_commit () case "$cur" in --cleanup=*) - __gitcomp "default strip verbatim whitespace + __gitcomp "default scissors strip verbatim whitespace " "" "${cur##--cleanup=}" return ;; @@ -1174,7 +1169,7 @@ __git_diff_common_options="--stat --numstat --shortstat --summary --no-prefix --src-prefix= --dst-prefix= --inter-hunk-context= --patience --histogram --minimal - --raw --word-diff + --raw --word-diff --word-diff-regex= --dirstat --dirstat= --dirstat-by-file --dirstat-by-file= --cumulative --diff-algorithm= @@ -1317,6 +1312,7 @@ _git_grep () --full-name --line-number --extended-regexp --basic-regexp --fixed-strings --perl-regexp + --threads --files-with-matches --name-only --files-without-match --max-depth @@ -1448,7 +1444,7 @@ _git_log () return ;; --decorate=*) - __gitcomp "long short" "" "${cur##--decorate=}" + __gitcomp "full short no" "" "${cur##--decorate=}" return ;; --*) @@ -1673,7 +1669,10 @@ _git_push () _git_rebase () { local dir="$(__gitdir)" - if [ -d "$dir"/rebase-apply ] || [ -d "$dir"/rebase-merge ]; then + if [ -f "$dir"/rebase-merge/interactive ]; then + __gitcomp "--continue --skip --abort --edit-todo" + return + elif [ -d "$dir"/rebase-apply ] || [ -d "$dir"/rebase-merge ]; then __gitcomp "--continue --skip --abort" return fi @@ -1689,8 +1688,12 @@ _git_rebase () --preserve-merges --stat --no-stat --committer-date-is-author-date --ignore-date --ignore-whitespace --whitespace= - --autosquash --fork-point --no-fork-point - --autostash + --autosquash --no-autosquash + --fork-point --no-fork-point + --autostash --no-autostash + --verify --no-verify + --keep-empty --root --force-rebase --no-ff + --exec " return @@ -1715,6 +1718,15 @@ __git_send_email_suppresscc_options="author self cc bodycc sob cccmd body all" _git_send_email () { + case "$prev" in + --to|--cc|--bcc|--from) + __gitcomp " + $(git --git-dir="$(__gitdir)" send-email --dump-aliases 2>/dev/null) + " + return + ;; + esac + case "$cur" in --confirm=*) __gitcomp " @@ -1739,6 +1751,12 @@ _git_send_email () " "" "${cur##--thread=}" return ;; + --to=*|--cc=*|--bcc=*|--from=*) + __gitcomp " + $(git --git-dir="$(__gitdir)" send-email --dump-aliases 2>/dev/null) + " "" "${cur#--*=}" + return + ;; --*) __gitcomp "--annotate --bcc --cc --cc-cmd --chain-reply-to --compose --confirm= --dry-run --envelope-sender @@ -1780,15 +1798,7 @@ __git_config_get_set_variables () 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 --git-dir="$(__gitdir)" config $config_file --name-only --list 2>/dev/null } _git_config () @@ -1803,7 +1813,7 @@ _git_config () return ;; branch.*.rebase) - __gitcomp "false true" + __gitcomp "false true preserve interactive" return ;; remote.pushdefault) @@ -1893,6 +1903,7 @@ _git_config () --get --get-all --get-regexp --add --unset --unset-all --remove-section --rename-section + --name-only " return ;; @@ -2049,6 +2060,7 @@ _git_config () core.sparseCheckout core.symlinks core.trustctime + core.untrackedCache core.warnAmbiguousRefs core.whitespace core.worktree @@ -2123,6 +2135,8 @@ _git_config () http.noEPSV http.postBuffer http.proxy + http.sslCipherList + http.sslVersion http.sslCAInfo http.sslCAPath http.sslCert @@ -2260,12 +2274,7 @@ _git_remote () __git_complete_remote_or_refspec ;; update) - local i c='' IFS=$'\n' - for i in $(git --git-dir="$(__gitdir)" config --get-regexp "remotes\..*" 2>/dev/null); do - i="${i#remotes.}" - c="$c ${i/ */}" - done - __gitcomp "$c" + __gitcomp "$(__git_get_config_variables "remotes")" ;; *) ;; @@ -2292,6 +2301,11 @@ _git_reset () _git_revert () { + local dir="$(__gitdir)" + if [ -f "$dir"/REVERT_HEAD ]; then + __gitcomp "--continue --quit --abort" + return + fi case "$cur" in --*) __gitcomp "--edit --mainline --no-edit --no-commit --signoff" @@ -2360,7 +2374,7 @@ _git_show_branch () case "$cur" in --*) __gitcomp " - --all --remotes --topo-order --current --more= + --all --remotes --topo-order --date-order --current --more= --list --independent --merge-base --no-name --color --no-color --sha1-name --sparse --topics --reflog @@ -2373,7 +2387,7 @@ _git_show_branch () _git_stash () { - local save_opts='--keep-index --no-keep-index --quiet --patch' + local save_opts='--all --keep-index --no-keep-index --quiet --patch --include-untracked' local subcommands='save list show apply clear drop pop create branch' local subcommand="$(__git_find_on_cmdline "$subcommands")" if [ -z "$subcommand" ]; then @@ -2395,9 +2409,20 @@ _git_stash () apply,--*|pop,--*) __gitcomp "--index --quiet" ;; - show,--*|drop,--*|branch,--*) + drop,--*) + __gitcomp "--quiet" ;; - show,*|apply,*|drop,*|pop,*|branch,*) + show,--*|branch,--*) + ;; + branch,*) + if [ $cword -eq 3 ]; then + __gitcomp_nl "$(__git_refs)"; + else + __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \ + | sed -n -e 's/:.*//p')" + fi + ;; + show,*|apply,*|drop,*|pop,*) __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \ | sed -n -e 's/:.*//p')" ;; diff --git a/completion/available/gradle.completion.bash b/completion/available/gradle.completion.bash new file mode 100644 index 00000000..2f55cade --- /dev/null +++ b/completion/available/gradle.completion.bash @@ -0,0 +1,50 @@ +function __gradle { + local cur=${COMP_WORDS[COMP_CWORD]} + local tasks='' + local cache_dir="$HOME/.gradle/completion_cache" + + case $OSTYPE in + darwin*) + local checksum_command="find . -name build.gradle -print0 | xargs -0 md5 -q | md5 -q" + ;; + *) + local checksum_command="find . -name build.gradle -print0 | xargs -0 md5sum | md5sum | cut -d ' ' -f 1" + ;; + esac + local parsing_command="gradle --console=plain --quiet tasks | grep -v Rules | sed -nE -e 's/^([a-zA-Z]+)($| - .+)/\1/p'" + + mkdir -p "${cache_dir}" + + local gradle_files_checksum='no_cache_file' + if [[ -f build.gradle ]]; then + gradle_files_checksum="$(eval "${checksum_command}")" + if [[ -f "${cache_dir}/${gradle_files_checksum}" ]]; then + newest_gradle_file="$(find . -type f -name build.gradle -newer "${cache_dir}/${gradle_files_checksum}")" + if [ -n "${newest_gradle_file}" ]; then + tasks="$(eval "${parsing_command}")" + [[ -n "${tasks}" ]] && echo "${tasks}" > "${cache_dir}/${gradle_files_checksum}" + else + tasks="$(cat "${cache_dir}/${gradle_files_checksum}")" + touch "${cache_dir}/${gradle_files_checksum}" + fi + else + tasks="$(eval "${parsing_command}")" + [[ -n "${tasks}" ]] && echo "${tasks}" > "${cache_dir}/${gradle_files_checksum}" + fi + else + tasks="$(eval "${parsing_command}")" + [[ -n "${tasks}" ]] && echo "${tasks}" > "${cache_dir}/${gradle_files_checksum}" + fi + COMPREPLY=( $(compgen -W "${tasks}" -- "${cur}") ) +} + +function __clear_gradle_cache { + local cache_dir="$HOME/.gradle/completion_cache" + [[ -d "${cache_dir}" ]] && find "${cache_dir}" -type f -mtime +7 -exec rm -f {} \; +} + +__clear_gradle_cache + +complete -F __gradle gradle +complete -F __gradle gradlew +complete -F __gradle ./gradlew diff --git a/completion/available/hub.completion.bash b/completion/available/hub.completion.bash new file mode 100644 index 00000000..3e99aca7 --- /dev/null +++ b/completion/available/hub.completion.bash @@ -0,0 +1,362 @@ +# hub tab-completion script for bash. +# This script complements the completion script that ships with git. + +# Check that git tab completion is available +if declare -F _git > /dev/null; then + # Duplicate and rename the 'list_all_commands' function + eval "$(declare -f __git_list_all_commands | \ + sed 's/__git_list_all_commands/__git_list_all_commands_without_hub/')" + + # Wrap the 'list_all_commands' function with extra hub commands + __git_list_all_commands() { + cat <<-EOF +alias +pull-request +fork +create +browse +compare +ci-status +EOF + __git_list_all_commands_without_hub + } + + # Ensure cached commands are cleared + __git_all_commands="" + + ########################## + # hub command completions + ########################## + + # hub alias [-s] [SHELL] + _git_alias() { + local i c=2 s=-s sh shells="bash zsh sh ksh csh fish" + while [ $c -lt $cword ]; do + i="${words[c]}" + case "$i" in + -s) + unset s + ;; + *) + for sh in $shells; do + if [ "$sh" = "$i" ]; then + unset shells + break + fi + done + ;; + esac + ((c++)) + done + __gitcomp "$s $shells" + } + + # hub browse [-u] [--|[USER/]REPOSITORY] [SUBPAGE] + _git_browse() { + local i c=2 u=-u repo subpage + local subpages_="commits issues tree wiki pulls branches stargazers + contributors network network/ graphs graphs/" + local subpages_network="members" + local subpages_graphs="commit-activity code-frequency punch-card" + while [ $c -lt $cword ]; do + i="${words[c]}" + case "$i" in + -u) + unset u + ;; + *) + if [ -z "$repo" ]; then + repo=$i + else + subpage=$i + fi + ;; + esac + ((c++)) + done + if [ -z "$repo" ]; then + __gitcomp "$u -- $(__hub_github_repos '\p')" + elif [ -z "$subpage" ]; then + case "$cur" in + */*) + local pfx="${cur%/*}" cur_="${cur#*/}" + local subpages_var="subpages_$pfx" + __gitcomp "${!subpages_var}" "$pfx/" "$cur_" + ;; + *) + __gitcomp "$u ${subpages_}" + ;; + esac + else + __gitcomp "$u" + fi + } + + # hub compare [-u] [USER[/REPOSITORY]] [[START...]END] + _git_compare() { + local i c=$((cword - 1)) u=-u user remote owner repo arg_repo rev + while [ $c -gt 1 ]; do + i="${words[c]}" + case "$i" in + -u) + unset u + ;; + *) + if [ -z "$rev" ]; then + # Even though the logic below is able to complete both user/repo + # and revision in the right place, when there is only one argument + # (other than -u) in the command, that argument will be taken as + # revision. For example: + # $ hub compare -u upstream + # > https://github.com/USER/REPO/compare/upstream + if __hub_github_repos '\p' | grep -Eqx "^$i(/[^/]+)?"; then + arg_repo=$i + else + rev=$i + fi + elif [ -z "$arg_repo" ]; then + arg_repo=$i + fi + ;; + esac + ((c--)) + done + + # Here we want to find out the git remote name of user/repo, in order to + # generate an appropriate revision list + if [ -z "$arg_repo" ]; then + user=$(__hub_github_user) + if [ -z "$user" ]; then + for i in $(__hub_github_repos); do + remote=${i%%:*} + repo=${i#*:} + if [ "$remote" = origin ]; then + break + fi + done + else + for i in $(__hub_github_repos); do + remote=${i%%:*} + repo=${i#*:} + owner=${repo%%/*} + if [ "$user" = "$owner" ]; then + break + fi + done + fi + else + for i in $(__hub_github_repos); do + remote=${i%%:*} + repo=${i#*:} + owner=${repo%%/*} + case "$arg_repo" in + "$repo"|"$owner") + break + ;; + esac + done + fi + + local pfx cur_="$cur" + case "$cur_" in + *..*) + pfx="${cur_%%..*}..." + cur_="${cur_##*..}" + __gitcomp_nl "$(__hub_revlist $remote)" "$pfx" "$cur_" + ;; + *) + if [ -z "${arg_repo}${rev}" ]; then + __gitcomp "$u $(__hub_github_repos '\o\n\p') $(__hub_revlist $remote)" + elif [ -z "$rev" ]; then + __gitcomp "$u $(__hub_revlist $remote)" + else + __gitcomp "$u" + fi + ;; + esac + } + + # hub create [NAME] [-p] [-d DESCRIPTION] [-h HOMEPAGE] + _git_create() { + local i c=2 name repo flags="-p -d -h" + while [ $c -lt $cword ]; do + i="${words[c]}" + case "$i" in + -d|-h) + ((c++)) + flags=${flags/$i/} + ;; + -p) + flags=${flags/$i/} + ;; + *) + name=$i + ;; + esac + ((c++)) + done + if [ -z "$name" ]; then + repo=$(basename "$(pwd)") + fi + case "$prev" in + -d|-h) + COMPREPLY=() + ;; + -p|*) + __gitcomp "$repo $flags" + ;; + esac + } + + # hub fork [--no-remote] + _git_fork() { + local i c=2 remote=yes + while [ $c -lt $cword ]; do + i="${words[c]}" + case "$i" in + --no-remote) + unset remote + ;; + esac + ((c++)) + done + if [ -n "$remote" ]; then + __gitcomp "--no-remote" + fi + } + + # hub pull-request [-f] [-m |-F |-i |] [-b ] [-h ] + _git_pull_request() { + local i c=2 flags="-f -m -F -i -b -h" + while [ $c -lt $cword ]; do + i="${words[c]}" + case "$i" in + -m|-F|-i|-b|-h) + ((c++)) + flags=${flags/$i/} + ;; + -f) + flags=${flags/$i/} + ;; + esac + ((c++)) + done + case "$prev" in + -i) + COMPREPLY=() + ;; + -b|-h) + # (Doesn't seem to need this...) + # Uncomment the following line when 'owner/repo:[TAB]' misbehaved + #_get_comp_words_by_ref -n : cur + __gitcomp_nl "$(__hub_heads)" + # __ltrim_colon_completions "$cur" + ;; + -F) + COMPREPLY=( "$cur"* ) + ;; + -f|*) + __gitcomp "$flags" + ;; + esac + } + + ################### + # Helper functions + ################### + + # __hub_github_user [HOST] + # Return $GITHUB_USER or the default github user defined in hub config + # HOST - Host to be looked-up in hub config. Default is "github.com" + __hub_github_user() { + if [ -n "$GITHUB_USER" ]; then + echo $GITHUB_USER + return + fi + local line h k v host=${1:-github.com} config=${HUB_CONFIG:-~/.config/hub} + if [ -f "$config" ]; then + while read line; do + if [ "$line" = "---" ]; then + continue + fi + k=${line%%:*} + v=${line#*:} + if [ -z "$v" ]; then + if [ "$h" = "$host" ]; then + break + fi + h=$k + continue + fi + k=${k#* } + v=${v#* } + if [ "$h" = "$host" ] && [ "$k" = "user" ]; then + echo "$v" + break + fi + done < "$config" + fi + } + + # __hub_github_repos [FORMAT] + # List all github hosted repository + # FORMAT - Format string contains multiple of these: + # \m remote + # \p owner/repo + # \o owner + # escaped characters (\n, \t ...etc) work + # If omitted, prints all github repos in the format of "remote:owner/repo" + __hub_github_repos() { + local f format=$1 + if [ -z "$(__gitdir)" ]; then + return + fi + if [ -z "$format" ]; then + format='\1:\2' + else + format=${format//\m/\1} + format=${format//\p/\2} + format=${format//\o/\3} + fi + command git config --get-regexp 'remote\.[^.]*\.url' | + grep -E ' ((https?|git)://|git@)github\.com[:/][^:/]+/[^/]+$' | + sed -E 's#^remote\.([^.]+)\.url +.+[:/](([^/]+)/[^.]+)(\.git)?$#'"$format"'#' + } + + # __hub_heads + # List all local "branch", and remote "owner/repo:branch" + __hub_heads() { + local i remote repo branch dir=$(__gitdir) + if [ -d "$dir" ]; then + command git --git-dir="$dir" for-each-ref --format='%(refname:short)' \ + "refs/heads/" + for i in $(__hub_github_repos); do + remote=${i%%:*} + repo=${i#*:} + command git --git-dir="$dir" for-each-ref --format='%(refname:short)' \ + "refs/remotes/${remote}/" | while read branch; do + echo "${repo}:${branch#${remote}/}" + done + done + fi + } + + # __hub_revlist [REMOTE] + # List all tags, and branches under REMOTE, without the "remote/" prefix + # REMOTE - Remote name to search branches from. Default is "origin" + __hub_revlist() { + local i remote=${1:-origin} dir=$(__gitdir) + if [ -d "$dir" ]; then + command git --git-dir="$dir" for-each-ref --format='%(refname:short)' \ + "refs/remotes/${remote}/" | while read i; do + echo "${i#${remote}/}" + done + command git --git-dir="$dir" for-each-ref --format='%(refname:short)' \ + "refs/tags/" + fi + } + + # Enable completion for hub even when not using the alias + complete -o bashdefault -o default -o nospace -F _git hub 2>/dev/null \ + || complete -o default -o nospace -F _git hub +fi diff --git a/completion/available/jboss7.completion.bash b/completion/available/jboss7.completion.bash new file mode 100644 index 00000000..66d07179 --- /dev/null +++ b/completion/available/jboss7.completion.bash @@ -0,0 +1,141 @@ +# Completions for JBoss Application Server 7 (EAP 6) +# VERSION: 0.6 +# DATE: 2012-10-30 +# rparree-at-edc4it-dot-com + + + + +_serverProfiles(){ + if [[ $COMP_WORDS == *standalone.sh* ]] + then + serverdir="../standalone/configuration/" + else + # assume is domain.sh + serverdir="../domain/configuration/" + fi + + for i in ${!COMP_WORDS[*]} + do + if [[ "${COMP_WORDS[i]}" == "-Djboss.server.base.dir" || "${COMP_WORDS[i]}" == "-Djboss.domain.base.dir" ]]; then + serverdir="${COMP_WORDS[i+2]}/configuration" + fi + + done + if [ -d "${serverdir}" ] + then + + IFS=$'\n' tmp="$(ls "${serverdir}" | grep xml)" + local fls="${tmp[@]// /\ }" + unset IFS + COMPREPLY=( $(compgen -W "${fls} initial boot last v" -- "$cur" )) + fi +} + +_bindingAddress(){ + # from /etc/bash_completion.d/ssh + COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W \ + "0.0.0.0 $( PATH="$PATH:/sbin" ifconfig -a | \ + sed -ne 's/.*addr:\([^[:space:]]*\).*/\1/p' \ + -ne 's/.*inet[[:space:]]\{1,\}\([^[:space:]]*\).*/\1/p' )" \ + -- "$cur" ) ) +} + +_jboss(){ + + local cur prev words cword + COMPREPLY=() + _get_comp_words_by_ref -n = cur prev words cword + + case $cur in + + -Djboss.socket.binding.port-offset=*) + cur=${cur#*=} + #static list of common bindings sets + local bindings="100 200 300 400 10000 20000 30000 40000" + COMPREPLY=( $(compgen -W "${bindings}" -- ${cur}) ) + return 0 + ;; + -Djboss.default.jgroups.stack=*) + cur=${cur#*=} + #static list of standard JGroups stacks + local stacks="udp udp-async udp-sync tcp tcp-sync" + COMPREPLY=( $(compgen -W "${stacks}" -- ${cur}) ) + return 0 + ;; + + -Dorg.jboss.ejb3.remoting.IsLocalInterceptor.passByRef=*|-Dcom.sun.management.jmxremote.authenticate=*|-Dcom.sun.management.jmxremote.ssl=*) + cur=${cur#*=} + local booleans="true false" + COMPREPLY=( $(compgen -W "${booleans}" -- ${cur}) ) + return 0 + ;; + + -Djboss.server.base.dir=*|-Djboss.home.dir=*|-Djboss.domain.base.dir=*) + cur=${cur#*=} + _filedir -d + return 0 + ;; + + -Djboss.domain.master.address=*|-Djboss.bind.address*=*) + cur=${cur#*=} + _bindingAddress + return 0 + ;; + --server-config=*|-c=|--host-config=*) + cur=${cur#*=} + _serverProfiles + return 0 + + + esac + + + case $prev in + -u) + # a few from RFC 2365 IPv4 Local Scope () + local addresses="239.255.0.1 239.255.0.2 239.255.0.3" + COMPREPLY=( $(compgen -W "${addresses}" -- ${cur}) ) + return 0 + ;; + -b*) + _bindingAddress + return 0 + ;; + -c) + _serverProfiles + return 0 + ;; + *) + ;; + esac + # *** from jboss5 ******************** + # *** -modulepath -c -m -g -l -d -p -n -B -L -C -Djboss.platform.mbeanserver -Djboss.server.base.directory + # *** -Djboss.Domain -Djboss.modcluster.proxyList -Djboss.jvmRoute -Djboss.default.jgroups.stack -Dorg.jboss.ejb3.remoting.IsLocalInterceptor.passByRef -Djboss.platform.mbeanserver -Dcom.sun.management.jmxremote.port -Dcom.sun.management.jmxremote.ssl + # ************************************* + + # standard commands for standalone and domain mode + local commandsWithoutEqualSign='-b -bmanagement -bunsecure -bpublic --admin-only -h -help -u -version -V -v' + local commandsWithEqualSign='-P -Djboss.node.name -Djboss.home.dir -Djboss.socket.binding.port-offset -Djboss.bind.address.management -Djboss.bind.address -Djboss.bind.address.unsecure' + + if [[ $COMP_WORDS == *standalone.sh* ]] + then + commandsWithoutEqualSign="${commandsWithoutEqualSign} -c" + commandsWithEqualSign="${commandsWithEqualSign} --server-config -Djboss.server.base.dir -c" + else + # assume is domain.sh + commandsWithoutEqualSign="${commandsWithoutEqualSign} --backup --cached-dc" + commandsWithEqualSign="${commandsWithEqualSign} -Djboss.domain.master.address --host-config -Djboss.domain.master.port -Djboss.domain.base.dir " + fi + + + + + COMPREPLY=( $( compgen -W "$commandsWithoutEqualSign" -- "$cur" ) + $( compgen -W "$commandsWithEqualSign" -S '=' -- "$cur" ) ) + return 0 + + +} +complete -o nospace -F _jboss standalone.sh +complete -o nospace -F _jboss domain.sh diff --git a/completion/available/projects.completion.bash b/completion/available/projects.completion.bash new file mode 100644 index 00000000..71d740cd --- /dev/null +++ b/completion/available/projects.completion.bash @@ -0,0 +1,39 @@ +_pj() { + [ -z "$PROJECT_PATHS" ] && return + shift + [ "$1" == "open" ] && shift + + local cur prev words cword + _init_completion || return + + local IFS=$'\n' i j k + + compopt -o filenames + + local -r mark_dirs=$(_rl_enabled mark-directories && echo y) + local -r mark_symdirs=$(_rl_enabled mark-symlinked-directories && echo y) + + for i in ${PROJECT_PATHS//:/$'\n'}; do + # create an array of matched subdirs + k="${#COMPREPLY[@]}" + for j in $( compgen -d $i/$cur ); do + if [[ ( $mark_symdirs && -h $j || $mark_dirs && ! -h $j ) && ! -d ${j#$i/} ]]; then + j+="/" + fi + COMPREPLY[k++]=${j#$i/} + done + done + + if [[ ${#COMPREPLY[@]} -eq 1 ]]; then + i=${COMPREPLY[0]} + if [[ "$i" == "$cur" && $i != "*/" ]]; then + COMPREPLY[0]="${i}/" + fi + fi + + return 0 +} + +complete -F _pj -o nospace pj +complete -F _pj -o nospace pjo + diff --git a/completion/available/sdkman.completion.bash b/completion/available/sdkman.completion.bash new file mode 100644 index 00000000..95545b87 --- /dev/null +++ b/completion/available/sdkman.completion.bash @@ -0,0 +1,61 @@ +_sdkman_complete() +{ + local CANDIDATES + local CANDIDATE_VERSIONS + + COMPREPLY=() + + if [ $COMP_CWORD -eq 1 ]; then + COMPREPLY=( $(compgen -W "install uninstall rm list ls use current outdated version default selfupdate broadcast offline help flush" -- ${COMP_WORDS[COMP_CWORD]}) ) + elif [ $COMP_CWORD -eq 2 ]; then + case "${COMP_WORDS[COMP_CWORD-1]}" in + "install" | "uninstall" | "rm" | "list" | "ls" | "use" | "current" | "outdated" ) + CANDIDATES=$(echo "${SDKMAN_CANDIDATES_CSV}" | tr ',' ' ') + COMPREPLY=( $(compgen -W "$CANDIDATES" -- ${COMP_WORDS[COMP_CWORD]}) ) + ;; + "offline" ) + COMPREPLY=( $(compgen -W "enable disable" -- ${COMP_WORDS[COMP_CWORD]}) ) + ;; + "selfupdate" ) + COMPREPLY=( $(compgen -W "force" -P "[" -S "]" -- ${COMP_WORDS[COMP_CWORD]}) ) + ;; + "flush" ) + COMPREPLY=( $(compgen -W "candidates broadcast archives temp" -- ${COMP_WORDS[COMP_CWORD]}) ) + ;; + *) + ;; + esac + elif [ $COMP_CWORD -eq 3 ]; then + case "${COMP_WORDS[COMP_CWORD-2]}" in + "install" | "uninstall" | "rm" | "use" | "default" ) + _sdkman_candidate_versions ${COMP_WORDS[COMP_CWORD-1]} + COMPREPLY=( $(compgen -W "$CANDIDATE_VERSIONS" -- ${COMP_WORDS[COMP_CWORD]}) ) + ;; + *) + ;; + esac + fi + + return 0 +} + +_sdkman_candidate_versions(){ + + CANDIDATE_LOCAL_VERSIONS=$(__sdkman_cleanup_local_versions $1) + if [ "$SDKMAN_OFFLINE_MODE" = "true" ]; then + CANDIDATE_VERSIONS=$CANDIDATE_LOCAL_VERSIONS + else + CANDIDATE_ONLINE_VERSIONS="$(curl -s "${SDKMAN_SERVICE}/candidates/$1" | tr ',' ' ')" + CANDIDATE_VERSIONS="$(echo $CANDIDATE_ONLINE_VERSIONS $CANDIDATE_LOCAL_VERSIONS |sort | uniq ) " + fi + +} + +__sdkman_cleanup_local_versions(){ + + __sdkman_build_version_csv $1 + echo $CSV | tr ',' ' ' + +} + +complete -F _sdkman_complete sdk diff --git a/completion/available/ssh.completion.bash b/completion/available/ssh.completion.bash index 396be8f2..1ab08000 100644 --- a/completion/available/ssh.completion.bash +++ b/completion/available/ssh.completion.bash @@ -14,19 +14,19 @@ _sshcomplete() { # parse all defined hosts from .ssh/config if [ -r "$HOME/.ssh/config" ]; then - COMPREPLY=($(compgen -W "$(grep ^Host "$HOME/.ssh/config" | awk '{print $2}' )" ${OPTIONS}) ) + COMPREPLY=($(compgen -W "$(grep ^Host "$HOME/.ssh/config" | awk '{for (i=2; i<=NF; i++) print $i}' )" ${OPTIONS}) ) fi # parse all hosts found in .ssh/known_hosts if [ -r "$HOME/.ssh/known_hosts" ]; then if grep -v -q -e '^ ssh-rsa' "$HOME/.ssh/known_hosts" ; then - COMPREPLY=( ${COMPREPLY[@]} $(compgen -W "$( awk '{print $1}' "$HOME/.ssh/known_hosts" | cut -d, -f 1 | sed -e 's/\[//g' | sed -e 's/\]//g' | cut -d: -f1 | grep -v ssh-rsa)" ${OPTIONS}) ) + COMPREPLY=( ${COMPREPLY[@]} $(compgen -W "$( awk '{print $1}' "$HOME/.ssh/known_hosts" | grep -v ^\| | cut -d, -f 1 | sed -e 's/\[//g' | sed -e 's/\]//g' | cut -d: -f1 | grep -v ssh-rsa)" ${OPTIONS}) ) fi fi # parse hosts defined in /etc/hosts if [ -r /etc/hosts ]; then - COMPREPLY=( ${COMPREPLY[@]} $(compgen -W "$( grep -v '^[[:space:]]*$' /etc/hosts | grep -v '^#' | awk '{print $2}' )" ${OPTIONS}) ) + COMPREPLY=( ${COMPREPLY[@]} $(compgen -W "$( grep -v '^[[:space:]]*$' /etc/hosts | grep -v '^#' | awk '{for (i=2; i<=NF; i++) print $i}' )" ${OPTIONS}) ) fi return 0 diff --git a/completion/available/system.completion.bash b/completion/available/system.completion.bash new file mode 100644 index 00000000..aeaa5375 --- /dev/null +++ b/completion/available/system.completion.bash @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# Loads the system's Bash completion modules. +# If Homebrew is installed (OS X), its Bash completion modules are loaded. + +if [ -f /etc/bash_completion ]; then + . /etc/bash_completion +fi + +if [ $(uname) = "Darwin" ] && command -v brew &>/dev/null ; then + BREW_PREFIX=$(brew --prefix) + + if [ -f "$BREW_PREFIX"/etc/bash_completion ]; then + . "$BREW_PREFIX"/etc/bash_completion + fi +fi diff --git a/completion/available/terraform.completion.bash b/completion/available/terraform.completion.bash new file mode 100644 index 00000000..729c72b6 --- /dev/null +++ b/completion/available/terraform.completion.bash @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# Bash Terraform completion + +_terraform() +{ + local cmds cur colonprefixes + cmds="apply destroy get graph init output plan push \ + refresh remote show taint version" + + COMPREPLY=() + cur=${COMP_WORDS[COMP_CWORD]} + # Work-around bash_completion issue where bash interprets a colon + # as a separator. + # Work-around borrowed from the darcs work-around for the same + # issue. + colonprefixes=${cur%"${cur##*:}"} + COMPREPLY=( $(compgen -W '$cmds' -- $cur)) + local i=${#COMPREPLY[*]} + while [ $((--i)) -ge 0 ]; do + COMPREPLY[$i]=${COMPREPLY[$i]#"$colonprefixes"} + done + + return 0 +} && +complete -F _terraform terraform diff --git a/completion/available/tmux.completion.bash b/completion/available/tmux.completion.bash index a1b8f069..ddadcbd8 100644 --- a/completion/available/tmux.completion.bash +++ b/completion/available/tmux.completion.bash @@ -5,92 +5,8 @@ # 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 () -{ +_tmux_expand () +{ [ "$cur" != "${cur%\\}" ] && cur="$cur"'\'; if [[ "$cur" == \~*/* ]]; then eval cur=$cur; @@ -103,8 +19,8 @@ _tmux_expand () fi } -_tmux_filedir () -{ +_tmux_filedir () +{ local IFS=' '; _tmux_expand || return 0; @@ -130,11 +46,11 @@ function _tmux_complete_window() { local cur="${1}" local session_name="$(echo "${cur}" | sed 's/\\//g' | cut -d ':' -f 1)" local sessions - + 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}" 2>/dev/null | 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/:/\\\\:/')" @@ -186,8 +102,8 @@ _tmux() { if [[ $COMP_CWORD -le $cmd_index ]]; then # The user has not specified a command yet - COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "${_tmux_cmds}" -- "${cur}") ) - else + COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "$(tmux start-server \; list-commands | cut -d' ' -f1)" -- "${cur}") ) + else case ${cmd} in attach-session|attach) case "$prev" in @@ -213,7 +129,7 @@ _tmux() { case "$prev" in -t) _tmux_complete_session "${cur}" ;; -[n|d|s]) options="-d -n -s -t --" ;; - *) + *) if [[ ${COMP_WORDS[option_index]} == -- ]]; then _command_offset ${option_index} else @@ -249,7 +165,7 @@ _tmux() { -t) _tmux_complete_session "${cur}" ;; *) options="-l -n -p -c -t" ;; esac ;; - + send-keys|send) case "$option" in -t) _tmux_complete_window "${cur}" ;; @@ -257,12 +173,12 @@ _tmux() { esac ;; esac # case ${cmd} fi # command specified - fi # not -f - + fi # not -f + if [[ -n "${options}" ]]; then COMPREPLY=( ${COMPREPLY[@]:-} $(compgen -W "${options}" -- "${cur}") ) fi - + return 0 } diff --git a/install.sh b/install.sh index bbd01411..17250eb0 100755 --- a/install.sh +++ b/install.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -BASH_IT="$HOME/.bash_it" +BASH_IT="$(cd "$(dirname "$0")" && pwd)" case $OSTYPE in darwin*) @@ -13,46 +13,64 @@ esac BACKUP_FILE=$CONFIG_FILE.bak if [ -e "$HOME/$BACKUP_FILE" ]; then - echo "Backup file already exists. Make sure to backup your .bashrc before running this installation." >&2 - while true - do - read -e -n 1 -r -p "Would you like to overwrite the existing backup? This will delete your existing backup file ($HOME/$BACKUP_FILE) [y/N] " RESP - case $RESP in - [yY]) - break - ;; - [nN]|"") - echo -e "\033[91mInstallation aborted. Please come back soon!\033[m" - exit 1 - ;; - *) - echo -e "\033[91mPlease choose y or n.\033[m" - ;; - esac - done + echo -e "\033[0;33mBackup file already exists. Make sure to backup your .bashrc before running this installation.\033[0m" >&2 + while true + do + read -e -n 1 -r -p "Would you like to overwrite the existing backup? This will delete your existing backup file ($HOME/$BACKUP_FILE) [y/N] " RESP + case $RESP in + [yY]) + break + ;; + [nN]|"") + echo -e "\033[91mInstallation aborted. Please come back soon!\033[m" + exit 1 + ;; + *) + echo -e "\033[91mPlease choose y or n.\033[m" + ;; + esac + done fi -test -w "$HOME/$CONFIG_FILE" && - cp -a "$HOME/$CONFIG_FILE" "$HOME/$CONFIG_FILE.bak" && - echo "Your original $CONFIG_FILE has been backed up to $CONFIG_FILE.bak" +while true +do + read -e -n 1 -r -p "Would you like to keep your $CONFIG_FILE and append bash-it templates at the end? [y/N] " choice + case $choice in + [yY]) + test -w "$HOME/$CONFIG_FILE" && + cp -aL "$HOME/$CONFIG_FILE" "$HOME/$CONFIG_FILE.bak" && + echo -e "\033[0;32mYour original $CONFIG_FILE has been backed up to $CONFIG_FILE.bak\033[0m" -cp "$HOME/.bash_it/template/bash_profile.template.bash" "$HOME/$CONFIG_FILE" + (sed "s|{{BASH_IT}}|$BASH_IT|" "$BASH_IT/template/bash_profile.template.bash" | tail -n +2) >> "$HOME/$CONFIG_FILE" + echo -e "\033[0;32mBash-it template has been added to your $CONFIG_FILE\033[0m" + break + ;; + [nN]|"") + test -w "$HOME/$CONFIG_FILE" && + cp -aL "$HOME/$CONFIG_FILE" "$HOME/$CONFIG_FILE.bak" && + echo -e "\033[0;32mYour original $CONFIG_FILE has been backed up to $CONFIG_FILE.bak\033[0m" + sed "s|{{BASH_IT}}|$BASH_IT|" "$BASH_IT/template/bash_profile.template.bash" > "$HOME/$CONFIG_FILE" + break + ;; + *) + echo -e "\033[91mPlease choose y or n.\033[m" + ;; + esac +done -echo "Copied the template $CONFIG_FILE into ~/$CONFIG_FILE, edit this file to customize bash-it" +echo -e "\033[0;32mCopied the template $CONFIG_FILE into ~/$CONFIG_FILE, edit this file to customize bash-it\033[0m" -function load_all() { +function load_one() { file_type=$1 - [ ! -d "$BASH_IT/$file_type/enabled" ] && mkdir "$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 "../available/${filename}" "${dest}" - else - echo "File ${dest} exists, skipping" - fi - done + file_to_enable=$2 + mkdir -p "$BASH_IT/${file_type}/enabled" + + dest="${BASH_IT}/${file_type}/enabled/${file_to_enable}" + if [ ! -e "${dest}" ]; then + ln -sf "../available/${file_to_enable}" "${dest}" + else + echo "File ${dest} exists, skipping" + fi } function load_some() { @@ -80,58 +98,31 @@ function load_some() { done } -if [[ "$1" == "--none" ]] +if [[ "$1" == "--interactive" ]] then - echo "Not enabling any aliases, plugins or completions" -elif [[ "$1" == "--all" ]] -then - echo "Enabling all aliases, plugins and completions." - load_all aliases - load_all plugins - load_all completion -else - while true - do - read -e -n 1 -p "Do you use Jekyll? (If you don't know what Jekyll is, answer 'n') [y/N] " RESP - case $RESP in - [yY]) - cp "$HOME/.bash_it/template/jekyllconfig.template.bash" "$HOME/.jekyllconfig" - echo "Copied the template .jekyllconfig into your home directory. Edit this file to customize bash-it for using the Jekyll plugins" - break - ;; - [nN]|"") - break - ;; - *) - echo -e "\033[91mPlease choose y or n.\033[m" - ;; - esac - done - for type in "aliases" "plugins" "completion" do - while true - do - read -p "Would you like to enable all, some, or no $type? Some of these may make bash slower to start up (especially completion). (all/some/none) " RESP - case $RESP - in - some) - load_some $type - break - ;; - all) - load_all $type - break - ;; - none) - break - ;; - *) - echo "Unknown choice. Please enter some, all, or none" - continue - ;; - esac - done + echo -e "\033[0;32mEnabling $type\033[0m" + load_some $type done -echo -e "\033[0;32mInstallation finished successfully! Enjoy bash-it!\033[0m" +else + echo "" + echo -e "\033[0;32mEnabling sane defaults\033[0m" + load_one completion bash-it.completion.bash + load_one completion system.completion.bash + load_one plugins base.plugin.bash + load_one plugins alias-completion.plugin.bash + load_one aliases general.aliases.bash fi + +echo "" +echo -e "\033[0;32mInstallation finished successfully! Enjoy bash-it!\033[0m" +echo -e "\033[0;32mTo start using it, open a new tab or 'source "$HOME/$CONFIG_FILE"'.\033[0m" +echo "" +echo "To show the available aliases/completions/plugins, type one of the following:" +echo " bash-it show aliases" +echo " bash-it show completions" +echo " bash-it show plugins" +echo "" +echo "To avoid issues and to keep your shell lean, please enable only features you really want to use." +echo "Enabling everything can lead to issues." diff --git a/lib/appearance.bash b/lib/appearance.bash index fecb4686..05e0e40a 100644 --- a/lib/appearance.bash +++ b/lib/appearance.bash @@ -7,7 +7,15 @@ export GREP_COLOR='1;33' # colored ls export LSCOLORS='Gxfxcxdxdxegedabagacad' +if [[ -z "$CUSTOM_THEME_DIR" ]]; then + CUSTOM_THEME_DIR="${BASH_IT}/custom/themes" +fi + # Load the theme if [[ $BASH_IT_THEME ]]; then - source "$BASH_IT/themes/$BASH_IT_THEME/$BASH_IT_THEME.theme.bash" + if [[ -f "$CUSTOM_THEME_DIR/$BASH_IT_THEME/$BASH_IT_THEME.theme.bash" ]]; then + source "$CUSTOM_THEME_DIR/$BASH_IT_THEME/$BASH_IT_THEME.theme.bash" + else + source "$BASH_IT/themes/$BASH_IT_THEME/$BASH_IT_THEME.theme.bash" + fi fi diff --git a/lib/helpers.bash b/lib/helpers.bash index ebd68119..c95f8d96 100644 --- a/lib/helpers.bash +++ b/lib/helpers.bash @@ -31,14 +31,16 @@ function reload_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) ]' + about 'Bash-it help and maintenance' + param '1: verb [one of: help | show | enable | disable | update | search ] ' + param '2: component type [one of: alias(es) | completion(s) | plugin(s) ] or search term(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' + example '$ bash-it enable plugin git [tmux]...' + example '$ bash-it disable alias hg [tmux]...' + example '$ bash-it update' + example '$ bash-it search ruby [[-]rake]... [--enable | --disable]' typeset verb=${1:-} shift typeset component=${1:-} @@ -53,6 +55,11 @@ bash-it () func=_disable-$component;; help) func=_help-$component;; + search) + _bash-it-search $component $* + return;; + update) + func=_bash-it_update;; *) reference bash-it return;; @@ -72,7 +79,15 @@ bash-it () fi fi fi - $func $* + + if [ x"$verb" == x"enable" -o x"$verb" == x"disable" ];then + for arg in "$@" + do + $func $arg + done + else + $func $* + fi } _is_function () @@ -107,6 +122,30 @@ _bash-it-plugins () _bash-it-describe "plugins" "a" "plugin" "Plugin" } +_bash-it_update() { + _about 'updates Bash-it' + _group 'lib' + + cd "${BASH_IT}" + if [ -z $BASH_IT_REMOTE ]; then + BASH_IT_REMOTE="origin" + fi + git fetch &> /dev/null + local status="$(git rev-list master..${BASH_IT_REMOTE}/master 2> /dev/null)" + if [[ -n "${status}" ]]; then + git pull --rebase &> /dev/null + if [[ $? -eq 0 ]]; then + echo "Bash-it successfully updated, enjoy!" + reload + else + echo "Error updating Bash-it, please, check if your Bash-it installation folder (${BASH_IT}) is clean." + fi + else + echo "Bash-it is up to date, nothing to do!" + fi + cd - &> /dev/null +} + _bash-it-describe () { _about 'summarizes available bash_it components' @@ -134,9 +173,9 @@ _bash-it-describe () 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 '%s\n' "$ bash-it enable $file_type <$file_type name> [$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" + printf '%s\n' "$ bash-it disable $file_type <$file_type name> [$file_type name]... -or- $ bash-it disable $file_type all" } _disable-plugin () @@ -198,7 +237,7 @@ _disable-thing () 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." + printf '%s\n' "sorry, $file_entity does not appear to be an enabled $file_type." return fi rm $BASH_IT/$subdirectory/enabled/$(basename $plugin) @@ -267,7 +306,7 @@ _enable-thing () 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." + printf '%s\n' "sorry, $file_entity does not appear to be an available $file_type." return fi @@ -347,6 +386,13 @@ _help-plugins() rm $grouplist 2> /dev/null } +_help-update () { + _about 'help message for update command' + _group 'lib' + + echo "Check for a new version of Bash-it and update it." +} + all_groups () { about 'displays all unique metadata groups' diff --git a/lib/history.bash b/lib/history.bash old mode 100755 new mode 100644 index d582192b..f7d3303c --- a/lib/history.bash +++ b/lib/history.bash @@ -2,10 +2,10 @@ # Bash History Handling -shopt -s histappend # append to bash_history if Terminal.app quits -export HISTCONTROL=erasedups # erase duplicates; alternative option: export HISTCONTROL=ignoredups -export HISTSIZE=5000 # resize history size -export AUTOFEATURE=true autotest +shopt -s histappend # append to bash_history if Terminal.app quits +export HISTCONTROL=${HISTCONTROL:-erasedups} # erase duplicates; alternative option: export HISTCONTROL=ignoredups +export HISTSIZE=${HISTSIZE:-5000} # resize history size +export AUTOFEATURE=${AUTOFEATURE:-true autotest} # Cucumber / Autotest integration function rh { history | awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | sort -rn | head diff --git a/lib/preview.bash b/lib/preview.bash index 6e0d0357..306b475a 100644 --- a/lib/preview.bash +++ b/lib/preview.bash @@ -10,7 +10,8 @@ then THEMES="$BASH_IT/themes/*/*.theme.bash" for theme in $THEMES do - BASH_IT_THEME=$(basename -s '.theme.bash' $theme) + BASH_IT_THEME=${theme%.theme.bash} + BASH_IT_THEME=${BASH_IT_THEME##*/} echo " $BASH_IT_THEME" echo "" | bash --init-file $BASH_IT/bash_it.sh -i diff --git a/lib/search.bash b/lib/search.bash new file mode 100644 index 00000000..aa9a13ea --- /dev/null +++ b/lib/search.bash @@ -0,0 +1,194 @@ +# +# Search by Konstantin Gredeskoul «github.com/kigster» +#——————————————————————————————————————————————————————————————————————————————— +# This function returns list of aliases, plugins and completions in bash-it, +# whose name or description matches one of the search terms provided as arguments. +# +# Usage: +# ❯ bash-it search term1 [[-]term2] ... [[-]termN] [ --enable | --disable ] +# +# Exmplanation: +# Single dash, as in "-chruby", indicates a negative search term. +# Double dash indicates a command that is to be applied to the search result. +# At the moment only --enable and --disable are supported. +# +# Examples: +# ❯ bash-it search ruby rbenv rvm gem rake +# aliases : bundler +# plugins : chruby chruby-auto rbenv ruby rvm +# completions : gem rake + +# ❯ bash-it search ruby rbenv rvm gem rake -chruby +# aliases : bundler +# plugins : rbenv ruby rvm +# completions : gem rake +# +# Examples of enabling or disabling results of the search: +# +# ❯ bash-it search ruby +# aliases => bundler +# plugins => chruby chruby-auto ruby +# +# ❯ bash-it search ruby -chruby --enable +# aliases => ✓bundler +# plugins => ✓ruby +# +# +_bash-it-search() { + _about 'searches for given terms amongst bash-it plugins, aliases and completions' + _param '1: term1' + _param '2: [ term2 ]...' + _example '$ _bash-it-search ruby rvm rake bundler' + + declare -a _components=(aliases plugins completions) + + for _component in "${_components[@]}" ; do + _bash-it-search-component "${_component}" "$@" + done +} + +#——————————————————————————————————————————————————————————————————————————————— +# array=("something to search for" "a string" "test2000") +# _bash-it-array-contains-element "a string" "${array[@]}" +# ( prints "true" or "false" ) +_bash-it-array-contains-element () { + local e + local r=false + for e in "${@:2}"; do [[ "$e" == "$1" ]] && r=true; done + echo -n $r +} + +_bash-it-search-component() { + _about 'searches for given terms amongst a given component' + _param '1: component type, one of: [ aliases | plugins | completions ]' + _param '2: term1 ' + _param '3: [-]term2 [-]term3 ...' + _example '$ _bash-it-search-component aliases rake bundler -chruby' + + _component=$1 + + local func=_bash-it-${_component} + local help=$($func) + shift + + # if one of the search terms is --enable or --disable, we will apply + # this action to the matches further down. + local action action_func component_singular + declare -a _search_commands=(enable disable) + for _search_command in "${_search_commands[@]}"; do + if [[ $(_bash-it-array-contains-element "--${_search_command}" "$@") == "true" ]]; then + action=$_search_command + component_singular=${_component} + component_singular=${component_singular/es/} # aliases -> alias + component_singular=${component_singular/ns/n} # plugins -> plugin + action_func="_${action}-${component_singular}" + break + fi + done + + local _grep=$(which egrep || which grep) + + declare -a terms=($@) # passed on the command line + declare -a matches=() # results that we found + declare -a negative_terms=() # terms that began with a dash + + for term in "${terms[@]}"; do + # -- can only be used for the actions: enable/disable + [[ "${term:0:2}" == "--" ]] && continue + [[ "${term:0:1}" == "-" ]] && negative_terms=(${negative_terms[@]} ${term:1}) && continue + + # print asterisk next to each result that is already enabled by the user + local term_match=($(echo "${help}"| ${_grep} -i -- ${term} | egrep '\[( |x)\]' | cut -b -30 | sed 's/ *\[ \]//g;s/ *\[x\]/*/g;' )) + [[ "${#term_match[@]}" -gt 0 ]] && { + matches=(${matches[@]} ${term_match[@]}) # append to the list of results + } + done + + # now check if we found any negative terms, and subtract them + [[ ${#negative_terms} -gt 0 ]] && { + declare -a filtered_matches=() + for match in "${matches[@]}"; do + local negations=0 + for nt in "${negative_terms[@]}"; do + [[ "${match}" =~ "${nt}" ]] && negations=$(($negations+1)) + done + [[ $negations -eq 0 ]] && filtered_matches=(${filtered_matches[@]} ${match}) + done + matches=(${filtered_matches[@]}) + } + + _bash-it-search-result $action $action_func + + unset matches filtered_matches terms +} + +_bash-it-search-result() { + local action=$1; shift + local action_func=$1; shift + local color_component color_enable color_disable color_off + + [[ -z "$NO_COLOR" ]] && { + color_component='\e[1;34m' + color_enable='\e[1;32m' + color_disable='\e[0;0m' + color_off='\e[0;0m' + color_sep=':' + } + + [[ -n "$NO_COLOR" ]] && { + color_component='' + color_sep=' => ' + color_enable='✓' + color_disable='' + color_off='' + } + + if [[ "${#matches[*]}" -gt 0 ]] ; then + printf "${color_component}%13s${color_sep} ${color_off}" "${_component}" + + sorted_matches=($(echo "${matches[*]}" | tr ' ' '\n' | sort | uniq)) + + for match in "${sorted_matches[@]}"; do + local match_color compatible_action + if [[ $match =~ "*" ]]; then + match_color=$color_enable + compatible_action="disable" + else + match_color=$color_disable + compatible_action="enable" + fi + + match_value=${match/\*/} # remove asterisk + len=${#match_value} + if [[ -n $NO_COLOR ]]; then + local m="${match_color}${match_value}" + len=${#m} + fi + + printf " ${match_color}${match_value}" # print current state + + if [[ "${action}" == "${compatible_action}" ]]; then + # oh, i see – we need to either disable enabled, or enable disabled + # component. Let's start with the most important part: redrawing + # the search result backwards. Because style. + + printf "\033[${len}D" + for a in {0..30}; do + [[ $a -gt $len ]] && break + printf "%.*s" $a " " + sleep 0.07 # who knew you could sleep for fraction of the cost :) + done + printf "\033[${len}D" + result=$(${action_func} ${match_value}) + local temp="color_${compatible_action}" + match_color=${!temp} + printf "${match_color}${match_value}" + fi + + printf "${color_off}" + done + + printf "\n" + fi + +} diff --git a/plugins/available/alias-completion.plugin.bash b/plugins/available/alias-completion.plugin.bash new file mode 100644 index 00000000..75c8263f --- /dev/null +++ b/plugins/available/alias-completion.plugin.bash @@ -0,0 +1,82 @@ +cite about-plugin +about-plugin 'Automatic completion of aliases' + +# References: +# http://superuser.com/a/437508/119764 +# http://stackoverflow.com/a/1793178/1228454 + +# This needs to be a plugin so it gets executed after the completions and the aliases have been defined. +# Bash-it loads its components in the order +# 1) Aliases +# 2) Completions +# 3) Plugins +# 4) Custom scripts + +# Automatically add completion for all aliases to commands having completion functions +function alias_completion { + local namespace="alias_completion" + + # parse function based completion definitions, where capture group 2 => function and 3 => trigger + local compl_regex='complete( +[^ ]+)* -F ([^ ]+) ("[^"]+"|[^ ]+)' + # parse alias definitions, where capture group 1 => trigger, 2 => command, 3 => command arguments + local alias_regex="alias ([^=]+)='(\"[^\"]+\"|[^ ]+)(( +[^ ]+)*)'" + + # create array of function completion triggers, keeping multi-word triggers together + eval "local completions=($(complete -p | sed -Ene "/$compl_regex/s//'\3'/p"))" + (( ${#completions[@]} == 0 )) && return 0 + + # create temporary file for wrapper functions and completions + rm -f "/tmp/${namespace}-*.tmp" # preliminary cleanup + local tmp_file; tmp_file="$(mktemp "/tmp/${namespace}-${RANDOM}XXX.tmp")" || return 1 + + local completion_loader; completion_loader="$(complete -p -D 2>/dev/null | sed -Ene 's/.* -F ([^ ]*).*/\1/p')" + + # read in " '' ''" lines from defined aliases + local line; while read line; do + eval "local alias_tokens; alias_tokens=($line)" 2>/dev/null || continue # some alias arg patterns cause an eval parse error + local alias_name="${alias_tokens[0]}" alias_cmd="${alias_tokens[1]}" alias_args="${alias_tokens[2]# }" + + # skip aliases to pipes, boolean control structures and other command lists + # (leveraging that eval errs out if $alias_args contains unquoted shell metacharacters) + eval "local alias_arg_words; alias_arg_words=($alias_args)" 2>/dev/null || continue + # avoid expanding wildcards + read -a alias_arg_words <<< "$alias_args" + + # skip alias if there is no completion function triggered by the aliased command + if [[ ! " ${completions[*]} " =~ " $alias_cmd " ]]; then + if [[ -n "$completion_loader" ]]; then + # force loading of completions for the aliased command + eval "$completion_loader $alias_cmd" + # 124 means completion loader was successful + [[ $? -eq 124 ]] || continue + completions+=($alias_cmd) + else + continue + fi + fi + local new_completion="$(complete -p "$alias_cmd")" + + # create a wrapper inserting the alias arguments if any + if [[ -n $alias_args ]]; then + local compl_func="${new_completion/#* -F /}"; compl_func="${compl_func%% *}" + # avoid recursive call loops by ignoring our own functions + if [[ "${compl_func#_$namespace::}" == $compl_func ]]; then + local compl_wrapper="_${namespace}::${alias_name}" + echo "function $compl_wrapper { + (( COMP_CWORD += ${#alias_arg_words[@]} )) + COMP_WORDS=($alias_cmd $alias_args \${COMP_WORDS[@]:1}) + (( COMP_POINT -= \${#COMP_LINE} )) + COMP_LINE=\${COMP_LINE/$alias_name/$alias_cmd $alias_args} + (( COMP_POINT += \${#COMP_LINE} )) + $compl_func + }" >> "$tmp_file" + new_completion="${new_completion/ -F $compl_func / -F $compl_wrapper }" + fi + fi + + # replace completion trigger by alias + new_completion="${new_completion% *} $alias_name" + echo "$new_completion" >> "$tmp_file" + done < <(alias -p | sed -Ene "s/$alias_regex/\1 '\2' '\3'/p") + source "$tmp_file" && rm -f "$tmp_file" +}; alias_completion diff --git a/plugins/available/autojump.plugin.bash b/plugins/available/autojump.plugin.bash new file mode 100644 index 00000000..7ba98879 --- /dev/null +++ b/plugins/available/autojump.plugin.bash @@ -0,0 +1,8 @@ +cite about-plugin +about-plugin 'Autojump configuration, see https://github.com/wting/autojump for more details' + +# Only supports the Homebrew variant at the moment. +# Feel free to provide a PR to support other install locations +if command -v brew &>/dev/null && [[ -s $(brew --prefix)/etc/profile.d/autojump.sh ]]; then + . $(brew --prefix)/etc/profile.d/autojump.sh +fi diff --git a/plugins/available/base.plugin.bash b/plugins/available/base.plugin.bash index accd3610..c094ac5b 100644 --- a/plugins/available/base.plugin.bash +++ b/plugins/available/base.plugin.bash @@ -99,33 +99,6 @@ function lsgrep () ls | grep "$*" } -function 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 -} - -function 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 -} - -function 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 -} - function quiet () { about 'what *does* this do?' @@ -223,3 +196,11 @@ function buf () local filetime=$(date +%Y%m%d_%H%M%S) cp -a "${filename}" "${filename}_${filetime}" } + +function del() { + about 'move files to hidden folder in tmp, that gets cleared on each reboot' + param 'file or folder to be deleted' + example 'del ./file.txt' + group 'base' + mkdir -p /tmp/.trash && mv "$@" /tmp/.trash; +} diff --git a/plugins/available/battery.plugin.bash b/plugins/available/battery.plugin.bash index 75741c4a..80ff5bdb 100644 --- a/plugins/available/battery.plugin.bash +++ b/plugins/available/battery.plugin.bash @@ -2,15 +2,15 @@ cite about-plugin about-plugin 'display info about your battery charge level' ac_adapter_connected(){ - if command_exists acpi; - then - acpi -a | grep "on-line" - if [[ "$?" -eq 0 ]]; then - return 1 - else - return 0 - fi - fi + if command_exists acpi; + then + acpi -a | grep -q "on-line" + return $? + elif command_exists ioreg; + then + ioreg -n AppleSmartBattery -r | grep -q '"ExternalConnected" = Yes' + return $? + fi } battery_percentage(){ @@ -32,30 +32,13 @@ battery_percentage(){ ;; esac ;; - *" Discharging"*) - local PERC_OUTPUT=$(echo $ACPI_OUTPUT | head -c 26 | tail -c 2) - case $PERC_OUTPUT in - *%) - echo "0${PERC_OUTPUT}" | head -c 2 - ;; - *) - echo ${PERC_OUTPUT} - ;; - esac - ;; - *" Charging"*) - local PERC_OUTPUT=$(echo $ACPI_OUTPUT | head -c 23 | tail -c 2) - case $PERC_OUTPUT in - *%) - echo "0${PERC_OUTPUT}" | head -c 2 - ;; - *) - echo ${PERC_OUTPUT} - ;; - esac + + *" Charging"* | *" Discharging"*) + local PERC_OUTPUT=$(echo $ACPI_OUTPUT | awk -F, '/,/{gsub(/ /, "", $0); gsub(/%/,"", $0); print $2}' ) + echo ${PERC_OUTPUT} ;; *" Full"*) - echo '99' + echo '100' ;; *) echo '-1' @@ -69,7 +52,7 @@ battery_percentage(){ local IOREG_OUTPUT=$(ioreg -n AppleSmartBattery -r | awk '$1~/Capacity/{c[$1]=$3} END{OFMT="%05.2f%%"; max=c["\"MaxCapacity\""]; print (max>0? 100*c["\"CurrentCapacity\""]/max: "?")}') case $IOREG_OUTPUT in 100*) - echo '99' + echo '100' ;; *) echo $IOREG_OUTPUT | head -c 2 diff --git a/plugins/available/boot2docker.bash b/plugins/available/boot2docker.plugin.bash similarity index 100% rename from plugins/available/boot2docker.bash rename to plugins/available/boot2docker.plugin.bash diff --git a/plugins/available/docker-machine.bash b/plugins/available/docker-machine.bash deleted file mode 100644 index 18bf8ace..00000000 --- a/plugins/available/docker-machine.bash +++ /dev/null @@ -1,11 +0,0 @@ -cite about-plugin -about-plugin 'Helpers to get Docker setup correctly for docker-machine' - -# Note, this might need to be different if you use a machine other than 'dev', -# or its configured for a different IP -if [[ `uname -s` == "Darwin" ]]; then - export DOCKER_HOST="tcp://192.168.99.100:2376" - export DOCKER_CERT_PATH="~/.docker/machine/machines/dev" - export DOCKER_TLS_VERIFY=1 - export DOCKER_MACHINE_NAME="dev" -fi diff --git a/plugins/available/docker-machine.plugin.bash b/plugins/available/docker-machine.plugin.bash new file mode 100644 index 00000000..95827f42 --- /dev/null +++ b/plugins/available/docker-machine.plugin.bash @@ -0,0 +1,13 @@ +cite about-plugin +about-plugin 'Helpers to get Docker setup correctly for docker-machine' + +[ -z ${BASH_IT_DOCKER_MACHINE+x} ] && BASH_IT_DOCKER_MACHINE='dev' + +# Note, this might need to be different if you use a machine other than 'dev' +if [[ `uname -s` == "Darwin" ]]; then + # check if dev machine is running + docker-machine ls | grep --quiet "$BASH_IT_DOCKER_MACHINE.*Running" + if [[ "$?" = "0" ]]; then + eval "$(docker-machine env $BASH_IT_DOCKER_MACHINE)" + fi +fi diff --git a/plugins/available/explain.plugin.bash b/plugins/available/explain.plugin.bash new file mode 100644 index 00000000..d57b78e2 --- /dev/null +++ b/plugins/available/explain.plugin.bash @@ -0,0 +1,24 @@ +cite about-plugin +about-plugin 'mankier.com explain function to explain other commands' + +explain () { + about 'explain any bash command via mankier.com manpage API' + param '1: Name of the command to explain' + example '$ explain # interactive mode. Type commands to explain in REPL' + example '$ explain 'cmd -o | ...' # one quoted command to explain it.' + group 'explain' + + if [ "$#" -eq 0 ]; then + while read -p "Command: " cmd; do + curl -Gs "https://www.mankier.com/api/explain/?cols="$(tput cols) --data-urlencode "q=$cmd" + done + echo "Bye!" + elif [ "$#" -eq 1 ]; then + curl -Gs "https://www.mankier.com/api/explain/?cols="$(tput cols) --data-urlencode "q=$1" + else + echo "Usage" + echo "explain interactive mode." + echo "explain 'cmd -o | ...' one quoted command to explain it." + fi +} + diff --git a/plugins/available/extract.plugin.bash b/plugins/available/extract.plugin.bash index bb520451..e357814a 100644 --- a/plugins/available/extract.plugin.bash +++ b/plugins/available/extract.plugin.bash @@ -1,27 +1,59 @@ cite about-plugin about-plugin 'one command to extract them all...' -extract () { - if [ $# -ne 1 ] - then - echo "Error: No file specified." - return 1 - fi - if [ -f $1 ] ; then - case $1 in - *.tar.bz2) tar xvjf $1 ;; - *.tar.gz) tar xvzf $1 ;; - *.bz2) bunzip2 $1 ;; - *.rar) unrar x $1 ;; - *.gz) gunzip $1 ;; - *.tar) tar xvf $1 ;; - *.tbz2) tar xvjf $1 ;; - *.tgz) tar xvzf $1 ;; - *.zip) unzip $1 ;; - *.Z) uncompress $1 ;; - *.7z) 7z x $1 ;; - *) echo "'$1' cannot be extracted via extract" ;; - esac - else - echo "'$1' is not a valid file" - fi + +# extract file(s) from compressed status +extract() { + local opt + local OPTIND=1 + while getopts "hv" opt; do + case "$opt" in + h) + cat < + options: + -h show this message and exit + -v verbosely list files processed +End-Of-Usage + return + ;; + v) + local -r verbose='v' + ;; + ?) + extract -h >&2 + return 1 + ;; + esac + done + shift $((OPTIND-1)) + + [ $# -eq 0 ] && extract -h && return 1 + while [ $# -gt 0 ]; do + if [ -f "$1" ]; then + case "$1" in + *.tar.bz2|*.tbz|*.tbz2) tar "x${verbose}jf" "$1" ;; + *.tar.gz|*.tgz) tar "x${verbose}zf" "$1" ;; + *.tar.xz) xz --decompress "$1"; set -- "$@" "${1:0:-3}" ;; + *.tar.Z) uncompress "$1"; set -- "$@" "${1:0:-2}" ;; + *.bz2) bunzip2 "$1" ;; + *.deb) dpkg-deb -x${verbose} "$1" "${1:0:-4}" ;; + *.pax.gz) gunzip "$1"; set -- "$@" "${1:0:-3}" ;; + *.gz) gunzip "$1" ;; + *.pax) pax -r -f "$1" ;; + *.pkg) pkgutil --expand "$1" "${1:0:-4}" ;; + *.rar) unrar x "$1" ;; + *.rpm) rpm2cpio "$1" | cpio -idm${verbose} ;; + *.tar) tar "x${verbose}f" "$1" ;; + *.txz) mv "$1" "${1:0:-4}.tar.xz"; set -- "$@" "${1:0:-4}.tar.xz" ;; + *.xz) xz --decompress "$1" ;; + *.zip|*.war|*.jar) unzip "$1" ;; + *.Z) uncompress "$1" ;; + *.7z) 7za x "$1" ;; + *) echo "'$1' cannot be extracted via extract" >&2;; + esac + else + echo "extract: '$1' is not a valid file" >&2 + fi + shift + done } diff --git a/plugins/available/fasd.plugin.bash b/plugins/available/fasd.plugin.bash index ee810e22..5db2b359 100755 --- a/plugins/available/fasd.plugin.bash +++ b/plugins/available/fasd.plugin.bash @@ -1,598 +1,33 @@ -#!/usr/bin/env sh +cite about-plugin +about-plugin 'initialize fasd (see https://github.com/clvv/fasd)' -# Fasd (this file) can be sourced or executed by any POSIX compatible shell. +__init_fasd() { + which fasd &> /dev/null + if [ $? -eq 1 ]; then + echo -e "You must install fasd before you can use this plugin" + echo -e "See: https://github.com/clvv/fasd" + else + eval "$(fasd --init posix-alias)" -# 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. + # Note, this is a custom bash-hook to ensure that the last exit status + # is maintained even while this hook is in place. This code can be + # removed once PR #72 is merged into fasd. + # + # See: https://github.com/clvv/fasd/pull/72 + _fasd_prompt_func() { + local _exit_code="$?" + eval "fasd --proc $(fasd --sanitize $(history 1 | \ + sed "s/^[ ]*[0-9]*[ ]*//"))" >> "/dev/null" 2>&1 + return $_exit_code + } -# 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 <> "$_FASD_SINK" 2>&1 - -EOS - ;; - - posix-alias) cat <> "$_FASD_SINK" 2>&1 -} -autoload -U add-zsh-hook -add-zsh-hook preexec _fasd_preexec - -EOS - ;; - - bash-hook) cat <> "$_FASD_SINK" 2>&1 -} -echo "\$PS1" | grep -v -q "_fasd_ps1_func" && \ -export PS1="\\\$(_fasd_ps1_func)\$PS1" - -EOS - ;; - - zsh-ccomp) cat <> "$_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 <> "$_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 <> "$_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 set command to execute on the result file - -b only use backend - -b add additional backend - -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 - +__init_fasd diff --git a/plugins/available/gh.plugin.bash b/plugins/available/gh.plugin.bash index 64b16567..fb429317 100644 --- a/plugins/available/gh.plugin.bash +++ b/plugins/available/gh.plugin.bash @@ -1,4 +1,4 @@ cite about-plugin -about-plugin 'load gh, if you are using it.' +about-plugin 'load gh, if you are using it (DEPRECATED, use hub instead)' -command -v gh >/dev/null 2>&1 && eval "$(gh alias -s)" +command -v gh 2> /dev/null && eval "$(gh alias -s)" diff --git a/plugins/available/git.plugin.bash b/plugins/available/git.plugin.bash index 6506ca45..d5aa6d8f 100644 --- a/plugins/available/git.plugin.bash +++ b/plugins/available/git.plugin.bash @@ -198,3 +198,80 @@ else fi } +function gittowork() { + about 'Places the latest .gitignore file for a given project type in the current directory, or concatenates onto an existing .gitignore' + group 'git' + param '1: the language/type of the project, used for determining the contents of the .gitignore file' + example '$ gittowork java' + + result=$(curl -L "https://www.gitignore.io/api/$1" 2>/dev/null) + + if [[ $result =~ ERROR ]]; then + echo "Query '$1' has no match. See a list of possible queries with 'gittowork list'" + elif [[ $1 = list ]]; then + echo "$result" + else + if [[ -f .gitignore ]]; then + result=`echo "$result" | grep -v "# Created by http://www.gitignore.io"` + echo ".gitignore already exists, appending..." + echo "$result" >> .gitignore + else + echo "$result" > .gitignore + fi + fi +} + +function gitignore-reload() { + about 'Empties the git cache, and readds all files not blacklisted by .gitignore' + group 'git' + example '$ gitignore-reload' + + # The .gitignore file should not be reloaded if there are uncommited changes. + # Firstly, require a clean work tree. The function require_clean_work_tree() + # was stolen with love from https://www.spinics.net/lists/git/msg142043.html + + # Begin require_clean_work_tree() + + # Update the index + git update-index -q --ignore-submodules --refresh + err=0 + + # Disallow unstaged changes in the working tree + if ! git diff-files --quiet --ignore-submodules -- + then + echo >&2 "ERROR: Cannot reload .gitignore: Your index contains unstaged changes." + git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2 + err=1 + fi + + # Disallow uncommited changes in the index + if ! git diff-index --cached --quiet HEAD --ignore-submodules + then + echo >&2 "ERROR: Cannot reload .gitignore: Your index contains uncommited changes." + git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2 + err=1 + fi + + # Prompt user to commit or stash changes and exit + if [ $err = 1 ] + then + echo >&2 "Please commit or stash them." + fi + + # End require_clean_work_tree() + + # If we're here, then there are no uncommited or unstaged changes dangling around. + # Proceed to reload .gitignore + if [ $err = 0 ]; then + # Remove all cached files + git rm -r --cached . + + # Re-add everything. The changed .gitignore will be picked up here and will exclude the files + # now blacklisted by .gitignore + echo >&2 "Running git add ." + git add . + echo >&2 "Files readded. Commit your new changes now." + fi +} + + diff --git a/plugins/available/history.plugin.bash b/plugins/available/history.plugin.bash index 386e05d1..efd33981 100644 --- a/plugins/available/history.plugin.bash +++ b/plugins/available/history.plugin.bash @@ -1,6 +1,8 @@ +cite about-plugin +about-plugin 'history manipulation' # enter a few characters and press UpArrow/DownArrow # to search backwards/forwards through the history -if [ -t 1 ]; +if [ -t 1 ] then bind '"":history-search-backward' bind '"":history-search-forward' diff --git a/plugins/available/hub.plugin.bash b/plugins/available/hub.plugin.bash new file mode 100644 index 00000000..0a67a7af --- /dev/null +++ b/plugins/available/hub.plugin.bash @@ -0,0 +1,4 @@ +cite about-plugin +about-plugin 'load hub, if you are using it' + +command -v hub &> /dev/null && eval "$(hub alias -s)" diff --git a/plugins/available/jenv.plugin.bash b/plugins/available/jenv.plugin.bash new file mode 100644 index 00000000..3cb2bcfc --- /dev/null +++ b/plugins/available/jenv.plugin.bash @@ -0,0 +1,9 @@ +cite about-plugin +about-plugin 'load jenv, if you are using it' + +export JENV_ROOT="$HOME/.jenv" +pathmunge "$JENV_ROOT/bin" + +if which jenv > /dev/null; then eval "$(jenv init -)"; fi + +[[ -e $JENV_ROOT/completions/jenv.bash ]] && source $JENV_ROOT/completions/jenv.bash diff --git a/plugins/available/less-pretty-cat.plugin.bash b/plugins/available/less-pretty-cat.plugin.bash index b6d31b86..9221dde6 100644 --- a/plugins/available/less-pretty-cat.plugin.bash +++ b/plugins/available/less-pretty-cat.plugin.bash @@ -23,6 +23,6 @@ if $(command -v pygmentize &> /dev/null) ; then about 'it pigments the file passed in and passes it to less for pagination' param '$1: the file to paginate with less' example 'less mysite/manage.py' - pygmentize "$*" | "$LESS_BIN" -R + pygmentize -g $* | "$LESS_BIN" -R } fi diff --git a/plugins/available/nvm.plugin.bash b/plugins/available/nvm.plugin.bash index 632de967..3959c236 100644 --- a/plugins/available/nvm.plugin.bash +++ b/plugins/available/nvm.plugin.bash @@ -1,318 +1,28 @@ -# Node Version Manager -# Implemented as a bash function -# To use source this file from your bash profile +# Bash-it no longer bundles nvm, as this was quickly becoming outdated. # -# Implemented by Tim Caswell -# with much bash help from Matthew Ranney +# Please install nvm from https://github.com/creationix/nvm.git if you want to use it. cite about-plugin -about-plugin 'node version manager, as a bash function' +about-plugin 'node version manager configuration' export NVM_DIR="$HOME/.nvm" - -if [ ! -d "$NVM_DIR" ]; then - mkdir $NVM_DIR +# This loads nvm +if command -v brew &>/dev/null && [ -s $(brew --prefix nvm)/nvm.sh ] +then + . $(brew --prefix nvm)/nvm.sh +else + [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" fi -# Auto detect the NVM_DIR -if [ ! -d "$NVM_DIR" ]; then - export NVM_DIR=$(cd $(dirname ${BASH_SOURCE[0]:-$0}); pwd) +if ! command -v nvm &>/dev/null +then + function nvm() { + echo "Bash-it no longer bundles the nvm script. Please install the latest version from" + echo "" + echo "https://github.com/creationix/nvm.git" + echo "" + echo "if you want to use nvm. You can keep this plugin enabled once you have installed nvm." + } + + nvm fi - -# Expand a version using the version cache -nvm_version() -{ - PATTERN=$1 - # The default version is the current one - if [ ! "$PATTERN" ]; then - PATTERN='current' - fi - - VERSION=`nvm_ls $PATTERN | tail -n1` - echo "$VERSION" - - if [ "$VERSION" = 'N/A' ]; then - return 13 - fi -} - -nvm_ls() -{ - PATTERN=$1 - VERSIONS='' - if [ "$PATTERN" = 'current' ]; then - echo `node -v 2>/dev/null` - return - fi - - if [ -f "$NVM_DIR/alias/$PATTERN" ]; then - nvm_version `cat $NVM_DIR/alias/$PATTERN` - return - fi - # If it looks like an explicit version, don't do anything funny - if [[ "$PATTERN" == v?*.?*.?* ]]; then - VERSIONS="$PATTERN" - else - VERSIONS=`(cd $NVM_DIR; \ls -d v${PATTERN}* 2>/dev/null) | sort -t. -k 1.2,1n -k 2,2n -k 3,3n` - fi - if [ ! "$VERSIONS" ]; then - echo "N/A" - return - fi - echo "$VERSIONS" - return -} - -print_versions() -{ - OUTPUT='' - for VERSION in $1; do - PADDED_VERSION=`printf '%10s' $VERSION` - if [[ -d "$NVM_DIR/$VERSION" ]]; then - PADDED_VERSION="\033[0;34m$PADDED_VERSION\033[0m" - fi - OUTPUT="$OUTPUT\n$PADDED_VERSION" - done - echo -e "$OUTPUT" | column -} - -nvm() -{ - about 'Node Version Manager' - param '1: command, see nvm help' - group 'nvm' - - if [ $# -lt 1 ]; then - nvm help - return - fi - case $1 in - "help" ) - echo - echo "Node Version Manager" - echo - echo "Usage:" - echo " nvm help Show this message" - echo " nvm install Download and install a " - echo " nvm uninstall Uninstall a version" - echo " nvm use Modify PATH to use " - echo " nvm run [] Run with as arguments" - echo " nvm ls List installed versions" - echo " nvm ls List versions matching a given description" - echo " nvm deactivate Undo effects of NVM on current shell" - echo " nvm alias [] Show all aliases beginning with " - echo " nvm alias Set an alias named pointing to " - echo " nvm unalias Deletes the alias named " - echo " nvm copy-packages Install global NPM packages contained in to current version" - echo - echo "Example:" - echo " nvm install v0.4.12 Install a specific version number" - echo " nvm use 0.2 Use the latest available 0.2.x release" - echo " nvm run 0.4.12 myApp.js Run myApp.js using node v0.4.12" - echo " nvm alias default 0.4 Auto use the latest installed v0.4.x version" - echo - ;; - "install" ) - if [ ! `which curl` ]; then - echo 'NVM Needs curl to proceed.' >&2; - fi - - if [ $# -ne 2 ]; then - nvm help - return - fi - VERSION=`nvm_version $2` - - [ -d "$NVM_DIR/$VERSION" ] && echo "$VERSION is already installed." && return - - tarball='' - if [ "`curl -Is "http://nodejs.org/dist/$VERSION/node-$VERSION.tar.gz" | grep '200 OK'`" != '' ]; then - tarball="http://nodejs.org/dist/$VERSION/node-$VERSION.tar.gz" - elif [ "`curl -Is "http://nodejs.org/dist/node-$VERSION.tar.gz" | grep '200 OK'`" != '' ]; then - tarball="http://nodejs.org/dist/node-$VERSION.tar.gz" - fi - if ( - [ ! -z $tarball ] && \ - mkdir -p "$NVM_DIR/src" && \ - cd "$NVM_DIR/src" && \ - curl -C - --progress-bar $tarball -o "node-$VERSION.tar.gz" && \ - tar -xzf "node-$VERSION.tar.gz" && \ - cd "node-$VERSION" && \ - ./configure --prefix="$NVM_DIR/$VERSION" && \ - make && \ - rm -f "$NVM_DIR/$VERSION" 2>/dev/null && \ - make install - ) - then - nvm use $VERSION - if ! which npm ; then - echo "Installing npm..." - if [[ "`expr match $VERSION '\(^v0\.1\.\)'`" != '' ]]; then - echo "npm requires node v0.2.3 or higher" - elif [[ "`expr match $VERSION '\(^v0\.2\.\)'`" != '' ]]; then - if [[ "`expr match $VERSION '\(^v0\.2\.[0-2]$\)'`" != '' ]]; then - echo "npm requires node v0.2.3 or higher" - else - curl http://npmjs.org/install.sh | clean=yes npm_install=0.2.19 sh - fi - else - curl http://npmjs.org/install.sh | clean=yes sh - fi - fi - else - echo "nvm: install $VERSION failed!" - fi - ;; - "uninstall" ) - [ $# -ne 2 ] && nvm help && return - if [[ $2 == `nvm_version` ]]; then - echo "nvm: Cannot uninstall currently-active node version, $2." - return - fi - VERSION=`nvm_version $2` - if [ ! -d $NVM_DIR/$VERSION ]; then - echo "$VERSION version is not installed yet" - return; - fi - - # Delete all files related to target version. - (mkdir -p "$NVM_DIR/src" && \ - cd "$NVM_DIR/src" && \ - rm -rf "node-$VERSION" 2>/dev/null && \ - rm -f "node-$VERSION.tar.gz" 2>/dev/null && \ - rm -rf "$NVM_DIR/$VERSION" 2>/dev/null) - echo "Uninstalled node $VERSION" - - # Rm any aliases that point to uninstalled version. - for A in `grep -l $VERSION $NVM_DIR/alias/*` - do - nvm unalias `basename $A` - done - - ;; - "deactivate" ) - if [[ $PATH == *$NVM_DIR/*/bin* ]]; then - export PATH=${PATH%$NVM_DIR/*/bin*}${PATH#*$NVM_DIR/*/bin:} - hash -r - echo "$NVM_DIR/*/bin removed from \$PATH" - else - echo "Could not find $NVM_DIR/*/bin in \$PATH" - fi - if [[ $MANPATH == *$NVM_DIR/*/share/man* ]]; then - export MANPATH=${MANPATH%$NVM_DIR/*/share/man*}${MANPATH#*$NVM_DIR/*/share/man:} - echo "$NVM_DIR/*/share/man removed from \$MANPATH" - else - echo "Could not find $NVM_DIR/*/share/man in \$MANPATH" - fi - ;; - "use" ) - if [ $# -ne 2 ]; then - nvm help - return - fi - VERSION=`nvm_version $2` - if [ ! -d $NVM_DIR/$VERSION ]; then - echo "$VERSION version is not installed yet" - return; - fi - if [[ $PATH == *$NVM_DIR/*/bin* ]]; then - PATH=${PATH%$NVM_DIR/*/bin*}$NVM_DIR/$VERSION/bin${PATH#*$NVM_DIR/*/bin} - else - PATH="$NVM_DIR/$VERSION/bin:$PATH" - fi - if [[ $MANPATH == *$NVM_DIR/*/share/man* ]]; then - MANPATH=${MANPATH%$NVM_DIR/*/share/man*}$NVM_DIR/$VERSION/share/man${MANPATH#*$NVM_DIR/*/share/man} - else - MANPATH="$NVM_DIR/$VERSION/share/man:$MANPATH" - fi - export PATH - hash -r - export MANPATH - export NVM_PATH="$NVM_DIR/$VERSION/lib/node" - export NVM_BIN="$NVM_DIR/$VERSION/bin" - echo "Now using node $VERSION" - ;; - "run" ) - # run given version of node - if [ $# -lt 2 ]; then - nvm help - return - fi - VERSION=`nvm_version $2` - if [ ! -d $NVM_DIR/$VERSION ]; then - echo "$VERSION version is not installed yet" - return; - fi - echo "Running node $VERSION" - $NVM_DIR/$VERSION/bin/node "${@:3}" - ;; - "ls" | "list" ) - print_versions "`nvm_ls $2`" - if [ $# -eq 1 ]; then - echo -ne "current: \t"; nvm_version current - nvm alias - fi - return - ;; - "alias" ) - mkdir -p $NVM_DIR/alias - if [ $# -le 2 ]; then - (cd $NVM_DIR/alias && for ALIAS in `\ls $2* 2>/dev/null`; do - DEST=`cat $ALIAS` - VERSION=`nvm_version $DEST` - if [ "$DEST" = "$VERSION" ]; then - echo "$ALIAS -> $DEST" - else - echo "$ALIAS -> $DEST (-> $VERSION)" - fi - done) - return - fi - if [ ! "$3" ]; then - rm -f $NVM_DIR/alias/$2 - echo "$2 -> *poof*" - return - fi - mkdir -p $NVM_DIR/alias - VERSION=`nvm_version $3` - if [ $? -ne 0 ]; then - echo "! WARNING: Version '$3' does not exist." >&2 - fi - echo $3 > "$NVM_DIR/alias/$2" - if [ ! "$3" = "$VERSION" ]; then - echo "$2 -> $3 (-> $VERSION)" - else - echo "$2 -> $3" - fi - ;; - "unalias" ) - mkdir -p $NVM_DIR/alias - [ $# -ne 2 ] && nvm help && return - [ ! -f $NVM_DIR/alias/$2 ] && echo "Alias $2 doesn't exist!" && return - rm -f $NVM_DIR/alias/$2 - echo "Deleted alias $2" - ;; - "copy-packages" ) - if [ $# -ne 2 ]; then - nvm help - return - fi - VERSION=`nvm_version $2` - ROOT=`nvm use $VERSION && npm -g root` - INSTALLS=`nvm use $VERSION > /dev/null && npm -g -p ll | grep "$ROOT\/[^/]\+$" | cut -d '/' -f 8 | cut -d ":" -f 2 | grep -v npm | tr "\n" " "` - npm install -g $INSTALLS - ;; - "clear-cache" ) - rm -f $NVM_DIR/v* 2>/dev/null - echo "Cache cleared." - ;; - "version" ) - print_versions "`nvm_version $2`" - ;; - * ) - nvm help - ;; - esac -} - -nvm ls default >/dev/null 2>&1 && nvm use default >/dev/null diff --git a/plugins/available/osx-timemachine.plugin.bash b/plugins/available/osx-timemachine.plugin.bash new file mode 100644 index 00000000..f29d6ece --- /dev/null +++ b/plugins/available/osx-timemachine.plugin.bash @@ -0,0 +1,84 @@ +cite about-plugin +about-plugin 'OS X Time Machine functions' + +function time-machine-destination() { + group "osx-timemachine" + about "Shows the OS X Time Machine destination/mount point" + + echo $(tmutil destinationinfo | grep "Mount Point" | sed -e 's/Mount Point : \(.*\)/\1/g') +} + +function time-machine-list-machines() { + group "osx-timemachine" + about "Lists the OS X Time Machine machines on the backup volume" + + local tmdest="$(time-machine-destination)/Backups.backupdb" + + find "$tmdest" -maxdepth 1 -mindepth 1 -type d | grep -v "/\." | while read line ; do + echo "$(basename "$line")" + done +} + +function time-machine-list-all-backups() { + group "osx-timemachine" + about "Shows all of the backups for the specified machine" + param "1: Machine name (optional)" + example "time-machine-list-all-backups my-laptop" + + # Use the local hostname if none provided + local COMPUTERNAME=${1:-$(scutil --get ComputerName)} + local BACKUP_LOCATION="$(time-machine-destination)/Backups.backupdb/$COMPUTERNAME" + + find "$BACKUP_LOCATION" -maxdepth 1 -mindepth 1 -type d | while read line ; do + echo "$line" + done +} + +function time-machine-list-old-backups() { + group "osx-timemachine" + about "Shows all of the backups for the specified machine, except for the most recent backup" + param "1: Machine name (optional)" + example "time-machine-list-old-backups my-laptop" + + # Use the local hostname if none provided + local COMPUTERNAME=${1:-$(scutil --get ComputerName)} + local BACKUP_LOCATION="$(time-machine-destination)/Backups.backupdb/$COMPUTERNAME" + + # List all but the most recent one + find "$BACKUP_LOCATION" -maxdepth 1 -mindepth 1 -type d -name 2\* | sed \$d | while read line ; do + echo "$line" + done +} + +# Taken from here: http://stackoverflow.com/a/30547074/1228454 +function _tm_startsudo() { + sudo -v + ( while true; do sudo -v; sleep 50; done; ) & + SUDO_PID="$!" + trap _tm_stopsudo SIGINT SIGTERM +} +function _tm_stopsudo() { + kill "$SUDO_PID" + trap - SIGINT SIGTERM + sudo -k +} + +function time-machine-delete-old-backups() { + group "osx-timemachine" + about "Deletes all of the backups for the specified machine, with the exception of the most recent one" + param "1: Machine name (optional)" + example "time-machine-delete-old-backups my-laptop" + + # Use the local hostname if none provided + local COMPUTERNAME=${1:-$(scutil --get ComputerName)} + + # Ask for sudo credentials only once + _tm_startsudo + + echo "$(time-machine-list-old-backups "$COMPUTERNAME")" | while read i ; do + # Delete the backup + sudo tmutil delete "$i" + done + + _tm_stopsudo +} diff --git a/plugins/available/osx.plugin.bash b/plugins/available/osx.plugin.bash index 8628ca3c..c1d2b18b 100644 --- a/plugins/available/osx.plugin.bash +++ b/plugins/available/osx.plugin.bash @@ -5,7 +5,7 @@ about-plugin 'osx-specific functions' if [ $(uname) = "Darwin" ]; then if type update_terminal_cwd > /dev/null 2>&1 ; then if ! [[ $PROMPT_COMMAND =~ (^|;)update_terminal_cwd($|;) ]] ; then - export PROMPT_COMMAND="update_terminal_cwd;$PROMPT_COMMAND" + export PROMPT_COMMAND="$PROMPT_COMMAND;update_terminal_cwd" fi fi fi @@ -63,8 +63,25 @@ function dock-switch() { fi } -# Download a file and open it in Preview +function pman () +{ + about 'view man documentation in Preview' + param '1: man page to view' + example '$ pman bash' + group 'osx' + man -t "${1}" | open -fa $PREVIEW +} +function pri () +{ + about 'display information about Ruby classes, modules, or methods, in Preview' + param '1: Ruby method, module, or class' + example '$ pri Array' + group 'osx' + ri -T "${1}" | open -fa $PREVIEW +} + +# Download a file and open it in Preview function prevcurl() { about 'download a file and open it in Preview' param '1: url' @@ -75,5 +92,8 @@ function prevcurl() { echo "This function only works with Mac OS X" return 1 fi - curl "$*" | open -fa "Preview" + curl "$*" | open -fa $PREVIEW } + +# Make this backwards compatible +alias pcurl='prevcurl' diff --git a/plugins/available/percol.plugin.bash b/plugins/available/percol.plugin.bash new file mode 100644 index 00000000..067c6c8f --- /dev/null +++ b/plugins/available/percol.plugin.bash @@ -0,0 +1,44 @@ +cite about-plugin +about-plugin 'Search&Select history and fasd with percol' + +# Notice +## You have to upgrade bash to bash 4.x on Mac OS X. +## http://stackoverflow.com/questions/16416195/how-do-i-upgrade-bash-in-mac-osx-mountain-lion-and-set-it-the-correct-path + +# Install +## (sudo) pip install percol +## bash-it enable percol +## optional: bash-it enable fasd + +# Usage +## C-r to search&select from history +## zz to search&select from fasd + +_replace_by_history() { + if command -v tac>/dev/null; then + alias _tac=tac + else + alias _tac="tail -r" + fi + local l=$(HISTTIMEFORMAT= history | _tac | sed -e 's/^\ *[0-9]*\ *//' | percol --query "$READLINE_LINE") + READLINE_LINE="$l" + READLINE_POINT=${#l} +} + + +if command -v percol>/dev/null; then + local current_version=${BASH_VERSION%%[^0-9]*} + if [ $current_version -lt 4 ]; then + echo "Warning:You have to upgrade bash to bash 4.x to use percol plugin." + else + bind -x '"\C-r": _replace_by_history' + + # bind zz to percol if fasd enable + if command -v fasd>/dev/null; then + zz(){ + local l=$(fasd -d | awk '{print $2}' | percol) + cd $l + } + fi + fi +fi diff --git a/plugins/available/plenv.plugin.bash b/plugins/available/plenv.plugin.bash new file mode 100644 index 00000000..1e527b72 --- /dev/null +++ b/plugins/available/plenv.plugin.bash @@ -0,0 +1,21 @@ +# plugin for plenv + +cite about-plugin +about-plugin 'plenv plugin for Perl' + +if [[ -e "${HOME}/.plenv/bin" ]] ; then + + # load plenv bin dir into path if it exists + pathmunge "${HOME}/.plenv/bin" + +fi + +if [[ `which plenv` ]] ; then + + # init plenv + eval "$(plenv init -)" + + # Load the auto-completion script if it exists. + [[ -e "${HOME}/.plenv/completions/plenv.bash" ]] && source "${HOME}/.plenv/completions/plenv.bash" + +fi diff --git a/plugins/available/projects.plugin.bash b/plugins/available/projects.plugin.bash new file mode 100644 index 00000000..e4dc39e2 --- /dev/null +++ b/plugins/available/projects.plugin.bash @@ -0,0 +1,75 @@ +cite about-plugin +about-plugin 'add "export PROJECT_PATHS=~/projects:~/intertrode/projects" to navigate quickly to your project directories with `pj` and `pjo`' + +function pj { +about 'navigate quickly to your various project directories' +group 'projects' + + +if [ -z "$PROJECT_PATHS" ]; then + echo "error: PROJECT_PATHS not set" + return 1 +fi + + +local cmd +local dest +local -a dests + + +if [ "$1" == "open" ]; then + shift + cmd="$EDITOR" +fi +cmd="${cmd:-cd}" + + +if [ -z "$1" ]; then + echo "error: no project provided" + return 1 +fi + + +# collect possible destinations to account for directories +# with the same name in project directories +for i in ${PROJECT_PATHS//:/$'\n'}; do + if [ -d "$i"/"$1" ]; then + dests+=("$i/$1") + fi +done + + +# when multiple destinations are found, present a menu +if [ ${#dests[@]} -eq 0 ]; then + echo "error: no such project '$1'" + return 1 + +elif [ ${#dests[@]} -eq 1 ]; then + dest="${dests[0]}" + +elif [ ${#dests[@]} -gt 1 ]; then + PS3="Multiple project directories found. Please select one: " + dests+=("cancel") + select d in "${dests[@]}"; do + case $d in + "cancel") + return + ;; + *) + dest=$d + break + ;; + esac + done + +else + echo "error: please report this error" + return 1 # should never reach this + +fi + + +$cmd "$dest" +} + +alias pjo="pj open" diff --git a/plugins/available/rails.plugin.bash b/plugins/available/rails.plugin.bash new file mode 100644 index 00000000..414fd9f9 --- /dev/null +++ b/plugins/available/rails.plugin.bash @@ -0,0 +1,18 @@ +cite about-plugin +about-plugin 'Helper functions for Ruby on Rails' + +# Quick function to kill a daemonized Rails server +function killrails() { + about 'Searches for a daemonized Rails server in tmp/pids and attempts to kill it.' + group 'rails' + + railsPid="$(cat tmp/pids/server.pid)" + if [ ! -z "$railsPid" ]; then + echo "[OK] Rails Server Process Id : ${railsPid}" + kill -9 $railsPid + echo "[OK] Process Killed" + else + echo "[FAIL] Error killing Rails server" + return 1 + fi +} diff --git a/plugins/available/sdkman.plugin.bash b/plugins/available/sdkman.plugin.bash new file mode 100644 index 00000000..0f3722b6 --- /dev/null +++ b/plugins/available/sdkman.plugin.bash @@ -0,0 +1,5 @@ +cite about-plugin +about-plugin 'Load Software Development Kit Manager' + +export SDKMAN_DIR="$HOME/.sdkman" +[[ -s "${SDKMAN_DIR}/bin/sdkman-init.sh" ]] && source "${SDKMAN_DIR}/bin/sdkman-init.sh" diff --git a/plugins/available/ssh.plugin.bash b/plugins/available/ssh.plugin.bash index 4e17206c..f670b98c 100644 --- a/plugins/available/ssh.plugin.bash +++ b/plugins/available/ssh.plugin.bash @@ -15,5 +15,5 @@ function sshlist() { about 'list hosts defined in ssh config' group 'ssh' - awk '$1 ~ /Host$/ { print $2 }' ~/.ssh/config + awk '$1 ~ /Host$/ {for (i=2; i<=NF; i++) print $i}' ~/.ssh/config } diff --git a/plugins/available/todo.plugin.bash b/plugins/available/todo.plugin.bash index ef9266e2..cf1479e2 100755 --- a/plugins/available/todo.plugin.bash +++ b/plugins/available/todo.plugin.bash @@ -1,21 +1,12 @@ #!/bin/bash +cite about-plugin +about-plugin 'Todo.txt integration' # 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 + # typing 't' by itself will list current todos + export TODOTXT_DEFAULT_ACTION=ls fi -# respect ENV var set in .bash_profile, default is 't' -alias $TODO='$TODO_SRC_DIR/todo.sh -d $TODO_SRC_DIR/todo.cfg' - -pathmunge $TODO_SRC_DIR after - -source $TODO_SRC_DIR/todo_completion # bash completion for todo.sh -complete -F _todo $TODO # enable completion for 't' alias +alias t='todo.sh' diff --git a/plugins/available/todo/todo.cfg b/plugins/available/todo/todo.cfg deleted file mode 100644 index d79bf77a..00000000 --- a/plugins/available/todo/todo.cfg +++ /dev/null @@ -1,75 +0,0 @@ -# === 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 deleted file mode 100755 index c2e149f0..00000000 --- a/plugins/available/todo/todo.sh +++ /dev/null @@ -1,1321 +0,0 @@ -#! /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 deleted file mode 100644 index 3f9d308a..00000000 --- a/plugins/available/todo/todo_completion +++ /dev/null @@ -1,107 +0,0 @@ -#!/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/visual-studio-code.plugin.bash b/plugins/available/visual-studio-code.plugin.bash new file mode 100644 index 00000000..5bc20995 --- /dev/null +++ b/plugins/available/visual-studio-code.plugin.bash @@ -0,0 +1,12 @@ +cite about-plugin +about-plugin 'Defines the `code` executable for Visual Studio Code on OS X' + +# Based on https://code.visualstudio.com/Docs/editor/setup +if [[ `uname -s` == "Darwin" ]]; then + function code () { + about 'Starts Visual Studio Code in the provided directory' + group 'visual-studio-code' + + VSCODE_CWD="$PWD" open -n -b "com.microsoft.VSCode" --args $* ; + } +fi diff --git a/template/bash_profile.template.bash b/template/bash_profile.template.bash index 9fda847e..32266133 100755 --- a/template/bash_profile.template.bash +++ b/template/bash_profile.template.bash @@ -1,12 +1,16 @@ #!/usr/bin/env bash # Path to the bash it configuration -export BASH_IT="$HOME/.bash_it" +export BASH_IT="{{BASH_IT}}" # Lock and Load a custom theme file # location /.bash_it/themes/ export BASH_IT_THEME='bobby' +# (Advanced): Change this to the name of your remote repo if you +# cloned bash-it with a remote other than origin such as `bash-it`. +# export BASH_IT_REMOTE='bash-it' + # Your place for hosting Git repos. I use this for private repos. export GIT_HOSTING='git@git.domain.com' @@ -23,7 +27,7 @@ export TODO="t" export SCM_CHECK=true # Set vcprompt executable path for scm advance info in prompt (demula theme) -# https://github.com/xvzf/vcprompt +# https://github.com/djl/vcprompt #export VCPROMPT_EXECUTABLE=~/.vcprompt/bin/vcprompt # Load Bash It diff --git a/template/jekyllconfig.template.bash b/template/jekyllconfig.template.bash deleted file mode 100644 index 291bf85e..00000000 --- a/template/jekyllconfig.template.bash +++ /dev/null @@ -1,21 +0,0 @@ -# This is a space-delimited list of your Jekyll project paths - -SITES="$HOME/sites/project_1 $HOME/sites/project_2" - -# This is another space-delimited list. -# This one is of the remote user@host:path location of your jekyll site -# NOTE: The locations of these must correspond to the locations -# of the sites in the first list -# For instance, the host for the first Jekyll site -# must be first in this list, the second second, etc. - -REMOTES="user@host_1:path user@host_2:path" - -# list of markup syntaxes to use for the sites, -# Same rules as above. Can be HTML, textile, or markdown - -MARKUPS="markdown textile" - -# If you want to use a different editor for Jekyll, change the value of this variable - -JEKYLL_EDITOR="$EDITOR" diff --git a/test/lib/helpers.bats b/test/lib/helpers.bats new file mode 100644 index 00000000..4f3e4ffa --- /dev/null +++ b/test/lib/helpers.bats @@ -0,0 +1,10 @@ +#!/usr/bin/env bats + +load ../../lib/composure +load ../../plugins/available/base.plugin + +cite _about _param _example _group _author _version + +load ../../lib/helpers + +## TODO: write some tests. diff --git a/test/lib/search.bats b/test/lib/search.bats new file mode 100644 index 00000000..ae9e9a89 --- /dev/null +++ b/test/lib/search.bats @@ -0,0 +1,53 @@ +#!/usr/bin/env bats + +load ../../lib/composure +load ../../plugins/available/base.plugin + +cite _about _param _example _group _author _version + +load ../../lib/helpers +load ../../lib/search + +NO_COLOR=true + +@test "helpers search aliases" { + run _bash-it-search-component 'plugins' 'base' + [[ "${lines[0]}" =~ 'plugins' && "${lines[0]}" =~ 'base' ]] +} + +@test "helpers search ruby gem bundle rake rails" { + # first disable them all, so that the output does not appear with a checkbox + # and we can compoare the result + run _bash-it-search 'ruby' 'gem' 'bundle' 'rake' 'rails' '--disable' + # Now perform the search + run _bash-it-search 'ruby' 'gem' 'bundle' 'rake' 'rails' + # And verify + [[ "${lines[0]/✓/}" == ' aliases => bundler rails' ]] && \ + [[ "${lines[1]/✓/}" == ' plugins => chruby chruby-auto rails ruby' ]] && \ + [[ "${lines[2]/✓/}" == ' completions => bundler gem rake' ]] +} + +@test "search ruby gem bundle -chruby rake rails" { + run _bash-it-search 'ruby' 'gem' 'bundle' 'rake' 'rails' '--disable' + run _bash-it-search 'ruby' 'gem' 'bundle' '-chruby' 'rake' 'rails' + [[ "${lines[0]/✓/}" == ' aliases => bundler rails' ]] && \ + [[ "${lines[1]/✓/}" == ' plugins => rails ruby' ]] && \ + [[ "${lines[2]/✓/}" == ' completions => bundler gem rake' ]] +} + +@test "search (rails enabled) ruby gem bundle rake rails" { + run _bash-it-search 'ruby' 'gem' 'bundle' 'rake' 'rails' '--disable' + run _enable-alias 'rails' + run _bash-it-search 'ruby' 'gem' 'bundle' 'rake' 'rails' + [[ "${lines[0]}" == ' aliases => bundler ✓rails' ]] && \ + [[ "${lines[1]}" == ' plugins => chruby chruby-auto rails ruby' ]] && \ + [[ "${lines[2]}" == ' completions => bundler gem rake' ]] +} + +@test "search (all enabled) ruby gem bundle rake rails" { + run _bash-it-search 'ruby' 'gem' 'bundle' 'rake' '-chruby' 'rails' '--enable' + run _bash-it-search 'ruby' 'gem' 'bundle' 'rake' '-chruby' 'rails' + [[ "${lines[0]}" == ' aliases => ✓bundler ✓rails' ]] && \ + [[ "${lines[1]}" == ' plugins => ✓rails ✓ruby' ]] && \ + [[ "${lines[2]}" == ' completions => ✓bundler ✓gem ✓rake' ]] +} diff --git a/test/run b/test/run index 1fb11518..397aec9c 100755 --- a/test/run +++ b/test/run @@ -1,4 +1,12 @@ #!/usr/bin/env bash -set -e +test_directory="$(cd "$(dirname "$0")" && pwd)" +bats_executable="${test_directory}/../bats/bin/bats" -exec bats ${CI:+--tap} test/{lib,plugins} +[ ! -e $bats_executable ] && \ + git clone --depth 1 https://github.com/sstephenson/bats.git ${test_directory}/../bats + +if [ -z "${BASH_IT}" ]; then + export BASH_IT=$(cd ${test_directory} && dirname $(pwd)) +fi + +exec $bats_executable ${CI:+--tap} ${test_directory}/{lib,plugins} diff --git a/themes/axin/axin.theme.bash b/themes/axin/axin.theme.bash new file mode 100644 index 00000000..0b95b531 --- /dev/null +++ b/themes/axin/axin.theme.bash @@ -0,0 +1,38 @@ +# Axin Bash Prompt, inspired by theme "Sexy" and "Bobby" +# thanks to them + +if [[ $COLORTERM = gnome-* && $TERM = xterm ]] && infocmp gnome-256color >/dev/null 2>&1; then export TERM=gnome-256color +elif [[ $TERM != dumb ]] && infocmp xterm-256color >/dev/null 2>&1; then export TERM=xterm-256color +fi + +if tput setaf 1 &> /dev/null; then + if [[ $(tput colors) -ge 256 ]] 2>/dev/null; then + MAGENTA=$(tput setaf 9) + ORANGE=$(tput setaf 172) + GREEN=$(tput setaf 190) + PURPLE=$(tput setaf 141) + WHITE=$(tput setaf 0) + else + MAGENTA=$(tput setaf 5) + ORANGE=$(tput setaf 4) + GREEN=$(tput setaf 2) + PURPLE=$(tput setaf 1) + WHITE=$(tput setaf 7) + fi + BOLD=$(tput bold) + RESET=$(tput sgr0) +else + MAGENTA="\033[1;31m" + ORANGE="\033[1;33m" + GREEN="\033[1;32m" + PURPLE="\033[1;35m" + WHITE="\033[1;37m" + BOLD="" + RESET="\033[m" +fi + +function prompt_command() { + PS1="\[${BOLD}${MAGENTA}\]\u \[$WHITE\]@ \[$ORANGE\]\h \[$WHITE\]in \[$GREEN\]\w\[$WHITE\]\[$SCM_THEME_PROMPT_PREFIX\]${white}\t \[$PURPLE\]\$(scm_prompt_info) \n\$ \[$RESET\]" +} + +PROMPT_COMMAND=prompt_command diff --git a/themes/base.theme.bash b/themes/base.theme.bash index 989e7cbc..d961b10d 100644 --- a/themes/base.theme.bash +++ b/themes/base.theme.bash @@ -10,13 +10,24 @@ SCM_THEME_PROMPT_PREFIX=' |' SCM_THEME_PROMPT_SUFFIX='|' SCM_THEME_BRANCH_PREFIX='' SCM_THEME_TAG_PREFIX='tag:' -SCM_THEME_COMMIT_PREFIX='commit:' -SCM_THEME_REMOTE_PREFIX='' +SCM_THEME_DETACHED_PREFIX='detached:' +SCM_THEME_BRANCH_TRACK_PREFIX=' → ' +SCM_THEME_BRANCH_GONE_PREFIX=' ⇢ ' +SCM_THEME_CURRENT_USER_PREFFIX=' ☺︎ ' +SCM_THEME_CURRENT_USER_SUFFIX='' + +CLOCK_CHAR='☆' +THEME_CLOCK_CHECK=${THEME_CLOCK_CHECK:=true} +THEME_BATTERY_PERCENTAGE_CHECK=${THEME_BATTERY_PERCENTAGE_CHECK:=true} SCM_GIT_SHOW_DETAILS=${SCM_GIT_SHOW_DETAILS:=true} +SCM_GIT_SHOW_REMOTE_INFO=${SCM_GIT_SHOW_REMOTE_INFO:=auto} +SCM_GIT_IGNORE_UNTRACKED=${SCM_GIT_IGNORE_UNTRACKED:=false} +SCM_GIT_SHOW_CURRENT_USER=${SCM_GIT_SHOW_CURRENT_USER:=false} SCM_GIT='git' SCM_GIT_CHAR='±' +SCM_GIT_DETACHED_CHAR='⌿' SCM_GIT_AHEAD_CHAR="↑" SCM_GIT_BEHIND_CHAR="↓" SCM_GIT_UNTRACKED_CHAR="?:" @@ -84,17 +95,50 @@ function scm_prompt_info { [[ $SCM == $SCM_SVN ]] && svn_prompt_info && return } +function git_status_summary { + awk ' + BEGIN { + untracked=0; + unstaged=0; + staged=0; + } + { + if (!after_first && $0 ~ /^##.+/) { + print $0 + seen_header = 1 + } else if ($0 ~ /^\?\? .+/) { + untracked += 1 + } else { + if ($0 ~ /^.[^ ] .+/) { + unstaged += 1 + } + if ($0 ~ /^[^ ]. .+/) { + staged += 1 + } + } + after_first = 1 + } + END { + if (!seen_header) { + print + } + print untracked "\t" unstaged "\t" staged + }' +} + function git_prompt_vars { local details='' SCM_STATE=${GIT_THEME_PROMPT_CLEAN:-$SCM_THEME_PROMPT_CLEAN} if [[ "$(git config --get bash-it.hide-status)" != "1" ]]; then - local status="$(git status -b --porcelain 2> /dev/null || git status --porcelain 2> /dev/null)" - if [[ -n "${status}" ]] && [[ "${status}" != "\n" ]] && [[ -n "$(grep -v ^# <<< "${status}")" ]]; then + [[ "${SCM_GIT_IGNORE_UNTRACKED}" = "true" ]] && local git_status_flags='-uno' + local status_lines=$((git status --porcelain ${git_status_flags} -b 2> /dev/null || + git status --porcelain ${git_status_flags} 2> /dev/null) | git_status_summary) + local status=$(awk 'NR==1' <<< "$status_lines") + local counts=$(awk 'NR==2' <<< "$status_lines") + IFS=$'\t' read untracked_count unstaged_count staged_count <<< "$counts" + if [[ "${untracked_count}" -gt 0 || "${unstaged_count}" -gt 0 || "${staged_count}" -gt 0 ]]; then SCM_DIRTY=1 if [[ "${SCM_GIT_SHOW_DETAILS}" = "true" ]]; then - local untracked_count="$(egrep -c '^\?\? .+' <<< "${status}")" - local unstaged_count="$(egrep -c '^.[^ ?#] .+' <<< "${status}")" - local staged_count="$(egrep -c '^[^ ?#]. .+' <<< "${status}")" [[ "${staged_count}" -gt 0 ]] && details+=" ${SCM_GIT_STAGED_CHAR}${staged_count}" && SCM_DIRTY=3 [[ "${unstaged_count}" -gt 0 ]] && details+=" ${SCM_GIT_UNSTAGED_CHAR}${unstaged_count}" && SCM_DIRTY=2 [[ "${untracked_count}" -gt 0 ]] && details+=" ${SCM_GIT_UNTRACKED_CHAR}${untracked_count}" && SCM_DIRTY=1 @@ -103,23 +147,52 @@ function git_prompt_vars { fi fi + [[ "${SCM_GIT_SHOW_CURRENT_USER}" == "true" ]] && details+="$(git_user_info)" + + SCM_CHANGE=$(git rev-parse --short HEAD 2>/dev/null) + local ref=$(git symbolic-ref -q HEAD 2> /dev/null) if [[ -n "$ref" ]]; then SCM_BRANCH=${SCM_THEME_BRANCH_PREFIX}${ref#refs/heads/} - else - ref=$(git describe --tags --exact-match 2> /dev/null) - if [[ -n "$ref" ]]; then - SCM_BRANCH=${SCM_THEME_TAG_PREFIX}${ref} - else - local commit_re='(^remotes/)?(.+-g[a-zA-Z0-9]+)$' - local remote_re='^remotes/(.+)$' - ref=$(git describe --tags --all --always 2> /dev/null) - if [[ "$ref" =~ ${commit_re} ]]; then - SCM_BRANCH=${SCM_THEME_COMMIT_PREFIX}${BASH_REMATCH[2]} - elif [[ "$ref" =~ ${remote_re} ]]; then - SCM_BRANCH=${SCM_THEME_REMOTE_PREFIX}${BASH_REMATCH[1]} + local tracking_info="$(grep "${SCM_BRANCH}\.\.\." <<< "${status}")" + if [[ -n "${tracking_info}" ]]; then + [[ "${tracking_info}" =~ .+\[gone\]$ ]] && local branch_gone="true" + tracking_info=${tracking_info#\#\# ${SCM_BRANCH}...} + tracking_info=${tracking_info% [*} + local remote_name=${tracking_info%%/*} + local remote_branch=${tracking_info#${remote_name}/} + local remote_info="" + local num_remotes=$(git remote | wc -l 2> /dev/null) + [[ "${SCM_BRANCH}" = "${remote_branch}" ]] && local same_branch_name=true + if ([[ "${SCM_GIT_SHOW_REMOTE_INFO}" = "auto" ]] && [[ "${num_remotes}" -ge 2 ]]) || + [[ "${SCM_GIT_SHOW_REMOTE_INFO}" = "true" ]]; then + remote_info="${remote_name}" + [[ "${same_branch_name}" != "true" ]] && remote_info+="/${remote_branch}" + elif [[ ${same_branch_name} != "true" ]]; then + remote_info="${remote_branch}" + fi + if [[ -n "${remote_info}" ]];then + if [[ "${branch_gone}" = "true" ]]; then + SCM_BRANCH+="${SCM_THEME_BRANCH_GONE_PREFIX}${remote_info}" + else + SCM_BRANCH+="${SCM_THEME_BRANCH_TRACK_PREFIX}${remote_info}" + fi fi fi + SCM_GIT_DETACHED="false" + else + local detached_prefix="" + ref=$(git describe --tags --exact-match 2> /dev/null) + if [[ -n "$ref" ]]; then + detached_prefix=${SCM_THEME_TAG_PREFIX} + else + ref=$(git describe --contains --all HEAD 2> /dev/null) + ref=${ref#remotes/} + [[ -z "$ref" ]] && ref=${SCM_CHANGE} + detached_prefix=${SCM_THEME_DETACHED_PREFIX} + fi + SCM_BRANCH=${detached_prefix}${ref} + SCM_GIT_DETACHED="true" fi local ahead_re='.+ahead ([0-9]+).+' @@ -134,7 +207,6 @@ function git_prompt_vars { SCM_PREFIX=${GIT_THEME_PROMPT_PREFIX:-$SCM_THEME_PROMPT_PREFIX} SCM_SUFFIX=${GIT_THEME_PROMPT_SUFFIX:-$SCM_THEME_PROMPT_SUFFIX} - SCM_CHANGE=$(git rev-parse HEAD 2>/dev/null) } function svn_prompt_vars { @@ -152,9 +224,9 @@ function svn_prompt_vars { } # this functions returns absolute location of .hg directory if one exists -# It starts in the current directory and moves its way up until it hits /. +# It starts in the current directory and moves its way up until it hits /. # If we get to / then no Mercurial repository was found. -# Example: +# Example: # - lets say we cd into ~/Projects/Foo/Bar # - .hg is located in ~/Projects/Foo/.hg # - get_hg_root starts at ~/Projects/Foo/Bar and sees that there is no .hg directory, so then it goes into ~/Projects/Foo @@ -184,16 +256,16 @@ function hg_prompt_vars { HG_ROOT=$(get_hg_root) - if [ -f $HG_ROOT/branch ]; then - # Mercurial holds it's current branch in .hg/branch file - SCM_BRANCH=$(cat $HG_ROOT/branch) + if [ -f "$HG_ROOT/branch" ]; then + # Mercurial holds it's current branch in .hg/branch file + SCM_BRANCH=$(cat "$HG_ROOT/branch") else SCM_BRANCH=$(hg summary 2> /dev/null | grep branch: | awk '{print $2}') fi - if [ -f $HG_ROOT/dirstate ]; then + if [ -f "$HG_ROOT/dirstate" ]; then # Mercurial holds various information about the working directory in .hg/dirstate file. More on http://mercurial.selenic.com/wiki/DirState - SCM_CHANGE=$(hexdump -n 10 -e '1/1 "%02x"' $HG_ROOT/dirstate | cut -c-12) + SCM_CHANGE=$(hexdump -n 10 -e '1/1 "%02x"' "$HG_ROOT/dirstate" | cut -c-12) else SCM_CHANGE=$(hg summary 2> /dev/null | grep parent: | awk '{print $2}') fi @@ -201,8 +273,8 @@ function hg_prompt_vars { function rvm_version_prompt { if which rvm &> /dev/null; then - rvm=$(rvm tools identifier) || return - if [ $rvm != "system" ]; then + rvm=$(rvm-prompt) || return + if [ -n "$rvm" ]; then echo -e "$RVM_THEME_PROMPT_PREFIX$rvm$RVM_THEME_PROMPT_SUFFIX" fi fi @@ -265,6 +337,13 @@ function python_version_prompt { echo -e "$(virtualenv_prompt)$(condaenv_prompt)$(py_interp_prompt)" } +function git_user_info { + # support two or more initials, set by 'git pair' plugin + SCM_CURRENT_USER=$(git config user.initials | sed 's% %+%') + # if `user.initials` weren't set, attempt to extract initials from `user.name` + [[ -z "${SCM_CURRENT_USER}" ]] && SCM_CURRENT_USER=$(printf "%s" $(for word in $(git config user.name | tr 'A-Z' 'a-z'); do printf "%1.1s" $word; done)) + [[ -n "${SCM_CURRENT_USER}" ]] && printf "%s" "$SCM_THEME_CURRENT_USER_PREFFIX$SCM_CURRENT_USER$SCM_THEME_CURRENT_USER_SUFFIX" +} # backwards-compatibility function git_prompt_info { @@ -291,11 +370,36 @@ function prompt_char { scm_char } +function clock_char { + if [[ "${THEME_CLOCK_CHECK}" = true ]]; then + DATE_STRING=$(date +"%Y-%m-%d %H:%M:%S") + echo -e "${bold_cyan}$DATE_STRING ${red}$CLOCK_CHAR" + fi +} + +function battery_char { + if [[ "${THEME_BATTERY_PERCENTAGE_CHECK}" = true ]]; then + echo -e "${bold_red}$(battery_percentage)%" + fi +} + if [ ! -e $BASH_IT/plugins/enabled/battery.plugin.bash ]; then -# if user has installed battery plugin, skip this... + # if user has installed battery plugin, skip this... function battery_charge (){ - # no op - echo -n + # no op + echo -n + } + + function battery_char (){ + # no op + echo -n } fi +function aws_profile { + if [[ $AWS_DEFAULT_PROFILE ]]; then + echo -e "${AWS_DEFAULT_PROFILE}" + else + echo -e "default" + fi +} diff --git a/themes/binaryanomaly/binaryanomaly.theme.bash b/themes/binaryanomaly/binaryanomaly.theme.bash new file mode 100644 index 00000000..58748f1d --- /dev/null +++ b/themes/binaryanomaly/binaryanomaly.theme.bash @@ -0,0 +1,105 @@ +#!/bin/bash + +# Set term to 256color mode, if 256color is not supported, colors won't work properly +if [[ $COLORTERM = gnome-* && $TERM = xterm ]] && infocmp gnome-256color >/dev/null 2>&1; then + export TERM=gnome-256color +elif infocmp xterm-256color >/dev/null 2>&1; then + export TERM=xterm-256color +fi + + +# Detect whether a rebbot is required +function show_reboot_required() { + if [ ! -z "$_bf_prompt_reboot_info" ]; then + if [ -f /var/run/reboot-required ]; then + printf "Reboot required!" + fi + fi +} + + +# Set different host color for local and remote sessions +function set_host_color() { + # Detect if connection is through SSH + if [[ ! -z $SSH_CLIENT ]]; then + printf "${lime_yellow}" + else + printf "${light_orange}" + fi +} + + +# Set different username color for users and root +function set_user_color() { + case $(id -u) in + 0) + printf "${red}" + ;; + *) + printf "${cyan}" + ;; + esac +} + + +scm_prompt() { + CHAR=$(scm_char) + if [ $CHAR = $SCM_NONE_CHAR ] + then + return + else + echo "[$(scm_char)$(scm_prompt_info)]" + fi +} + + + +# Define custom colors we need +# non-printable bytes in PS1 need to be contained within \[ \]. +# Otherwise, bash will count them in the length of the prompt +function set_custom_colors() { + dark_grey="\[$(tput setaf 8)\]" + light_grey="\[$(tput setaf 248)\]" + + light_orange="\[$(tput setaf 172)\]" + bright_yellow="\[$(tput setaf 220)\]" + lime_yellow="\[$(tput setaf 190)\]" + + powder_blue="\[$(tput setaf 153)\]" +} + + +function prompt_command() { + ps_reboot="${bright_yellow}$(show_reboot_required)${normal}\n" + ps_time="${dark_grey}\t${normal}\n" + + ps_username="$(set_user_color)\u${normal}" + ps_uh_separator="${dark_grey}@${normal}" + ps_hostname="$(set_host_color)\h${normal}" + + ps_path="${yellow}\w${normal}" + ps_scm_prompt="${light_grey}$(scm_prompt)" + + ps_user_mark="${normal} ${normal}" + ps_user_input="${normal}" + + # Set prompt + PS1="$ps_reboot$ps_time$ps_username$ps_uh_separator$ps_hostname $ps_path $ps_scm_prompt$ps_user_mark$ps_user_input" +} + + + +# Initialize custom colors +set_custom_colors + +# scm theming +SCM_THEME_PROMPT_PREFIX="" +SCM_THEME_PROMPT_SUFFIX="" + +SCM_THEME_PROMPT_DIRTY=" ${bold_red}✗${light_grey}" +SCM_THEME_PROMPT_CLEAN=" ${green}✓${light_grey}" +SCM_GIT_CHAR="${green}±${light_grey}" +SCM_SVN_CHAR="${bold_cyan}⑆${light_grey}" +SCM_HG_CHAR="${bold_red}☿${light_grey}" + +PROMPT_COMMAND=prompt_command; diff --git a/themes/bobby/bobby.theme.bash b/themes/bobby/bobby.theme.bash index 308b412b..e0011759 100644 --- a/themes/bobby/bobby.theme.bash +++ b/themes/bobby/bobby.theme.bash @@ -14,7 +14,7 @@ RVM_THEME_PROMPT_SUFFIX="|" function prompt_command() { #PS1="${bold_cyan}$(scm_char)${green}$(scm_prompt_info)${purple}$(ruby_version_prompt) ${yellow}\h ${reset_color}in ${green}\w ${reset_color}\n${green}→${reset_color} " - PS1="\n${yellow}$(ruby_version_prompt) ${purple}\h ${reset_color}in ${green}\w\n${bold_cyan}$(scm_char)${green}$(scm_prompt_info) ${green}→${reset_color} " + PS1="\n$(battery_char) $(clock_char) ${yellow}$(ruby_version_prompt) ${purple}\h ${reset_color}in ${green}\w\n${bold_cyan}$(scm_char)${green}$(scm_prompt_info) ${green}→${reset_color} " } PROMPT_COMMAND=prompt_command; diff --git a/themes/colors.theme.bash b/themes/colors.theme.bash index 2feb3e9a..da42f66b 100644 --- a/themes/colors.theme.bash +++ b/themes/colors.theme.bash @@ -5,54 +5,54 @@ function __ { } function __make_ansi { - next=$1 && shift + next=$1; shift echo "\[\e[$(__$next $@)m\]" } function __make_echo { - next=$1 && shift + next=$1; shift echo "\033[$(__$next $@)m" } function __reset { - next=$1 && shift + next=$1; shift out="$(__$next $@)" echo "0${out:+;${out}}" } function __bold { - next=$1 && shift + next=$1; shift out="$(__$next $@)" echo "${out:+${out};}1" } function __faint { - next=$1 && shift + next=$1; shift out="$(__$next $@)" echo "${out:+${out};}2" } function __italic { - next=$1 && shift + next=$1; shift out="$(__$next $@)" echo "${out:+${out};}3" } function __underline { - next=$1 && shift + next=$1; shift out="$(__$next $@)" echo "${out:+${out};}4" } function __negative { - next=$1 && shift + next=$1; shift out="$(__$next $@)" echo "${out:+${out};}7" } function __crossed { - next=$1 && shift + next=$1; shift out="$(__$next $@)" echo "${out:+${out};}8" } @@ -114,18 +114,18 @@ function __color_rgb { } function __color { - color=$1 && shift + color=$1; shift case "$1" in - fg|bg) side="$1" && shift ;; + fg|bg) side="$1"; shift ;; *) side=fg;; esac case "$1" in - normal|bright) mode="$1" && shift;; + normal|bright) mode="$1"; shift;; *) mode=normal;; esac - [[ $color == "rgb" ]] && rgb="$1 $2 $3" && shift 3 + [[ $color == "rgb" ]] && rgb="$1 $2 $3"; shift 3 - next=$1 && shift + next=$1; shift out="$(__$next $@)" echo "$(__color_${mode}_${side} $(__color_${color} $rgb))${out:+;${out}}" } @@ -169,7 +169,7 @@ function __rgb { function __color_parse { - next=$1 && shift + next=$1; shift echo "$(__$next $@)" } @@ -182,89 +182,89 @@ function echo_color { } -black="$(color reset black)" -red="$(color reset red)" -green="$(color reset green)" -yellow="$(color reset yellow)" -blue="$(color reset blue)" -purple="$(color reset magenta)" -cyan="$(color reset cyan)" -white="$(color reset white bold)" -orange="$(color reset red fg bright)" +black="\[\e[0;30m\]" +red="\[\e[0;31m\]" +green="\[\e[0;32m\]" +yellow="\[\e[0;33m\]" +blue="\[\e[0;34m\]" +purple="\[\e[0;35m\]" +cyan="\[\e[0;36m\]" +white="\[\e[0;37;1m\]" +orange="\[\e[0;91m\]" -bold_black="$(color black bold)" -bold_red="$(color red bold)" -bold_green="$(color green bold)" -bold_yellow="$(color yellow bold)" -bold_blue="$(color blue bold)" -bold_purple="$(color magenta bold)" -bold_cyan="$(color cyan bold)" -bold_white="$(color white bold)" -bold_orange="$(color red fg bright bold)" +bold_black="\[\e[30;1m\]" +bold_red="\[\e[31;1m\]" +bold_green="\[\e[32;1m\]" +bold_yellow="\[\e[33;1m\]" +bold_blue="\[\e[34;1m\]" +bold_purple="\[\e[35;1m\]" +bold_cyan="\[\e[36;1m\]" +bold_white="\[\e[37;1m\]" +bold_orange="\[\e[91;1m\]" -underline_black="$(color black underline)" -underline_red="$(color red underline)" -underline_green="$(color green underline)" -underline_yellow="$(color yellow underline)" -underline_blue="$(color blue underline)" -underline_purple="$(color magenta underline)" -underline_cyan="$(color cyan underline)" -underline_white="$(color white underline)" -underline_orange="$(color red fg bright underline)" +underline_black="\[\e[30;4m\]" +underline_red="\[\e[31;4m\]" +underline_green="\[\e[32;4m\]" +underline_yellow="\[\e[33;4m\]" +underline_blue="\[\e[34;4m\]" +underline_purple="\[\e[35;4m\]" +underline_cyan="\[\e[36;4m\]" +underline_white="\[\e[37;4m\]" +underline_orange="\[\e[91;4m\]" -background_black="$(color black bg)" -background_red="$(color red bg)" -background_green="$(color green bg)" -background_yellow="$(color yellow bg)" -background_blue="$(color blue bg)" -background_purple="$(color magenta bg)" -background_cyan="$(color cyan bg)" -background_white="$(color white bg bold)" -background_orange="$(color red bg bright)" +background_black="\[\e[40m\]" +background_red="\[\e[41m\]" +background_green="\[\e[42m\]" +background_yellow="\[\e[43m\]" +background_blue="\[\e[44m\]" +background_purple="\[\e[45m\]" +background_cyan="\[\e[46m\]" +background_white="\[\e[47;1m\]" +background_orange="\[\e[101m\]" -normal="$(color reset)" -reset_color="$(__make_ansi '' 39)" +normal="\[\e[0m\]" +reset_color="\[\e[39m\]" # These colors are meant to be used with `echo -e` -echo_black="$(echo_color reset black)" -echo_red="$(echo_color reset red)" -echo_green="$(echo_color reset green)" -echo_yellow="$(echo_color reset yellow)" -echo_blue="$(echo_color reset blue)" -echo_purple="$(echo_color reset magenta)" -echo_cyan="$(echo_color reset cyan)" -echo_white="$(echo_color reset white bold)" -echo_orange="$(echo_color reset red fg bright)" +echo_black="\033[0;30m" +echo_red="\033[0;31m" +echo_green="\033[0;32m" +echo_yellow="\033[0;33m" +echo_blue="\033[0;34m" +echo_purple="\033[0;35m" +echo_cyan="\033[0;36m" +echo_white="\033[0;37;1m" +echo_orange="\033[0;91m" -echo_bold_black="$(echo_color black bold)" -echo_bold_red="$(echo_color red bold)" -echo_bold_green="$(echo_color green bold)" -echo_bold_yellow="$(echo_color yellow bold)" -echo_bold_blue="$(echo_color blue bold)" -echo_bold_purple="$(echo_color magenta bold)" -echo_bold_cyan="$(echo_color cyan bold)" -echo_bold_white="$(echo_color white bold)" -echo_bold_orange="$(echo_color red fg bright bold)" +echo_bold_black="\033[30;1m" +echo_bold_red="\033[31;1m" +echo_bold_green="\033[32;1m" +echo_bold_yellow="\033[33;1m" +echo_bold_blue="\033[34;1m" +echo_bold_purple="\033[35;1m" +echo_bold_cyan="\033[36;1m" +echo_bold_white="\033[37;1m" +echo_bold_orange="\033[91;1m" -echo_underline_black="$(echo_color black underline)" -echo_underline_red="$(echo_color red underline)" -echo_underline_green="$(echo_color green underline)" -echo_underline_yellow="$(echo_color yellow underline)" -echo_underline_blue="$(echo_color blue underline)" -echo_underline_purple="$(echo_color magenta underline)" -echo_underline_cyan="$(echo_color cyan underline)" -echo_underline_white="$(echo_color white underline)" -echo_underline_orange="$(echo_color red fg bright underline)" +echo_underline_black="\033[30;4m" +echo_underline_red="\033[31;4m" +echo_underline_green="\033[32;4m" +echo_underline_yellow="\033[33;4m" +echo_underline_blue="\033[34;4m" +echo_underline_purple="\033[35;4m" +echo_underline_cyan="\033[36;4m" +echo_underline_white="\033[37;4m" +echo_underline_orange="\033[91;4m" -echo_background_black="$(echo_color black bg)" -echo_background_red="$(echo_color red bg)" -echo_background_green="$(echo_color green bg)" -echo_background_yellow="$(echo_color yellow bg)" -echo_background_blue="$(echo_color blue bg)" -echo_background_purple="$(echo_color magenta bg)" -echo_background_cyan="$(echo_color cyan bg)" -echo_background_white="$(echo_color white bg bold)" -echo_background_orange="$(echo_color red bg bright)" +echo_background_black="\033[40m" +echo_background_red="\033[41m" +echo_background_green="\033[42m" +echo_background_yellow="\033[43m" +echo_background_blue="\033[44m" +echo_background_purple="\033[45m" +echo_background_cyan="\033[46m" +echo_background_white="\033[47;1m" +echo_background_orange="\033[101m" -echo_normal="$(echo_color reset)" -echo_reset_color="$(__make_echo '' 39)" +echo_normal="\033[0m" +echo_reset_color="\033[39m" diff --git a/themes/cooperkid/cooperkid.theme.bash b/themes/cooperkid/cooperkid.theme.bash new file mode 100644 index 00000000..ff4df68e --- /dev/null +++ b/themes/cooperkid/cooperkid.theme.bash @@ -0,0 +1,39 @@ +# ------------------------------------------------------------------# +# FILE: cooperkid.zsh-theme # +# BY: Alfredo Bejarano # +# BASED ON: Mr Briggs by Matt Brigg (matt@mattbriggs.net) # +# ------------------------------------------------------------------# + +SCM_THEME_PROMPT_DIRTY="${red} ✗${reset_color}" +SCM_THEME_PROMPT_AHEAD="${yellow} ↑${reset_color}" +SCM_THEME_PROMPT_CLEAN="${green} ✓${reset_color}" +SCM_THEME_PROMPT_PREFIX=" " +SCM_THEME_PROMPT_SUFFIX="" +GIT_SHA_PREFIX="${blue}" +GIT_SHA_SUFFIX="${reset_color}" + +function rvm_version_prompt { + if which rvm &> /dev/null; then + rvm=$(rvm-prompt) || return + if [ -n "$rvm" ]; then + echo -e "$rvm" + fi + fi +} + +function git_short_sha() { + SHA=$(git rev-parse --short HEAD 2> /dev/null) && echo "$GIT_SHA_PREFIX$SHA$GIT_SHA_SUFFIX" +} + +function prompt() { + local return_status="" + local ruby="${red}$(ruby_version_prompt)${reset_color}" + local user_host="${green}\h @ \w${reset_color}" + local git_branch="$(git_short_sha)${cyan}$(scm_prompt_info)${reset_color}" + local prompt_symbol=' ' + local prompt_char="${purple}>_${reset_color} " + + PS1="\n${user_host}${prompt_symbol}${ruby} ${git_branch} ${return_status}\n${prompt_char}" +} + +PROMPT_COMMAND=prompt diff --git a/themes/gallifrey/gallifrey.theme.bash b/themes/gallifrey/gallifrey.theme.bash new file mode 100644 index 00000000..a601db12 --- /dev/null +++ b/themes/gallifrey/gallifrey.theme.bash @@ -0,0 +1,41 @@ +# scm theming +SCM_THEME_PROMPT_PREFIX="${yellow}(" +SCM_THEME_PROMPT_SUFFIX=")${normal}" + +SCM_THEME_PROMPT_DIRTY="*" +SCM_THEME_PROMPT_CLEAN="" +SCM_GIT_CHAR="g" +SCM_SVN_CHAR="s" +SCM_HG_CHAR="h" + +### TODO: openSUSE has already colors enabled, check if those differs from stock +# LS colors, made with http://geoff.greer.fm/lscolors/ +# export LSCOLORS="Gxfxcxdxbxegedabagacad" +# export LS_COLORS='no=00:fi=00:di=01;34:ln=00;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=41;33;01:ex=00;32:*.cmd=00;32:*.exe=01;32:*.com=01;32:*.bat=01;32:*.btm=01;32:*.dll=01;32:*.tar=00;31:*.tbz=00;31:*.tgz=00;31:*.rpm=00;31:*.deb=00;31:*.arj=00;31:*.taz=00;31:*.lzh=00;31:*.lzma=00;31:*.zip=00;31:*.zoo=00;31:*.z=00;31:*.Z=00;31:*.gz=00;31:*.bz2=00;31:*.tb2=00;31:*.tz2=00;31:*.tbz2=00;31:*.avi=01;35:*.bmp=01;35:*.fli=01;35:*.gif=01;35:*.jpg=01;35:*.jpeg=01;35:*.mng=01;35:*.mov=01;35:*.mpg=01;35:*.pcx=01;35:*.pbm=01;35:*.pgm=01;35:*.png=01;35:*.ppm=01;35:*.tga=01;35:*.tif=01;35:*.xbm=01;35:*.xpm=01;35:*.dl=01;35:*.gl=01;35:*.wmv=01;35:*.aiff=00;32:*.au=00;32:*.mid=00;32:*.mp3=00;32:*.ogg=00;32:*.voc=00;32:*.wav=00;32:' + +scm_prompt() { + CHAR=$(scm_char) + if [ $CHAR = $SCM_NONE_CHAR ] + then + return + else + echo "$(scm_prompt_info) " + fi +} + +pure_prompt() { + ps_host="${green}\h${normal}"; + ps_user_mark="${bold}\$${normal}"; + ps_root_mark="${normal}§" + ps_path="${normal}\w"; + + # make it work + case $(id -u) in + 0) PS1="$ps_host $ps_path $(scm_prompt)$ps_root_mark " + ;; + *) PS1="$ps_host $ps_path $(scm_prompt)$ps_user_mark " + ;; + esac +} + +PROMPT_COMMAND=pure_prompt; diff --git a/themes/iterate/iterate.theme.bash b/themes/iterate/iterate.theme.bash index b417f34f..7b375f44 100644 --- a/themes/iterate/iterate.theme.bash +++ b/themes/iterate/iterate.theme.bash @@ -40,17 +40,20 @@ function git_prompt_info { echo -e "$SCM_PREFIX$SCM_BRANCH$SCM_STATE$SCM_GIT_AHEAD$SCM_GIT_BEHIND$SCM_GIT_STASH$SCM_SUFFIX" } -LAST_PROMPT_INFO="" +LAST_PROMPT="" function prompt_command() { - local prompt_info="\n${bold_cyan}$(scm_char)${yellow}$(ruby_version_prompt)${green}\w $(scm_prompt_info)" - if [ "$LAST_PROMPT_INFO" = "$prompt_info" ]; then - prompt_info="" + local new_PS1="${bold_cyan}$(scm_char)${yellow}$(ruby_version_prompt)${green}\w $(scm_prompt_info)" + local new_prompt=$(PS1="$new_PS1" "$BASH" --norc -i &1 | sed -n '${s/^\(.*\)exit$/\1/p;}') + + if [ "$LAST_PROMPT" = "$new_prompt" ]; then + new_PS1="" else - LAST_PROMPT_INFO="$prompt_info" + LAST_PROMPT="$new_prompt" fi + local wrap_char="" - [[ ${#prompt_info} -gt $(($COLUMNS/1)) ]] && wrap_char="\n" - PS1="${prompt_info}${green}${wrap_char}→${reset_color} " + [[ ${#new_PS1} -gt $(($COLUMNS/1)) ]] && wrap_char="\n" + PS1="${new_PS1}${green}${wrap_char}→${reset_color} " } PROMPT_COMMAND=prompt_command; diff --git a/themes/mairan/mairan.theme.bash b/themes/mairan/mairan.theme.bash new file mode 100644 index 00000000..3451d3cb --- /dev/null +++ b/themes/mairan/mairan.theme.bash @@ -0,0 +1,130 @@ +# Mairan Bash Prompt, inspired by "Zork" + +if tput setaf 1 &> /dev/null; then + if [[ $(tput colors) -ge 256 ]] 2>/dev/null; then + MAGENTA=$(tput setaf 9) + ORANGE=$(tput setaf 172) + GREEN=$(tput setaf 190) + PURPLE=$(tput setaf 141) + WHITE=$(tput setaf 0) + else + MAGENTA=$(tput setaf 5) + ORANGE=$(tput setaf 4) + GREEN=$(tput setaf 2) + PURPLE=$(tput setaf 1) + WHITE=$(tput setaf 7) + fi + BOLD=$(tput bold) + RESET=$(tput sgr0) +else + MAGENTA="\033[1;31m" + ORANGE="\033[1;33m" + GREEN="\033[1;32m" + PURPLE="\033[1;35m" + WHITE="\033[1;37m" + BOLD="" + RESET="\033[m" +fi + +# prompt_symbol='λ' +# prompt_symbol='⚡' +prompt_symbol='' +BRACKET_COLOR=$ORANGE + +SCM_THEME_PROMPT_PREFIX="" +SCM_THEME_PROMPT_SUFFIX="" + +SCM_THEME_PROMPT_DIRTY=" ${bold_red}✗${normal}" +SCM_THEME_PROMPT_CLEAN=" ${bold_green}✓${normal}" +SCM_GIT_CHAR="${bold_green}±${normal}" +SCM_SVN_CHAR="${bold_cyan}⑆${normal}" +SCM_HG_CHAR="${bold_red}☿${normal}" + +#Mysql Prompt +export MYSQL_PS1="(\u@\h) [\d]> " + +case $TERM in + xterm*) + TITLEBAR="\[\033]0;\w\007\]" + ;; + *) + TITLEBAR="" + ;; +esac + +PS3=">> " + +__my_rvm_ruby_version() { + local gemset=$(echo $GEM_HOME | awk -F'@' '{print $2}') + [ "$gemset" != "" ] && gemset="@$gemset" + local version=$(echo $MY_RUBY_HOME | awk -F'-' '{print $2}') + local full="$version$gemset" + [ "$full" != "" ] && echo "[$full]" +} + +is_vim_shell() { + if [ ! -z "$VIMRUNTIME" ] + then + echo "[${cyan}vim shell${normal}]" + fi +} + +modern_scm_prompt() { + CHAR=$(scm_char) + if [ $CHAR = $SCM_NONE_CHAR ] + then + return + else + echo "[$(scm_char)][$GREEN$(scm_prompt_info)]" + fi +} + +# show chroot if exist +chroot(){ + if [ -n "$debian_chroot" ] + then + my_ps_chroot="${bold_cyan}$debian_chroot${normal}"; + echo "($my_ps_chroot)"; + fi + } + +# show virtualenvwrapper +my_ve(){ + if [ -n "$VIRTUAL_ENV" ] + then + my_ps_ve="${bold_purple}$ve${normal}"; + echo "($my_ps_ve)"; + fi + echo ""; + } + +prompt() { + + my_ps_host="$BOLD$ORANGE\h${normal}"; + # yes, these are the the same for now ... + my_ps_host_root="$ORANGE\h${normal}"; + + my_ps_user="$BOLD$GREEN\u${normal}" + my_ps_root="${bold_red}\u${normal}"; + + if [ -n "$VIRTUAL_ENV" ] + then + ve=`basename $VIRTUAL_ENV`; + fi + + # nice prompt + case "`id -u`" in + 0) PS1="\n${TITLEBAR}${BRACKET_COLOR}┌─${normal}$(my_ve)$(chroot)[$my_ps_root][$my_ps_host_root]$(modern_scm_prompt)$(__my_rvm_ruby_version)[${green}\w${normal}]$(is_vim_shell)${BRACKET_COLOR} +└─▪ ${prompt_symbol} ${normal}" + ;; + *) PS1="\n${TITLEBAR}${BRACKET_COLOR}┌─${normal}$(my_ve)$(chroot)[$my_ps_user][$my_ps_host]$(modern_scm_prompt)${normal}$(__my_rvm_ruby_version)[${green}\w${normal}]$(is_vim_shell)${BRACKET_COLOR} +└─▪ ${prompt_symbol} ${normal}" + ;; + esac +} + +PS2="└─▪ " + + + +PROMPT_COMMAND=prompt diff --git a/themes/morris/morris.theme.bash b/themes/morris/morris.theme.bash new file mode 100644 index 00000000..da51e55a --- /dev/null +++ b/themes/morris/morris.theme.bash @@ -0,0 +1,28 @@ + +# prompt theming + +# added TITLEBAR for updating the tab and window titles with the pwd +case $TERM in + xterm*) + TITLEBAR=$(printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}") + ;; + screen) + TITLEBAR=$(printf "\033]0;%s@%s:%s\033\\" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}") + ;; + *) + TITLEBAR="" + ;; +esac + +function prompt_command() { + PS1="${TITLEBAR}[\u@\h \W $(scm_prompt_info)]\$ " +} + +# scm theming +SCM_THEME_PROMPT_DIRTY=" ${red}✗" +SCM_THEME_PROMPT_CLEAN=" ${bold_green}✓" +SCM_THEME_PROMPT_PREFIX="${green}(" +SCM_THEME_PROMPT_SUFFIX="${green})${reset_color}" + + +PROMPT_COMMAND=prompt_command; diff --git a/themes/nwinkler_random_colors/README.md b/themes/nwinkler_random_colors/README.md new file mode 100644 index 00000000..80620efb --- /dev/null +++ b/themes/nwinkler_random_colors/README.md @@ -0,0 +1,29 @@ +# Nwinkler Random Color Theme + +## Description + +The *Nwinkler Random Color* Theme is based on the [nwinkler theme](https://github.com/Bash-it/bash-it/wiki/Themes#nwinkler), but it randomizes the colors for: + +* time +* username +* hostname +* path + +The random colors are chosen the first time this theme is used and saved to the `~/.nwinkler_random_colors` file. So, the next time you connect to the same machine, you will get the same colors. + +To force new random colors to be selected, run the command: + +```sh +randomize_nwinkler +``` + +## Screenshot + +Here it is in action: + +![alt text](screenshot.png "Nwinkler Random Color Theme in Action!") + +## Usage Scenario + +This theme is especially useful when connecting to many different machines and switching between them often. Yes, the hostname *is* present in the prompt. But I argue that it's a lot faster to get a "feel" of what machine you are currently on because of the custom colors on that machine's prompt than by reading the hostname. + diff --git a/themes/nwinkler_random_colors/nwinkler_random_colors.theme.bash b/themes/nwinkler_random_colors/nwinkler_random_colors.theme.bash new file mode 100644 index 00000000..23634276 --- /dev/null +++ b/themes/nwinkler_random_colors/nwinkler_random_colors.theme.bash @@ -0,0 +1,112 @@ +#!/bin/bash + +# Two line prompt showing the following information: +# (time) SCM [username@hostname] pwd (SCM branch SCM status) +# → +# +# Example: +# (14:00:26) ± [foo@bar] ~/.bash_it (master ✓) +# → +# +# The arrow on the second line is showing the exit status of the last command: +# * Green: 0 exit status +# * Red: non-zero exit status +# +# The exit code functionality currently doesn't work if you are using the 'fasd' plugin, +# since 'fasd' is messing with the $PROMPT_COMMAND + +RANDOM_COLOR_FILE=$HOME/.nwinkler_random_colors + +function randomize_nwinkler { + declare -a AVAILABLE_COLORS + + AVAILABLE_COLORS=( + $black + $red + $green + $yellow + $blue + $purple + $cyan + $white + $orange + $bold_black + $bold_red + $bold_green + $bold_yellow + $bold_blue + $bold_purple + $bold_cyan + $bold_white + $bold_orange + ) + # Uncomment these to allow underlines: + #$underline_black + #$underline_red + #$underline_green + #$underline_yellow + #$underline_blue + #$underline_purple + #$underline_cyan + #$underline_white + #$underline_orange + #) + + USERNAME_COLOR=${AVAILABLE_COLORS[$RANDOM % ${#AVAILABLE_COLORS[@]} ]} + HOSTNAME_COLOR=${AVAILABLE_COLORS[$RANDOM % ${#AVAILABLE_COLORS[@]} ]} + TIME_COLOR=${AVAILABLE_COLORS[$RANDOM % ${#AVAILABLE_COLORS[@]} ]} + PATH_COLOR=${AVAILABLE_COLORS[$RANDOM % ${#AVAILABLE_COLORS[@]} ]} + + echo "$USERNAME_COLOR,$HOSTNAME_COLOR,$TIME_COLOR,$PATH_COLOR," > $RANDOM_COLOR_FILE +} + +if [ -f $RANDOM_COLOR_FILE ]; +then + # read the colors already stored in the file + IFS=',' read -ra COLORS < $RANDOM_COLOR_FILE + USERNAME_COLOR=${COLORS[0]} + HOSTNAME_COLOR=${COLORS[1]} + TIME_COLOR=${COLORS[2]} + PATH_COLOR=${COLORS[3]} +else + # No colors stored yet. Generate them! + randomize_nwinkler + + echo + echo "Looks like you are using the nwinkler_random_color bashit theme for the first time." + echo "Random colors have been generated to be used in your prompt." + echo "If you don't like them, run the command:" + echo " randomize_nwinkler" + echo "until you get a combination that you like." + echo +fi + +PROMPT_END_CLEAN="${green}→${reset_color}" +PROMPT_END_DIRTY="${red}→${reset_color}" + +function prompt_end() { + echo -e "$PROMPT_END" +} + +prompt_setter() { + local exit_status=$? + if [[ $exit_status -eq 0 ]]; then PROMPT_END=$PROMPT_END_CLEAN + else PROMPT_END=$PROMPT_END_DIRTY + fi + # Save history + history -a + history -c + history -r + PS1="(${TIME_COLOR}\t${reset_color}) $(scm_char) [${USERNAME_COLOR}\u${reset_color}@${HOSTNAME_COLOR}\H${reset_color}] ${PATH_COLOR}\w${reset_color}$(scm_prompt_info) ${reset_color}\n$(prompt_end) " + PS2='> ' + PS4='+ ' +} + +PROMPT_COMMAND=prompt_setter + +SCM_THEME_PROMPT_DIRTY=" ${bold_red}✗${normal}" +SCM_THEME_PROMPT_CLEAN=" ${bold_green}✓${normal}" +SCM_THEME_PROMPT_PREFIX=" (" +SCM_THEME_PROMPT_SUFFIX=")" +RVM_THEME_PROMPT_PREFIX=" (" +RVM_THEME_PROMPT_SUFFIX=")" diff --git a/themes/nwinkler_random_colors/screenshot.png b/themes/nwinkler_random_colors/screenshot.png new file mode 100644 index 00000000..e8cc75d8 Binary files /dev/null and b/themes/nwinkler_random_colors/screenshot.png differ diff --git a/themes/powerline-multiline/README.md b/themes/powerline-multiline/README.md new file mode 100644 index 00000000..8f353ac6 --- /dev/null +++ b/themes/powerline-multiline/README.md @@ -0,0 +1,58 @@ +# Powerline Multiline Theme + +A colorful multiline theme, where the first line shows information about your shell session (divided into two parts, left and right), and the second one is where the shell commands are introduced. + +**IMPORTANT:** This theme requires that [a font with the Powerline symbols](https://github.com/powerline/fonts) needs to be used in your terminal emulator, otherwise the prompt won't be displayed correctly, i.e. some of the additional icons and characters will be missing. Please follow your operating system's instructions to install one of the fonts from the above link and select it in your terminal emulator. + +## Provided Information + +* Current path +* Current username and hostname +* An indicator when connected by SSH +* An indicator when `sudo` has the credentials cached (see the `sudo` manpage for more info about this) +* An indicator when the current shell is inside the Vim editor +* Battery charging status (depends on the [../../plugins/available/battery.plugin.bash](battery plugin)) +* SCM Repository status (e.g. Git, SVN) +* The current Python environment (Virtualenv, venv, and Conda are supported) in use +* The current Ruby environment (RVM) in use +* Last command exit code (only shown when the exit code is greater than 0) + +## Configuration + +This theme is pretty configurable, all the configuration is done by setting environment variables. + +### User Information + +By default, the username and hostname are shown on the right hand side, but you can change this behavior by setting the value of the following variable: + + POWERLINE_PROMPT_USER_INFO_MODE="sudo" + +For now, the only supported value is `sudo`, which hides the username and hostname, and shows an indicator when `sudo` has the credentials cached. Other values have no effect at this time. + +### Clock Format + +By default, the current time is shown on the right hand side, you can change the format using the following variable: + + POWERLINE_PROMPT_CLOCK_FORMAT="%H:%M:%S" + +The time/date is printed by the `date` command, so refer to its man page to change the format. + +### Segment Order + +The contents of both prompt sides can be "reordered", all the "segments" (every piece of information) can take any place. The currently available segments are: + +* battery +* clock +* cwd +* in_vim +* python_venv +* rvm +* scm +* user_info + +Two variables can be defined to set the order of the prompt segments: + + POWERLINE_LEFT_PROMPT="scm python_venv rvm cwd" + POWERLINE_RIGHT_PROMPT="in_vim clock battery user_info" + +The example values above are the current default values, but if you want to remove anything from the prompt, simply remove the "string" that represents the segment from the corresponding variable. diff --git a/themes/powerline-multiline/powerline-multiline.theme.bash b/themes/powerline-multiline/powerline-multiline.theme.bash index 66f57241..c4833756 100644 --- a/themes/powerline-multiline/powerline-multiline.theme.bash +++ b/themes/powerline-multiline/powerline-multiline.theme.bash @@ -1,15 +1,12 @@ #!/usr/bin/env bash -THEME_PROMPT_SEPARATOR="" -THEME_PROMPT_LEFT_SEPARATOR="" +USER_INFO_SSH_CHAR=${POWERLINE_USER_INFO_SSH_CHAR:=" "} +USER_INFO_THEME_PROMPT_COLOR=32 +USER_INFO_THEME_PROMPT_COLOR_SUDO=202 -SHELL_SSH_CHAR=${SHELL_SSH_CHAR:=" "} -SHELL_THEME_PROMPT_COLOR=32 -SHELL_THEME_PROMPT_COLOR_SUDO=202 - -VIRTUALENV_CHAR=${POWERLINE_VIRTUALENV_CHAR:="❲p❳ "} -CONDA_VIRTUALENV_CHAR=${POWERLINE_CONDA_VIRTUALENV_CHAR:="❲c❳ "} -VIRTUALENV_THEME_PROMPT_COLOR=35 +PYTHON_VENV_CHAR=${POWERLINE_PYTHON_VENV_CHAR:="❲p❳ "} +CONDA_PYTHON_VENV_CHAR=${POWERLINE_CONDA_PYTHON_VENV_CHAR:="❲c❳ "} +PYTHON_VENV_THEME_PROMPT_COLOR=35 SCM_NONE_CHAR="" SCM_GIT_CHAR=${POWERLINE_SCM_GIT_CHAR:=" "} @@ -26,8 +23,11 @@ SCM_THEME_PROMPT_COLOR=${SCM_THEME_PROMPT_CLEAN_COLOR} RVM_THEME_PROMPT_PREFIX="" RVM_THEME_PROMPT_SUFFIX="" -RVM_THEME_PROMPT_COLOR=161 -RVM_CHAR=${POWERLINE_RVM_CHAR:="❲r❳ "} +RBENV_THEME_PROMPT_PREFIX="" +RBENV_THEME_PROMPT_SUFFIX="" + +RUBY_THEME_PROMPT_COLOR=161 +RUBY_CHAR=${POWERLINE_RUBY_CHAR:="❲r❳"} CWD_THEME_PROMPT_COLOR=240 @@ -35,188 +35,209 @@ LAST_STATUS_THEME_PROMPT_COLOR=196 CLOCK_THEME_PROMPT_COLOR=240 -BATTERY_AC_CHAR="⚡" +BATTERY_AC_CHAR=${BATTERY_AC_CHAR:="⚡"} BATTERY_STATUS_THEME_PROMPT_GOOD_COLOR=70 BATTERY_STATUS_THEME_PROMPT_LOW_COLOR=208 BATTERY_STATUS_THEME_PROMPT_CRITICAL_COLOR=160 -THEME_PROMPT_CLOCK_FORMAT=${THEME_PROMPT_CLOCK_FORMAT:="%H:%M:%S"} +THEME_PROMPT_CLOCK_FORMAT=${POWERLINE_PROMPT_CLOCK_FORMAT:="%H:%M:%S"} + +IN_VIM_THEME_PROMPT_COLOR=245 +IN_VIM_THEME_PROMPT_TEXT="vim" + +POWERLINE_LEFT_PROMPT=${POWERLINE_LEFT_PROMPT:="scm python_venv ruby cwd"} +POWERLINE_RIGHT_PROMPT=${POWERLINE_RIGHT_PROMPT:="in_vim clock battery user_info"} function set_rgb_color { - if [[ "${1}" != "-" ]]; then - fg="38;5;${1}" - fi - if [[ "${2}" != "-" ]]; then - bg="48;5;${2}" - [[ -n "${fg}" ]] && bg=";${bg}" - fi - echo -e "\[\033[${fg}${bg}m\]" + if [[ "${1}" != "-" ]]; then + fg="38;5;${1}" + fi + if [[ "${2}" != "-" ]]; then + bg="48;5;${2}" + [[ -n "${fg}" ]] && bg=";${bg}" + fi + echo -e "\[\033[${fg}${bg}m\]" } -function powerline_shell_prompt { - SHELL_PROMPT_COLOR=${SHELL_THEME_PROMPT_COLOR} - if sudo -n uptime 2>&1 | grep -q "load"; then - SHELL_PROMPT_COLOR=${SHELL_THEME_PROMPT_COLOR_SUDO} - fi - SEGMENT_AT_RIGHT=0 - if [[ -n "${SSH_CLIENT}" ]]; then - SHELL_PROMPT="${SHELL_SSH_CHAR}${USER}@${HOSTNAME}" +function __powerline_user_info_prompt { + local user_info="" + local color=${USER_INFO_THEME_PROMPT_COLOR} + + if sudo -n uptime 2>&1 | grep -q "load"; then + color=${USER_INFO_THEME_PROMPT_COLOR_SUDO} + fi + case "${POWERLINE_PROMPT_USER_INFO_MODE}" in + "sudo") + if [[ "${color}" == "${USER_INFO_THEME_PROMPT_COLOR_SUDO}" ]]; then + user_info="!" + fi + ;; + *) + if [[ -n "${SSH_CLIENT}" ]]; then + user_info="${USER_INFO_SSH_CHAR}${USER}@${HOSTNAME}" + else + user_info="${USER}" + fi + ;; + esac + [[ -n "${user_info}" ]] && echo "${user_info}|${color}" +} + +function __powerline_ruby_prompt { + local ruby_version="" + + if command_exists rvm; then + ruby_version="$(rvm_version_prompt)" + elif command_exists rbenv; then + ruby_version=$(rbenv_version_prompt) + fi + + [[ -n "${ruby_version}" ]] && echo "${RUBY_CHAR}${ruby_version}|${RUBY_THEME_PROMPT_COLOR}" +} + +function __powerline_python_venv_prompt { + local python_venv="" + + if [[ -n "${CONDA_DEFAULT_ENV}" ]]; then + python_venv="${CONDA_DEFAULT_ENV}" + PYTHON_VENV_CHAR=${CONDA_PYTHON_VENV_CHAR} + elif [[ -n "${VIRTUAL_ENV}" ]]; then + python_venv=$(basename "${VIRTUAL_ENV}") + fi + + [[ -n "${python_venv}" ]] && echo "${PYTHON_VENV_CHAR}${python_venv}|${PYTHON_VENV_THEME_PROMPT_COLOR}" +} + +function __powerline_scm_prompt { + local color="" + local scm_prompt="" + + scm_prompt_vars + + if [[ "${SCM_NONE_CHAR}" != "${SCM_CHAR}" ]]; then + if [[ "${SCM_DIRTY}" -eq 3 ]]; then + color=${SCM_THEME_PROMPT_STAGED_COLOR} + elif [[ "${SCM_DIRTY}" -eq 2 ]]; then + color=${SCM_THEME_PROMPT_UNSTAGED_COLOR} + elif [[ "${SCM_DIRTY}" -eq 1 ]]; then + color=${SCM_THEME_PROMPT_DIRTY_COLOR} else - SHELL_PROMPT="${USER}" + color=${SCM_THEME_PROMPT_CLEAN_COLOR} fi - RIGHT_PROMPT_LENGTH=$(( ${RIGHT_PROMPT_LENGTH} + ${#SHELL_PROMPT} + 2 )) - SHELL_PROMPT="$(set_rgb_color - ${SHELL_PROMPT_COLOR}) ${SHELL_PROMPT} ${normal}" - LAST_THEME_COLOR=${SHELL_PROMPT_COLOR} - (( SEGMENT_AT_RIGHT += 1 )) + if [[ "${SCM_GIT_CHAR}" == "${SCM_CHAR}" ]]; then + scm_prompt+="${SCM_CHAR}${SCM_BRANCH}${SCM_STATE}" + fi + echo "${scm_prompt}${scm}|${color}" + fi } -function powerline_rvm_prompt { - local environ="" - - if command_exists rvm; then - rvm_prompt=$(rvm_version_prompt) - if [[ "${rvm_prompt}" != $(rvm strings default) ]]; then - RVM_PROMPT="$(set_rgb_color - ${RVM_THEME_PROMPT_COLOR}) ${RVM_CHAR}${rvm_prompt} ${normal}" - if [[ "${SEGMENT_AT_LEFT}" -gt 0 ]]; then - RVM_PROMPT=$(set_rgb_color ${LAST_THEME_COLOR} ${RVM_THEME_PROMPT_COLOR})${THEME_PROMPT_SEPARATOR}${normal}${RVM_PROMPT} - fi - LAST_THEME_COLOR=${RVM_THEME_PROMPT_COLOR} - (( SEGMENT_AT_LEFT += 1 )) - else - RVM_PROMPT="" - fi - fi +function __powerline_cwd_prompt { + echo "$(pwd | sed "s|^${HOME}|~|")|${CWD_THEME_PROMPT_COLOR}" } -function powerline_virtualenv_prompt { - local environ="" +function __powerline_clock_prompt { + echo "$(date +"${THEME_PROMPT_CLOCK_FORMAT}")|${CLOCK_THEME_PROMPT_COLOR}" +} - if [[ -n "$CONDA_DEFAULT_ENV" ]]; then - environ="$CONDA_DEFAULT_ENV" - VIRTUALENV_CHAR=${CONDA_VIRTUALENV_CHAR} - elif [[ -n "$VIRTUAL_ENV" ]]; then - environ=$(basename "$VIRTUAL_ENV") - fi +function __powerline_battery_prompt { + local color="" + local battery_status="$(battery_percentage 2> /dev/null)" - if [[ -n "$environ" ]]; then - VIRTUALENV_PROMPT="$(set_rgb_color - ${VIRTUALENV_THEME_PROMPT_COLOR}) ${VIRTUALENV_CHAR}$environ ${normal}" - if [[ "${SEGMENT_AT_LEFT}" -gt 0 ]]; then - VIRTUALENV_PROMPT=$(set_rgb_color ${LAST_THEME_COLOR} ${VIRTUALENV_THEME_PROMPT_COLOR})${THEME_PROMPT_SEPARATOR}${normal}${VIRTUALENV_PROMPT} - fi - LAST_THEME_COLOR=${VIRTUALENV_THEME_PROMPT_COLOR} - (( SEGMENT_AT_LEFT += 1 )) + if [[ -z "${battery_status}" ]] || [[ "${battery_status}" = "-1" ]] || [[ "${battery_status}" = "no" ]]; then + true + else + if [[ "$((10#${battery_status}))" -le 5 ]]; then + color="${BATTERY_STATUS_THEME_PROMPT_CRITICAL_COLOR}" + elif [[ "$((10#${battery_status}))" -le 25 ]]; then + color="${BATTERY_STATUS_THEME_PROMPT_LOW_COLOR}" else - VIRTUALENV_PROMPT="" + color="${BATTERY_STATUS_THEME_PROMPT_GOOD_COLOR}" fi + ac_adapter_connected && battery_status="${BATTERY_AC_CHAR}${battery_status}" + echo "${battery_status}%|${color}" + fi } -function powerline_scm_prompt { - scm_prompt_vars - if [[ "${SCM_NONE_CHAR}" != "${SCM_CHAR}" ]]; then - if [[ "${SCM_DIRTY}" -eq 3 ]]; then - SCM_THEME_PROMPT_COLOR=${SCM_THEME_PROMPT_STAGED_COLOR} - elif [[ "${SCM_DIRTY}" -eq 2 ]]; then - SCM_THEME_PROMPT_COLOR=${SCM_THEME_PROMPT_UNSTAGED_COLOR} - elif [[ "${SCM_DIRTY}" -eq 1 ]]; then - SCM_THEME_PROMPT_COLOR=${SCM_THEME_PROMPT_DIRTY_COLOR} - else - SCM_THEME_PROMPT_COLOR=${SCM_THEME_PROMPT_CLEAN_COLOR} - fi - if [[ "${SCM_GIT_CHAR}" == "${SCM_CHAR}" ]]; then - SCM_PROMPT=" ${SCM_CHAR}${SCM_BRANCH}${SCM_STATE}" - fi - SCM_PROMPT="$(set_rgb_color - ${SCM_THEME_PROMPT_COLOR})${SCM_PROMPT} ${normal}" - LAST_THEME_COLOR=${SCM_THEME_PROMPT_COLOR} - (( SEGMENT_AT_LEFT += 1 )) - else - SCM_PROMPT="" - fi +function __powerline_in_vim_prompt { + if [ -n "$VIMRUNTIME" ]; then + echo "${IN_VIM_THEME_PROMPT_TEXT}|${IN_VIM_THEME_PROMPT_COLOR}" + fi } -function powerline_cwd_prompt { - CWD_PROMPT="$(set_rgb_color - ${CWD_THEME_PROMPT_COLOR}) \w ${normal}$(set_rgb_color ${CWD_THEME_PROMPT_COLOR} -)${normal}$(set_rgb_color ${CWD_THEME_PROMPT_COLOR} -)${THEME_PROMPT_SEPARATOR}${normal}" - if [[ "${SEGMENT_AT_LEFT}" -gt 0 ]]; then - CWD_PROMPT=$(set_rgb_color ${LAST_THEME_COLOR} ${CWD_THEME_PROMPT_COLOR})${THEME_PROMPT_SEPARATOR}${normal}${CWD_PROMPT} - SEGMENT_AT_LEFT=0 - fi - LAST_THEME_COLOR=${CWD_THEME_PROMPT_COLOR} +function __powerline_last_status_prompt { + [[ "$1" -ne 0 ]] && echo "$(set_rgb_color ${LAST_STATUS_THEME_PROMPT_COLOR} -) ${1} ${normal}" } -function powerline_last_status_prompt { - if [[ "$1" -eq 0 ]]; then - LAST_STATUS_PROMPT="" - else - LAST_STATUS_PROMPT="$(set_rgb_color ${LAST_STATUS_THEME_PROMPT_COLOR} -) ${LAST_STATUS} ${normal}" - fi +function __powerline_left_segment { + local OLD_IFS="${IFS}"; IFS="|" + local params=( $1 ) + IFS="${OLD_IFS}" + local separator_char="" + local separator="" + + if [[ "${SEGMENTS_AT_LEFT}" -gt 0 ]]; then + separator="$(set_rgb_color ${LAST_SEGMENT_COLOR} ${params[1]})${separator_char}${normal}${normal}" + fi + LEFT_PROMPT+="${separator}$(set_rgb_color - ${params[1]}) ${params[0]} ${normal}" + LAST_SEGMENT_COLOR=${params[1]} + (( SEGMENTS_AT_LEFT += 1 )) } -function powerline_clock_prompt { - if [[ -z "${THEME_PROMPT_CLOCK_FORMAT}" ]]; then - CLOCK_PROMPT="" - else - local CLOCK=" $(date +"${THEME_PROMPT_CLOCK_FORMAT}") " +function __powerline_right_segment { + local OLD_IFS="${IFS}"; IFS="|" + local params=( $1 ) + IFS="${OLD_IFS}" + local separator_char="" + local padding=2 + local separator_color="" - CLOCK_PROMPT=$(set_rgb_color - ${CLOCK_THEME_PROMPT_COLOR})${CLOCK}${normal} - if [[ "${SEGMENT_AT_RIGHT}" -gt 0 ]]; then - CLOCK_PROMPT+=$(set_rgb_color ${LAST_THEME_COLOR} ${CLOCK_THEME_PROMPT_COLOR})${THEME_PROMPT_LEFT_SEPARATOR}${normal} - (( RIGHT_PROMPT_LENGTH += SEGMENT_AT_RIGHT - 1 )) - fi - RIGHT_PROMPT_LENGTH=$(( ${RIGHT_PROMPT_LENGTH} + ${#CLOCK} )) - LAST_THEME_COLOR=${CLOCK_THEME_PROMPT_COLOR} - (( SEGMENT_AT_RIGHT += 1 )) - fi + if [[ "${SEGMENTS_AT_RIGHT}" -eq 0 ]]; then + separator_color="$(set_rgb_color ${params[1]} -)" + else + separator_color="$(set_rgb_color ${params[1]} ${LAST_SEGMENT_COLOR})" + (( padding += 1 )) + fi + RIGHT_PROMPT+="${separator_color}${separator_char}${normal}$(set_rgb_color - ${params[1]}) ${params[0]} ${normal}$(set_rgb_color - ${COLOR})${normal}" + RIGHT_PROMPT_LENGTH=$(( ${#params[0]} + RIGHT_PROMPT_LENGTH + padding )) + LAST_SEGMENT_COLOR="${params[1]}" + (( SEGMENTS_AT_RIGHT += 1 )) } -function powerline_battery_status_prompt { - BATTERY_STATUS="$(battery_percentage 2> /dev/null)" - if [[ -z "${BATTERY_STATUS}" ]] || [[ "${BATTERY_STATUS}" = "-1" ]] || [[ "${BATTERY_STATUS}" = "no" ]]; then - BATTERY_PROMPT="" - else - if [[ "$((10#${BATTERY_STATUS}))" -le 5 ]]; then - BATTERY_STATUS_THEME_PROMPT_COLOR="${BATTERY_STATUS_THEME_PROMPT_CRITICAL_COLOR}" - elif [[ "$((10#${BATTERY_STATUS}))" -le 25 ]]; then - BATTERY_STATUS_THEME_PROMPT_COLOR="${BATTERY_STATUS_THEME_PROMPT_LOW_COLOR}" - else - BATTERY_STATUS_THEME_PROMPT_COLOR="${BATTERY_STATUS_THEME_PROMPT_GOOD_COLOR}" - fi - [[ "$(ac_adapter_connected)" ]] && BATTERY_STATUS="${BATTERY_AC_CHAR}${BATTERY_STATUS}" - BATTERY_PROMPT="$(set_rgb_color - ${BATTERY_STATUS_THEME_PROMPT_COLOR}) ${BATTERY_STATUS}% " - if [[ "${SEGMENT_AT_RIGHT}" -gt 0 ]]; then - BATTERY_PROMPT+=$(set_rgb_color ${LAST_THEME_COLOR} ${BATTERY_STATUS_THEME_PROMPT_COLOR})${THEME_PROMPT_LEFT_SEPARATOR}${normal} - (( RIGHT_PROMPT_LENGTH += SEGMENT_AT_RIGHT )) - fi - RIGHT_PROMPT_LENGTH=$(( ${RIGHT_PROMPT_LENGTH} + ${#BATTERY_STATUS} + 2 )) - LAST_THEME_COLOR=${BATTERY_STATUS_THEME_PROMPT_COLOR} - (( SEGMENT_AT_RIGHT += 1 )) - fi +function __powerline_prompt_command { + local last_status="$?" ## always the first + local separator_char="" + local move_cursor_rightmost='\033[500C' + + LEFT_PROMPT="" + RIGHT_PROMPT="" + RIGHT_PROMPT_LENGTH=0 + SEGMENTS_AT_LEFT=0 + SEGMENTS_AT_RIGHT=0 + LAST_SEGMENT_COLOR="" + + ## left prompt ## + for segment in $POWERLINE_LEFT_PROMPT; do + local info="$(__powerline_${segment}_prompt)" + [[ -n "${info}" ]] && __powerline_left_segment "${info}" + done + [[ -n "${LEFT_PROMPT}" ]] && LEFT_PROMPT+="$(set_rgb_color ${LAST_SEGMENT_COLOR} -)${separator_char}${normal}" + + ## right prompt ## + if [[ -n "${POWERLINE_RIGHT_PROMPT}" ]]; then + LEFT_PROMPT+="${move_cursor_rightmost}" + for segment in $POWERLINE_RIGHT_PROMPT; do + local info="$(__powerline_${segment}_prompt)" + [[ -n "${info}" ]] && __powerline_right_segment "${info}" + done + LEFT_PROMPT+="\033[${RIGHT_PROMPT_LENGTH}D" + fi + + PS1="${LEFT_PROMPT}${RIGHT_PROMPT}\n$(__powerline_last_status_prompt ${last_status})${PROMPT_CHAR} " + + ## cleanup ## + unset LAST_SEGMENT_COLOR \ + LEFT_PROMPT RIGHT_PROMPT RIGHT_PROMPT_LENGTH \ + SEGMENTS_AT_LEFT SEGMENTS_AT_RIGHT } -function powerline_prompt_command() { - local LAST_STATUS="$?" - local MOVE_CURSOR_RIGHTMOST='\033[500C' - RIGHT_PROMPT_LENGTH=1 - - ## left prompt ## - powerline_scm_prompt - powerline_virtualenv_prompt - powerline_rvm_prompt - powerline_cwd_prompt - powerline_last_status_prompt LAST_STATUS - - LEFT_PROMPT="${SCM_PROMPT}${VIRTUALENV_PROMPT}${RVM_PROMPT}${CWD_PROMPT}${MOVE_CURSOR_RIGHTMOST}" - - ## right prompt ## - LAST_THEME_COLOR="-" - powerline_shell_prompt - powerline_battery_status_prompt - powerline_clock_prompt - - [[ "${SEGMENT_AT_RIGHT}" -eq 1 ]] && (( RIGHT_PROMPT_LENGTH-=1 )) - - RIGHT_PROMPT="\033[${RIGHT_PROMPT_LENGTH}D$(set_rgb_color ${LAST_THEME_COLOR} -)${THEME_PROMPT_LEFT_SEPARATOR}${normal}" - RIGHT_PROMPT+="${CLOCK_PROMPT}${BATTERY_PROMPT}${SHELL_PROMPT}${normal}" - - PS1="${LEFT_PROMPT}${RIGHT_PROMPT}\n${LAST_STATUS_PROMPT}${PROMPT_CHAR} " -} - -PROMPT_COMMAND=powerline_prompt_command +PROMPT_COMMAND=__powerline_prompt_command diff --git a/themes/powerline-plain/powerline-plain.theme.bash b/themes/powerline-plain/powerline-plain.theme.bash index dbe0f7c2..5c3ca826 100644 --- a/themes/powerline-plain/powerline-plain.theme.bash +++ b/themes/powerline-plain/powerline-plain.theme.bash @@ -5,7 +5,10 @@ SHELL_THEME_PROMPT_COLOR=32 SHELL_SSH_THEME_PROMPT_COLOR=208 VIRTUALENV_CHAR="ⓔ " -VIRTUALENV_THEME_PROMPT_COLOR=35 +VIRTUALENV_THEME_PROMPT_COLOR=25 + +GEMSET_CHAR="ⓔ " +GEMSET_THEME_PROMPT_COLOR=25 SCM_NONE_CHAR="" SCM_GIT_CHAR="⎇ " @@ -59,6 +62,17 @@ function powerline_virtualenv_prompt { fi } +function powerline_gemset_prompt { + local gemset=$(rvm-prompt 2>/dev/null) + + if [[ -n "$gemset" ]]; then + GEMSET_PROMPT="$(set_rgb_color ${LAST_THEME_COLOR} ${GEMSET_THEME_PROMPT_COLOR})${THEME_PROMPT_SEPARATOR}${normal}$(set_rgb_color - ${GEMSET_THEME_PROMPT_COLOR}) ${VIRTUALENV_CHAR}$gemset ${normal}" + LAST_THEME_COLOR=${GEMSET_THEME_PROMPT_COLOR} + else + GEMSET_PROMPT="" + fi +} + function powerline_scm_prompt { scm_prompt_vars @@ -98,11 +112,12 @@ function powerline_prompt_command() { powerline_shell_prompt powerline_virtualenv_prompt + powerline_gemset_prompt powerline_scm_prompt powerline_cwd_prompt powerline_last_status_prompt LAST_STATUS - PS1="${SHELL_PROMPT}${VIRTUALENV_PROMPT}${SCM_PROMPT}${CWD_PROMPT}${LAST_STATUS_PROMPT} " + PS1="${SHELL_PROMPT}${GEMSET_PROMPT}${VIRTUALENV_PROMPT}${SCM_PROMPT}${CWD_PROMPT}${LAST_STATUS_PROMPT} " } PROMPT_COMMAND=powerline_prompt_command diff --git a/themes/powerline/powerline.theme.bash b/themes/powerline/powerline.theme.bash index 944414db..f486eedf 100644 --- a/themes/powerline/powerline.theme.bash +++ b/themes/powerline/powerline.theme.bash @@ -25,6 +25,10 @@ CWD_THEME_PROMPT_COLOR=240 LAST_STATUS_THEME_PROMPT_COLOR=52 +IN_VIM_PROMPT_COLOR=35 +IN_VIM_PROMPT_TEXT="vim" + + function set_rgb_color { if [[ "${1}" != "-" ]]; then fg="38;5;${1}" @@ -103,16 +107,26 @@ function powerline_last_status_prompt { fi } +function powerline_in_vim_prompt { + if [ -z "$VIMRUNTIME" ]; then + IN_VIM_PROMPT="" + else + IN_VIM_PROMPT="$(set_rgb_color ${LAST_THEME_COLOR} ${IN_VIM_PROMPT_COLOR})${THEME_PROMPT_SEPARATOR}${normal}$(set_rgb_color - ${IN_VIM_PROMPT_COLOR}) ${IN_VIM_PROMPT_TEXT} ${normal}$(set_rgb_color ${IN_VIM_PROMPT_COLOR} -)${normal}" + LAST_THEME_COLOR=${IN_VIM_PROMPT_COLOR} + fi +} + function powerline_prompt_command() { local LAST_STATUS="$?" powerline_shell_prompt + powerline_in_vim_prompt powerline_virtualenv_prompt powerline_scm_prompt powerline_cwd_prompt powerline_last_status_prompt LAST_STATUS - PS1="${SHELL_PROMPT}${VIRTUALENV_PROMPT}${SCM_PROMPT}${CWD_PROMPT}${LAST_STATUS_PROMPT} " + PS1="${SHELL_PROMPT}${IN_VIM_PROMPT}${VIRTUALENV_PROMPT}${SCM_PROMPT}${CWD_PROMPT}${LAST_STATUS_PROMPT} " } PROMPT_COMMAND=powerline_prompt_command diff --git a/themes/primer/primer.theme.bash b/themes/primer/primer.theme.bash new file mode 100644 index 00000000..0b01088e --- /dev/null +++ b/themes/primer/primer.theme.bash @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +# based of the candy theme, but minimized by odbol +function prompt_command() { + PS1="${blue}\T ${reset_color}${white}\w${reset_color}$(scm_prompt_info)${blue} →${bold_blue} ${reset_color} "; +} + +PROMPT_COMMAND=prompt_command; \ No newline at end of file diff --git a/themes/pro/pro.theme.bash b/themes/pro/pro.theme.bash new file mode 100644 index 00000000..6ac697bf --- /dev/null +++ b/themes/pro/pro.theme.bash @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +SCM_THEME_PROMPT_DIRTY=" ${red}✗" +SCM_THEME_PROMPT_CLEAN=" ${green}✓" +SCM_THEME_PROMPT_PREFIX=" ${blue}scm:( " +SCM_THEME_PROMPT_SUFFIX="${blue} )" + +GIT_THEME_PROMPT_DIRTY=" ${red}✗" +GIT_THEME_PROMPT_CLEAN=" ${green}✓" +GIT_THEME_PROMPT_PREFIX="${green}git:( " +GIT_THEME_PROMPT_SUFFIX="${green} )" + +function git_prompt_info { + git_prompt_vars + echo -e "$SCM_PREFIX$SCM_BRANCH$SCM_STATE$SCM_SUFFIX" +} + +function prompt() { + PS1="\h: \W $(scm_prompt_info)${reset_color} $ " +} + +PROMPT_COMMAND=prompt diff --git a/themes/simple/simple.theme.bash b/themes/simple/simple.theme.bash index 39e16a1c..8b897ddc 100644 --- a/themes/simple/simple.theme.bash +++ b/themes/simple/simple.theme.bash @@ -11,11 +11,15 @@ case $TERM in TITLEBAR="" ;; esac -PROMPT="${TITLEBAR}${orange}${reset_color}${green}\w${bold_blue}\[\$(scm_prompt_info)\]${reset_color} " +function prompt_command() { + PS1="${TITLEBAR}${orange}${reset_color}${green}\w${bold_blue}\[\$(scm_prompt_info)\]${reset_color} " +} # scm themeing SCM_THEME_PROMPT_DIRTY=" ✗" SCM_THEME_PROMPT_CLEAN=" ✓" SCM_THEME_PROMPT_PREFIX="(" SCM_THEME_PROMPT_SUFFIX=")" + +PROMPT_COMMAND=prompt_command; diff --git a/themes/zork/zork.theme.bash b/themes/zork/zork.theme.bash index c71f1344..c022a408 100644 --- a/themes/zork/zork.theme.bash +++ b/themes/zork/zork.theme.bash @@ -46,27 +46,45 @@ modern_scm_prompt() { fi } +# show chroot if exist +chroot(){ + if [ -n "$debian_chroot" ] + then + my_ps_chroot="${bold_cyan}$debian_chroot${normal}"; + echo "($my_ps_chroot)"; + fi + } + +# show virtualenvwrapper +my_ve(){ + if [ -n "$VIRTUAL_ENV" ] + then + my_ps_ve="${bold_purple}$ve${normal}"; + echo "($my_ps_ve)"; + fi + echo ""; + } + prompt() { - case $HOSTNAME in - "zork"* ) my_ps_host="${green}\h${normal}"; - ;; - "pandora") my_ps_host="${red}\h${normal}"; - ;; - * ) my_ps_host="${green}\h${normal}"; - ;; - esac + my_ps_host="${green}\h${normal}"; + # yes, these are the the same for now ... + my_ps_host_root="${green}\h${normal}"; + + my_ps_user="${bold_green}\u${normal}" + my_ps_root="${bold_red}\u${normal}"; - my_ps_user="\[\033[01;32m\]\u\[\033[00m\]"; - my_ps_root="\[\033[01;31m\]\u\[\033[00m\]"; - my_ps_path="\[\033[01;36m\]\w\[\033[00m\]"; + if [ -n "$VIRTUAL_ENV" ] + then + ve=`basename $VIRTUAL_ENV`; + fi # nice prompt case "`id -u`" in - 0) PS1="${TITLEBAR}┌─[$my_ps_root][$my_ps_host]$(modern_scm_prompt)$(__my_rvm_ruby_version)[${cyan}\w${normal}]$(is_vim_shell) + 0) PS1="${TITLEBAR}┌─$(my_ve)$(chroot)[$my_ps_root][$my_ps_host_root]$(modern_scm_prompt)$(__my_rvm_ruby_version)[${cyan}\w${normal}]$(is_vim_shell) └─▪ " ;; - *) PS1="${TITLEBAR}┌─[$my_ps_user][$my_ps_host]$(modern_scm_prompt)$(__my_rvm_ruby_version)[${cyan}\w${normal}]$(is_vim_shell) + *) PS1="${TITLEBAR}┌─$(my_ve)$(chroot)[$my_ps_user][$my_ps_host]$(modern_scm_prompt)$(__my_rvm_ruby_version)[${cyan}\w${normal}]$(is_vim_shell) └─▪ " ;; esac diff --git a/uninstall.sh b/uninstall.sh old mode 100644 new mode 100755