From 783ab79ab721593b0ac85ab4d8ea9b74fa5fe72e Mon Sep 17 00:00:00 2001
From: Cody Hiar <codyfh@gmail.com>
Date: Mon, 13 Feb 2017 09:54:26 -0700
Subject: Adding tpm

---
 .gitignore                                         |   2 +
 plugins/tpm/.gitattributes                         |   9 +
 plugins/tpm/.gitignore                             |   4 +
 plugins/tpm/.gitmodules                            |   3 +
 plugins/tpm/.travis.yml                            |  19 ++
 plugins/tpm/CHANGELOG.md                           |  83 ++++++
 plugins/tpm/HOW_TO_PLUGIN.md                       |   2 +
 plugins/tpm/LICENSE.md                             |  20 ++
 plugins/tpm/README.md                              | 107 ++++++++
 plugins/tpm/bin/clean_plugins                      |  14 +
 plugins/tpm/bin/install_plugins                    |  14 +
 plugins/tpm/bin/update_plugins                     |  24 ++
 plugins/tpm/bindings/clean_plugins                 |  19 ++
 plugins/tpm/bindings/install_plugins               |  19 ++
 plugins/tpm/bindings/update_plugins                |  49 ++++
 plugins/tpm/docs/automatic_tpm_installation.md     |  12 +
 plugins/tpm/docs/changing_plugins_install_dir.md   |  14 +
 plugins/tpm/docs/how_to_create_plugin.md           | 108 ++++++++
 plugins/tpm/docs/managing_plugins_via_cmd_line.md  |  36 +++
 plugins/tpm/docs/tpm_not_working.md                |  80 ++++++
 plugins/tpm/scripts/check_tmux_version.sh          |  78 ++++++
 plugins/tpm/scripts/clean_plugins.sh               |  41 +++
 plugins/tpm/scripts/helpers/plugin_functions.sh    |  86 +++++++
 .../tpm/scripts/helpers/shell_echo_functions.sh    |   7 +
 plugins/tpm/scripts/helpers/tmux_echo_functions.sh |  28 ++
 plugins/tpm/scripts/helpers/tmux_utils.sh          |   3 +
 plugins/tpm/scripts/helpers/utility.sh             |  17 ++
 plugins/tpm/scripts/install_plugins.sh             |  66 +++++
 plugins/tpm/scripts/source_plugins.sh              |  41 +++
 plugins/tpm/scripts/update_plugin.sh               |  71 ++++++
 .../tpm/scripts/update_plugin_prompt_handler.sh    |  18 ++
 plugins/tpm/scripts/variables.sh                   |  13 +
 plugins/tpm/tests/expect_failed_plugin_download    |  36 +++
 plugins/tpm/tests/expect_successful_clean_plugins  |  35 +++
 .../expect_successful_multiple_plugins_download    |  44 ++++
 .../tpm/tests/expect_successful_plugin_download    |  50 ++++
 .../expect_successful_update_of_a_single_plugin    |  55 ++++
 .../tests/expect_successful_update_of_all_plugins  |  59 +++++
 plugins/tpm/tests/helpers/tpm.sh                   |  13 +
 plugins/tpm/tests/test_plugin_clean.sh             |  67 +++++
 plugins/tpm/tests/test_plugin_installation.sh      | 284 +++++++++++++++++++++
 .../tpm/tests/test_plugin_installation_legacy.sh   | 100 ++++++++
 plugins/tpm/tests/test_plugin_sourcing.sh          |  78 ++++++
 plugins/tpm/tests/test_plugin_update.sh            |  60 +++++
 plugins/tpm/tpm                                    |  72 ++++++
 45 files changed, 2060 insertions(+)
 create mode 100644 plugins/tpm/.gitattributes
 create mode 100644 plugins/tpm/.gitignore
 create mode 100644 plugins/tpm/.gitmodules
 create mode 100644 plugins/tpm/.travis.yml
 create mode 100644 plugins/tpm/CHANGELOG.md
 create mode 100644 plugins/tpm/HOW_TO_PLUGIN.md
 create mode 100644 plugins/tpm/LICENSE.md
 create mode 100644 plugins/tpm/README.md
 create mode 100755 plugins/tpm/bin/clean_plugins
 create mode 100755 plugins/tpm/bin/install_plugins
 create mode 100755 plugins/tpm/bin/update_plugins
 create mode 100755 plugins/tpm/bindings/clean_plugins
 create mode 100755 plugins/tpm/bindings/install_plugins
 create mode 100755 plugins/tpm/bindings/update_plugins
 create mode 100644 plugins/tpm/docs/automatic_tpm_installation.md
 create mode 100644 plugins/tpm/docs/changing_plugins_install_dir.md
 create mode 100644 plugins/tpm/docs/how_to_create_plugin.md
 create mode 100644 plugins/tpm/docs/managing_plugins_via_cmd_line.md
 create mode 100644 plugins/tpm/docs/tpm_not_working.md
 create mode 100755 plugins/tpm/scripts/check_tmux_version.sh
 create mode 100755 plugins/tpm/scripts/clean_plugins.sh
 create mode 100644 plugins/tpm/scripts/helpers/plugin_functions.sh
 create mode 100644 plugins/tpm/scripts/helpers/shell_echo_functions.sh
 create mode 100644 plugins/tpm/scripts/helpers/tmux_echo_functions.sh
 create mode 100644 plugins/tpm/scripts/helpers/tmux_utils.sh
 create mode 100644 plugins/tpm/scripts/helpers/utility.sh
 create mode 100755 plugins/tpm/scripts/install_plugins.sh
 create mode 100755 plugins/tpm/scripts/source_plugins.sh
 create mode 100755 plugins/tpm/scripts/update_plugin.sh
 create mode 100755 plugins/tpm/scripts/update_plugin_prompt_handler.sh
 create mode 100644 plugins/tpm/scripts/variables.sh
 create mode 100755 plugins/tpm/tests/expect_failed_plugin_download
 create mode 100755 plugins/tpm/tests/expect_successful_clean_plugins
 create mode 100755 plugins/tpm/tests/expect_successful_multiple_plugins_download
 create mode 100755 plugins/tpm/tests/expect_successful_plugin_download
 create mode 100755 plugins/tpm/tests/expect_successful_update_of_a_single_plugin
 create mode 100755 plugins/tpm/tests/expect_successful_update_of_all_plugins
 create mode 100644 plugins/tpm/tests/helpers/tpm.sh
 create mode 100755 plugins/tpm/tests/test_plugin_clean.sh
 create mode 100755 plugins/tpm/tests/test_plugin_installation.sh
 create mode 100755 plugins/tpm/tests/test_plugin_installation_legacy.sh
 create mode 100755 plugins/tpm/tests/test_plugin_sourcing.sh
 create mode 100755 plugins/tpm/tests/test_plugin_update.sh
 create mode 100755 plugins/tpm/tpm

diff --git a/.gitignore b/.gitignore
index ce3ed24..e685675 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
 .vimcache
+plugin/*
+!plugin/tpm
diff --git a/plugins/tpm/.gitattributes b/plugins/tpm/.gitattributes
new file mode 100644
index 0000000..80772e4
--- /dev/null
+++ b/plugins/tpm/.gitattributes
@@ -0,0 +1,9 @@
+# Force text files to have unix eols, so Windows/Cygwin does not break them
+*.* eol=lf
+
+# These files are unfortunately not recognized as text files so
+# explicitly listing them here
+tpm eol=lf
+bin/* eol=lf
+bindings/* eol=lf
+tests/* eol=lf
diff --git a/plugins/tpm/.gitignore b/plugins/tpm/.gitignore
new file mode 100644
index 0000000..8a94156
--- /dev/null
+++ b/plugins/tpm/.gitignore
@@ -0,0 +1,4 @@
+**/.vagrant/
+run_tests
+tests/run_tests_in_isolation
+tests/helpers/helpers.sh
diff --git a/plugins/tpm/.gitmodules b/plugins/tpm/.gitmodules
new file mode 100644
index 0000000..5e44e3c
--- /dev/null
+++ b/plugins/tpm/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "lib/tmux-test"]
+	path = lib/tmux-test
+	url = https://github.com/tmux-plugins/tmux-test.git
diff --git a/plugins/tpm/.travis.yml b/plugins/tpm/.travis.yml
new file mode 100644
index 0000000..ac45d8b
--- /dev/null
+++ b/plugins/tpm/.travis.yml
@@ -0,0 +1,19 @@
+# generic packages and tmux
+before_install:
+  - sudo apt-get update
+  - sudo apt-get install -y git-core expect
+  - sudo apt-get install -y python-software-properties software-properties-common
+  - sudo apt-get install -y libevent-dev libncurses-dev
+  - git clone https://github.com/tmux/tmux.git
+  - cd tmux
+  - git checkout 2.0
+  - sh autogen.sh
+  - ./configure && make && sudo make install
+
+install:
+  - git fetch --unshallow --recurse-submodules || git fetch --recurse-submodules
+  # manual `git clone` required for testing `tmux-test` plugin itself
+  - git clone https://github.com/tmux-plugins/tmux-test lib/tmux-test; true
+  - lib/tmux-test/setup
+
+script: ./tests/run_tests_in_isolation
diff --git a/plugins/tpm/CHANGELOG.md b/plugins/tpm/CHANGELOG.md
new file mode 100644
index 0000000..672d3e7
--- /dev/null
+++ b/plugins/tpm/CHANGELOG.md
@@ -0,0 +1,83 @@
+# Changelog
+
+### master
+- upgrade to new version of `tmux-test`
+- bug: when using `emacs` copy mode, Enter does not quit screen after tpm
+  installation/update. Fix by making `Escape` the key for emacs mode.
+- add a doc with troubleshooting instructions
+- add `.gitattributes` file that forces linefeed characters (classic `\n`) as
+  line endings - helps with misconfigured git on windows/cygwin
+- readme update: announce Cygwin support
+- un-deprecate old plugin definition syntax: `set -g @tpm_plugins`
+
+### v3.0.0, 2015-08-03
+- refactor `shared_set_tpm_path_constant` function
+- move all instructions to `docs/` dir
+- add `bin/install_plugins` cli executable script
+- improved test runner function
+- switch to using [tmux-test](https://github.com/tmux-plugins/tmux-test)
+  framework
+- add `bin/update_plugins` cli executable script
+- refactor test `expect` scripts, make them simpler and ensure they properly
+  assert expectations
+- refactor code that sets 'TMUX_PLUGIN_MANAGER_PATH' global env var
+- stop using global variable for 'tpm path'
+- support defining plugins via `set -g @plugin` in sourced files as well
+
+### v2.0.0, 2015-07-07
+- enable overriding default key bindings
+- start using `C-c` to clear screen
+- add uninstall/clean procedure and keybinding (prefix+alt+u) (@chilicuil)
+- add new `set @plugin 'repo'` plugin defintion syntax (@chilicuil)
+- revert back to using `-g` flag in new plugin definition syntax
+- permit leading whitespace with new plugin definition syntax (thanks @chilicuil)
+- make sure `TMUX_PLUGIN_MANAGER_PATH` always has trailng slash
+- ensure old/deprecated plugin syntax `set -g @tpm_plugins` works alongside new
+  `set -g @plugin` syntax
+
+### v1.2.2, 2015-02-08
+- set GIT_TERMINAL_PROMPT=0 when doing `git clone`, `pull` or `submodule update`
+  to ensure git does not prompt for username/password in any case
+
+### v1.2.1, 2014-11-21
+- change the way plugin name is expanded. It now uses the http username
+  and password by default, like this: `https://git::@github.com/`. This prevents
+  username and password prompt (and subsequently tmux install hanging) with old
+  git versions. Fixes #7.
+
+### v1.2.0, 2014-11-20
+- refactor tests so they can be used on travis
+- add travis.yml, add travis badge to the readme
+
+### v1.1.0, 2014-11-19
+- if the plugin is not downloaded do not source it
+- remove `PLUGINS.md`, an obsolete list of plugins
+- update readme with instructions about uninstalling plugins
+- tilde char and `$HOME` in `TMUX_SHARED_MANAGER_PATH` couldn't be used because
+  they are just plain strings. Fixing the problem by manually expanding them.
+- bugfix: fragile `*.tmux` file globbing (@majutsushi)
+
+### v1.0.0, 2014-08-05
+- update readme because of github organization change to
+  [tmux-plugins](https://github.com/tmux-plugins)
+- update tests to pass
+- update README to suggest different first plugin
+- update list of plugins in the README
+- remove README 'about' section
+- move key binding to the main file. Delete `key_binding.sh`.
+- rename `display_message` -> `echo_message`
+- installing plugins installs just new plugins. Already installed plugins aren't
+  updated.
+- add 'update plugin' binding and functionality
+- add test for updating a plugin
+
+### v0.0.2, 2014-07-17
+- run all *.tmux plugin files as executables
+- fix all redirects to /dev/null
+- fix bug: TPM shared path is created before sync (cloning plugins from github
+  is done)
+- add test suite running in Vagrant
+- add Tmux version check. `TPM` won't run if Tmux version is less than 1.9.
+
+### v0.0.1, 2014-05-21
+- get TPM up and running
diff --git a/plugins/tpm/HOW_TO_PLUGIN.md b/plugins/tpm/HOW_TO_PLUGIN.md
new file mode 100644
index 0000000..9901619
--- /dev/null
+++ b/plugins/tpm/HOW_TO_PLUGIN.md
@@ -0,0 +1,2 @@
+Instructions moved to
+[docs/how_to_create_plugin.md](docs/how_to_create_plugin.md).
diff --git a/plugins/tpm/LICENSE.md b/plugins/tpm/LICENSE.md
new file mode 100644
index 0000000..1222865
--- /dev/null
+++ b/plugins/tpm/LICENSE.md
@@ -0,0 +1,20 @@
+MIT license
+Copyright (C) 2014 Bruno Sutic
+
+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.
diff --git a/plugins/tpm/README.md b/plugins/tpm/README.md
new file mode 100644
index 0000000..647fd6f
--- /dev/null
+++ b/plugins/tpm/README.md
@@ -0,0 +1,107 @@
+# Tmux Plugin Manager
+
+[![Build Status](https://travis-ci.org/tmux-plugins/tpm.png?branch=master)](https://travis-ci.org/tmux-plugins/tpm)
+
+Installs and loads TMUX plugins.
+
+Tested and working on Linux, OSX, and Cygwin.
+
+### Installation
+
+Requirements: `tmux` version 1.9 (or higher), `git`, `bash`.
+
+Clone TPM:
+
+    $ git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
+
+Put this at the bottom of `.tmux.conf`:
+
+    # List of plugins
+    set -g @plugin 'tmux-plugins/tpm'
+    set -g @plugin 'tmux-plugins/tmux-sensible'
+
+    # Other examples:
+    # set -g @plugin 'github_username/plugin_name'
+    # set -g @plugin 'git@github.com/user/plugin'
+    # set -g @plugin 'git@bitbucket.com/user/plugin'
+
+    # Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
+    run '~/.tmux/plugins/tpm/tpm'
+
+Reload TMUX environment so TPM is sourced:
+
+    # type this in terminal if tmux is already running
+    $ tmux source ~/.tmux.conf
+
+That's it!
+
+### Installing plugins
+
+1. Add new plugin to `~/.tmux.conf` with `set -g @plugin '...'`
+2. Press `prefix + I` (capital I, as in **I**nstall) to fetch the plugin.
+
+You're good to go! The plugin was cloned to `~/.tmux/plugins/` dir and sourced.
+
+### Uninstalling plugins
+
+1. Remove (or comment out) plugin from the list.
+2. Press `prefix + alt + u` (lowercase u as in **u**ninstall) to remove the plugin.
+
+All the plugins are installed to `~/.tmux/plugins/` so alternatively you can
+find plugin directory there and remove it.
+
+### Key bindings
+
+`prefix + I`
+- Installs new plugins from GitHub or any other git repository
+- Refreshes TMUX environment
+
+`prefix + U`
+- updates plugin(s)
+
+`prefix + alt + u`
+- remove/uninstall plugins not on the plugin list
+
+### More plugins
+
+For more plugins, check [here](https://github.com/tmux-plugins).
+
+### Docs
+
+- [Help, tpm not working](docs/tpm_not_working.md) - problem solutions
+
+More advanced features and instructions, regular users probably do not need
+this:
+
+- [How to create a plugin](docs/how_to_create_plugin.md). It's easy.
+- [Managing plugins via the command line](docs/managing_plugins_via_cmd_line.md)
+- [Changing plugins install dir](docs/changing_plugins_install_dir.md)
+- [Automatic TPM installation on a new machine](docs/automatic_tpm_installation.md)
+
+### Tests
+
+Tests for this project run on [travis](https://travis-ci.org/tmux-plugins/tpm).
+
+When run locally, [vagrant](https://www.vagrantup.com/) is required.
+Run tests with:
+
+    # within project directory
+    $ ./run_tests
+
+### Other goodies
+
+- [tmux-copycat](https://github.com/tmux-plugins/tmux-copycat) - a plugin for
+  regex searches in tmux and fast match selection
+- [tmux-yank](https://github.com/tmux-plugins/tmux-yank) - enables copying
+  highlighted text to system clipboard
+- [tmux-open](https://github.com/tmux-plugins/tmux-open) - a plugin for quickly
+  opening highlighted file or a url
+- [tmux-continuum](https://github.com/tmux-plugins/tmux-continuum) - automatic
+  restoring and continuous saving of tmux env
+
+You might want to follow [@brunosutic](https://twitter.com/brunosutic) on
+twitter if you want to hear about new tmux plugins or feature updates.
+
+### License
+
+[MIT](LICENSE.md)
diff --git a/plugins/tpm/bin/clean_plugins b/plugins/tpm/bin/clean_plugins
new file mode 100755
index 0000000..12f8730
--- /dev/null
+++ b/plugins/tpm/bin/clean_plugins
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+# Script intended for use via the command line.
+#
+# `.tmux.conf` needs to be set for TPM. Tmux has to be installed on the system,
+# but does not need to be started in order to run this script.
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+SCRIPTS_DIR="$CURRENT_DIR/../scripts"
+
+main() {
+	"$SCRIPTS_DIR/clean_plugins.sh" # has correct exit code
+}
+main
diff --git a/plugins/tpm/bin/install_plugins b/plugins/tpm/bin/install_plugins
new file mode 100755
index 0000000..c66b15b
--- /dev/null
+++ b/plugins/tpm/bin/install_plugins
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+# Script intended for use via the command line.
+#
+# `.tmux.conf` needs to be set for TPM. Tmux has to be installed on the system,
+# but does not need to be started in order to run this script.
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+SCRIPTS_DIR="$CURRENT_DIR/../scripts"
+
+main() {
+	"$SCRIPTS_DIR/install_plugins.sh" # has correct exit code
+}
+main
diff --git a/plugins/tpm/bin/update_plugins b/plugins/tpm/bin/update_plugins
new file mode 100755
index 0000000..30a5646
--- /dev/null
+++ b/plugins/tpm/bin/update_plugins
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+# Script intended for use via the command line.
+#
+# `.tmux.conf` needs to be set for TPM. Tmux has to be installed on the system,
+# but does not need to be started in order to run this script.
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+SCRIPTS_DIR="$CURRENT_DIR/../scripts"
+PROGRAM_NAME="$0"
+
+if [ $# -eq 0 ]; then
+	echo "usage:"
+	echo "  $PROGRAM_NAME all                   update all plugins"
+	echo "  $PROGRAM_NAME tmux-foo              update plugin 'tmux-foo'"
+	echo "  $PROGRAM_NAME tmux-bar tmux-baz     update multiple plugins"
+	exit 1
+fi
+
+main() {
+	"$SCRIPTS_DIR/update_plugin.sh" --shell-echo "$*" # has correct exit code
+}
+main "$*"
+
diff --git a/plugins/tpm/bindings/clean_plugins b/plugins/tpm/bindings/clean_plugins
new file mode 100755
index 0000000..9a0d5d7
--- /dev/null
+++ b/plugins/tpm/bindings/clean_plugins
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+# Tmux key-binding script.
+# Scripts intended to be used via the command line are in `bin/` directory.
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+SCRIPTS_DIR="$CURRENT_DIR/../scripts"
+HELPERS_DIR="$SCRIPTS_DIR/helpers"
+
+source "$HELPERS_DIR/tmux_echo_functions.sh"
+source "$HELPERS_DIR/tmux_utils.sh"
+
+main() {
+	reload_tmux_environment
+	"$SCRIPTS_DIR/clean_plugins.sh" --tmux-echo >/dev/null 2>&1
+	reload_tmux_environment
+	end_message
+}
+main
diff --git a/plugins/tpm/bindings/install_plugins b/plugins/tpm/bindings/install_plugins
new file mode 100755
index 0000000..3ade3c4
--- /dev/null
+++ b/plugins/tpm/bindings/install_plugins
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+# Tmux key-binding script.
+# Scripts intended to be used via the command line are in `bin/` directory.
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+SCRIPTS_DIR="$CURRENT_DIR/../scripts"
+HELPERS_DIR="$SCRIPTS_DIR/helpers"
+
+source "$HELPERS_DIR/tmux_echo_functions.sh"
+source "$HELPERS_DIR/tmux_utils.sh"
+
+main() {
+	reload_tmux_environment
+	"$SCRIPTS_DIR/install_plugins.sh" --tmux-echo >/dev/null 2>&1
+	reload_tmux_environment
+	end_message
+}
+main
diff --git a/plugins/tpm/bindings/update_plugins b/plugins/tpm/bindings/update_plugins
new file mode 100755
index 0000000..28cc281
--- /dev/null
+++ b/plugins/tpm/bindings/update_plugins
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+
+# Tmux key-binding script.
+# Scripts intended to be used via the command line are in `bin/` directory.
+
+# This script:
+# - shows a list of installed plugins
+# - starts a prompt to enter the name of the plugin that will be updated
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+SCRIPTS_DIR="$CURRENT_DIR/../scripts"
+HELPERS_DIR="$SCRIPTS_DIR/helpers"
+
+source "$HELPERS_DIR/plugin_functions.sh"
+source "$HELPERS_DIR/tmux_echo_functions.sh"
+source "$HELPERS_DIR/tmux_utils.sh"
+
+display_plugin_update_list() {
+	local plugins="$(tpm_plugins_list_helper)"
+	tmux_echo "Installed plugins:"
+	tmux_echo ""
+
+	for plugin in $plugins; do
+		# displaying only installed plugins
+		if plugin_already_installed "$plugin"; then
+			local plugin_name="$(plugin_name_helper "$plugin")"
+			tmux_echo "  $plugin_name"
+		fi
+	done
+
+	tmux_echo ""
+	tmux_echo "Type plugin name to update it."
+	tmux_echo ""
+	tmux_echo "- \"all\" - updates all plugins"
+	tmux_echo "- ENTER - cancels"
+}
+
+update_plugin_prompt() {
+	tmux command-prompt -p 'plugin update:' " \
+		send-keys C-c; \
+		run-shell '$SCRIPTS_DIR/update_plugin_prompt_handler.sh %1'"
+}
+
+main() {
+	reload_tmux_environment
+	display_plugin_update_list
+	update_plugin_prompt
+}
+main
diff --git a/plugins/tpm/docs/automatic_tpm_installation.md b/plugins/tpm/docs/automatic_tpm_installation.md
new file mode 100644
index 0000000..630573f
--- /dev/null
+++ b/plugins/tpm/docs/automatic_tpm_installation.md
@@ -0,0 +1,12 @@
+# Automatic tpm installation
+
+One of the first things we do on a new machine is cloning our dotfiles. Not everything comes with them though, so for example `tpm` most likely won't be installed.
+
+If you want to install `tpm` and plugins automatically when tmux is started, put the following snippet in `.tmux.conf` before the final `run '~/.tmux/plugins/tpm/tpm'`:
+
+```
+if "test ! -d ~/.tmux/plugins/tpm" \
+   "run 'git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm && ~/.tmux/plugins/tpm/bin/install_plugins'"
+```
+
+This useful tip was submitted by @acr4 and narfman0.
diff --git a/plugins/tpm/docs/changing_plugins_install_dir.md b/plugins/tpm/docs/changing_plugins_install_dir.md
new file mode 100644
index 0000000..93af675
--- /dev/null
+++ b/plugins/tpm/docs/changing_plugins_install_dir.md
@@ -0,0 +1,14 @@
+# Changing plugins install dir
+
+By default, TPM installs plugins to `~/.tmux/plugins/`.
+
+You can change the install path by putting this in `.tmux.conf`:
+
+    set-environment -g TMUX_PLUGIN_MANAGER_PATH '/some/other/path/'
+
+Tmux plugin manager initialization in `.tmux.conf` should also be updated:
+
+    # initializes TMUX plugin manager in a new path
+    run /some/other/path/tpm/tpm
+
+Please make sure that the `run` line is at the very bottom of `.tmux.conf`.
diff --git a/plugins/tpm/docs/how_to_create_plugin.md b/plugins/tpm/docs/how_to_create_plugin.md
new file mode 100644
index 0000000..b1a68f9
--- /dev/null
+++ b/plugins/tpm/docs/how_to_create_plugin.md
@@ -0,0 +1,108 @@
+# How to create Tmux plugins
+
+Creating a new plugin is easy.
+
+For demonstration purposes we'll create a simple plugin that lists all
+installed TPM plugins. Yes, a plugin that lists plugins :) We'll bind that to
+`prefix + T`.
+
+The source code for this example plugin can be found
+[here](https://github.com/tmux-plugins/tmux-example-plugin).
+
+### 1. create a new git project
+
+TPM depends on git for downloading and updating plugins.
+
+To create a new git project:
+
+    $ mkdir tmux_my_plugin
+    $ cd tmux_my_plugin
+    $ git init
+
+### 2. create a `*.tmux` plugin run file
+
+When it sources a plugin, TPM executes all `*.tmux` files in your plugins'
+directory. That's how plugins are run.
+
+Create a plugin run file in plugin directory:
+
+    $ touch my_plugin.tmux
+    $ chmod u+x my_plugin.tmux
+
+You can have more than one `*.tmux` file, and all will get executed. However, usually
+you'll need just one.
+
+### 3. create a plugin key binding
+
+We want the behavior of the plugin to trigger when a user hits `prefix + T`.
+
+Key `T` is chosen because:
+ - it's "kind of" a mnemonic for `TPM`
+ - the key is not used by Tmux natively. Tmux man page, KEY BINDINGS section
+   contains a list of all the bindings Tmux uses. There's plenty of unused keys
+   and we don't want to override any of Tmux default key bindings.
+
+Open the plugin run file in your favorite text editor:
+
+    $ vim my_plugin.tmux
+    # or
+    $ subl my_plugin.tmux
+
+Put the following content in the file:
+
+    #!/usr/bin/env bash
+
+    CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+    tmux bind-key T run-shell "$CURRENT_DIR/scripts/tmux_list_plugins.sh"
+
+As you can see, plugin run file is a simple bash script that sets up the binding.
+
+When pressed, `prefix + T` will execute another shell script:
+`tmux_list_plugins.sh`. That script should be in `scripts/` directory -
+relative to the plugin run file.
+
+
+### 4. listing plugins
+
+Now that we have the binding, let's create a script that's invoked with
+`prefix + T`.
+
+    $ mkdir scripts
+    $ touch scripts/tmux_list_plugins.sh
+    $ chmod u+x scripts/tmux_list_plugins.sh
+
+And here's the script content:
+
+    #!/usr/bin/env bash
+
+    # fetching the directory where plugins are installed
+    plugin_path="$(tmux show-env -g TMUX_PLUGIN_MANAGER_PATH | cut -f2 -d=)"
+
+    # listing installed plugins
+    ls -1 "$plugin_path"
+
+### 5. try it out
+
+To see if this works, execute the plugin run file:
+
+    $ ./my_plugin.tmux
+
+That should set up the key binding. Now hit `prefix + T` and see if it works.
+
+### 6. publish the plugin
+
+When everything is ready, push the plugin to an online git repository,
+preferably Github.
+
+Other users can install your plugin by just adding plugin git URL to the
+`@plugin` list in their `.tmux.conf`.
+
+If the plugin is on Github, your users will be able to use the shorthand of
+`github_username/repository`.
+
+### Conclusion
+
+Hopefully, that was easy. As you can see, it's mostly shell scripting.
+
+You can use other scripting languages (ruby, python etc) but plain old shell
+is preferred because of portability.
diff --git a/plugins/tpm/docs/managing_plugins_via_cmd_line.md b/plugins/tpm/docs/managing_plugins_via_cmd_line.md
new file mode 100644
index 0000000..7aefd7d
--- /dev/null
+++ b/plugins/tpm/docs/managing_plugins_via_cmd_line.md
@@ -0,0 +1,36 @@
+# Managing plugins via the command line
+
+Aside from tmux key bindings, TPM provides shell interface for managing plugins
+via scripts located in [bin/](../bin/) directory.
+
+Tmux does not need to be started in order to run scripts (but it's okay if it
+is). If you [changed tpm install dir](../docs/changing_plugins_install_dir.md)
+in `.tmux.conf` that should work fine too.
+
+Prerequisites:
+
+- tmux installed on the system (doh)
+- `.tmux.conf` set up for TPM
+
+### Installing plugins
+
+As usual, plugins need to be specified in `.tmux.conf`. Run the following
+command to install plugins:
+
+    ~/.tmux/plugins/tpm/bin/install_plugins
+
+### Updating plugins
+
+To update all installed plugins:
+
+    ~/.tmux/plugins/tpm/bin/update_plugins all
+
+or update a single plugin:
+
+    ~/.tmux/plugins/tpm/bin/update_plugins tmux-sensible
+
+### Removing plugins
+
+To remove plugins not on the plugin list:
+
+    ~/.tmux/plugins/tpm/bin/clean_plugins
diff --git a/plugins/tpm/docs/tpm_not_working.md b/plugins/tpm/docs/tpm_not_working.md
new file mode 100644
index 0000000..87d2998
--- /dev/null
+++ b/plugins/tpm/docs/tpm_not_working.md
@@ -0,0 +1,80 @@
+# Help, tpm not working!
+
+Here's the list of issues users had with `tpm`:
+
+<hr />
+
+> Nothing works. `tpm` key bindings `prefix + I`, `prefix + U` not even
+  defined.
+
+Related [issue #22](https://github.com/tmux-plugins/tpm/issues/22)
+
+- Do you have required `tmux` version to run `tpm`?<br/>
+  Check `tmux` version with `$ tmux -V` command and make sure it's higher or
+  equal to the required version for `tpm` as stated in the readme.
+
+- ZSH tmux plugin might be causing issues.<br/>
+  If you have it installed, try disabling it and see if `tpm` works then.
+
+<hr />
+
+> Help, I'm using custom config file with `tmux -f /path/to/my_tmux.conf`
+to start Tmux and for some reason plugins aren't loaded!?
+
+Related [issue #57](https://github.com/tmux-plugins/tpm/issues/57)
+
+`tpm` has a known issue when using custom config file with `-f` option.
+The solution is to use alternative plugin definition syntax. Here are the steps
+to make it work:
+
+1. remove all `set -g @plugin` lines from tmux config file
+2. in the config file define the plugins in the following way:
+
+        # List of plugins
+        set -g @tpm_plugins '          \
+          tmux-plugins/tpm             \
+          tmux-plugins/tmux-sensible   \
+          tmux-plugins/tmux-resurrect  \
+        '
+
+        # Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
+        run '~/.tmux/plugins/tpm/tpm'
+
+3. Reload TMUX environment so TPM is sourced: `$ tmux source /path/to/my_tmux.conf`
+
+The plugins should now be working.
+
+<hr />
+
+> Weird sequence of characters show up when installing or updating plugins
+
+Related: [issue #25](https://github.com/tmux-plugins/tpm/issues/25)
+
+- This could be caused by [tmuxline.vim](https://github.com/edkolev/tmuxline.vim)
+  plugin. Uninstall it and see if things work.
+
+<hr />
+
+> "failed to connect to server" error when sourcing .tmux.conf
+
+Related: [issue #48](https://github.com/tmux-plugins/tpm/issues/48)
+
+- Make sure `tmux source ~/.tmux.conf` command is ran from inside `tmux`.
+
+<hr />
+
+> tpm not working: '~/.tmux/plugins/tpm/tpm' returned 2 (Windows / Cygwin)
+
+Related: [issue #81](https://github.com/tmux-plugins/tpm/issues/81)
+
+This issue is most likely caused by Windows line endings. For example, if you
+have git's `core.autocrlf` option set to `true`, git will automatically convert
+all the files to Windows line endings which might cause a problem.
+
+The solution is to convert all line ending to Unix newline characters. This
+command handles that for all files under `.tmux/` dir (skips `.git`
+subdirectories):
+
+```bash
+find ~/.tmux -type d -name '.git*' -prune -o -type f -print0 | xargs -0 dos2unix
+```
diff --git a/plugins/tpm/scripts/check_tmux_version.sh b/plugins/tpm/scripts/check_tmux_version.sh
new file mode 100755
index 0000000..b0aedec
--- /dev/null
+++ b/plugins/tpm/scripts/check_tmux_version.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+VERSION="$1"
+UNSUPPORTED_MSG="$2"
+
+get_tmux_option() {
+	local option=$1
+	local default_value=$2
+	local option_value=$(tmux show-option -gqv "$option")
+	if [ -z "$option_value" ]; then
+		echo "$default_value"
+	else
+		echo "$option_value"
+	fi
+}
+
+# Ensures a message is displayed for 5 seconds in tmux prompt.
+# Does not override the 'display-time' tmux option.
+display_message() {
+	local message="$1"
+
+	# display_duration defaults to 5 seconds, if not passed as an argument
+	if [ "$#" -eq 2 ]; then
+		local display_duration="$2"
+	else
+		local display_duration="5000"
+	fi
+
+	# saves user-set 'display-time' option
+	local saved_display_time=$(get_tmux_option "display-time" "750")
+
+	# sets message display time to 5 seconds
+	tmux set-option -gq display-time "$display_duration"
+
+	# displays message
+	tmux display-message "$message"
+
+	# restores original 'display-time' value
+	tmux set-option -gq display-time "$saved_display_time"
+}
+
+# this is used to get "clean" integer version number. Examples:
+# `tmux 1.9` => `19`
+# `1.9a`     => `19`
+get_digits_from_string() {
+	local string="$1"
+	local only_digits="$(echo "$string" | tr -dC '[:digit:]')"
+	echo "$only_digits"
+}
+
+tmux_version_int() {
+	local tmux_version_string=$(tmux -V)
+	echo "$(get_digits_from_string "$tmux_version_string")"
+}
+
+unsupported_version_message() {
+	if [ -n "$UNSUPPORTED_MSG" ]; then
+		echo "$UNSUPPORTED_MSG"
+	else
+		echo "Error, Tmux version unsupported! Please install Tmux version $VERSION or greater!"
+	fi
+}
+
+exit_if_unsupported_version() {
+	local current_version="$1"
+	local supported_version="$2"
+	if [ "$current_version" -lt "$supported_version" ]; then
+		display_message "$(unsupported_version_message)"
+		exit 1
+	fi
+}
+
+main() {
+	local supported_version_int="$(get_digits_from_string "$VERSION")"
+	local current_version_int="$(tmux_version_int)"
+	exit_if_unsupported_version "$current_version_int" "$supported_version_int"
+}
+main
diff --git a/plugins/tpm/scripts/clean_plugins.sh b/plugins/tpm/scripts/clean_plugins.sh
new file mode 100755
index 0000000..a025524
--- /dev/null
+++ b/plugins/tpm/scripts/clean_plugins.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+HELPERS_DIR="$CURRENT_DIR/helpers"
+
+source "$HELPERS_DIR/plugin_functions.sh"
+source "$HELPERS_DIR/utility.sh"
+
+if [ "$1" == "--tmux-echo" ]; then # tmux-specific echo functions
+	source "$HELPERS_DIR/tmux_echo_functions.sh"
+else # shell output functions
+	source "$HELPERS_DIR/shell_echo_functions.sh"
+fi
+
+clean_plugins() {
+	local plugins plugin plugin_directory
+	plugins="$(tpm_plugins_list_helper)"
+
+	for plugin_directory in "$(tpm_path)"/*; do
+		[ -d "${plugin_directory}" ] || continue
+		plugin="$(plugin_name_helper "${plugin_directory}")"
+		case "${plugins}" in
+			*"${plugin}"*) : ;;
+			*)
+			[ "${plugin}" = "tpm" ] && continue
+			echo_ok "Removing \"$plugin\""
+			rm -rf "${plugin_directory}" >/dev/null 2>&1
+			[ -d "${plugin_directory}" ] &&
+			echo_err "  \"$plugin\" clean fail" ||
+			echo_ok "  \"$plugin\" clean success"
+			;;
+		esac
+	done
+}
+
+main() {
+	ensure_tpm_path_exists
+	clean_plugins
+	exit_value_helper
+}
+main
diff --git a/plugins/tpm/scripts/helpers/plugin_functions.sh b/plugins/tpm/scripts/helpers/plugin_functions.sh
new file mode 100644
index 0000000..d2778d5
--- /dev/null
+++ b/plugins/tpm/scripts/helpers/plugin_functions.sh
@@ -0,0 +1,86 @@
+# using @tpm_plugins is now deprecated in favor of using @plugin syntax
+tpm_plugins_variable_name="@tpm_plugins"
+
+# manually expanding tilde char or `$HOME` variable.
+_manual_expansion() {
+	local path="$1"
+	local expanded_tilde="${path/#\~/$HOME}"
+	echo "${expanded_tilde/#\$HOME/$HOME}"
+}
+
+_tpm_path() {
+	local string_path="$(tmux start-server\; show-environment -g TMUX_PLUGIN_MANAGER_PATH | cut -f2 -d=)/"
+	_manual_expansion "$string_path"
+}
+
+_CACHED_TPM_PATH="$(_tpm_path)"
+
+_tmux_conf_contents() {
+	cat /etc/tmux.conf ~/.tmux.conf 2>/dev/null
+	if [ "$1" == "full" ]; then # also output content from sourced files
+		local file
+		for file in $(_sourced_files); do
+			cat $(_manual_expansion "$file") 2>/dev/null
+		done
+	fi
+}
+
+# return files sourced from tmux config files
+_sourced_files() {
+	_tmux_conf_contents |
+		awk '/^[ \t]*source(-file)? +/ { gsub(/'\''/,""); gsub(/'\"'/,""); print $2 }'
+}
+
+# Want to be able to abort in certain cases
+trap "exit 1" TERM
+export TOP_PID=$$
+
+_fatal_error_abort() {
+	echo >&2 "Aborting."
+	kill -s TERM $TOP_PID
+}
+
+# PUBLIC FUNCTIONS BELOW
+
+tpm_path() {
+	if [ "$_CACHED_TPM_PATH" == "/" ]; then
+		echo >&2 "FATAL: Tmux Plugin Manager not configured in tmux.conf"
+		_fatal_error_abort
+	fi
+	echo "$_CACHED_TPM_PATH"
+}
+
+tpm_plugins_list_helper() {
+	# lists plugins from @tpm_plugins option
+	echo "$(tmux start-server\; show-option -gqv "$tpm_plugins_variable_name")"
+
+	# read set -g @plugin "tmux-plugins/tmux-example-plugin" entries
+	_tmux_conf_contents "full" |
+		awk '/^[ \t]*set(-option)? +-g +@plugin/ { gsub(/'\''/,""); gsub(/'\"'/,""); print $4 }'
+}
+
+# Allowed plugin name formats:
+# 1. "git://github.com/user/plugin_name.git"
+# 2. "user/plugin_name"
+plugin_name_helper() {
+	local plugin="$1"
+	# get only the part after the last slash, e.g. "plugin_name.git"
+	local plugin_basename="$(basename "$plugin")"
+	# remove ".git" extension (if it exists) to get only "plugin_name"
+	local plugin_name="${plugin_basename%.git}"
+	echo "$plugin_name"
+}
+
+plugin_path_helper() {
+	local plugin="$1"
+	local plugin_name="$(plugin_name_helper "$plugin")"
+	echo "$(tpm_path)${plugin_name}/"
+}
+
+plugin_already_installed() {
+	local plugin="$1"
+	local plugin_path="$(plugin_path_helper "$plugin")"
+	[ -d "$plugin_path" ] &&
+		cd "$plugin_path" &&
+		git remote >/dev/null 2>&1
+}
diff --git a/plugins/tpm/scripts/helpers/shell_echo_functions.sh b/plugins/tpm/scripts/helpers/shell_echo_functions.sh
new file mode 100644
index 0000000..ecaa37e
--- /dev/null
+++ b/plugins/tpm/scripts/helpers/shell_echo_functions.sh
@@ -0,0 +1,7 @@
+echo_ok() {
+	echo "$*"
+}
+
+echo_err() {
+	fail_helper "$*"
+}
diff --git a/plugins/tpm/scripts/helpers/tmux_echo_functions.sh b/plugins/tpm/scripts/helpers/tmux_echo_functions.sh
new file mode 100644
index 0000000..7a6ef0a
--- /dev/null
+++ b/plugins/tpm/scripts/helpers/tmux_echo_functions.sh
@@ -0,0 +1,28 @@
+_has_emacs_mode_keys() {
+	$(tmux show -gw mode-keys | grep -q emacs)
+}
+
+tmux_echo() {
+	local message="$1"
+	tmux run-shell "echo '$message'"
+}
+
+echo_ok() {
+	tmux_echo "$*"
+}
+
+echo_err() {
+	tmux_echo "$*"
+}
+
+end_message() {
+	if _has_emacs_mode_keys; then
+		local continue_key="ESCAPE"
+	else
+		local continue_key="ENTER"
+	fi
+	tmux_echo ""
+	tmux_echo "TMUX environment reloaded."
+	tmux_echo ""
+	tmux_echo "Done, press $continue_key to continue."
+}
diff --git a/plugins/tpm/scripts/helpers/tmux_utils.sh b/plugins/tpm/scripts/helpers/tmux_utils.sh
new file mode 100644
index 0000000..e39946a
--- /dev/null
+++ b/plugins/tpm/scripts/helpers/tmux_utils.sh
@@ -0,0 +1,3 @@
+reload_tmux_environment() {
+	tmux source-file ~/.tmux.conf >/dev/null 2>&1
+}
diff --git a/plugins/tpm/scripts/helpers/utility.sh b/plugins/tpm/scripts/helpers/utility.sh
new file mode 100644
index 0000000..de6eb35
--- /dev/null
+++ b/plugins/tpm/scripts/helpers/utility.sh
@@ -0,0 +1,17 @@
+ensure_tpm_path_exists() {
+	mkdir -p "$(tpm_path)"
+}
+
+fail_helper() {
+	local message="$1"
+	echo "$message" >&2
+	FAIL="true"
+}
+
+exit_value_helper() {
+	if [ "$FAIL" == "true" ]; then
+		exit 1
+	else
+		exit 0
+	fi
+}
diff --git a/plugins/tpm/scripts/install_plugins.sh b/plugins/tpm/scripts/install_plugins.sh
new file mode 100755
index 0000000..7958ab5
--- /dev/null
+++ b/plugins/tpm/scripts/install_plugins.sh
@@ -0,0 +1,66 @@
+#!/usr/bin/env bash
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+HELPERS_DIR="$CURRENT_DIR/helpers"
+
+source "$HELPERS_DIR/plugin_functions.sh"
+source "$HELPERS_DIR/utility.sh"
+
+if [ "$1" == "--tmux-echo" ]; then # tmux-specific echo functions
+	source "$HELPERS_DIR/tmux_echo_functions.sh"
+else # shell output functions
+	source "$HELPERS_DIR/shell_echo_functions.sh"
+fi
+
+clone() {
+	local plugin="$1"
+	cd "$(tpm_path)" &&
+		GIT_TERMINAL_PROMPT=0 git clone --recursive "$plugin" >/dev/null 2>&1
+}
+
+# tries cloning:
+# 1. plugin name directly - works if it's a valid git url
+# 2. expands the plugin name to point to a github repo and tries cloning again
+clone_plugin() {
+	local plugin="$1"
+	clone "$plugin" ||
+		clone "https://git::@github.com/$plugin"
+}
+
+# clone plugin and produce output
+install_plugin() {
+	local plugin="$1"
+	local plugin_name="$(plugin_name_helper "$plugin")"
+
+	if plugin_already_installed "$plugin"; then
+		echo_ok "Already installed \"$plugin_name\""
+	else
+		echo_ok "Installing \"$plugin_name\""
+		clone_plugin "$plugin" &&
+			echo_ok "  \"$plugin_name\" download success" ||
+			echo_err "  \"$plugin_name\" download fail"
+	fi
+}
+
+install_plugins() {
+	local plugins="$(tpm_plugins_list_helper)"
+	for plugin in $plugins; do
+		install_plugin "$plugin"
+	done
+}
+
+verify_tpm_path_permissions() {
+	local path="$(tpm_path)"
+	# check the write permission flag for all users to ensure
+	# that we have proper access
+	[ -w "$path" ] ||
+		echo_err "$path is not writable!"
+}
+
+main() {
+	ensure_tpm_path_exists
+	verify_tpm_path_permissions
+	install_plugins
+	exit_value_helper
+}
+main
diff --git a/plugins/tpm/scripts/source_plugins.sh b/plugins/tpm/scripts/source_plugins.sh
new file mode 100755
index 0000000..bb79c26
--- /dev/null
+++ b/plugins/tpm/scripts/source_plugins.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+HELPERS_DIR="$CURRENT_DIR/helpers"
+
+source "$HELPERS_DIR/plugin_functions.sh"
+
+plugin_dir_exists() {
+	[ -d "$1" ]
+}
+
+# Runs all *.tmux files from the plugin directory.
+# Files are ran as executables.
+# No errors if the plugin dir does not exist.
+silently_source_all_tmux_files() {
+	local plugin_path="$1"
+	local plugin_tmux_files="$plugin_path*.tmux"
+	if plugin_dir_exists "$plugin_path"; then
+		for tmux_file in $plugin_tmux_files; do
+			# if the glob didn't find any files this will be the
+			# unexpanded glob which obviously doesn't exist
+			[ -f "$tmux_file" ] || continue
+			# runs *.tmux file as an executable
+			$tmux_file >/dev/null 2>&1
+		done
+	fi
+}
+
+source_plugins() {
+	local plugin plugin_path
+	local plugins="$(tpm_plugins_list_helper)"
+	for plugin in $plugins; do
+		plugin_path="$(plugin_path_helper "$plugin")"
+		silently_source_all_tmux_files "$plugin_path"
+	done
+}
+
+main() {
+	source_plugins
+}
+main
diff --git a/plugins/tpm/scripts/update_plugin.sh b/plugins/tpm/scripts/update_plugin.sh
new file mode 100755
index 0000000..7d856ee
--- /dev/null
+++ b/plugins/tpm/scripts/update_plugin.sh
@@ -0,0 +1,71 @@
+#!/usr/bin/env bash
+
+# this script handles core logic of updating plugins
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+HELPERS_DIR="$CURRENT_DIR/helpers"
+
+source "$HELPERS_DIR/plugin_functions.sh"
+source "$HELPERS_DIR/utility.sh"
+
+if [ "$1" == "--tmux-echo" ]; then # tmux-specific echo functions
+	source "$HELPERS_DIR/tmux_echo_functions.sh"
+else # shell output functions
+	source "$HELPERS_DIR/shell_echo_functions.sh"
+fi
+
+# from now on ignore first script argument
+shift
+
+pull_changes() {
+	local plugin="$1"
+	local plugin_path="$(plugin_path_helper "$plugin")"
+	cd "$plugin_path" &&
+		GIT_TERMINAL_PROMPT=0 git pull &&
+		GIT_TERMINAL_PROMPT=0 git submodule update --init --recursive
+}
+
+update() {
+	local plugin="$1"
+	$(pull_changes "$plugin" > /dev/null 2>&1) &&
+		echo_ok "  \"$plugin\" update success" ||
+		echo_err "  \"$plugin\" update fail"
+}
+
+update_all() {
+	echo_ok "Updating all plugins!"
+	echo_ok ""
+	local plugins="$(tpm_plugins_list_helper)"
+	for plugin in $plugins; do
+		local plugin_name="$(plugin_name_helper "$plugin")"
+		# updating only installed plugins
+		if plugin_already_installed "$plugin_name"; then
+			update "$plugin_name" &
+		fi
+	done
+	wait
+}
+
+update_plugins() {
+	local plugins="$*"
+	for plugin in $plugins; do
+		local plugin_name="$(plugin_name_helper "$plugin")"
+		if plugin_already_installed "$plugin_name"; then
+			update "$plugin_name" &
+		else
+			echo_err "$plugin_name not installed!" &
+		fi
+	done
+	wait
+}
+
+main() {
+	ensure_tpm_path_exists
+	if [ "$1" == "all" ]; then
+		update_all
+	else
+		update_plugins "$*"
+	fi
+	exit_value_helper
+}
+main "$*"
diff --git a/plugins/tpm/scripts/update_plugin_prompt_handler.sh b/plugins/tpm/scripts/update_plugin_prompt_handler.sh
new file mode 100755
index 0000000..5e1f7d9
--- /dev/null
+++ b/plugins/tpm/scripts/update_plugin_prompt_handler.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+HELPERS_DIR="$CURRENT_DIR/helpers"
+
+if [ $# -eq 0 ]; then
+	exit 0
+fi
+
+source "$HELPERS_DIR/tmux_echo_functions.sh"
+source "$HELPERS_DIR/tmux_utils.sh"
+
+main() {
+	"$CURRENT_DIR/update_plugin.sh" --tmux-echo "$*"
+	reload_tmux_environment
+	end_message
+}
+main "$*"
diff --git a/plugins/tpm/scripts/variables.sh b/plugins/tpm/scripts/variables.sh
new file mode 100644
index 0000000..5601a86
--- /dev/null
+++ b/plugins/tpm/scripts/variables.sh
@@ -0,0 +1,13 @@
+install_key_option="@tpm-install"
+default_install_key="I"
+
+update_key_option="@tpm-update"
+default_update_key="U"
+
+clean_key_option="@tpm-clean"
+default_clean_key="M-u"
+
+SUPPORTED_TMUX_VERSION="1.9"
+
+DEFAULT_TPM_ENV_VAR_NAME="TMUX_PLUGIN_MANAGER_PATH"
+DEFAULT_TPM_PATH="$HOME/.tmux/plugins/"
diff --git a/plugins/tpm/tests/expect_failed_plugin_download b/plugins/tpm/tests/expect_failed_plugin_download
new file mode 100755
index 0000000..b970477
--- /dev/null
+++ b/plugins/tpm/tests/expect_failed_plugin_download
@@ -0,0 +1,36 @@
+#!/usr/bin/env expect
+
+# disables script output
+log_user 0
+
+spawn tmux
+
+# Waiting for tmux to attach. If this is not done, next command, `send` will
+# not work properly.
+sleep 1
+
+# this is tmux prefix + I
+send "I"
+
+# cloning might take a while
+set timeout 20
+
+expect_after {
+  timeout { exit 1 }
+}
+
+expect {
+  "Installing \"non-existing-plugin\""
+}
+
+expect {
+  "\"non-existing-plugin\" download fail"
+}
+
+expect {
+  "Done, press ENTER to continue" {
+    exit 0
+  }
+}
+
+exit 1
diff --git a/plugins/tpm/tests/expect_successful_clean_plugins b/plugins/tpm/tests/expect_successful_clean_plugins
new file mode 100755
index 0000000..987c49d
--- /dev/null
+++ b/plugins/tpm/tests/expect_successful_clean_plugins
@@ -0,0 +1,35 @@
+#!/usr/bin/env expect
+
+# disables script output
+log_user 0
+
+spawn tmux
+
+# Waiting for tmux to attach. If this is not done, next command, `send` will
+# not work properly.
+sleep 1
+
+# this is tmux prefix + alt + u
+send "u"
+
+set timeout 5
+
+expect_after {
+  timeout { exit 1 }
+}
+
+expect {
+  "Removing \"tmux-example-plugin\""
+}
+
+expect {
+  "\"tmux-example-plugin\" clean success"
+}
+
+expect {
+  "Done, press ENTER to continue." {
+    exit 0
+  }
+}
+
+exit 1
diff --git a/plugins/tpm/tests/expect_successful_multiple_plugins_download b/plugins/tpm/tests/expect_successful_multiple_plugins_download
new file mode 100755
index 0000000..cc87a26
--- /dev/null
+++ b/plugins/tpm/tests/expect_successful_multiple_plugins_download
@@ -0,0 +1,44 @@
+#!/usr/bin/env expect
+
+# disables script output
+log_user 0
+
+spawn tmux
+
+# Waiting for tmux to attach. If this is not done, next command, `send` will
+# not work properly.
+sleep 1
+
+# this is tmux prefix + I
+send "I"
+
+# cloning might take a while
+set timeout 15
+
+expect_after {
+  timeout { exit 1 }
+}
+
+expect {
+  "Installing \"tmux-example-plugin\""
+}
+
+expect {
+  "\"tmux-example-plugin\" download success"
+}
+
+expect {
+  "Installing \"tmux-copycat\""
+}
+
+expect {
+  "\"tmux-copycat\" download success"
+}
+
+expect {
+  "Done, press ENTER to continue." {
+    exit 0
+  }
+}
+
+exit 1
diff --git a/plugins/tpm/tests/expect_successful_plugin_download b/plugins/tpm/tests/expect_successful_plugin_download
new file mode 100755
index 0000000..388f05d
--- /dev/null
+++ b/plugins/tpm/tests/expect_successful_plugin_download
@@ -0,0 +1,50 @@
+#!/usr/bin/env expect
+
+# disables script output
+log_user 0
+
+spawn tmux
+
+# Waiting for tmux to attach. If this is not done, next command, `send` will
+# not work properly.
+sleep 1
+
+# this is tmux prefix + I
+send "I"
+
+# cloning might take a while
+set timeout 15
+
+expect_after {
+  timeout { exit 1 }
+}
+
+expect {
+  "Installing \"tmux-example-plugin\""
+}
+
+expect {
+  "\"tmux-example-plugin\" download success"
+}
+
+expect {
+  "Done, press ENTER to continue" {
+    send "
"
+  }
+}
+
+sleep 1
+# this is tmux prefix + I
+send "I"
+
+expect {
+  "Already installed \"tmux-example-plugin\""
+}
+
+expect {
+  "Done, press ENTER to continue" {
+    exit 0
+  }
+}
+
+exit 1
diff --git a/plugins/tpm/tests/expect_successful_update_of_a_single_plugin b/plugins/tpm/tests/expect_successful_update_of_a_single_plugin
new file mode 100755
index 0000000..bcd64fe
--- /dev/null
+++ b/plugins/tpm/tests/expect_successful_update_of_a_single_plugin
@@ -0,0 +1,55 @@
+#!/usr/bin/env expect
+
+# disables script output
+log_user 0
+
+spawn tmux
+
+# Waiting for tmux to attach. If this is not done, next command, `send` will
+# not work properly.
+sleep 1
+
+# this is tmux prefix + U
+send "U"
+
+set timeout 15
+
+expect_after {
+  timeout { exit 1 }
+}
+
+expect {
+  "Installed plugins"
+}
+
+expect {
+  "tmux-example-plugin"
+}
+
+expect {
+  "\"all\" - updates all plugins"
+}
+
+expect {
+  "ENTER - cancels"
+}
+
+# wait for tmux to display prompt before sending characters
+sleep 1
+send "tmux-example-plugin\r"
+
+expect {
+  "Updating \"tmux-example-plugin\""
+}
+
+expect {
+  "\"tmux-example-plugin\" update success"
+}
+
+expect {
+  "Done, press ENTER to continue." {
+    exit 0
+  }
+}
+
+exit 1
diff --git a/plugins/tpm/tests/expect_successful_update_of_all_plugins b/plugins/tpm/tests/expect_successful_update_of_all_plugins
new file mode 100755
index 0000000..4f3a4a3
--- /dev/null
+++ b/plugins/tpm/tests/expect_successful_update_of_all_plugins
@@ -0,0 +1,59 @@
+#!/usr/bin/env expect
+
+# disables script output
+log_user 0
+
+spawn tmux
+
+# Waiting for tmux to attach. If this is not done, next command, `send` will
+# not work properly.
+sleep 1
+
+# this is tmux prefix + U
+send "U"
+
+set timeout 5
+
+expect_after {
+  timeout { exit 1 }
+}
+
+expect {
+  "Installed plugins"
+}
+
+expect {
+  "tmux-example-plugin"
+}
+
+expect {
+  "\"all\" - updates all plugins"
+}
+
+expect {
+  "ENTER - cancels"
+}
+
+# wait for tmux to display prompt before sending characters
+sleep 1
+send "all\r"
+
+expect {
+  "Updating all plugins!"
+}
+
+expect {
+  "Updating \"tmux-example-plugin\""
+}
+
+expect {
+  "\"tmux-example-plugin\" update success"
+}
+
+expect {
+  "Done, press ENTER to continue." {
+    exit 0
+  }
+}
+
+exit 1
diff --git a/plugins/tpm/tests/helpers/tpm.sh b/plugins/tpm/tests/helpers/tpm.sh
new file mode 100644
index 0000000..1594afb
--- /dev/null
+++ b/plugins/tpm/tests/helpers/tpm.sh
@@ -0,0 +1,13 @@
+check_dir_exists_helper() {
+	[ -d "$1" ]
+}
+
+# runs the scripts and asserts it has the correct output and exit code
+script_run_helper() {
+	local script="$1"
+	local expected_output="$2"
+	local expected_exit_code="${3:-0}"
+	$script 2>&1 |
+		grep "$expected_output" >/dev/null 2>&1 && # grep -q flag quits the script early
+		[ "${PIPESTATUS[0]}" -eq "$expected_exit_code" ]
+}
diff --git a/plugins/tpm/tests/test_plugin_clean.sh b/plugins/tpm/tests/test_plugin_clean.sh
new file mode 100755
index 0000000..d36c468
--- /dev/null
+++ b/plugins/tpm/tests/test_plugin_clean.sh
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+TPM_DIR="$PWD"
+PLUGINS_DIR="$HOME/.tmux/plugins"
+
+source "$CURRENT_DIR/helpers/helpers.sh"
+source "$CURRENT_DIR/helpers/tpm.sh"
+
+manually_install_the_plugin() {
+	rm -rf "$PLUGINS_DIR"
+	mkdir -p "$PLUGINS_DIR"
+	cd "$PLUGINS_DIR"
+	git clone --quiet https://github.com/tmux-plugins/tmux-example-plugin
+}
+
+# TMUX KEY-BINDING TESTS
+
+test_plugin_uninstallation_via_tmux_key_binding() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	manually_install_the_plugin
+
+	"$CURRENT_DIR/expect_successful_clean_plugins" ||
+		fail_helper "[key-binding] clean fails"
+
+	teardown_helper
+}
+
+# SCRIPT TESTS
+
+test_plugin_uninstallation_via_script() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	manually_install_the_plugin
+
+	script_run_helper "$TPM_DIR/bin/clean_plugins" '"tmux-example-plugin" clean success' ||
+		fail_helper "[script] plugin cleaning fails"
+
+	teardown_helper
+}
+
+test_unsuccessful_plugin_uninstallation_via_script() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	manually_install_the_plugin
+	chmod 000 "$PLUGINS_DIR/tmux-example-plugin" # disable directory deletion
+
+	local expected_exit_code=1
+	script_run_helper "$TPM_DIR/bin/clean_plugins" '"tmux-example-plugin" clean fail' "$expected_exit_code" ||
+		fail_helper "[script] unsuccessful plugin cleaning doesn't fail"
+
+	chmod 755 "$PLUGINS_DIR/tmux-example-plugin" # enable directory deletion
+
+	teardown_helper
+}
+
+run_tests
diff --git a/plugins/tpm/tests/test_plugin_installation.sh b/plugins/tpm/tests/test_plugin_installation.sh
new file mode 100755
index 0000000..94fb674
--- /dev/null
+++ b/plugins/tpm/tests/test_plugin_installation.sh
@@ -0,0 +1,284 @@
+#!/usr/bin/env bash
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+PLUGINS_DIR="$HOME/.tmux/plugins"
+TPM_DIR="$PWD"
+
+CUSTOM_PLUGINS_DIR="$HOME/foo/plugins"
+ADDITIONAL_CONFIG_FILE_1="$HOME/.tmux/additional_config_file_1"
+ADDITIONAL_CONFIG_FILE_2="$HOME/.tmux/additional_config_file_2"
+
+source "$CURRENT_DIR/helpers/helpers.sh"
+source "$CURRENT_DIR/helpers/tpm.sh"
+
+# TMUX KEY-BINDING TESTS
+
+test_plugin_installation_via_tmux_key_binding() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set -g @plugin "tmux-plugins/tmux-example-plugin"
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	"$CURRENT_DIR/expect_successful_plugin_download" ||
+		fail_helper "[key-binding] plugin installation fails"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[key-binding] plugin download fails"
+
+	teardown_helper
+}
+
+test_plugin_installation_via_tmux_key_binding_set_option() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set-option -g @plugin "tmux-plugins/tmux-example-plugin"
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	"$CURRENT_DIR/expect_successful_plugin_download" ||
+		fail_helper "[key-binding][set-option] plugin installation fails"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[key-binding][set-option] plugin download fails"
+
+	teardown_helper
+}
+
+test_plugin_installation_custom_dir_via_tmux_key_binding() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set-environment -g TMUX_PLUGIN_MANAGER_PATH '$CUSTOM_PLUGINS_DIR'
+
+	set -g @plugin "tmux-plugins/tmux-example-plugin"
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	"$CURRENT_DIR/expect_successful_plugin_download" ||
+		fail_helper "[key-binding][custom dir] plugin installation fails"
+
+	check_dir_exists_helper "$CUSTOM_PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[key-binding][custom dir] plugin download fails"
+
+	teardown_helper
+	rm -rf "$CUSTOM_PLUGINS_DIR"
+}
+
+test_non_existing_plugin_installation_via_tmux_key_binding() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set -g @plugin "tmux-plugins/non-existing-plugin"
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	"$CURRENT_DIR/expect_failed_plugin_download" ||
+		fail_helper "[key-binding] non existing plugin installation doesn't fail"
+
+	teardown_helper
+}
+
+test_multiple_plugins_installation_via_tmux_key_binding() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set -g @plugin "tmux-plugins/tmux-example-plugin"
+	\ \ set  -g    @plugin 'tmux-plugins/tmux-copycat'
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	"$CURRENT_DIR/expect_successful_multiple_plugins_download" ||
+		fail_helper "[key-binding] multiple plugins installation fails"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[key-binding] plugin download fails (tmux-example-plugin)"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-copycat/" ||
+		fail_helper "[key-binding] plugin download fails (tmux-copycat)"
+
+	teardown_helper
+}
+
+test_plugins_installation_from_sourced_file_via_tmux_key_binding() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	source '$ADDITIONAL_CONFIG_FILE_1'
+	set -g @plugin 'tmux-plugins/tmux-example-plugin'
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	mkdir ~/.tmux
+	echo "set -g @plugin 'tmux-plugins/tmux-copycat'" > "$ADDITIONAL_CONFIG_FILE_1"
+
+	"$CURRENT_DIR/expect_successful_multiple_plugins_download" ||
+		fail_helper "[key-binding][sourced file] plugins installation fails"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[key-binding][sourced file] plugin download fails (tmux-example-plugin)"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-copycat/" ||
+		fail_helper "[key-binding][sourced file] plugin download fails (tmux-copycat)"
+
+	teardown_helper
+}
+
+test_plugins_installation_from_multiple_sourced_files_via_tmux_key_binding() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	\ \ source    '$ADDITIONAL_CONFIG_FILE_1'
+	source-file '$ADDITIONAL_CONFIG_FILE_2'
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	mkdir ~/.tmux
+	echo "set -g @plugin 'tmux-plugins/tmux-example-plugin'" > "$ADDITIONAL_CONFIG_FILE_1"
+	echo "  set -g @plugin 'tmux-plugins/tmux-copycat'" > "$ADDITIONAL_CONFIG_FILE_2"
+
+	"$CURRENT_DIR/expect_successful_multiple_plugins_download" ||
+		fail_helper "[key-binding][multiple sourced files] plugins installation fails"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[key-binding][multiple sourced files] plugin download fails (tmux-example-plugin)"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-copycat/" ||
+		fail_helper "[key-binding][multiple sourced files] plugin download fails (tmux-copycat)"
+
+	teardown_helper
+}
+
+# SCRIPT TESTS
+
+test_plugin_installation_via_script() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set -g @plugin "tmux-plugins/tmux-example-plugin"
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	script_run_helper "$TPM_DIR/bin/install_plugins" '"tmux-example-plugin" download success' ||
+		fail_helper "[script] plugin installation fails"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[script] plugin download fails"
+
+	script_run_helper "$TPM_DIR/bin/install_plugins" 'Already installed "tmux-example-plugin"' ||
+		fail_helper "[script] plugin already installed message fail"
+
+	teardown_helper
+}
+
+test_plugin_installation_custom_dir_via_script() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set-environment -g TMUX_PLUGIN_MANAGER_PATH '$CUSTOM_PLUGINS_DIR'
+
+	set -g @plugin "tmux-plugins/tmux-example-plugin"
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	script_run_helper "$TPM_DIR/bin/install_plugins" '"tmux-example-plugin" download success' ||
+		fail_helper "[script][custom dir] plugin installation fails"
+
+	check_dir_exists_helper "$CUSTOM_PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[script][custom dir] plugin download fails"
+
+	script_run_helper "$TPM_DIR/bin/install_plugins" 'Already installed "tmux-example-plugin"' ||
+		fail_helper "[script][custom dir] plugin already installed message fail"
+
+	teardown_helper
+	rm -rf "$CUSTOM_PLUGINS_DIR"
+}
+
+test_non_existing_plugin_installation_via_script() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set -g @plugin "tmux-plugins/non-existing-plugin"
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	local expected_exit_code=1
+	script_run_helper "$TPM_DIR/bin/install_plugins" '"non-existing-plugin" download fail' "$expected_exit_code" ||
+		fail_helper "[script] non existing plugin installation doesn't fail"
+
+	teardown_helper
+}
+
+test_multiple_plugins_installation_via_script() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set -g @plugin "tmux-plugins/tmux-example-plugin"
+	\ \ set  -g    @plugin 'tmux-plugins/tmux-copycat'
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	script_run_helper "$TPM_DIR/bin/install_plugins" '"tmux-example-plugin" download success' ||
+		fail_helper "[script] multiple plugins installation fails"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[script] plugin download fails (tmux-example-plugin)"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-copycat/" ||
+		fail_helper "[script] plugin download fails (tmux-copycat)"
+
+	script_run_helper "$TPM_DIR/bin/install_plugins" 'Already installed "tmux-copycat"' ||
+		fail_helper "[script] multiple plugins already installed message fail"
+
+	teardown_helper
+}
+
+test_plugins_installation_from_sourced_file_via_script() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	source '$ADDITIONAL_CONFIG_FILE_1'
+	set -g @plugin 'tmux-plugins/tmux-example-plugin'
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	mkdir ~/.tmux
+	echo "set -g @plugin 'tmux-plugins/tmux-copycat'" > "$ADDITIONAL_CONFIG_FILE_1"
+
+	script_run_helper "$TPM_DIR/bin/install_plugins" '"tmux-copycat" download success' ||
+		fail_helper "[script][sourced file] plugins installation fails"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[script][sourced file] plugin download fails (tmux-example-plugin)"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-copycat/" ||
+		fail_helper "[script][sourced file] plugin download fails (tmux-copycat)"
+
+	script_run_helper "$TPM_DIR/bin/install_plugins" 'Already installed "tmux-copycat"' ||
+		fail_helper "[script][sourced file] plugins already installed message fail"
+
+	teardown_helper
+}
+
+test_plugins_installation_from_multiple_sourced_files_via_script() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	\ \ source    '$ADDITIONAL_CONFIG_FILE_1'
+	source-file '$ADDITIONAL_CONFIG_FILE_2'
+	set -g @plugin 'tmux-plugins/tmux-example-plugin'
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	mkdir ~/.tmux
+	echo " set   -g @plugin 'tmux-plugins/tmux-copycat'" > "$ADDITIONAL_CONFIG_FILE_1"
+	echo "set -g @plugin 'tmux-plugins/tmux-sensible'" > "$ADDITIONAL_CONFIG_FILE_2"
+
+	script_run_helper "$TPM_DIR/bin/install_plugins" '"tmux-sensible" download success' ||
+		fail_helper "[script][multiple sourced files] plugins installation fails"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[script][multiple sourced files] plugin download fails (tmux-example-plugin)"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-copycat/" ||
+		fail_helper "[script][multiple sourced files] plugin download fails (tmux-copycat)"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-sensible/" ||
+		fail_helper "[script][multiple sourced files] plugin download fails (tmux-sensible)"
+
+	script_run_helper "$TPM_DIR/bin/install_plugins" 'Already installed "tmux-sensible"' ||
+		fail_helper "[script][multiple sourced files] plugins already installed message fail"
+
+	teardown_helper
+}
+
+run_tests
diff --git a/plugins/tpm/tests/test_plugin_installation_legacy.sh b/plugins/tpm/tests/test_plugin_installation_legacy.sh
new file mode 100755
index 0000000..b1d0cf6
--- /dev/null
+++ b/plugins/tpm/tests/test_plugin_installation_legacy.sh
@@ -0,0 +1,100 @@
+#!/usr/bin/env bash
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+PLUGINS_DIR="$HOME/.tmux/plugins"
+TPM_DIR="$PWD"
+
+source "$CURRENT_DIR/helpers/helpers.sh"
+source "$CURRENT_DIR/helpers/tpm.sh"
+
+# TMUX KEY-BINDING TESTS
+
+test_plugin_installation_via_tmux_key_binding() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set -g @tpm_plugins "tmux-plugins/tmux-example-plugin"
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	# opens tmux and test it with `expect`
+	$CURRENT_DIR/expect_successful_plugin_download ||
+		fail_helper "[key-binding] plugin installation fails"
+
+	# check plugin dir exists after download
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[key-binding] plugin download fails"
+
+	teardown_helper
+}
+
+test_legacy_and_new_syntax_for_plugin_installation_work_via_tmux_key_binding() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set -g @tpm_plugins "                   \
+		tmux-plugins/tmux-example-plugin    \
+	"
+	set -g @plugin 'tmux-plugins/tmux-copycat'
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	# opens tmux and test it with `expect`
+	"$CURRENT_DIR"/expect_successful_multiple_plugins_download ||
+		fail_helper "[key-binding] multiple plugins installation fails"
+
+	# check plugin dir exists after download
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[key-binding] plugin download fails (tmux-example-plugin)"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-copycat/" ||
+		fail_helper "[key-binding] plugin download fails (tmux-copycat)"
+
+	teardown_helper
+}
+
+# SCRIPT TESTS
+
+test_plugin_installation_via_script() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set -g @tpm_plugins "tmux-plugins/tmux-example-plugin"
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	script_run_helper "$TPM_DIR/bin/install_plugins" '"tmux-example-plugin" download success' ||
+		fail_helper "[script] plugin installation fails"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[script] plugin download fails"
+
+	script_run_helper "$TPM_DIR/bin/install_plugins" 'Already installed "tmux-example-plugin"' ||
+		fail_helper "[script] plugin already installed message fail"
+
+	teardown_helper
+}
+
+test_legacy_and_new_syntax_for_plugin_installation_work_via_script() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set -g @tpm_plugins "                   \
+		tmux-plugins/tmux-example-plugin    \
+	"
+	set -g @plugin 'tmux-plugins/tmux-copycat'
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	script_run_helper "$TPM_DIR/bin/install_plugins" '"tmux-example-plugin" download success' ||
+		fail_helper "[script] multiple plugin installation fails"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-example-plugin/" ||
+		fail_helper "[script] plugin download fails (tmux-example-plugin)"
+
+	check_dir_exists_helper "$PLUGINS_DIR/tmux-copycat/" ||
+		fail_helper "[script] plugin download fails (tmux-copycat)"
+
+	script_run_helper "$TPM_DIR/bin/install_plugins" 'Already installed "tmux-copycat"' ||
+		fail_helper "[script] multiple plugins already installed message fail"
+
+	teardown_helper
+}
+
+run_tests
diff --git a/plugins/tpm/tests/test_plugin_sourcing.sh b/plugins/tpm/tests/test_plugin_sourcing.sh
new file mode 100755
index 0000000..c06f1fe
--- /dev/null
+++ b/plugins/tpm/tests/test_plugin_sourcing.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+TPM_DIR="$PWD"
+PLUGINS_DIR="$HOME/.tmux/plugins"
+
+CUSTOM_PLUGINS_DIR="$HOME/foo/plugins"
+
+source "$CURRENT_DIR/helpers/helpers.sh"
+source "$CURRENT_DIR/helpers/tpm.sh"
+
+check_binding_defined() {
+	local binding="$1"
+	tmux list-keys | grep -q "$binding"
+}
+
+create_test_plugin_helper() {
+	local plugin_path="$PLUGINS_DIR/tmux_test_plugin/"
+	rm -rf "$plugin_path"
+	mkdir -p "$plugin_path"
+
+	while read line; do
+		echo "$line" >> "$plugin_path/test_plugin.tmux"
+	done
+	chmod +x "$plugin_path/test_plugin.tmux"
+}
+
+check_tpm_path() {
+	local correct_tpm_path="$1"
+	local tpm_path="$(tmux start-server\; show-environment -g TMUX_PLUGIN_MANAGER_PATH | cut -f2 -d=)"
+	[ "$correct_tpm_path" == "$tpm_path" ]
+}
+
+test_plugin_sourcing() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set -g @plugin "doesnt_matter/tmux_test_plugin"
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	# manually creates a local tmux plugin
+	create_test_plugin_helper <<- HERE
+	tmux bind-key R run-shell foo_command
+	HERE
+
+	tmux new-session -d  # tmux starts detached
+	check_binding_defined "R run-shell foo_command" ||
+		fail_helper "Plugin sourcing fails"
+
+	teardown_helper
+}
+
+test_default_tpm_path() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	check_tpm_path "${PLUGINS_DIR}/" ||
+		fail_helper "Default TPM path not correct"
+
+	teardown_helper
+}
+
+test_custom_tpm_path() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set-environment -g TMUX_PLUGIN_MANAGER_PATH '$CUSTOM_PLUGINS_DIR'
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	check_tpm_path "$CUSTOM_PLUGINS_DIR" ||
+		fail_helper "Custom TPM path not correct"
+
+	teardown_helper
+}
+
+run_tests
diff --git a/plugins/tpm/tests/test_plugin_update.sh b/plugins/tpm/tests/test_plugin_update.sh
new file mode 100755
index 0000000..4924d16
--- /dev/null
+++ b/plugins/tpm/tests/test_plugin_update.sh
@@ -0,0 +1,60 @@
+#!/usr/bin/env bash
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+TPM_DIR="$PWD"
+PLUGINS_DIR="$HOME/.tmux/plugins"
+
+source "$CURRENT_DIR/helpers/helpers.sh"
+source "$CURRENT_DIR/helpers/tpm.sh"
+
+manually_install_the_plugin() {
+	mkdir -p "$PLUGINS_DIR"
+	cd "$PLUGINS_DIR"
+	git clone --quiet https://github.com/tmux-plugins/tmux-example-plugin
+}
+
+# TMUX KEY-BINDING TESTS
+
+test_plugin_update_via_tmux_key_binding() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set -g @plugin "tmux-plugins/tmux-example-plugin"
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	manually_install_the_plugin
+
+	"$CURRENT_DIR/expect_successful_update_of_all_plugins" ||
+		fail_helper "[key-binding] 'update all plugins' fails"
+
+	"$CURRENT_DIR/expect_successful_update_of_a_single_plugin" ||
+		fail_helper "[key-binding] 'update single plugin' fails"
+
+	teardown_helper
+}
+
+# SCRIPT TESTS
+
+test_plugin_update_via_script() {
+	set_tmux_conf_helper <<- HERE
+	set -g mode-keys vi
+	set -g @plugin "tmux-plugins/tmux-example-plugin"
+	run-shell "$TPM_DIR/tpm"
+	HERE
+
+	manually_install_the_plugin
+
+	local expected_exit_code=1
+	script_run_helper "$TPM_DIR/bin/update_plugins" 'usage' "$expected_exit_code" ||
+		fail_helper "[script] running update plugins without args should fail"
+
+	script_run_helper "$TPM_DIR/bin/update_plugins tmux-example-plugin" '"tmux-example-plugin" update success' ||
+		fail_helper "[script] plugin update fails"
+
+	script_run_helper "$TPM_DIR/bin/update_plugins all" '"tmux-example-plugin" update success' ||
+		fail_helper "[script] update all plugins fails"
+
+	teardown_helper
+}
+
+run_tests
diff --git a/plugins/tpm/tpm b/plugins/tpm/tpm
new file mode 100755
index 0000000..570d58b
--- /dev/null
+++ b/plugins/tpm/tpm
@@ -0,0 +1,72 @@
+#!/usr/bin/env bash
+
+CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+BINDINGS_DIR="$CURRENT_DIR/bindings"
+SCRIPTS_DIR="$CURRENT_DIR/scripts"
+
+source "$SCRIPTS_DIR/variables.sh"
+
+get_tmux_option() {
+	local option="$1"
+	local default_value="$2"
+	local option_value="$(tmux show-option -gqv "$option")"
+	if [ -z "$option_value" ]; then
+		echo "$default_value"
+	else
+		echo "$option_value"
+	fi
+}
+
+tpm_path_set() {
+	tmux show-environment -g "$DEFAULT_TPM_ENV_VAR_NAME" >/dev/null 2>&1
+}
+
+set_default_tpm_path() {
+	tmux set-environment -g "$DEFAULT_TPM_ENV_VAR_NAME" "$DEFAULT_TPM_PATH"
+}
+
+# Ensures TMUX_PLUGIN_MANAGER_PATH global env variable is set.
+#
+# Put this in `.tmux.conf` to override the default:
+# `set-environment -g TMUX_PLUGIN_MANAGER_PATH "/some/other/path/"`
+set_tpm_path() {
+	if ! tpm_path_set; then
+		set_default_tpm_path
+	fi
+}
+
+# 1. Fetches plugin names from `@plugin` variables
+# 2. Creates full plugin path
+# 3. Sources all *.tmux files from each of the plugin directories
+#	 - no errors raised if directory does not exist
+# Files are sourced as tmux config files, not as shell scripts!
+source_plugins() {
+	"$SCRIPTS_DIR/source_plugins.sh" >/dev/null 2>&1
+}
+
+# prefix + I - downloads TPM plugins and reloads TMUX environment
+# prefix + U - updates a plugin (or all of them) and reloads TMUX environment
+# prefix + alt + u - remove unused TPM plugins and reloads TMUX environment
+set_tpm_key_bindings() {
+	local install_key="$(get_tmux_option "$install_key_option" "$default_install_key")"
+	tmux bind-key "$install_key" run-shell "$BINDINGS_DIR/install_plugins"
+
+	local update_key="$(get_tmux_option "$update_key_option" "$default_update_key")"
+	tmux bind-key "$update_key" run-shell "$BINDINGS_DIR/update_plugins"
+
+	local clean_key="$(get_tmux_option "$clean_key_option" "$default_clean_key")"
+	tmux bind-key "$clean_key" run-shell "$BINDINGS_DIR/clean_plugins"
+}
+
+supported_tmux_version_ok() {
+	"$SCRIPTS_DIR/check_tmux_version.sh" "$SUPPORTED_TMUX_VERSION"
+}
+
+main() {
+	if supported_tmux_version_ok; then
+		set_tpm_path
+		set_tpm_key_bindings
+		source_plugins
+	fi
+}
+main
-- 
cgit v1.2.3