├── .gitattributes ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── open.tmux ├── scripts ├── helpers.sh └── tmux_open_error_message.sh └── video ├── screencast_img.png └── script.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Force text files to have unix eols, so Windows/Cygwin does not break them 2 | *.* eol=lf 3 | 4 | # Except for images because then on checkout the files have been altered. 5 | *.png binary 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ### master 4 | - fix a problem where we try to bind `editor` from `@open-editor` 5 | 6 | ### v3.0.0, Nov 01, 2017 7 | - enable extensibility via search engines (@vasconcelloslf) 8 | - cygwin support 9 | - add support for tmux 2.4 and above (@docwhat) 10 | 11 | ### v2.0.0, Nov 01, 2014 12 | - 'open editor' command can now open files that have spaces 13 | - system open command can now open files that have spaces 14 | - change "@open-editor" options to use hyphens (bc tmux core uses those too) 15 | 16 | ### v1.0.0, Aug 03, 2014 17 | - if $EDITOR env var is not set, provide fallback 18 | - increase `open` command reliability by first `cd`-ing to the current PWD 19 | - add links to related plugins to the readme 20 | - add screencast script to the repo 21 | - add screencast video link to the README 22 | - add installation instructions 23 | 24 | ### v0.0.2, Aug 02, 2014 25 | - add readme 26 | - refactor `command_generator` 27 | - improve open (`o`) command 28 | 29 | ### v0.0.1, Aug 01, 2014 30 | - started the project 31 | - first working version 32 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014 Bruno Sutic 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the "Software"), 5 | to deal in the Software without restriction, including without limitation 6 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the 8 | Software is furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included 11 | in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 16 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 17 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 18 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 19 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tmux open 2 | 3 | Plugin for opening highlighted selection directly from Tmux copy mode. 4 | 5 | Tested and working on Linux, OSX and Cygwin. 6 | 7 | ### Key bindings 8 | 9 | In tmux copy mode: 10 | 11 | - `o` - "open" a highlighted selection with the system default program. `open` 12 | for OS X or `xdg-open` for Linux. 13 | - `Ctrl-o` - open a highlighted selection with the `$EDITOR` 14 | - `Shift-s` - search the highlighted selection directly inside a search engine (defaults to google). 15 | 16 | ### Examples 17 | 18 | In copy mode: 19 | 20 | - highlight `file.pdf` and press `o` - file will open in the default PDF viewer. 21 | - highlight `file.doc` and press `o` - file will open in system default `.doc` 22 | file viewer. 23 | - highlight `http://example.com` and press `o` - link will be opened in the 24 | default browser. 25 | - highlight `file.txt` and press `Ctrl-o` - file will open in `$EDITOR`. 26 | - highlight `TypeError: 'undefined' is not a function` and press `Shift-s` - the text snipped will be searched directly inside google by default 27 | 28 | ### Screencast 29 | 30 | [![screencast screenshot](/video/screencast_img.png)](http://vimeo.com/102455265) 31 | 32 | ### Installation with [Tmux Plugin Manager](https://github.com/tmux-plugins/tpm) (recommended) 33 | 34 | Add plugin to the list of TPM plugins in `.tmux.conf`: 35 | 36 | set -g @plugin 'tmux-plugins/tmux-open' 37 | 38 | Hit `prefix + I` to fetch the plugin and source it. You should now be able to 39 | use the plugin. 40 | 41 | ### Manual Installation 42 | 43 | Clone the repo: 44 | 45 | $ git clone https://github.com/tmux-plugins/tmux-open ~/clone/path 46 | 47 | Add this line to the bottom of `.tmux.conf`: 48 | 49 | run-shell ~/clone/path/open.tmux 50 | 51 | Reload TMUX environment: 52 | 53 | # type this in terminal 54 | $ tmux source-file ~/.tmux.conf 55 | 56 | You should now be able to use the plugin. 57 | 58 | ### Configuration 59 | 60 | > How can I change the default "o" key binding to something else? For example, 61 | > key "x"? 62 | 63 | Put `set -g @open 'x'` in `tmux.conf`. 64 | 65 | > How can I change the default "Ctrl-o" key binding to "Ctrl-x"? 66 | 67 | Put `set -g @open-editor 'C-x'` in `tmux.conf`. 68 | 69 | > How can I change the default search engine to "duckduckgo" or any other one? 70 | 71 | Put `set -g @open-S 'https://www.duckduckgo.com/?q='` in `tmux.conf` 72 | 73 | > How can I use multiple search engines? 74 | 75 | Put: 76 | 77 | ``` 78 | set -g @open-B 'https://www.bing.com/search?q=' 79 | set -g @open-S 'https://www.google.com/search?q=' 80 | ``` 81 | 82 | in `tmux.conf` 83 | 84 | ### Other goodies 85 | 86 | `tmux-open` works great with: 87 | 88 | - [tmux-copycat](https://github.com/tmux-plugins/tmux-copycat) - a plugin for 89 | regex searches in tmux and fast match selection 90 | - [tmux-yank](https://github.com/tmux-plugins/tmux-yank) - enables copying 91 | highlighted text to system clipboard 92 | 93 | ### License 94 | 95 | [MIT](LICENSE.md) 96 | -------------------------------------------------------------------------------- /open.tmux: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | source "$CURRENT_DIR/scripts/helpers.sh" 6 | 7 | default_open_key="o" 8 | open_option="@open" 9 | 10 | default_open_editor_key="C-o" 11 | open_editor_option="@open-editor" 12 | open_editor_override="@open-editor-command" 13 | 14 | command_exists() { 15 | local command="$1" 16 | type "$command" >/dev/null 2>&1 17 | } 18 | 19 | is_osx() { 20 | local platform=$(uname) 21 | [ "$platform" == "Darwin" ] 22 | } 23 | 24 | is_cygwin() { 25 | [[ "$(uname)" =~ CYGWIN ]] 26 | } 27 | 28 | get_editor_from_the_env_var() { 29 | if [ -z $EDITOR ]; then 30 | # $EDITOR not set, fallback 31 | echo "vi" 32 | else 33 | echo "$EDITOR" 34 | fi 35 | } 36 | 37 | preserve_url_hash() { 38 | echo "sed s/##/####/g" 39 | } 40 | 41 | command_generator() { 42 | local command_string="$1" 43 | echo "$(preserve_url_hash) | xargs -I {} tmux run-shell -b 'cd #{pane_current_path}; $command_string \"{}\" > /dev/null'" 44 | } 45 | 46 | search_command_generator() { 47 | local command_string="$1" 48 | local engine="$2" 49 | 50 | echo "$(preserve_url_hash) | sed 's/\ /+/g' | xargs -I {} tmux run-shell -b 'cd #{pane_current_path}; $command_string $engine\"{}\" > /dev/null'" 51 | } 52 | 53 | generate_open_command() { 54 | if is_osx; then 55 | echo "$(command_generator "open")" 56 | elif is_cygwin; then 57 | echo "$(command_generator "cygstart")" 58 | elif command_exists "xdg-open"; then 59 | echo "$(command_generator "xdg-open")" 60 | else 61 | # error command for Linux machines when 'xdg-open' not installed 62 | "$CURRENT_DIR/scripts/tmux_open_error_message.sh" "xdg-open" 63 | fi 64 | } 65 | 66 | generate_open_search_command() { 67 | local engine="$1" 68 | if is_osx; then 69 | echo "$(search_command_generator "open" "$engine")" 70 | elif is_cygwin; then 71 | echo "$(command_generator "cygstart")" 72 | elif command_exists "xdg-open"; then 73 | echo "$(search_command_generator "xdg-open" "$engine")" 74 | else 75 | # error command for Linux machines when 'xdg-open' not installed 76 | "$CURRENT_DIR/scripts/tmux_open_error_message.sh" "xdg-open" 77 | fi 78 | } 79 | 80 | # 1. write a command to the terminal, example: 'vim -- some_file.txt' 81 | # 2. invoke the command by pressing enter/C-m 82 | generate_editor_command() { 83 | local environment_editor=$(get_editor_from_the_env_var) 84 | local editor=$(get_tmux_option "$open_editor_override" "$environment_editor") 85 | # vim freezes terminal unless there's the '--' argument. Other editors seem 86 | # to be fine with it (textmate [mate], light table [table]). 87 | echo "$(preserve_url_hash) | xargs -I {} tmux send-keys '$editor -- \"{}\"'; tmux send-keys 'C-m'" 88 | } 89 | 90 | set_copy_mode_open_bindings() { 91 | local open_command="$(generate_open_command)" 92 | local key_bindings=$(get_tmux_option "$open_option" "$default_open_key") 93 | local key 94 | for key in $key_bindings; do 95 | if tmux-is-at-least 2.4; then 96 | tmux bind-key -T copy-mode-vi "$key" send-keys -X copy-pipe-and-cancel "$open_command" 97 | tmux bind-key -T copy-mode "$key" send-keys -X copy-pipe-and-cancel "$open_command" 98 | else 99 | tmux bind-key -t vi-copy "$key" copy-pipe "$open_command" 100 | tmux bind-key -t emacs-copy "$key" copy-pipe "$open_command" 101 | fi 102 | done 103 | } 104 | 105 | set_copy_mode_open_editor_bindings() { 106 | local editor_command="$(generate_editor_command)" 107 | local key_bindings=$(get_tmux_option "$open_editor_option" "$default_open_editor_key") 108 | local key 109 | for key in $key_bindings; do 110 | if tmux-is-at-least 2.4; then 111 | tmux bind-key -T copy-mode-vi "$key" send-keys -X copy-pipe-and-cancel "$editor_command" 112 | tmux bind-key -T copy-mode "$key" send-keys -X copy-pipe-and-cancel "$editor_command" 113 | else 114 | tmux bind-key -t vi-copy "$key" copy-pipe "$editor_command" 115 | tmux bind-key -t emacs-copy "$key" copy-pipe "$editor_command" 116 | fi 117 | done 118 | } 119 | 120 | set_copy_mode_open_search_bindings() { 121 | local stored_engine_vars="$(stored_engine_vars)" 122 | local engine_var 123 | local engine 124 | local key 125 | 126 | for engine_var in $stored_engine_vars; do 127 | engine="$(get_engine "$engine_var")" 128 | 129 | if tmux-is-at-least 2.4; then 130 | tmux bind-key -T copy-mode-vi "$engine_var" send-keys -X copy-pipe-and-cancel "$(generate_open_search_command "$engine")" 131 | tmux bind-key -T copy-mode "$engine_var" send-keys -X copy-pipe-and-cancel "$(generate_open_search_command "$engine")" 132 | else 133 | tmux bind-key -t vi-copy "$engine_var" copy-pipe "$(generate_open_search_command "$engine")" 134 | tmux bind-key -t emacs-copy "$engine_var" copy-pipe "$(generate_open_search_command "$engine")" 135 | fi 136 | 137 | done 138 | } 139 | 140 | main() { 141 | set_copy_mode_open_bindings 142 | set_copy_mode_open_editor_bindings 143 | set_copy_mode_open_search_bindings 144 | } 145 | 146 | main 147 | -------------------------------------------------------------------------------- /scripts/helpers.sh: -------------------------------------------------------------------------------- 1 | get_tmux_option() { 2 | local option="$1" 3 | local default_value="$2" 4 | local option_value=$(tmux show-option -gqv "$option") 5 | if [ -z "$option_value" ]; then 6 | echo "$default_value" 7 | else 8 | echo "$option_value" 9 | fi 10 | } 11 | 12 | # Ensures a message is displayed for 5 seconds in tmux prompt. 13 | # Does not override the 'display-time' tmux option. 14 | display_message() { 15 | local message="$1" 16 | 17 | # display_duration defaults to 5 seconds, if not passed as an argument 18 | if [ "$#" -eq 2 ]; then 19 | local display_duration="$2" 20 | else 21 | local display_duration="5000" 22 | fi 23 | 24 | # saves user-set 'display-time' option 25 | local saved_display_time=$(get_tmux_option "display-time" "750") 26 | 27 | # sets message display time to 5 seconds 28 | tmux set-option -gq display-time "$display_duration" 29 | 30 | # displays message 31 | tmux display-message "$message" 32 | 33 | # restores original 'display-time' value 34 | tmux set-option -gq display-time "$saved_display_time" 35 | } 36 | 37 | stored_engine_vars() { 38 | tmux show-options -g | 39 | grep -i "^@open-" | 40 | grep -vi "^@open-editor" | 41 | cut -d '-' -f2 | 42 | cut -d ' ' -f1 | 43 | xargs 44 | } 45 | 46 | get_engine() { 47 | local engine_var="$1" 48 | tmux show-options -g | grep -i "^@open-$engine_var" | cut -d ' ' -f2 | xargs 49 | } 50 | 51 | tmux_version="$(tmux -V | cut -d ' ' -f 2 | sed 's/next-//'))" 52 | tmux-is-at-least() { 53 | if [[ $tmux_version == $1 ]] 54 | then 55 | return 0 56 | fi 57 | 58 | local IFS=. 59 | local i tver=($tmux_version) wver=($1) 60 | 61 | # fill empty fields in tver with zeros 62 | for ((i=${#tver[@]}; i<${#wver[@]}; i++)); do 63 | tver[i]=0 64 | done 65 | 66 | # fill empty fields in wver with zeros 67 | for ((i=${#wver[@]}; i<${#tver[@]}; i++)); do 68 | wver[i]=0 69 | done 70 | 71 | for ((i=0; i<${#tver[@]}; i++)); do 72 | if ((10#${tver[i]} < 10#${wver[i]})); then 73 | return 1 74 | elif ((10#${tver[i]} > 10#${wver[i]})); then 75 | return 0 76 | fi 77 | done 78 | return 0 79 | } 80 | -------------------------------------------------------------------------------- /scripts/tmux_open_error_message.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | 5 | source "$CURRENT_DIR/helpers.sh" 6 | 7 | MISSING_PROGRAM="$1" 8 | 9 | main() { 10 | display_message "tmux-open error! Please make sure '$MISSING_PROGRAM' is installed." 11 | } 12 | main 13 | -------------------------------------------------------------------------------- /video/screencast_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tmux-plugins/tmux-open/763d0a852e6703ce0f5090a508330012a7e6788e/video/screencast_img.png -------------------------------------------------------------------------------- /video/script.md: -------------------------------------------------------------------------------- 1 | # Screencast script 2 | 3 | 1. Intro 4 | ======== 5 | Let's demo tmux-open plugin. 6 | 7 | Tmux open defines 2 copy mode key bindings: o and control-o. 8 | - o is a mnemonic for 'open' and it can open various files, directories and 9 | urls. 10 | - control-o opens files with the default text editor. 11 | 12 | 2. o - features 13 | =============== 14 | Let's first show the 'o' key functionality. 15 | 16 | I'm in a git project so I can invoke 'git status'. 17 | 18 | I want to open that example directory. I'll quickly highlight it using 19 | tmux copycat. 20 | Now I can press 'o' for opening. 21 | 22 | You can see the directory is opened in the OS X Finder app - the default file 23 | manager. 24 | 25 | 26 | I'm also curious about that 'tmux.pdf' file too. 27 | Again, I'll highlight it. 28 | And then press 'o'. 29 | 30 | Oh cool, it's a book about tmux. 31 | 32 | 33 | Nice thing with 'o' key binding is that it works for url's too. 34 | I'll start a local web-server that serves current project README file. 35 | I'll highlight the url, 36 | - press 'o' 37 | - and the url is opened in the default web browser. 38 | 39 | 3. ctrl-o - features 40 | ==================== 41 | Control-o has a more narrow scope: it can open any file in the default text 42 | editor. 43 | 44 | I'll invoke git status again. 45 | There I have a text file I want to open. I'll highlight it, 46 | and press ctrl-o. 47 | 48 | As you can see, the file is opened in vim, which is my default text editor. 49 | 50 | 4. Outro 51 | ======== 52 | That's it for this screencast. I hope you'll find tmux-open plugin useful. 53 | --------------------------------------------------------------------------------